<resource schema="wfpdb">
	<meta name="creationDate">2015-02-18T15:55:00Z</meta>
	<meta name="schema-rank">100</meta>
	<meta name="title">Wide-Field Plate Database WFPDB</meta>
	<meta name="creator"
		>Tsvetkov, M.K.; Stavrev, K.Y.; Tsvetkova, K.P.; Mutafov, A.S.;
			Semkov, E.H.; Kalaglarsky, D.</meta>
	<meta name="description" format="rst">
		The Wide-Field Plate Database (WFPDB_) contains the descriptive information
		for the astronomical wide-field (>1°) photographic observations stored in
		numerous archives all over the world. The total number of these
		observations, obtained since the end of the 19th century with more
		then 200 instruments (telescopes) is about 2 550 000 from 509 archives.

		The WFPDB is continually being updated, providing currently access to the
		information for about 640 000 plates from 117 plate archives (30% of the
		estimated total number of wide-field plates)

		.. _WFPDB: http://www.skyarchive.org/
	</meta>
	<meta name="source">1995LNP...454..412T</meta>

	<meta name="subject">astrophotography</meta>
	<meta name="subject">history-of-astronomy</meta>

	<meta name="coverage.waveband">Optical</meta>

	<!-- ######################### the observatory/telescope table -->
	<table id="archives" onDisk="True" adql="True" primary="archive_id">
		<meta name="title">WFPDB Archives Table</meta>
		<meta name="description">
			A table of plate archives included in the WFPDB or scheduled
			for inclusion, as well as the properties of the instruments
			used to take the data.
		</meta>

		<column name="instr_id" type="text"
			ucd="meta.id;instr"
			tablehead="Instr. Id"
			description="WFPDB-internal instrument designation"
			verbLevel="1"/>
		<column name="archive_id" type="text"
			ucd="meta.id;meta.main"
			tablehead="Archive Id"
			description="WFPDB-internal archive designation, consisting
				of the instrument id, the archive code, and the site code."/>
		<column name="wfpdb_status" type="text"
			ucd="meta.code"
			tablehead="Inc?"
			description="Inclusion status of plates from this archive:
				* - at disposal in SSADC, not yet converted in computer-readable form,
				** - in preparation in SSADC, converted in computer readable form,
				*** - included in the WFPDB and available on-line."
			verbLevel="15"/>
		<column name="instr_name" type="text"
			ucd="meta.id;instr"
			tablehead="Instr. name"
			description="Original name of the instrument as used by the relevant
				observatory"
			verbLevel="1"/>
		<column name="archive_location" type="text"
			ucd="meta.id;instr.obsty"
			tablehead="Location"
			description="Location of the plate archive"
			verbLevel="15"/>
		<column name="arch_part" type="integer" required="True"
			tablehead="Part"
			description="Code for a sub-archive when an instrument's archive is
				split across several sites"
			verbLevel="25"/>
		<column name="inst_name" type="text"
			tablehead="Institute"
			description="Name of the hosting institution"
			verbLevel="20"/>
		<column name="site_code" type="char" required="True"
			ucd="meta.id"
			tablehead="C"
			description="Code for the instrument site when the instrument was
				operated from several locations."
			verbLevel="25"/>
		<column name="site_name" type="text"
			ucd="meta.id;instr.obsty"
			tablehead="Site"
			description="Observatory site"
			verbLevel="5"/>
		<column name="country" type="text"
			ucd="meta.id;pos.earth"
			tablehead="Country"
			description="Country the observatory is located in."
			verbLevel="25"/>
		<column name="mpc_number" type="integer"
			ucd="meta.id;instr.obsty"
			tablehead="MPC"
			description="Minor Planet Center observatory code"
			verbLevel="15">
			<values nullLiteral="-1"/>
		</column>
		<column name="time_zone"
			unit="h" ucd="time;arith.diff"
			tablehead="Zone"
			description="Time difference to Greenwich"
			verbLevel="15"/>
		<column name="long"
			unit="deg" ucd="pos.earth.lon"
			tablehead="Long."
			description="Geographical longitude of the observatory."
			verbLevel="15"/>
		<column name="lat"
			unit="deg" ucd="pos.earth.lat"
			tablehead="Lat."
			description="Geographical latitude of the observatory."
			verbLevel="15"/>
		<column name="altitude"
			unit="m" ucd="pos.earth.altitude"
			tablehead="Alt."
			description="Altitude of the observatory."
			verbLevel="15"/>
		<column name="n_tubes" type="text"
			ucd="meta.number;instr.tel"
			tablehead="#Tubes"
			description="Number of telescope tubes."
			verbLevel="25">
			<values nullLiteral="1"/>
		</column>
		<column name="aperture"
			unit="m" ucd="phys.size;instr.tel"
			tablehead="Aper."
			description="Clear aperture of the telescope."
			verbLevel="5"/>
		<column name="diameter"
			unit="m" ucd=""
			tablehead="Diameter"
			description="Diameter of the primary mirror or the objective lens"
			verbLevel="5"/>
		<column name="focal_length"
			unit="m" ucd="instr.tel.focalLength"
			tablehead="F.l."
			description="Focal length of the telescope"
			verbLevel="15"/>
		<column name="plate_scale"
			unit="arcsec/mm"
			tablehead="Scale"
			description="Plate scale"
			verbLevel="25"/>
		<column name="inst_type" type="text"
			ucd=""
			tablehead="Type"
			description="Instrument type: Ast-astrograph, Cam-camera, FEC-fish eye
				camera, Men-meniscus, RCr-Ritchey-Chretien, Rfl-reflector,
				Rfr- refractor, Sch-Schmidt"
			verbLevel="15"/>
		<column name="ang_size"
			unit="deg" ucd="phys.angsize;instr.fov"
			tablehead="Size"
			description="Maximum angular size of the field of view."
			verbLevel="15"/>
		<column name="op_begin"
			ucd="time.epoch"
			unit="yr"
			tablehead="From"
			description="Year telescope operations started."
			verbLevel="25"/>
		<column name="op_end"
			ucd="time.epoch"
			unit="yr"
			tablehead="To"
			description="Year telescope operations ended."
			verbLevel="25"/>
		<column name="det_type" type="char"
			ucd="meta.code;instr"
			tablehead="Det"
			description="Detector used:  blank--plate, F--film, X--film and plate"
			verbLevel="25">
			<values nullLiteral="/"/>
		</column>
		<column name="n_direct" type="integer"
			ucd="meta.number;obs"
			tablehead="#Direct"
			description="Number of direct plates in the archive."
			verbLevel="15">
			<values nullLiteral="0"/>
		</column>
		<column name="n_prism" type="integer"
			ucd="meta.number;obs"
			tablehead="#Prism"
			description="Number of prism plates in the archive."
			verbLevel="15">
			<values nullLiteral="0"/>
		</column>
		<column name="contact" type="text"
			tablehead="Contact"
			description="Name of the contact person."
			verbLevel="15"/>
	</table>

	<data id="import_archives">
		<sources pattern="data/Cat*.csv"/>
		<csvGrammar names="instr_id, wfpdb_status, instr_name, archive_location,
			arch_part, ignored, inst_name, ignored, site_code, site_name, country,
			mpc_number, time_zone, long, lat, altitude, n_tubes, aperture,
			diameter, focal_length, plate_scale, inst_type, ang_size, op_begin,
			op_end, det_type, n_direct, ignored, ignored, ignored,
			n_prism, ignored, ignored, contact"/>
		<make table="archives">
			<rowmaker idmaps="*">
				<var key="archive_id"
					>("%s_%s%s"%(@instr_id, @arch_part, @site_code)).strip()</var>
				<map key="lat" nullExcs="ValueError">dmsToDeg(@lat) if @lat else 0.</map>
				<map key="long" nullExcs="ValueError">dmsToDeg(@long) if @long else 0.</map>
			</rowmaker>
		</make>
	</data>


	<!-- ################################ the main (plates) table -->

	<table id="main" onDisk="True" adql="True" primary="wfpdbid"
			mixin="//scs#q3cindex">
		<mixin>//scs#pgs-pos-index</mixin>
		<index columns="epoch"/>
		<index columns="object"/>
		<index columns="object_type"/>
		<index columns="waveband"/>
		<index columns="instr_id"/>

		<foreignKey source="instr_id" inTable="archives" metaOnly="True"/>

		<meta name="title">WFPDB TAP-queriable Table</meta>
		<meta name="description">
			WFPDB's table of plates, including position observed and the
			epoch of observation.
		</meta>

		<column name="instr_id" type="text"
			ucd="meta.id;instr"
			tablehead="Instr."
			description="WFPDB instrument identifier. TDB: Foreign key"
			verbLevel="15"/>
		<column name="wfpdbid" type="text"
			ucd="meta.id;meta.main"
			description="WFPDB identifier of the plate, consisting
				of an observatory identifier, the instrument aperture,
				an instrument suffix, a plate number, and a suffix to it."
			verbLevel="1"/>
			
		<column name="raj2000"
			unit="deg" ucd="pos.eq.ra;meta.main"
			tablehead="RA"
			description="Right ascension of the plate center (ICRS)"
			displayHint="sf=5"
			verbLevel="1"
			note="p"/>
		<column name="dej2000"
			tablehead="Dec"
			unit="deg" ucd="pos.eq.dec;meta.main"
			description="Declination of the plate center (ICRS)"
			displayHint="sf=5"
			verbLevel="1"
			note="p"/>
		<column name="coord_problem" type="text"
			ucd="meta.note"
			tablehead="Coords?"
			description="Quality flag for the coordinates (empty means no known
				problems)"
			verbLevel="15"/>
		<column name="epoch" type="double precision"
			unit="yr" ucd="time.epoch"
			tablehead="Obs. Epoch"
			description="Epoch of observation start (UT)"
			displayHint="type=humanDate"
			verbLevel="1">
			<values min="1858.8788501" max="2189.00616016"/>
		</column>
		<column name="time_problem" type="text"
			ucd="meta.note"
			tablehead="Epoch?"
			description="Quality flag for the epoch (empty means no known
				problems)"
			verbLevel="15"/>
		<column name="object" type="unicode"
			ucd="meta.id;src"
			tablehead="Object"
			description="Object or field name as given by observer"
			verbLevel="5"/>
		<column name="object_type" type="text"
			ucd="src.class"
			tablehead="Type"
			description="Type of the target object"
			verbLevel="15"/>
		<column name="method" type="text"
			ucd="instr.setup"
			tablehead="Method"
			description="Method of observation"
			verbLevel="15"/>
		<column name="exptime"
			unit="s" ucd="time.duration;obs.exposure"
			tablehead="Exp. Time"
			description="Exposure time (for multiple exposures, this is for
				the first exposure; for the others, see notes)"
			verbLevel="15"/>
		<column name="emulsion" type="text"
			ucd="instr.plate.emulsion"
			tablehead="Emulsion"
			description="Emulsion type"
			verbLevel="15"/>
		<column name="filter" type="text"
			ucd="meta.id;instr.filter"
			tablehead="Filter"
			description="Filter type"
			verbLevel="15"/>
		<column name="waveband" type="text"
			ucd="instr.bandpass"
			tablehead="Band"
			description="Spectral Band"
			verbLevel="15"/>
		<column name="xsize"
			unit="cm" ucd="phys.size;instr.det"
			tablehead="Width"
			description="Width of the plate"
			verbLevel="23"/>
		<column name="ysize"
			unit="cm" ucd="phys.size;instr.det"
			tablehead="Height"
			description="Height of the plate"
			verbLevel="23"/>
		<column name="observer" type="unicode"
			ucd="obs.observer"
			tablehead="Observer"
			description="Name(s) of the persons having performed the
				observation."
			verbLevel="23"/>
		<column name="notes" type="unicode"
			ucd="meta.note"
			tablehead="Notes"
			description="Various longer remarks"
			verbLevel="15"/>
		<column name="quality" type="unicode"
			ucd="meta.note"
			tablehead="Quality"
			description="Quality-related information in free text."
			verbLevel="15"/>
		<column name="availability" type="text"
			ucd="meta.note"
			tablehead="Availability"
			description="Free text on how to find the plate."
			verbLevel="25"
			displayHint="type=keephtml"/>
		<column name="digitization" type="unicode"
			ucd="meta.note"
			tablehead="Digitization"
			description="Information on possible ways to access plate scans
				in free text."
			verbLevel="25"/>
		
		<meta name="note" tag="1">
			The identifier in the WFPDB is a string unique for each plate.
			For information, it is currently formed as:

			* 3 characters observatory identifier
			* 3 characters instrument aperture
			* 1 character suffix for disambiguation or similar
			* 6 characters plate number
			* 1 character plate suffix

			This structure is not guaranteed, and it is unwise to rely on
			it in queries.
		</meta>

		<meta name="note" tag="p">
			Positions are from the observatory logs where a plate solution is not
			available.  They are taken from empirical plate solutions otherwise.
		</meta>
	</table>

	<coverage>
		<updater sourceTable="main" mocOrder="4"/>
		<temporal>0 120579</temporal>
		<spatial>0/0-11</spatial>
	</coverage>

	<table id="observers" primary="wfpdbid">
		<meta name="description">
			A helper table for building WFPDB's main.
		</meta>
		<column original="main.wfpdbid"/>
		<column original="main.observer"/>
	</table>

	<table id="notes" primary="wfpdbid">
		<meta name="description">
			A helper table for building WFPDB's main.
		</meta>
		<column original="main.wfpdbid"/>
		<column original="main.notes"/>
	</table>

	<table id="quality" primary="wfpdbid">
		<meta name="description">
			A helper table for building WFPDB's main.
		</meta>
		<column original="main.wfpdbid"/>
		<column original="main.quality"/>
	</table>

	<table id="availability" primary="wfpdbid">
		<meta name="description">
			A helper table for building WFPDB's main.
		</meta>
		<column original="main.wfpdbid"/>
		<column original="main.availability"/>
	</table>

	<table id="digitization" primary="wfpdbid">
		<meta name="description">
			A helper table for building WFPDB's main.
		</meta>
		<column original="main.wfpdbid"/>
		<column original="main.digitization"/>
	</table>

	<procDef type="apply" id="get_from_helper_table">
		<doc>
			Sets destCol from the srcCol field of the entry for dataCol
			in the primary table we get from importing srcData.

			We need this as WFPDB has split the content of its main tables
			over several files.
		</doc>
		<setup>
			<par key="srcCol" description="Column to get the key from."/>
			<par key="dataCol" description="Name of the column to copy."/>
			<par key="srcId" description="id of the data element to
				read the source table"/>
			<code>
				from gavo import rsc

				@utils.memoized
				def getTable():
					return rsc.makeData(rd.getById(srcId)
						).getPrimaryTable()
			</code>
		</setup>
		<code>
			try:
				vars[dataCol] = getTable().getRow(vars[srcCol])[dataCol]
			except KeyError:
				vars[dataCol] = None
		</code>
	</procDef>

	<procDef  type="apply" id="flexinull">
		<doc>WFPDB is quite inconsistent in its use of null values.
		We're trying to cope here by converting, in vars,
		a number of different strings to None</doc>
		<setup>
			<par key="colName" description="name of the source and dest column"/>
			<par key="nullLiterals" description="set of strings that count
				as NULL">frozenset(["NIL", "None", ""])</par>
		</setup>
		<code>
			if vars[colName] in nullLiterals:
				vars[colName] = None
		</code>
	</procDef>

	<data id="import_main">
		<sources pattern="data/*maindata*"/>
		<columnGrammar enc="cp1251" id="maindata_grammar">
			<colDefs>
				wfpdbid: 1-14
				instr_id: 1-7
				plateid: 8-14
				raj2000:15-20
				dej2000:21-27
				coord_problem:28
				epoch:29-42
				time_problem: 43
				object: 44-63
				object_type: 64-65
				method: 66-67
				multex: 68-69
				exptime: 70- 75
				emulsion: 76-86
				filter: 87- 93
				waveband: 94- 95
				xsize: 96- 97
				ysize: 98- 99
			</colDefs>
		</columnGrammar>
		<make table="main">
			<rowmaker idmaps="*">
				<var key="wfpdbid">"%-7s%6s"%(@instr_id, @plateid)</var>
				<apply procDef="//procs#dictMap">
					<bind key="mapping">{
						"E": "Coordinates wrong",
						"M": "Coordinates missing",
						"U": "Coordinates uncertain"}
					</bind>
					<bind key="default">None</bind>
					<bind key="key">"coord_problem"</bind>
				</apply>

				<apply procDef="//procs#dictMap">
					<bind key="mapping">{
						"E": "Epoch error",
						"M": "Epoch missing",
						"U": "Epoch uncertain"}
					</bind>
					<bind key="default">None</bind>
					<bind key="key">"time_problem"</bind>
				</apply>

				<apply procDef="//procs#dictMap">
					<bind key="mapping">{
						"A1": "planet",
						"A2": "moon",
						"A3": "sun",
						"A4": "asteroid",
						"A5": "comet",
						"S1": "star",
						"S2": "double star",
						"S3": "variable star",
						"S4": "star cluster",
						"S5": "HII region",
						"S6": "nebula",
						"S7": "planetary nebula",
						"S8": "supernova",
						"S9": "fundamental star",
						"SR": "reference star around a radio source",
						"G1": "galaxy",
						"G2": "QSO",
						"G3": "group of galaxies",
						"G4": "cluster of galaxies",
						"G5": "supercluster",
						"G6": "void",
						"F": "field",}
					</bind>
					<bind key="default">None</bind>
					<bind key="key">"object_type"</bind>
				</apply>

				<apply procDef="//procs#dictMap">
					<bind key="mapping">{
						"1": "direct photograph",
						"2": "direct photograph, multiexposure",
						"3": "stellar tracks",
						"4": "objective prism",
						"5": "objective prism, multiexposure",
						"6": "Metcalf's method",
						"7": "proper motions",
						"8": "no guiding",
						"9": "out of focus",
						"10": "test plate",
						"11": "Hartmann test",
						"12": "with mask",
						"14": "sub-beam (Pickering) prism",
						"24": "objective grating",}
					</bind>
					<bind key="default">None</bind>
					<bind key="key">"method"</bind>
				</apply>

				<apply>
					<code>
						try:
							@epoch = dateTimeToJYear(
								parseTimestamp(@epoch, "%Y%m%d%H%M%S"))
						except ValueError:
							try:
								@epoch = dateTimeToJYear(
									parseTimestamp(@epoch, "%Y%m%d"))
							except ValueError:
								try:
									@epoch = dateTimeToJYear(
										parseTimestamp(@epoch, "%Y%m"))
								except ValueError:
									@epoch = None
					</code>
				</apply>

				<LOOP listItems="observer notes quality availability digitization">
					<events>
						<apply name="add_\item" procDef="get_from_helper_table">
							<bind key="srcCol">"wfpdbid"</bind>
							<bind key="dataCol">"\item"</bind>
							<bind key="srcId">"import_\item"</bind>
						</apply>
					</events>
				</LOOP>

				<LOOP listItems="filter waveband emulsion">
					<events>
						<apply name="nullify_\item" procDef="flexinull">
							<bind key="colName">"\item"</bind>
						</apply>
					</events>
				</LOOP>

				<map key="exptime">scale(parseFloat(@exptime), 60)</map>
			
				<map key="raj2000" nullExcs="ValueError"
					>hmsToDeg(@raj2000, "")</map>
				<map key="dej2000" nullExcs="ValueError"
					>dmsToDeg(@dej2000, "")</map>
			</rowmaker>
		</make>
	</data>

	<data id="import_observer" auto="False">
		<sources pattern="data/*observer*"/>
		<columnGrammar enc="cp1251" id="observers_grammar">
			<colDefs>
				wfpdbid: 1-14
				observer: 16-57
			</colDefs>
		</columnGrammar>
		<make table="observers"/>
	</data>

	<data id="import_quality" auto="False">
		<sources pattern="data/*quality*"/>
		<columnGrammar enc="cp1251" id="quality_grammar">
			<colDefs>
				wfpdbid: 1-14
				quality: 16-80
			</colDefs>
		</columnGrammar>
		<make table="quality"/>
	</data>

	<data id="import_availability" auto="False">
		<sources pattern="data/*availability*"/>
		<columnGrammar id="availability_grammar">
			<colDefs>
				wfpdbid: 1-14
				availability: 16-246
			</colDefs>
		</columnGrammar>
		<make table="availability"/>
	</data>

	<data id="import_digitization" auto="False">
		<sources pattern="data/*digitization*"/>
		<columnGrammar enc="cp1251">
			<colDefs>
				wfpdbid: 1-14
				digitization: 16-246
			</colDefs>
		</columnGrammar>
		<make table="digitization"/>
	</data>

	<data id="import_notes" auto="False">
		<sources pattern="data/*notes*"/>
		<embeddedGrammar id="notes_grammar">
			<iterator>
				<code>
					# continuation lines, my ass
					with open(self.sourceToken, encoding="cp1251") as f:
						lines = iter(f)
						ln = next(lines)
						lastId, notes = ln[:13].strip(), ln[15:].strip()
						for ln in lines:
							id = ln[:13].strip()
							if lastId==id:
								notes = notes+"\n"+ln[15:].strip()
							else:
								yield {"wfpdbid": lastId, "notes": notes}
								notes = ln[15:].strip()
								lastId = id
						yield {"wfpdbid": lastId, "notes": notes}
				</code>
			</iterator>
		</embeddedGrammar>
		<make table="notes"/>
	</data>


	<!-- ######################### services                        -->

	<service id="cone" allowed="scs.xml,form,external">
		<meta>
			shortName: wfpdb cone
			testQuery.ra: 0
			testQuery.dec: 0
			testQuery.sr: 1
		</meta>

		<publish sets="ivo_managed" render="scs.xml"/>
		<publish render="external" sets="ivo_managed,local">
			<meta name="accessURL">http://skyarchive.org/</meta>
		</publish>

		<scsCore queriedTable="main">
			<FEED source="//scs#coreDescs"/>
			<condDesc buildFrom="wfpdbid"/>
			<condDesc buildFrom="epoch"/>
			<condDesc buildFrom="object"/>
			<condDesc>
				<inputKey original="object_type">
					<values fromdb="object_type from wfpdb.main"/>
				</inputKey>
			</condDesc>
			<condDesc>
				<inputKey original="waveband">
					<values fromdb="waveband from wfpdb.main"/>
				</inputKey>
			</condDesc>
		</scsCore>
	</service>

	<regSuite id="data">
		<regTest title="WFPDB data present">
			<url RA="0.52500" DEC="-89.22170" SR="0.05"
				wfpdbid="AAO390 000001">cone/scs.xml</url>
			<code>
				row = self.getFirstVOTableRow()
				self.assertEqual(row["object"], "POLAR REGION HA+-15M")
				self.assertEqual(row["emulsion"], "IIaO")
				self.assertEqual(row["exptime"], 1800.0)
				self.assertEqual(row["time_problem"], "Epoch missing")
			</code>
		</regTest>
	</regSuite>
</resource>
