<resource schema="feros">
	<meta name="title">FEROS Public Spectra</meta>
	<meta name="creationDate">2012-04-04T13:32:00</meta>
	<meta name="schema-rank">100</meta>
	<meta name="description">
		Spectra from FEROS spectrograph at La Silla's 1.5m telescope as obtained
		during commissioning and guaranteed time.
	</meta>
	<meta name="copyright" format="rst"><![CDATA[
		If you use this data, please reference
		Kaufer, A., et al: Commissioning FEROS, the new high-resolution
		spectrograph at La-Silla, :bibcode:`1999Msngr..95....8K`.
	]]></meta>
	<meta name="creator">Kaufer, A.; Stahl, O.; Tubbesing, S.; Nørregaard,
	P.; Avila, G.; Francois, P.; Pasquini, L.; Pizzella, A.; Wolf, B.</meta>

	<meta name="subject">spectroscopy</meta>
	<meta name="subject">ob-stars</meta>

	<meta name="source">1999Msngr..95....8K</meta>
	<meta name="facility">La Silla ESO 1.5m telescope</meta>
	<meta name="instrument">FEROS</meta>
	<meta name="content.type">Archive</meta>
	<meta name="coverage.waveband">Optical</meta>

	<meta name="_longdoc" format="rst">
	Issues
	------

	The FITS RA and DEC header cards contain positions obtained from the
	telescope guidance system.  These positions are frequently off by several
	arcminutes with respect to the actual object.  Therefore, in the metadata
	table, the positions used for SSA location are obtained from SIMBAD
	whenever the target names could be resolved.

	The nomenclature of objects in the FITS header is somewhat eclectic.  For the
	SSA target name, we use translated names that can be resolved using SIMBAD.
	
	However, there are quite a few names we could no longer make sense of;
	we marked these in the SSA target names with a tilda (~).  For
	these spectra, the SSA location is constructed from the (flaky) positions
	in the RA, DEC header cards.  Any assistance in figuring
	out proper designations for the objects observed is appreciated.

	This service currently only serves data from the commissioning phase
	and from guaranteed time on the instrument.  Spectra taken
	in visitor mode may be available from ESO in unreduced form.

	If you have reduced spectra obtained with FEROS and would like to publish
	them, please do not hesitate to contact gavo@ari.uni-heidelberg.de.
	</meta>

	<table id="headersmeta" onDisk="True" adql="hidden" mixin="//products#table">
		<meta name="description">The basic metadata obtained from the
			spectrum headers (not for user consumption; use the data table
			instead).</meta>

		<index columns="spec_min"/>
		<index columns="spec_max"/>

		<mixin>//ssap#plainlocation</mixin>
		<mixin>//ssap#simpleCoverage</mixin>

		<FEED source="//scs#splitPosIndex"
			long="degrees(long(ssa_location))" lat="degrees(lat(ssa_location))"
			columns="ssa_location"/>
		<FEED source="//ssap#obscore-time-index"
			dateObs="date_obs" timeExt="exptime"/>

		<column name="cleaned_object" type="text"
			ucd="meta.id"
			description="Normalised object name."/>
		<column name="spec_min"
			unit="m"
			description="Minimal wavelength in the spectrum"/>
		<column name="spec_max"
			unit="m"
			description="Maximal wavelength in the spectrum"/>
		<column name="length" type="integer" required="True"
			description="#samples in the spectrum"/>
		<column name="date_obs" type="double precision"
			unit="d"
			description="Date of observation"/>
		<column name="cdate" type="timestamp"
			description="Creation date of the FITS spectrum"/>
		<column name="dstitle" type="text"
			description="Dataset title suitable for display."/>
		<column name="ra" type="double precision"
			description="RA of spectrum's location (possibly from Simbad)."/>
		<column name="dec" type="double precision"
			description="Dec of spectrum's location (possibly from Simbad)."/>
		<column name="exptime" unit="s"
			description="Exposure time"/>
		<column name="pubdid" type="text"
			description="The dataset's publisher DID."/>
		<column name="objtype" type="text"
			description="Type of object observed"/>
	</table>

	<data id="import" recreateAfter="make_view">
		<property key="previewDir">previews</property>
		<sources pattern="data/*.fits"/>
		<fitsProdGrammar qnd="True">
			<ignoreOn name="expungeCalibration">
				<keyIs key="EXPTYPE" value="FLATFIELD"/>
				<keyIs key="EXPTIME" value="0.0000"/>
			</ignoreOn>
			<ignoreOn name="ignoreWeirds">
				<and>
					<keyIs key="RA" value="0." type="real"/>
					<keyIs key="DEC" value="0." type="real"/>
				</and>
			</ignoreOn>
			<rowfilter procDef="//products#define">
				<bind name="table">"\schema.data"</bind>
				<bind name="preview">\standardPreviewPath</bind>
				<bind name="preview_mime">"image/png"</bind>
			</rowfilter>
			<rowfilter name="addSDM">
				<code>
					yield row
					row["prodtblAccref"] = row["prodtblPath"]+".vot"
					row["prodtblPath"] = \fullDLURL{sdl}
					row["prodtblMime"] = "application/x-votable+xml"
					yield row
				</code>
			</rowfilter>
		</fitsProdGrammar>

		<make table="headersmeta">
			<rowmaker idmaps="*" id="make_headerrow">
				<var name="specVal">float(@CRVAL1)</var>
				<var name="specPix">float(@CRPIX1)</var>
				<var name="specDel">float(@CDELT1)</var>
				<var name="specLen">int(@NAXIS1)</var>

				<var name="localKey">vars["FILENAME"].strip()</var>
				<var name="spec_min">(@specVal+(1-@specPix)*@specDel)*1e-10</var>
				<var name="spec_max">(@specVal+(@specLen-@specPix)*@specDel)*1e-10</var>

				<var name="pubdid">\standardPubDID</var>
				<var name="length">@specLen</var>
				<var name="cdate">utils.parseISODT(@DATE.strip())</var>
				<var name="date_obs">float(@MJD_OBS)</var>
				<var name="exptime">float(@EXPTIME)</var>

				<apply name="getObjectName">
					<doc>
					The object name can be in OBJECT or, failing that, in CIDENT.
					This apply leaves whatever is collected in @rawObject,
					which becomes "UNKNOWN" if all fails.
					</doc>
					<code>
						objName = @OBJECT.strip()
						if not objName:
							objName = vars.get("CIDENT", "").strip()
						vars["rawObject"] = objName or "UNKNOWN"
					</code>
				</apply>

				<apply name="cleanObject" procDef="//procs#mapValue">
					<bind name="destination">"cleanedObject"</bind>
					<bind name="failuresMapThrough">True</bind>
					<bind name="value">@rawObject</bind>
					<bind name="sourceName">"feros/res/namefixes.txt"</bind>
				</apply>

				<apply name="classifyObject">
					<doc>
						adds an objClass var based on the value of the object
						header.  Instrument frames are identified here, and their
						processing is cut short.
					</doc>
					<setup>
						<par name="objClasses"> {
							"Ganymede": "planet",
							"ThAr": "instrument",
							"TEST1": "instrument",
						}
						</par>
					</setup>
					<code>
						vars["objtype"] = objClasses.get(@cleanedObject, "star")
						if vars["objtype"]=="instrument":
							raise IgnoreThisRow()
					</code>
				</apply>

				<apply name="addSimbadCoos" procDef="//procs#resolveObject">
					<!-- there are coordinates in the headers, but they come from
					the rather flaky telescope guidance on the ESO 1.52m.  So, when
					we have a Simbad-resolvable object, rather take coordinates
					from there. -->
					<bind name="identifier">@cleanedObject</bind>
				</apply>
				
				<apply procDef="//ssap#fill-plainlocation">
					<bind name="ra">vars.get("simbadAlpha", float(@RA))</bind>
					<bind name="dec">vars.get("simbadDelta", float(@DEC))</bind>
					<bind name="aperture">0.00075</bind>
				</apply>

				<map name="cleaned_object">@cleanedObject</map>
				<map name="dstitle"
						>"Feros %s MJD %s"%(@cleanedObject, @MJD_OBS)</map>
			</rowmaker>
		</make>

	</data>

	<table id="data" onDisk="true" adql="True">
		<mixin
			sourcetable="headersmeta"
			ssa_aperture="0.00075"
			ssa_bandpass="'Optical'"
			ssa_collection="'Feros'"
			ssa_creationtype="'archival'"
			ssa_dateObs="date_obs"
			ssa_datasource="'pointed'"
			ssa_dstitle="dstitle"
			ssa_fluxcalib="'UNCALIBRATED'"
			ssa_instrument="'FEROS'"
			ssa_length="length"
			ssa_location="ssa_location"
			ssa_pubDID="pubdid"
			ssa_region="ssa_region"
			ssa_speccalib="'ABSOLUTE'"
			ssa_specend="spec_max"
			ssa_specext="spec_max-spec_min"
			ssa_specmid="(spec_max+spec_min)/2."
			ssa_specstart="spec_min"
			ssa_specres="0.03e-10"
			ssa_spectralunit="'Angstrom'"
			ssa_targclass="objtype"
			ssa_targname="cleaned_object"
			ssa_timeExt="exptime"
		>//ssap#view</mixin>
		<mixin
			calibLevel="1"
			coverage="ssa_region">//obscore#publishSSAPMIXC</mixin>
		<mixin>//ssap#simpleCoverage</mixin>

		<meta name="_associatedDatalinkService">
			<meta name="serviceId">sdl</meta>
			<meta name="idColumn">ssa_pubDID</meta>
		</meta>
	</table>

	<data id="make_view" auto="False">
		<make table="data"/>
	</data>

	<table id="spectrum">
		<mixin ssaTable="data"
			fluxDescription="Flux relative to continuum"
			spectralDescription="Wavelength"
			>//ssap#sdm-instance</mixin>
	</table>

	<coverage>
		<updater sourceTable="data" mocOrder="6"/>
		<spectral>2.15425e-19 5.64217e-19</spectral>
		<temporal>51093 51394.4</temporal>
		<spatial>6/137,161,183,210,341,689,1102,3003,4419,4614,4892,4920,6161,8210,12544,12864,14646,16667,16807,16821,16834,17171,17395,17425,17578,18094,18139,18206,18416,18468,18549,18712,18775,18915,18978,19017,19097,19202,19402,19585,19959,20145,20331,20523,20699,20823-20824,20828,20915,21060,21083,21177,21289,21316,21394,21402,21418,21421,21436,21438-21439,21447,21456,21482,21515,21638,21643,21646,21665,21704,21744,21746,21833,21962,22023,22088,22333,22448,22466,22517,22615,22707,22787,22805,22828,22854,22888,22895,22911,23190,23236,23342,23369,23375,23533,23547,23637,23669,23769,24212,24312,24713,24839,25246,25487,25554,25766,25789,26975,27884,27903,28352,28491,28804,28921,29005,29116,29196,29360,29711,29893,30040,30106,30176,30293,30859,31227,32956,33027,33076,33091,33094-33095,33097-33098,33100,33102,33112-33113,33121,33123-33124,33211,33294-33295,33304,33306,33317,33328,33351,33490,33717,34278,34502,34577,34792,34896,35064,35079,35327,35532,35702,35768,35948,36365,36379,36612,36664,36693,36697,36711,36850,36942,36956,37186,37212,37232,37244,37253,37307,37327,37333,37339,37353,37358,37362,37395,37452,37639,37660,37729,37787,37790,37826,37831,37865,37871,37881,37886,37916,37922,37924,37926,37930,37934,38002,38016,38018,38023,38045,38049,38051,38238,38382,38411,38566,38660,38682,39216,39267,39281,39374,39396,39486,39532,39645,39671,39832,39863,39877,39899,39923,39937,40410,40584,40593,40617,40716,40828,41171,41339,41472,41591,41630,41648,41689,42101,42274,42394,42407,42416,42714,42862,42959,43024,43033,43075,43141,43152,43310,43365,43407,43748,45408,45676,45821,46053,46079,47056,47091,47125,47246,47916,48072,48152,48534,48736</spatial>
	</coverage>

	<data id="build_sdm_data" auto="False">
		<embeddedGrammar>
			<iterator>
				<setup>
					<code>
						from gavo.protocols import products
						from gavo.utils import pyfits
					</code>
				</setup>
				<code>

				# split off artificial .vot off the accref to get the inputs-relative
				# path to the source FITS.
				accref = self.sourceToken["accref"]
				if accref.endswith(".vot"):
					accref = accref[:-4]
				fitsPath = os.path.join(
					base.getConfig("inputsDir"), accref)
				hdu = pyfits.open(fitsPath)[0]

				crval1, crpix1 = hdu.header["CRVAL1"], hdu.header["CRPIX1"]
				cdelt1 = hdu.header["CDELT1"]

				def specTrans(pixNo):
					return crval1+(pixNo+1-crpix1)*cdelt1

				for spec, flux in enumerate(hdu.data):
					yield {"spectral": specTrans(spec), "flux": flux}
				</code>
			</iterator>
		</embeddedGrammar>
		<make table="spectrum">
			<parmaker>
				<apply procDef="//ssap#feedSSAToSDM"/>
			</parmaker>
		</make>
	</data>

	<service id="sdl" allowed="dlget,dlmeta">
		<meta name="title">FEROS Datalink Service</meta>
		<meta name="_example" title="Usage Example">
			On published datasets like
			:dl-id:`ivo://org.gavo.dc/~?feros/q/f04031.bdf`,
			this service lets you do cutouts, translations into FITS binary
			tables, ASCII, and possibly more, as well as simple recalibration.
		</meta>

		<datalinkCore>
			<descriptorGenerator procDef="//soda#sdm_genDesc" name="dg">
				<bind name="ssaTD">"\rdId#data"</bind>
			</descriptorGenerator>
			<dataFunction procDef="//soda#sdm_genData">
				<bind name="builder">"\rdId#build_sdm_data"</bind>
			</dataFunction>
			<FEED source="//soda#sdm_plainfluxcalib"/>
			<FEED source="//soda#sdm_cutout"/>
			<FEED source="//soda#sdm_format"/>
		</datalinkCore>
	</service>

	<service id="web" defaultRenderer="form">
		<meta name="shortName">FEROS Web</meta>
		<meta name="title">FEROS Public Spectra Web Interface</meta>
		<meta name="_related" title="FEROS SSAP"
			>\internallink{feros/q/ssa/info}</meta>
		
		<dbCore queriedTable="data">
			<condDesc>
				<inputKey original="ssa_targname" showItems="10"
						multiplicity="multiple">
					<values fromdb=
						"ssa_targname from feros.data order by ssa_targname"/>
					<description>
					Somewhat cleaned name of the target object as
					given in the file.  The names should either be SIMBAD-resolvable
					or give a reference for the source.  Some names we could not make
					sense of are marked with a tilda (~); any help figuring out what
					they are is appreciated.
					</description>
				</inputKey>
			</condDesc>
			<condDesc buildFrom="ssa_location"/>
			<condDesc buildFrom="ssa_dateObs"/>
			<condDesc>
				<inputKey original="mime">
					<property name="defaultForForm">application/x-votable+xml</property>
					<values>
						<option title="SDM VOTable">application/x-votable+xml</option>
						<option title="1D FITS image">application/fits</option>
					</values>
				</inputKey>
			</condDesc>
		</dbCore>

		<outputTable>
			<outputField name="dlurl" type="text" select="accref"
				tablehead="Datalink Access"
				description="URL of a datalink document for the dataset
					(cutouts, different formats, etc)">
				<formatter>
					yield T.a(href=getDatalinkMetaLink(
						rd.getById("sdl"), data)
						)["Datalink"]
				</formatter>
				<property name="targetType"
					>application/x-votable+xml;content=datalink</property>
				<property name="targetTitle">Datalink</property>
			</outputField>
			<autoCols>accref, mime, ssa_targname,
				ssa_aperture, ssa_dateObs</autoCols>
			<FEED source="//ssap#atomicCoords"/>
			<outputField original="ssa_specstart" displayHint="displayUnit=Angstrom"/>
			<outputField original="ssa_specend" displayHint="displayUnit=Angstrom"/>
		</outputTable>
	</service>

	<service id="ssa" allowed="form,ssap.xml">
		<meta name="shortName">FEROS SSAP</meta>
		<meta name="ssap.dataSource">pointed</meta>
		<meta name="ssap.testQuery">MAXREC=1</meta>
		<meta name="ssap.creationType">archival</meta>
		<meta name="ssap.complianceLevel">query</meta>
		<publish render="ssap.xml" sets="ivo_managed"/>
		<publish render="form" sets="ivo_managed,local" service="web"/>

		<ssapCore queriedTable="data">
			<property name="previews">auto</property>
			<FEED source="//ssap#hcd_condDescs"/>
		</ssapCore>
	</service>

	<regSuite title="FEROS regression">
		<regTest title="FEROS SSA response looks ok">
			<url REQUEST="queryData"
				POS="64.94834937,15.6276431" SIZE="0.0001"
				TIME="1998-10-09/1998-10-10"
				FORMAT="votable"
				>ssa/ssap.xml</url>
			<code>
				self.assertXpath("//v:FIELD[@name='ssa_datasource']", {
					"utype": "ssa:DataID.DataSource"})
				self.assertXpath("//v:FIELD[@name='ssa_targname']", {
					"utype": "ssa:Target.Name",
					"datatype": "char"})
				self.assertXpath(
					"v:RESOURCE[1]/v:TABLE[1]/v:DATA[1]/v:TABLEDATA[1]/v:TR[1]/v:TD["
						"count(//v:FIELD[@name='ssa_targname']/preceding::v:FIELD)+1]",
					{None: "HD 27371"})
				self.assertXpath(
					"v:RESOURCE[1]/v:TABLE[1]/v:DATA[1]/v:TABLEDATA[1]/v:TR[1]/v:TD["
						"count(//v:FIELD[@name='ssa_datasource']/preceding::v:FIELD)+1]",
					{None: "pointed"})
			
				# "direct SODA" service
				self.assertXpath(
					"v:RESOURCE[@utype='adhoc:service' and "
						"v:PARAM[@name='standardID']/@value='ivo://ivoa.net/std/soda#"
						"sync-1.0']/v:GROUP[@name='inputParams']/v:PARAM[@name='BAND']"
						"/v:VALUES/v:MIN",
						{"value": EqualingRE(r"3.5298\d*e-07")})

				# datalink meta service
				self.assertXpath(
					"v:RESOURCE[@utype='adhoc:service' and "
						"v:PARAM[@name='standardID']/@value='ivo://ivoa.net/std/datalink"
						"#links-1.1']/v:GROUP[@name='inputParams']/v:PARAM[@name='ID']",
						{"ref": "ssa_pubDID"})
			</code>
		</regTest>

		<regTest title="FEROS datalink plausible">
			<url
				Id="feros/data/f04031.fits"
				>sdl/dlmeta</url>
			<code>
				self.assertHasStrings(
					'value="http://', '/feros/q/sdl/dlget"',
					"getproduct/feros/data/f04031.fits?preview=True&lt;/TD>",
					'&lt;MIN value="3.5298')
			</code>
		</regTest>

		<regTest title="FEROS cutout works">
			<url
				BAND="4.5e-7 4.6e-7"
				FLUXCALIB="RELATIVE"
				FORMAT="text/csv"
				ID="feros/data/f04031.fits"
				>sdl/dlget</url>
			<code>
				self.assertHasStrings("4504.59,0.01448")
			</code>
		</regTest>

		<regTest title="FEROS preview">
			<url>/getproduct/feros/data/f04031.fits?preview=True</url>
			<code>
				self.assertHasStrings("PNG", "IDAT")
			</code>
		</regTest>
	</regSuite>
</resource>
