<?xml version="1.0" encoding="utf-8"?>

<resource resdir="ppmx">
	<schema>ppmx</schema>

	<meta name="creationDate">2007-07-23T10:57:33Z</meta>
	<meta name="schema-rank">1000</meta>
	<meta name="title">The PPM-Extended (PPMX) catalogue of positions and proper
	motions</meta>
	<meta name="creator">Röser, S.; Schilbach, E.; Schwan, H.; Kharchenko,
	N.V.; Piskunov, A.; Scholz, R.</meta>
	<meta name="source" >2008A&amp;A...488..401R</meta>

	<meta name="subject">stars</meta>
	<meta name="subject">surveys</meta>
	<meta name="subject">astrometry</meta>
	<meta name="subject">proper-motions</meta>

	<meta name="description">PPM-Extended (PPMX) is a catalogue of 18 088 919 stars on the ICRS system
containing astrometric and photometric information.
Its limiting magnitude is about 15.2 in the GSC photometric system.</meta>
	<meta name="_longdoc" format="rst">
PPM-Extended (PPMX) is a catalogue of 18 088 919 stars on the ICRS system
containing astrometric and photometric information.
Its limiting magnitude is about 15.2 in the GSC photometric system.
PPMX consists of three parts:

1) a survey complete down to RU = 12.8 in the magnitude system of UCAC2;
2) additional stars of high-precision proper motions, and
3) all other stars from GSC 1.2 identified in 2MASS.

The typical accuracy of the proper motions is 2 mas/y for 66 percent of
the survey stars (1) and the high-precision stars (2), and about 10 mas/y
for all other stars. PPMX contains photometric information from
ASCC-2.5 and 2MASS.

We performed a rigorous weighted least-squares adjustment
of individual observations, spread over more than a century,
to determine mean positions and proper motions.
The stellar content of PPMX is taken from GSC 1.2 supplemented
by catalogues like ARIHIP, PPM and Tycho-2 at the bright end.
All observations have been weighted according to their individual
accuracy. The catalogue has been screened towards rejecting false
entries in the various source catalogues.	
	</meta>

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

	<meta name="_news" author="MD" date="2011-02-08">
		Fixed a bug that would give bogus V errors.  Also, warning at this
		point: the Ru magnitudes result from extrapolating 2MASS magnitudes.
		Where those are missing or bad, the Ru magnitudes are bad, too.
	</meta>

	<meta name="_news" author="MD" date="2011-06-06">
		Silent update: 7836 objects had Ru magnitudes computed although at
		least one 2MASS magnitude was NULL.  In consequence, these objects
		had large negative Ru magnitudes.  These erroneous Ru magnitudes
		are now NULL.
	</meta>

	<coverage>
		<spatial>0/0-11</spatial>
	</coverage>

		<STREAM id="positionsFields">
		<doc>
			Old-style positions.  Use naked q3c instead.
		</doc>
		<!-- fill these using the handleEquatorialPosition macro defined below;
		no rowmakers required. -->
		<column name="alphaFloat" unit="deg" type="double precision"
			ucd="pos.eq.ra;meta.main" verbLevel="1"
			tablehead="RA" description="Main value of right ascension"/>
		<column name="deltaFloat" unit="deg" type="double precision"
			ucd="pos.eq.dec;meta.main" verbLevel="1"
			tablehead="Dec" description="Main value of declination"/>
		<column name="c_x" type="real" verbLevel="30"
			tablehead="c_x" unit="" ucd="pos.cartesian.x" description=
				"x coordinate of intersection of radius vector and unit sphere"/>
		<column name="c_y" type="real" verbLevel="30"
			tablehead="c_y" unit="" ucd="pos.cartesian.y" description=
				"y coordinate of intersection of radius vector and unit sphere"/>
		<column name="c_z" type="real" verbLevel="30" tablehead="c_z"
			unit="" ucd="pos.cartesian.z" description=
			"z coordinate of intersection of radius vector and unit sphere"/>
	</STREAM>

	<mixinDef id="positions">
		<doc><![CDATA[
			A mixin adding standardized columns for equatorial positions to the
			table.

			It consists of the fields alphaFloat, deltaFloat (float angles
			in degrees, J2000.0) and c_x, c_y, c_z (intersection of the radius
			vector to alphaFloat, deltaFloat with the unit sphere).

			You will usually use it in conjunction with the eqFloat procDef that
			preparse these fields for you.

			Thus, you could say::

				<proc procDef="eqFloat">
					<arg name="alpha">alphaSrc</arg>
					<arg name="delta">deltaSrc</arg>
				</proc>
			
			Note, however, that it's usually much better to not mess with the
			table structure and handle positions using the q3cindex mixin.
		]]></doc>
		<events>
			<FEED source="positionsFields"/>
		</events>
	</mixinDef>

	<mixinDef id="q3cpositions">
		<doc>
			An extension of `the positions mixin`_ adding a positional index.
		
			This works exactly like the positions interface, except that behind
			the scenes some magic code generates a q3c index on the fields
			alphaFloat and deltaFloat.

			This will fail without the q3c extension to postgres.  Again,
			in general use the plain q3cindex.
		</doc>
		<events>
			<FEED source="positionsFields"/>
		</events>
		<lateEvents>
			<FEED source="//scs#q3cIndexDef"/>
		</lateEvents>
	</mixinDef>

	<procDef id="eqFloat">
		<doc>
			A proc feeding alphaFloat and deltaFloat as well as c_[x|y|z] from
			equatorial coordinates.

			This is now considered a misguided experiment.  Do not use it in new
			RDs.

			Specifically, it generates alphaFloat, deltaFloat as well as
			c_x, c_y, c_z (cartesian coordinates of the intersection of the
			direction vector with the unit sphere).

			TODO: Equinox handling (this will probably be handled through an
			optional arguments srcEquinox and destEquinox, both J2000.0 by default).
			
			Setup pars:

			* raFormat -- the literal format of Right Ascension.  By default,
				a sexagesimal time angle is expected.  Supported formats include
				mas (RA in milliarcsecs), ...
			* decFormat -- as raFormat, only the default is sexagesimal angle.
			* sepChar (optional) -- seperator for alpha, defaults to whitespace
			* alphaKey, deltaKey -- keys to take alpha and delta from.
			
			If alpha and delta use different seperators, you'll have to fix
			this using preprocessing macros.
		</doc>
		<setup>
			<par key="alphaFormat"><description>the literal format of Right
				Ascension.  Supported formats include
				mas (RA in milliarcsecs), hour (hours minutes seconds), sexag
				(degrees minutes seconds), and binary (copy through).
				</description>'hour'</par>
			<par key="deltaFormat" description="see alphaFormat">'sexag'</par>
			<par key="alphaKey" description="name of the column containing the RA"
				>'alpha'</par>
			<par key="deltaKey" description="name of the column containing the
				Declination">'delta'</par>
			<par key="sepChar" description="separator for RA and Dec (default
				means any whitespace)">None</par>
			<code>
				coordComputer = {
					"hour": lambda hms: utils.hmsToDeg(hms, sepChar),
					"sexag": lambda dms: utils.dmsToDeg(dms, sepChar),
					"mas": lambda mas: float(mas)/3.6e6,
					"binary": lambda a: a,
				}
				def convertCoo(literalForm, literal):
					return coordComputer[literalForm](literal)
				def computeCoos(alpha, delta):
					alphaFloat = convertCoo(alphaFormat, alpha)
					deltaFloat = convertCoo(deltaFormat, delta)
					return (alphaFloat, deltaFloat)+tuple(
						coords.computeUnitSphereCoords(alphaFloat, deltaFloat))
			</code>
		</setup>
		<code>
			alpha, delta = vars[alphaKey], vars[deltaKey]
			if alpha is None or delta is None:
				alphaFloat, deltaFloat, c_x, c_y, c_z = [None]*5
			else:
				alphaFloat, deltaFloat, c_x, c_y, c_z = computeCoos(
					alpha, delta)
			result["alphaFloat"] = alphaFloat
			result["deltaFloat"] = deltaFloat
			result["c_x"] = c_x
			result["c_y"] = c_y
			result["c_z"] = c_z
		</code>
	</procDef>

	<table id="data" onDisk="true" adql="True" primary="localid"
			mixin="q3cpositions">
		<stc>
		  Time TT 2000-01-01T00:00:00
			Position ICRS Epoch J2000 "alphaFloat" "deltaFloat"
				Error "RAErr" "DecErr"
				Velocity "pmRA" "pmDE"
					Error "PMRAErr" "PMDEErr"
		</stc>
		<index columns="Cmag"/>
		<index columns="Vmag"/>
		<index columns="pm_total"/>
		<column name="localid" ucd="meta.id;meta.main"
			type="text" tablehead="Identifier" description=
			"Name (IAU convention HHMMSS.s+DDMMSS), p or f appended to desambiguate"
			verbLevel="1"/>
		<column name="pmRA" ucd="pos.pm;pos.eq.ra" type="real"
			tablehead="PM (alpha)" unit="arcsec/yr"
			description="Proper Motion in RA*cos(delta)" verbLevel="9"/>
		<column name="pmDE" ucd="pos.pm;pos.eq.dec" type="real"
			tablehead="PM (delta)" unit="arcsec/yr"
			description="Proper Motion in Dec" verbLevel="9"/>
		<column name="RAErr" ucd="stat.error;pos.eq.ra" type="real"
			tablehead="Err. alpha" unit="mas"
			description="Mean error in RA*cos(DEmas) at epRA"
			verbLevel="15"/>
		<column name="DecErr" ucd="stat.error;pos.eq.dec"
			tablehead="Err. delta" unit="mas" type="real"
			description="Mean error in DE at epDE" verbLevel="15"/>
		<column name="PMRAErr"
			ucd="stat.error;pos.pm;pos.eq.ra" type="real"
			tablehead="Err. PM (alpha)" unit="arcsec/yr"
			description="Mean error in pmRA*cos(DEmas)" verbLevel="21"/>
		<column name="PMDEErr"
			ucd="stat.error;pos.pm;pos.eq.ra" type="real"
			tablehead="Err. PM (delta)" unit="arcsec/yr"
			description="Mean error in pmDE" verbLevel="21"/>
		<column name="epRA" ucd="time.epoch;pos.eq.ra"
			tablehead="Mean Ep. RA" unit="yr" type="date"
			description="Mean Epoch (RA)"
			verbLevel="11"/>
		<column name="epDE" ucd="time.epoch;pos.eq.dec"
			tablehead="Mean Ep. DE" unit="yr" type="date"
			description="Mean Epoch (Dec)"
			verbLevel="11"/>
		<column name="Cmag" ucd="phot.mag" type="real"
			tablehead="Cat. mag." unit="mag"
			description="Catalogue magnitude from source"
			verbLevel="9"/>

		<column name="Rmag" ucd="phot.mag;em.opt.R" type="real"
			tablehead="m_R" unit="mag"
			description="calculated Ru magnitude from source"
			verbLevel="23"/>

		<column name="Bmag" ucd="phot.mag;em.opt.B" type="real"
			tablehead="m_B" unit="mag"
			description="B magnitude in Johnson system" verbLevel="23"/>
		<column name="e_Bmag" ucd="stat.error;phot.mag;em.opt.B"
			type="real" tablehead="Err(m_B)" unit="mag"
			description="Standard error on B magnitude" verbLevel="29"/>

		<column name="Vmag" ucd="phot.mag;em.opt.V"
			tablehead="m_V" unit="mag" type="real"
			description="V magnitude in Johnson system" verbLevel="23"/>
		<column name="e_Vmag" ucd="stat.error;phot.mag;em.opt.V"
			tablehead="Err(m_V)" unit="mag" type="real"
			description="Standard error on V magnitude" verbLevel="29"/>

		<column name="Jmag" ucd="phot.mag;em.IR.J"
			tablehead="m_J" unit="mag" type="real"
			description="J magnitude in Johnson system" verbLevel="23"/>
		<column name="e_Jmag" ucd="stat.error;phot.mag;em.IR.J"
			tablehead="Err(m_J)" unit="mag" type="real"
			description="Standard error on J magnitude" verbLevel="29"/>

		<column name="Hmag" ucd="phot.mag;em.IR.H"
			tablehead="m_H" unit="mag" type="real"
			description="H magnitude in Johnson system" verbLevel="23"/>
		<column name="e_Hmag" ucd="stat.error;phot.mag;em.IR.H"
			tablehead="Err(m_H)" unit="mag" type="real"
			description="Standard error on H magnitude" verbLevel="29"/>

		<column name="Kmag" ucd="phot.mag;em.IR.K"
			tablehead="m_K" unit="mag" type="real"
			description="K magnitude in Johnson system" verbLevel="23"/>
		<column name="e_Kmag" ucd="stat.error;phot.mag;em.IR.K"
			tablehead="Err(m_K)" unit="mag" type="real"
			description="Standard error on K magnitude" verbLevel="29"/>

		<column name="n_obs" type="integer"
			tablehead="#obs in fit" ucd="meta.number;obs"
			description="number of observations in LSQ fit" verbLevel="25">
			<values nullLiteral="-1"/>
		</column>
		<column name="p_flag" type="boolean" required="True"
			ucd="meta.code.qual"
			tablehead="LSQ fit bad?"
			description="True if LSQ fit is bad" verbLevel="25"/>
		<column name="sub_flag" type="text"
			tablehead="Subset flag" ucd="meta.code"
			description="Subset flag"/>

		<column name="srccat" type="char"
			tablehead="Source catalogue" description="Source catalogue"
			ucd="meta.ref">
			<values nullLiteral=" "/>
		</column>
		<column name="srcId" type="text"
			tablehead="Id in source" ucd="meta.id.cross"
			description="Star identifier in the source catalogue"/>

		<column name="pm_total" type="real" displayHint="sf=2"
			tablehead="PM" description="Total proper motion"
			unit="arcsec/yr" verbLevel="15"
			ucd="pos.pm"/>
		<column name="angle_pm" type="real" displayHint="sf=0"
			unit="deg" tablehead="PA of PM" ucd="pos.posAng;pos.pm"
			description="Position angle of total proper motion"
			verbLevel="15"/>

	</table>
	
	<data id="importBoost">
		<sources pattern="data/ppmx.*"/>
		<directGrammar id="booster" cBooster="res/boosterfunc.c"/>
		<make table="data"/>
	</data>


	<service id="scs" allowed="form,scs.xml">
		<publish render="form" sets="local,ivo_managed"/>
		<publish render="scs.xml" sets="ivo_managed"/>
		<meta name="title">PPMX query</meta>

		<meta name="shortName">ppmx_scs</meta>
		<meta name="testQuery.ra">49.83504</meta>
		<meta name="testQuery.dec">19.51816</meta>

		<meta name="_plotOptions">{"xselIndex": 2}</meta>

		<scsCore id="qcore" queriedTable="data">
			<FEED source="//scs#coreDescs"/>
			<condDesc buildFrom="deltaFloat"/>
			<condDesc buildFrom="pm_total"/>
			<condDesc buildFrom="angle_pm"/>
			<condDesc buildFrom="Rmag"/>
			<condDesc buildFrom="Bmag"/>
			<condDesc buildFrom="Vmag"/>
			<condDesc buildFrom="n_obs"/>
			<condDesc buildFrom="localid"/>
		</scsCore>

		<outputTable namePath="data">
			<outputField original="_r"/>
			<outputField original="localid"/>
			<outputField original="alphaFloat" displayHint="type=hms,sf=3"/>
			<outputField original="deltaFloat" displayHint="type=dms,sf=2"/>
			<outputField original="Cmag"/>
			<outputField original="pm_total"/>
			<outputField original="angle_pm"/>
			<outputField original="PMRAErr"/>
			<outputField original="PMDEErr"/>
			<outputField original="n_obs"/>
			<outputField name="aladin" verbLevel="40" type="raw"
				select="array[alphaFloat,deltaFloat]"
				description="View in Aladin"
				tablehead="Aladin" displayHint="noxml=true">
				<formatter>
				aladinPrefix = ("http://aladin.u-strasbg.fr/java/nph-aladin.pl"
						"?frame=launching&amp;script=")
				script = "get aladin() %s %s"%(utils.degToHms(data[0]), utils.degToDms(data[1]))
				return T.a(href=aladinPrefix+urllib.parse.quote(script),
					target="aladin")["[Aladin]"]
				</formatter>
			</outputField>
		</outputTable>
	</service>

	<regSuite id="dachs" title="PPMX DaCHS regression">
		<regTest title="Table info looks credible">
			<url>/tableinfo/ppmx.data</url>
			<code>
				self.assertHasStrings("Table information", "ADQL", "Bmag", "Unit",
					"The following services")
			</code>
		</regTest>

		<regTest title="SCS error reporting 1">
			<url>scs/scs.xml</url>
			<code>
				self.assertHasStrings("VOTABLE",
					'value="Field RA: Required parameter \\'RA\\' missing."')
			</code>
		</regTest>

		<regTest title="SCS error reporting 2">
			<url SR="a" DEC="30" RA="17.0">scs/scs.xml</url>
			<code>
				self.assertHasStrings("VOTABLE",
					"value=\"Field SR: 'a' is not a valid literal for SR")
			</code>
		</regTest>

		<regTest title="SCS successful query, binary with request INFO">
			<url SR="0.006" DEC="19.006" RA="315.376">scs/scs.xml</url>
			<code>
				self.assertHasStrings("VOTABLE", 'encoding="base64">')
				row = self.getFirstVOTableRow()
				self.assertEqual(row["localid"], "210130.2+190021")

				self.assertXpath('//v:INFO[@name="request"]', {
					"value": EqualingRE(r"http.*/ppmx/res/ppmx/scs/scs.xml\\?SR=0.006&amp;DEC=19.006&amp;RA=315.376")})
			</code>
		</regTest>

		<regTest title="SCS successful query, tdenc">
			<url SR="0.006" DEC="19.006" RA="315.376" RESPONSEFORMAT="votabletd"
				>scs/scs.xml</url>
			<code><![CDATA[
				self.assertHasStrings("VOTABLE", "TABLEDATA><TR><TD>1.73",
					"</TD><TD>210130")
			]]></code>
		</regTest>

		<regTest title="SCS successful query, TSV">
			<url SR="0.006" DEC="19.006" RA="315.376"
				RESPONSEFORMAT="tsv" _VERB="HTML">scs/scs.xml</url>
			<code>
				self.assertHasStrings("210130.2+190021\\t315.37599083")
			</code>
		</regTest>

		<regTest title="DB Timeout works on form cone searches">
			<url parSet="form" _DBOPTIONS_ORDER="angle_pm" hscs_sr="5000"
				hscs_pos="10 10" _TIMEOUT="-12">scs/form</url>
			<code>
				self.assertHasStrings(
				"Query timed out (took", "PA of PM")
			</code>
		</regTest>

		<regTest title="SCS query times out gracefully and has request INFO">
			<url MAXREC="100" _DBOPTIONS_ORDER="angle_pm" SR="20"
				RA="20" _TIMEOUT="-12" DEC="20">scs/scs.xml</url>
			<code>
				self.assertXpath('//v:INFO[@ID="Error"]', {
					"value": EqualingRE(r"Field query: Query timed out.*"
						"Unless you know.* please contact .*@.*"),
					"name": "Error"})
				self.assertXpath('//v:INFO[@name="request"]', {
					"value": EqualingRE(r"http.*/ppmx/res/ppmx/scs/scs.xml\\?MAXREC=100&amp;_DBOPTIONS_ORDER=angle_pm&amp;SR=20&amp;RA=20&amp;_TIMEOUT=-12&amp;DEC=20")})
			</code>
		</regTest>

		<regTest title="ADQL region output is DALI compliant.">
			<url parSet="form"
				query="select POINT('fk4', alphaFloat, deltaFloat) as p
					from ppmx.data
					where 1=contains(point('icrs',alphaFloat,deltaFloat),
						circle('icrs', 315.5, 19.05, 0.05))"
				_TDENC="on" _VERB="H" _FORMAT="VOTable" MAXREC="4"
					>/__system__/adql/query/form</url>
			<code><![CDATA[
				self.assertHasStrings(
					'xtype="point"',
					'<TD>315.50138527777773 19.011923055555556</TD>',
					" Query result probably incomplete due to the match limit")
			]]></code>
		</regTest>

		<regTest title="PPMX forms query looks all right">
			<url parSet="form" MAXREC="100" hscs_pos="Arcturus"
				_DBOPTIONS_ORDER="pm_total" hscs_sr="14.0" pm_total=">0.02"
				>/ppmx/res/ppmx/scs/form</url>
			<code>
				self.assertHasStrings("PM: &amp;gt;0.02", "+19 10 56.82", "-114")
			</code>
		</regTest>

		<regTest title="PPMX SCS returns translated UCDs and some
				sensible binary content">
			<url SR="0.05" DEC="19.2" RA="150.0" VERB="1">scs/scs.xml</url>
			<code>
				self.assertXpath('//v:FIELD[@ID="alphaFloat"]', {
					"datatype": "double", "ucd": "POS_EQ_RA_MAIN" })
				self.assertXpath('//v:STREAM',
					{None: EqualingRE(".*AAAADzA5NTk1Ni41KzE5")})
			</code>
		</regTest>

		<regTest title="PPMX SCS returns weird fields with VERB=3.">
			<url SR="0.02" DEC="19.2" RA="150.1" VERB="3"
				>scs/scs.xml</url>
			<code>
				self.assertXpath('//v:FIELD[@ID="c_z"]', {
					"datatype": "float", "ucd": "pos.cartesian.z"})
			</code>
		</regTest>

		<regTest title="PPMX SCS COOSYS present">
			<url SR="0.02" DEC="19.2" RA="150.1" VERB="3"
				>scs/scs.xml</url>
			<code>
				from lxml import etree as lxtree
				tree = lxtree.fromstring(self.data)
				sysId = tree.xpath("//v:FIELD[@name='pmRA']",
					namespaces=self.XPATH_NAMESPACE_MAP)[0].get("ref")
				self.assertEqual(
					tree.xpath("//v:COOSYS[@ID='%s']"%sysId,
						namespaces=self.XPATH_NAMESPACE_MAP)[0].get("system"),
					"ICRS")
			</code>
		</regTest>

		<regTest title="PPMX TAP result has COOSYS">
			<url REQUEST="doQuery" QUERY="SELECT TOP 1 alphaFloat, deltaFloat
				FROM ppmx.data" LANG="ADQL">/tap/sync</url>
			<code>
				from lxml import etree as lxtree
				tree = lxtree.fromstring(self.data)
				sysId = tree.xpath("//v:FIELD[@name='alphaFloat']",
					namespaces=self.XPATH_NAMESPACE_MAP)[0].get("ref")
				self.assertEqual(
					tree.xpath("//v:COOSYS[@ID='%s']"%sysId,
						namespaces=self.XPATH_NAMESPACE_MAP)[0].get("epoch"),
					"J2000.0")
			</code>
		</regTest>

		<regTest title="Coverage requested by a normal client looks like a
				FITS MOC">
			<url>scs/coverage</url>
			<code>
				self.assertHasStrings("XTENSION= 'BINTABLE'",
					"PIXTYPE = 'HEALPIX '",
					"MOCORDER=                    0",
					"\\x00\\x00\\x00\\x04")
			</code>
		</regTest>

		<regTest title="Coverage requested by a browser looks like a PNG">
			<url>
				<httpHeader key="accept">image/png</httpHeader>scs/coverage</url>
			<code>
				self.assertHasStrings("PNG", "IDATx")
			</code>
		</regTest>
	</regSuite>
</resource>
