<resource schema="ppmxl">
	<meta name="description" format="rst">
	PPMXL is a catalog of positions, proper motions, 2MASS- and optical
	photometry of 900 million stars and galaxies, aiming to be complete
	down to about V=20 full-sky. It is the result
	of a re-reduction of USNO-B1 together with 2MASS to the ICRS as
	represented by PPMX.  This service additionally provides improved proper
	motions computed according to Vickers et al, 2016
	(:bibcode:`2016AJ....151...99V`).
	</meta>
	<meta name="title">The PPMXL Catalog</meta>
	<meta name="creationDate">2009-10-15T14:01:23</meta>
	<meta name="schema-rank">50</meta>
	<meta name="source">2010AJ....139.2440R</meta>
	<meta name="doi">10.21938/puTViqDkMGcQZu8LSDZ5Sg</meta>

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

	<coverage>
		<spatial>0/0-11</spatial>
		<spectral>8.332e-20 5.369e-19</spectral>
	</coverage>

	<meta name="_longdoc" format="rst"><![CDATA[
		To query this data, you can use

		* a \RSTservicelink{ppmxl/q/cone/form}{web form} (mainly for cone searches)
		* the equivalent SCS service using your favourite VO client (e.g., topcat)
		* our \RSTservicelink{cross/q/match/form}{web-based crossmatcher} to
		  retrieve PPMXL data (e.g., proper motions and photometry) for your
		  object list
		* \RSTservicelink{__system__/adql/query/form}{web-based ADQL} or,
		  preferentially,
		* \RSTservicelink{tap}{TAP} for more advanced queries.
		
		You can retrieve also the whole data set as a
		gzipped text file (43.5 GiB) from the `download service`_.
		The columns in the text file are in database order as
		documented in
		\RSTservicelink{/__system__/dc_tables/show/tableinfo/ppmxl.main?dbOrder=True}{the table info in DB order}
		with columns separated by vertical bars ("|").

		If you run DaCHS yourself, you can use a
		\RSTservicelink{ppmxl/q/corr/static/parseFromDump.c}{C booster}
		kindly provided by Hailong Zhang.  Instructions on
		usage are at the head of the file.

		David Tholen kindly provided
		\RSTservicelink{ppmxl/q/corr/static/reformat-and-split.f90}{code
		to convert} this into a collection
		of files for easy consumption by FORTRAN programs.

		In 2016, John Vickers provided a global correction of the PPMXL proper
		motions based on extragalactic objects (:bibcode:`2016AJ....151...99V`).
		The results are given in the vickers_pmra and vickers_pmde columns.
		The coefficients we used are available at
		\RSTservicelink{ppmxl/q/corr/static/vickers-pmr-coefficients.csv}{pmr-coefficients.csv}
		and
		\RSTservicelink{ppmxl/q/corr/static/vickers-pmd-coefficients.csv}{pmd-coefficients.csv}.
		When used with the \RSTservicelink{ppmxl/q/corr/static/recenter.py}{Code
		we actually used} to compute the corrected values (adding healpix
		interpolation to the upstream from
		https://github.com/johnjvickers/PPMXL_Correction), these files have to be
		renamed pmr.csv and pmd.csv, respectively.

		.. _download service: /ppmxl/q/download
	]]></meta>

	<meta name="creator">Röser, S.; Demleitner, M.; Schilbach, E.; Vickers, J. J.</meta>

	<FEED source="//procs#license-cc0" what="PPMXL"/>

	<meta name="_news" author="MD" date="2011-06-08">
		Silent update: 6169 objects copied from PPMX were affected by a PPMX
		bug that computed Ru magnitudes although at least one 2MASS magnitude
		was NULL.  This resulted in large negative r1mags for these objects
		in PPMXL.  The erroneous magnitudes have been set to NULL.
	</meta>
	<meta name="_news" author="MD" date="2016-04-20">
		Added vickers_pmra and vickers_pmde columns based on a global
		correction model for PPMXL proper motions as discussed in
		2016AJ....151...99V.
	</meta>
	<meta name="_news" author="MD" date="2017-12-15">
		The corrections to USNO-B1 published in the the ppxml.usnocorr table
		had originally been computed against the original USNO-B rather than
		the version cleaned with Barron's list of spurious detections as
		advertised.  This is now corrected.  Individual corrections changed by up
		to 10%.  If you used the table or the service
		ivo://org.gavo.dc/ppmxl/q/corr to correct positions obtained against
		USNO-B1, we advise to repeat the procedure with the corrected values.
	</meta>

	<table id="main" onDisk="True" mixin="//scs#q3cindex" adql="True"
			nrows="900000000">
		<index name="mainid" columns="ipix"/>
		<index name="ra" columns="raj2000"/>
		<index name="dec" columns="dej2000"/>
		<index name="pmra" columns="pmRA"/>
		<index name="pmde" columns="pmDE"/>
		<stc>
			Position ICRS BARYCENTER Epoch J2000.0 "raj2000" "dej2000"
				Error "e_raepRA" "e_deepDE"
			Velocity "pmRA" "pmDE"
				Error "e_pmRA" "e_pmDE"
		</stc>
		<column name="ipix" type="bigint" ucd="meta.id;meta.main"
			required="True"
			description="Identifier (Q3C ipix of the USNO-B 1.0 object)"
			tablehead="Id" verbLevel="5"/>
		<column name="raj2000" type="double precision" ucd="pos.eq.ra;meta.main"
			description="Right Ascension J2000.0, epoch 2000.0"
			tablehead="RA" unit="deg" verbLevel="1"/>
		<column name="dej2000" type="double precision" ucd="pos.eq.dec;meta.main"
			description="Declination J2000.0, epoch 2000.0" tablehead="Dec"
			unit="deg" verbLevel="1"/>
		<column name="e_raepRA" type="real" ucd="stat.error;pos.eq.ra;meta.main"
			description="Mean error in RA*cos(delta) at mean epoch"
			unit="deg" verbLevel="15"/>
		<column name="e_deepDE" type="real" ucd="stat.error;pos.eq.dec;meta.main"
			description="Mean error in Dec at mean epoch"
			unit="deg" verbLevel="15"/>
		<column name="pmRA" type="real" ucd="pos.pm;pos.eq.ra" unit="deg/yr"
			description="Proper Motion in RA*cos(delta)" tablehead="PM(RA)"
			verbLevel="1"/>
		<column name="pmDE" type="real" ucd="pos.pm;pos.eq.dec" unit="deg/yr"
			description="Proper Motion in Dec" tablehead="PM(Dec)"
			verbLevel="1"/>
		<column name="e_pmRA" type="real" ucd="stat.error;pos.pm;pos.eq.ra"
			unit="deg/yr" description="Mean error in pmRA*cos(delta)"
			tablehead="Err. PM(RA)" verbLevel="15"/>
		<column name="e_pmDE" type="real" ucd="stat.error;pos.pm;pos.eq.dec"
			unit="deg/yr" description="Mean error in pmDE"
			tablehead="Err. PM(Dec)" verbLevel="15"/>
		<column name="nobs" type="smallint" ucd="meta.number;obs"
			description="Number of observations used" tablehead="#obs"
			verbLevel="20" note="4">
			<values nullLiteral="-1"/></column>
		<column name="epRA" type="real" ucd="time.epoch;pos.eq.ra"
			unit="yr" description="Mean Epoch (RA)" verbLevel="25"/>
		<column name="epDE" type="real" ucd="time.epoch;pos.eq.dec"
			unit="yr" description="Mean Epoch (Dec)" verbLevel="25"/>
		<column name="Jmag" unit="mag" tablehead="m_J"
			description="J selected default magnitude from 2MASS"
			ucd="phot.mag;em.IR.J" verbLevel="15"/>
		<column name="e_Jmag" unit="mag"
			tablehead="Err(m_J)"
			description="J total magnitude uncertainty"
			ucd="stat.error;phot.mag;em.IR.J" verbLevel="20"/>
		<column name="Hmag" unit="mag" tablehead="m_H"
			description="H selected default magnitude from 2MASS"
			ucd="phot.mag;em.IR.H" verbLevel="15"/>
		<column name="e_Hmag" unit="mag"  tablehead="Err(m_H)"
			description="H total magnitude uncertainty"
			ucd="stat.error;phot.mag;em.IR.H" verbLevel="25"/>
		<column name="Kmag" unit="mag" tablehead="m_K_s"
			description="K_s selected default magnitude from 2MASS"
			ucd="phot.mag;em.IR.K" verbLevel="15"/>
		<column name="e_Kmag" unit="mag" tablehead="Err(m_K_s)"
			description="K_s total magnitude uncertainty"
			ucd="stat.error;phot.mag;em.IR.K" verbLevel="25"/>

		<LOOP>
			<csvItems>
				band, uBand, colName, description
				B, B1, "b1mag", "B mag from USNO-B, first epoch"
				B, B2, "b2mag", "B mag from USNO-B, second epoch"
				R, R1, "r1mag", "R mag from USNO-B, first epoch"
				R, R2, "r2mag", "R mag from USNO-B, second epoch"
				I, I, "imag", "I mag from USNO-B"
			</csvItems>
			<events>
				<column name="\colName" ucd="phot.mag;em.opt.\band"
					description="\description" unit="mag"
					tablehead="USNO mag (\uBand)"
					verbLevel="25" note="1"/>
			</events>
		</LOOP>
		<column name="magSurveys" type="text" ucd="meta.code"
			description="Surveys the USNO-B magnitudes are taken from"
			verbLevel="28" tablehead="USNO Mag src." note="2"/>
		<column name="flags" type="smallint" required="True"
			ucd="meta.code"
			description="Flags" verbLevel="28" note="3"/>

		<column name="vickers_pmra"
			ucd="pos.pm;pos.eq.ra" unit="deg/yr"
			tablehead="PM'(RA)"
			description="Proper motion in RA as re-corrected according
				to 2016AJ....151...99V, cos(delta) applied.  This is only
				available for objects with 2MASS J magnitudes.  e_pmRA still
				is suitable as an error estimate."
			verbLevel="10"/>
		<column name="vickers_pmde"
			ucd="pos.pm;pos.eq.dec" unit="deg/yr"
			tablehead="PM'(Dec)"
			description="Proper motion in Dec as re-corrected according
				to 2016AJ....151...99V.  This is only
				available for objects with 2MASS J magnitudes. e_pmDE still
				is suitable as an error estimate."
			verbLevel="10"/>

		<meta name="note" tag="1"><![CDATA[
			Magnitudes from USNO-B should be used with
			care.  Photometric calibration may be severely off for some
			plates.
			
			For objects from PPMX (bit 1 set in flags), these magnitudes
			have a special meaning as per the following table:

			============ =========== ===============================
			PPMXL column PPMX column PPMX content
			============ =========== ===============================
			   b1mag        Cmag     Catalogue magnitude from source
			   b2mag        Bmag     Johnson B magnitude
			   r1mag        Rmag     calc. Ru magnitude from source
			   r2mag        N/A      always None
			   imag         Vmag     Johnson V magnitude
			============ =========== ===============================

			See also the `PPMX table info </__system__/dc_tables/show/tableinfo/ppmx.data>`_ .
		]]></meta>

		<meta name="note" tag="2">
			magSurveys is built by concatenating
			the digits assigned to the surveys for b1mag, b2mag, r1mag, r2mag,
			and imag (in this sequence).  The digits are those of given in Note h to
			Table 3 in 2003AJ....125..984M, except we do not distinguish
			POSS-II N and SERC-I as a part of POSS-I-N (i.e., both 7 and 9 are
			7 here).
			
			From this field, you can also see which of the surveys contributing
			to USNO-B had positions for the object.</meta>

		<meta name="note" tag="3">
			The flags column contains a bitwise or of
			warnings and similar conditions.  The bit's meaning is as follows:
			
			:bit 0:
				If set, one of the coordinates had an excessively large chisquare.
			:bit 1:
				Row is from PPMX.  These objects are mostly Tycho stars that were
				masked out of USNO-B.  For these, the USNO magnitudes (b1mag through
				imag) have special meanings.  See the note on magnitudes.
			:bit 2:
				Row is from PPMX and replaces a single row from USNO-B.
				This is done when the astrometry from PPMX was better (in terms
				of error estimates) than the astrometry of the corresponding PPMXL
				object.
			:bit 3:
				Row replaces multiple USNO-B1.0 objects.   When
				PPMX contains an object that has more than one counterpart in
				PPMX-L, all such counterparts are discarded on the assumption that
				they should have been matched in USNO-B1.0 or result from erroneous
				matches.  For these rows, bit 1 is always 1.
		</meta>
		<meta name="note" tag="4">
			nobs may be NULL for stars coming from ARIHIP or Tycho-2 via PPMX
			(i.e., bit 1 is set in flags).
		</meta>
	</table>

	<data id="import_rawdata" auto="False">
		<sources>
			<pattern>data/PPMXLnorth.gz</pattern>
			<pattern>data/PPMXLsouth.gz</pattern>
		</sources>
		<directGrammar cBooster="res/boosterfunc.c"
			gzippedInput="True"/>
		<make table="main">

			<!-- pull in 2MASS magnitudes -->
<!--  this takes forever and cannot be watched			<script lang="SQL" type="postCreation" name="join_2mass">
				COMMIT;
				BEGIN;
				SET work_mem=512000;
				UPDATE ppmxl.main
				SET
					Kmag=tm.Kmag, e_Kmag=tm.e_Kmag,
					Jmag=tm.Jmag, e_Jmag=tm.e_Jmag,
					Hmag=tm.Hmag, e_Hmag=tm.e_Hmag
				FROM (
					SELECT ipix, Kmag, e_Kmag, Jmag, e_Jmag, Hmag, e_Hmag
					FROM usnob.twomasscross
					JOIN twomass.data on (twomassid=mainid)) as tm
				WHERE
					tm.ipix=ppmxl.main.ipix;
				COMMIT;
				VACUUM FULL \curtable;
				CLUSTER \curtable;
				VACUUM ANALYZE \curtable;
			</script> -->

			<script lang="SQL" type="postCreation" name="join_2mass">
				COMMIT;
				SET work_mem=800000;
				SET maintenance_work_mem=100000;
				VACUUM FULL ppmxl.main;
				BEGIN;

				CREATE OR REPLACE FUNCTION add2massmags() RETURNS VOID AS $body$
				-- adds 2mass magnitudes to ppmxl.
				-- needs the 2mass to usno-b crossmatch in usnob.twomasscross
				-- (and, of course, twomass.data and ppmxl.main
					DECLARE
						count INTEGER;
						mags CURSOR FOR (SELECT
								ipix, Kmag, e_Kmag, Jmag, e_Jmag, Hmag, e_Hmag
							FROM usnob.twomasscross
							JOIN twomass.data on (twomassid=mainid));
						rec RECORD;
					BEGIN
						count := 0;
						OPEN mags;
						LOOP
							FETCH mags INTO rec;
							EXIT WHEN rec.ipix IS NULL;
							UPDATE ppmxl.main SET
								Kmag=rec.Kmag, e_Kmag=rec.e_Kmag,
								Jmag=rec.Jmag, e_Jmag=rec.e_Jmag,
								Hmag=rec.Hmag, e_Hmag=rec.e_Hmag
							WHERE ipix=rec.ipix;
							count := count+1;
							IF count%10000=0 THEN
								RAISE NOTICE 'Processed %', count;
							END IF;
						END LOOP;
					END
				$body$ LANGUAGE plpgsql;

				SELECT add2massmags();
				DROP FUNCTION add2massmags();

				COMMIT;
				VACUUM ANALYZE ppmxl.main;
				CLUSTER ppmxl.main;
				VACUUM ANALYZE ppmxl.main;
			</script>

			<script lang="SQL" id="insert_ppmx" type="postCreation"
					name="Insert PPMX info into PPMXL">
				COMMIT;
				VACUUM FULL ppmxl.main;
				BEGIN;
				SET work_mem=512000;
				CREATE FUNCTION ts_to_jyear(arg TIMESTAMP) RETURNS REAL AS $body$
				-- return something like 2010.3 in julian.
				-- note that Postgres' definition of julian day differs from the right
				-- one by 12 hours.  We fix this by adapting JD(2000.0) to
				-- postgres' notion
				BEGIN
					RETURN (to_char(arg, 'J')::REAL-2451545.5)/365.25+2000;
				END
				$body$ LANGUAGE plpgsql;

				CREATE FUNCTION ppmxl_insert_ppmxrow(
					pr ppmx.data, in_flags INTEGER) RETURNS VOID AS $body$
				-- insert a ppmx row into ppmxl; flags specifies the reason for the
				-- insertion (see note 3)
				BEGIN
						INSERT INTO ppmxl.main (
							ipix,
							raj2000, dej2000, e_raepRA, e_deepDE,
							pmRA, pmDE, e_pmRA, e_pmDE,
							nobs, epRA, epDE,
							Jmag, e_Jmag, Hmag, e_Hmag, Kmag, e_Kmag,
							b1mag, b2mag, r1mag, imag,
							flags)
						VALUES (
							q3c_ang2ipix(pr.alphaFloat, pr.deltaFloat),
							pr.alphaFloat, pr.deltaFloat, pr.RAErr/3600000.,
							pr.DECErr/3600000.,
							pr.pmRA/3600., pr.pmDE/3600., pr.PMRAErr/3600., pr.PMDEErr/3600.,
							pr.n_obs, ts_to_jyear(pr.epRA), ts_to_jyear(pr.epDE),
							pr.Jmag, pr.e_Jmag, pr.Hmag, pr.e_Hmag, pr.Kmag, pr.e_Kmag,
							pr.Cmag, pr.Bmag, pr.Rmag, pr.Vmag,
							in_flags);
				END
				$body$ LANGUAGE plpgsql;

				CREATE FUNCTION ppmxl_merge_ppmx(pr ppmx.data) RETURNS VOID AS $body$
				-- Take a row from ppmx and merge it into ppmxl in one of three ways.
				DECLARE
					numberMatching INTEGER;
					xlr ppmxl.main; -- the match for pr in ppmxl
				BEGIN
					SELECT count(*) INTO numberMatching FROM ppmxl.main
						WHERE q3c_radial_query(raj2000, dej2000,
							pr.alphaFloat, pr.deltaFloat, 1.5/3600.);

					IF numberMatching=0 THEN -- nothing in ppmxl: add ppmx row
						PERFORM ppmxl_insert_ppmxrow(pr, 2);
						--RAISE NOTICE 'Replaced % %', pr.alphaFloat, pr.deltaFloat;

					ELSEIF numberMatching=1 THEN
					-- compare errors on PMs, then take astrometry from
					-- whichever is better
						SELECT * INTO xlr FROM ppmxl.main
							WHERE q3c_radial_query(raj2000, dej2000,
								pr.alphaFloat, pr.deltaFloat, 1.5/3600.);
						IF xlr.flags&amp;2=2 THEN -- Tycho-2 binary star,
						                          -- already from PPMX, add new
							PERFORM ppmxl_insert_ppmxrow(pr, 2);
						ELSEIF sqrt((pr.PMRAErr/3600.)^2+(pr.PMDEErr/3600.)^2)&lt;
								sqrt((xlr.e_pmRA)^2+(xlr.e_pmDE)^2) THEN
							-- ppmx has better astrometry, update on ppmx
							DELETE FROM ppmxl.main WHERE ipix=xlr.ipix;
							PERFORM ppmxl_insert_ppmxrow(pr, 10);
							--RAISE NOTICE 'Astrometry % %', pr.alphaFloat, pr.deltaFloat;
						-- else ppmxl is better, things are fine as they are
						END IF;

					ELSE
						-- multiple objects matching.  Remove mess from USNO-B and insert
						-- ppmx record(s)
						DELETE FROM ppmxl.main WHERE q3c_radial_query(raj2000, dej2000,
								pr.alphaFloat, pr.deltaFloat, 1.5/3600.);
						PERFORM ppmxl_insert_ppmxrow(pr, 10);
						--RAISE NOTICE 'Replaced many % %', pr.alphaFloat, pr.deltaFloat;
					END IF;
				END
				$body$ LANGUAGE plpgsql;


				SELECT ppmxl_merge_ppmx(ppmx.data.*) FROM ppmx.data;

				DROP FUNCTION ppmxl_merge_ppmx(ppmx.data);
				DROP FUNCTION ppmxl_insert_ppmxrow(ppmx.data, INTEGER);
				DROP FUNCTION ts_to_jyear(TIMESTAMP);
				COMMIT;
				VACUUM ANALYZE ppmxl.main;
				CLUSTER ppmxl.main;
				CLUSTER ppmxl.main;
				VACUUM ANALYZE ppmxl.main;
			</script>
		</make>
	</data>

	<data id="import_dump" auto="False">
		<!-- import data that already has 2MASS mags added; see README -->
		<sources pattern="data/ppmxl-dump.gz"/>
		<directGrammar cBooster="static/parseFromDump.c"
			preFilter="zcat"/>
		<make table="main"/>
	</data>

	<table id="usnocorr" onDisk="True" adql="True" mixin="//scs#q3cindex">
		<mixin>//scs#pgs-pos-index</mixin>
		<meta name="description">Corrections between USNO-B1
			and PPMXL on a grid of degrees, obtained by substracting
			PPMXL from USNO in cones of radius sqrt(2)/2 degrees around
			the given center position.</meta>
		
		<column name="nob" type="integer" required="True"
			tablehead="N"
			description="Number of objects the correction is based on"
			ucd="meta.number" verbLevel="18"/>
		<column name="alpha" type="real" ucd="pos.eq.ra;meta.main"
			description="Center for field, RA" verbLevel="1"
			tablehead="Center RA" unit="deg"/>
		<column name="delta" type="real" ucd="pos.eq.dec;meta.main"
			description="Center for field, Dec" verbLevel="1"
			tablehead="Center Dec" unit="deg"/>
		<column name="d_alpha" type="real" tablehead="PPMXL-USNO, RA"
			description="Correction PPMXL-USNO in alpha (Epoch 2000.0)"
			verbLevel="1" ucd="pos.eq.ra;arith.diff" unit="deg"/>
		<column name="d_delta" type="real" tablehead="PPMXL-USNO, Dec"
			description="Correction PPMXL-USNO in delta (Epoch 2000.0)"
			verbLevel="1" ucd="pos.eq.dec;arith.diff" unit="deg"/>
		<column name="d_pmalpha" type="real" tablehead="PPMXL-USNO, PM RA"
			description="Correction PPMXL-USNO in proper motion alpha*cos(delta)"
			verbLevel="1" ucd="pos.pm;pos.eq.ra;arith.diff" unit="deg/yr"/>
		<column name="d_pmdelta" type="real" tablehead="PPMXL-USNO, PM Dec"
			description="Correction PPMXL-USNO in delta"
			verbLevel="1" ucd="pos.pm;pos.eq.dec;arith.diff" unit="deg/yr"/>
	</table>

	<data id="compute_usnocorr" auto="False">
		<!-- compute raw corrections -->
		<make table="usnocorr">
		<!-- changed the sign of the correction after the fact, hence the
		crazy "-" in front of the selects. -->
			<script type="postCreation" lang="SQL" name="define_corr_functions">
				<![CDATA[
				CREATE OR REPLACE FUNCTION ppmxl_computeOneBCorr(
					centerAlpha REAL, centerDelta REAL) RETURNS SETOF ppmxl.usnocorr AS $$
				DECLARE
					rec RECORD;
				BEGIN
					RAISE NOTICE 'Computing correction for %, %', centerAlpha, centerDelta;
					FOR rec IN (SELECT
							count(*)::integer AS nob,
							centerAlpha::REAL AS alpha,
							centerDelta::REAL AS delta,
							-avg(CASE
								WHEN b.raj2000-a.raj2000<-10 THEN b.raj2000-a.raj2000+360
								WHEN b.raj2000-a.raj2000>10 THEN b.raj2000-a.raj2000-360
								ELSE b.raj2000-a.raj2000 END)::REAL AS d_alpha,
							-avg(b.dej2000-a.dej2000)::REAL AS d_delta,
							-avg(b.pmra-a.pmra)::REAL as d_pmra,
							-avg(b.pmde-a.pmde)::REAL as d_pmde
						FROM (
							SELECT
								ipix,
								raj2000,
								dej2000,
								pmra,
								pmde
							FROM ppmxl.main
							WHERE q3c_radial_query(raj2000, dej2000,
								centerAlpha, centerDelta, 0.70710678)) AS a
						JOIN (
							SELECT
								q3c_ang2ipix(raj2000, dej2000) as ipix,
								raj2000,
								dej2000,
								pmra,
								pmde
							FROM usnob.data
							WHERE q3c_radial_query(raj2000, dej2000,
								centerAlpha, centerDelta, 0.70710678)) AS b
						USING (ipix))
					LOOP
						RETURN NEXT rec;
					END LOOP;
				END;
        $$ LANGUAGE plpgsql;

				CREATE OR REPLACE FUNCTION ppmxl_compute_usnocorr(
					) RETURNS VOID AS $$
				DECLARE
					rec RECORD;
				BEGIN
					FOR rec IN (
						SELECT a+0.5 as centerAlpha, d+0.5 as centerDelta
						FROM
							generate_series(-90, 89) AS d
						CROSS JOIN
							generate_series(0, 359) AS a)
					LOOP
						INSERT INTO ppmxl.usnocorr (
							SELECT * FROM ppmxl_computeOneBCorr(
								rec.centerAlpha, rec.centerDelta));
					END LOOP;
				END;
        $$ LANGUAGE plpgsql;
				
				SELECT ppmxl_compute_usnocorr();

				DROP FUNCTION ppmxl_compute_usnocorr();
				DROP FUNCTION ppmxl_computeOneBCorr(REAL, REAL);
				]]>
			</script>
		</make>
	</data>

	<service id="download" allowed="form">
		<!-- I don't want to have the endless download to be handled by DaCHS,
		as I'd hate it if I'd have to wait for many hours for one of these
		huge downloads to finish.  Thus, I let nginx handle the actual
		download.  This needs something like

        location /ppmxl/ {
                alias /data/gavo/inputs/ppmxl/static/;
        }

		in nginx's vo.ari.conf on alnilam. -->

		<meta name="title">Download Guard for the PPMXL Dump</meta>
		<template key="form">res/downloadguard.html</template>
		<pythonCore>
			<inputTable>
				<inputKey type="text" name="input" multiplicity="single"
					tablehead="I read the warning"
					description="Type in 'yes' here to pull the data"/>
			</inputTable>
			<outputTable/>
			<coreProc>
				<code>
					from gavo import svcs

					if inputTable.getParam("input")=="yes":
						raise svcs.WebRedirect(
							"http://vo.ari.uni-heidelberg.de/ppmxl/dump-for-web.gz")
					else:
						raise base.ValidationError("This must be 'yes' (without any"
							" quotes)", "input")
				</code>
			</coreProc>
		</pythonCore>
	</service>

	<dbCore id="corrcore" queriedTable="usnocorr">
	  <condDesc original="__system__/scs#humanInput">
			<phraseMaker original="__system__/scs#humanSCSPhrase">
				<setup original="__system__/scs#scsSetup" id="proxQuery">
					<code><![CDATA[
						def genQuery(_, inPars, outPars):
							if abs(inPars["DEC"])>=90:
								inPars["DEC"] = 89.5*inPars["DEC"]/abs(inPars["DEC"])
							return ("alpha=floor(%%(%s)s)+0.5 "
								" and delta=floor(%%(%s)s)+0.5")%(
									base.getSQLKey("RA", inPars["RA"], outPars),
									base.getSQLKey("DEC", inPars["DEC"], outPars))
					]]></code>
				</setup>
			</phraseMaker>
			<inputKey name="hscs_sr" description="Ignored"
				tablehead="Ignored" widgetFactory="Hidden">0.1</inputKey>
		</condDesc>

		<condDesc original="//scs#protoInput">
			<phraseMaker original="__system__/scs#scsPhrase">
				<setup original="proxQuery"/>
			</phraseMaker>
		</condDesc>
	</dbCore>

	<service id="corr" core="corrcore" allowed="static,form">
		<property name="staticData">static</property>
		<meta name="shortName">PPMXL USNO corr</meta>
		<publish render="form" sets="local,ivo_managed,gavo"/>
<!--		<template key="response">res/corrform.template</template>-->

		<meta name="title">Corrections between USNO-B and PPMXL</meta>
		<meta name="_related" title="PPMXL">/ppmxl/q/cone/form</meta>
		<meta name="_related" title="USNO-B">/usnob/res/usnob/q/form</meta>
		<meta name="description" format="rst"><![CDATA[
			Differences between USNO-B and PPMXL in positions and proper
			motions, on
			an all-sky one-degree grid. At each gridpoint we give the
			differences X(PPMXL)- X(USNO-B1.0) averaged over all stars in
			a sqrt(2)/2-degrees environment around the gridpoint given. The
			corrections given here should bring USNO-B based astrometry to the ICRS.
			]]></meta>

		<meta name="_intro" format="rst"><![CDATA[
			For information on how to obtain the full correction tables
			or do bulk corrections, see the `service info <./info>`_.
			]]></meta>

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

		<meta name="_longdoc" format="rst"><![CDATA[
			Observers using USNO-B1.0 for the reduction of their CCD frames get
			positions of their targets which are not on the ICRS. Such positions
			can neither be used to derive inertial stellar proper motions, nor
			should they be used for in orbit determinations
			in the case of solar system bodies.
			According to
			`2009DDA....40.1704C <http://ads.ari.uni-heidelberg.de/abs/2009DDA....40.1704C>`_,
			there are millions of minor planet positions based on USNO-B1.0 in recent
			years.

			To aid in reducing these observations to ICRS, we present systematic
			correction tables from USNO-B1.0 to PPMXL for positions at epoch 2000.0
			and for proper motions.
			The tables give means of the differences in positions and
			proper motions between PPMXL and USNO-B1.0 in circles of radius
			sqrt(2)/2 around the centers of 360 by 180 spherical squares covering
			the sky.  The application of these tables is straighforward. Suppose you
			have an observation (α,δ) based on USNO-B1.0 at epoch T (in
			years). To locate the corrections in downloaded tables (see below), compute
			floor(α)+0.5, floor(δ)+0.5 or use the
			\RSTservicelink{/ppmxl/q/corr/form}{web service}.

			The conversion to ICRS is given by
			
			.. image:: ./static/simplecorr.png

			In applying these formulae note that they are not rigorous, with
			the approximations used breaking down close to the poles.
			Also, be careful when crossing α=0 during the correction.

			The full correction table can be downloaded as
			`VOTable </ppmxl/q/corr/static/usnocorr.vot.gz>`_ or
			`plain text </ppmxl/q/corr/static/usnocorr.ascii.gz>`_ .
			
			Here are maps of the corrections over the entire sky for
			RA, Declination and the proper motions:

			.. image:: ./static/usnocorrplots.png
		]]></meta>


	</service>

	<scsCore id="xlcore" queriedTable="main">
		<FEED source="//scs#coreDescs"/>
		<condDesc buildFrom="ipix"/>
	</scsCore>

	<service id="cone" core="xlcore" allowed="form,scs.xml">
		<publish render="scs.xml" sets="ivo_managed"/>
		<publish render="form" sets="local,ivo_managed,gavo"/>

		<meta name="shortName">GAVO PPMXL</meta>
		<meta name="_related" title="ADQL query">/__system__/adql/query/form</meta>
		<meta name="_related" title="Correction to USNO-B">/ppmxl/q/corr/form</meta>
		<meta name="_related" title="Correction to UCAC-3">/ucac3/q/corr/form</meta>
		<meta name="_intro" format="rst">
			For more advanced queries to PPMXL, consider using
			\RSTservicelink{/__system__/adql/query/form}{ADQL}.  See also the
			service info.
		</meta>

		<meta name="testQuery.ra">10</meta>
		<meta name="testQuery.dec">10</meta>
		<meta name="testQuery.sr">0.01</meta>

		<outputTable namePath="main">
			<outputField original="_r"/>
			<outputField original="ipix"/>
			<outputField original="raj2000"/>
			<outputField original="dej2000"/>
			<outputField original="pmRA" displayHint="displayUnit=mas/yr,sf=1"/>
			<outputField original="pmDE" displayHint="displayUnit=mas/yr,sf=1"/>
			<outputField original="e_raepRA" displayHint="displayUnit=mas,sf=1"/>
			<outputField original="e_deepDE" displayHint="displayUnit=mas,sf=1"/>
			<outputField original="e_pmRA" displayHint="displayUnit=mas/yr,sf=1"/>
			<outputField original="e_pmDE" displayHint="displayUnit=mas/yr,sf=1"/>
			<outputField original="Jmag"/>
			<outputField original="Hmag"/>
			<outputField original="Kmag"/>
			<outputField original="b1mag"/>
			<outputField original="b2mag"/>
			<outputField original="imag"/>
			<outputField original="r1mag"/>
			<outputField original="r2mag"/>
		</outputTable>

	</service>

	<regSuite title="PPMXL regression">
			<regTest title="PPMXL corrections service appears to work">
				<url parSet="form" hscs_pos="320,-80">/ppmxl/q/corr/form</url>
				<code>
					self.assertHasStrings('Center RA', '320.5', '14860',
						".000155")
				</code>
			</regTest>

		<regTest title="PPMXL main table values look about right">
			<url RA="231.387614" DEC="-37.626702" SR="0.001"
				VERB="3">cone/scs.xml</url>
			<code>
				row = self.getFirstVOTableRow()
				self.assertEqual(row["Jmag"], None)
				self.assertAlmostEqual(row["epRA"], 1986.6099853515625)
				self.assertEqual(row["vickers_pmde"], None)
			</code>
		</regTest>
	</regSuite>

	<regSuite title="PPMXL citations">
		<regTest title="PPMXL citation instructions have relevant elements">
			<url>/ppmxl/q/cone/howtocite</url>
			<code>
				self.assertHasStrings("This service has an associated publication",
					'class="bibsource"',
					"abs/2010AJ....139.2440R",
					"ADS BibTeX",
					"@MISC{vo:GAVO_PPMXL,",
					"title={The {PPMXL} Catalog},",
					"doi = {10.21938/puTViqDkMGcQZu8LSDZ5Sg}",
					'href="http://creativecommons.org/publicdomain/zero/1.0/"')
			</code>
		</regTest>

		<regTest title="PPMXL citation link in sidebar">
			<url>/ppmxl/q/cone/form</url>
			<code><![CDATA[
				self.assertHasStrings('class="exploHead">Cite this</h4>',
					'/ppmxl/q/cone/howtocite">Advice')
			]]></code>
		</regTest>

		<regTest title="PPMXL table citation">
			<url>/tableinfo/ppmxl.main</url>
			<code>
				self.assertHasStrings("Citing this table&lt;/h2>",
					"@MISC{vo:ppmxl_main",
					"url={", "tableinfo/ppmxl.main},",
					"doi = {10.21938/puTViqDkMGcQZu8LSDZ5Sg}")
			</code>
		</regTest>

		<regTest title="PPMXL cone search contains citation info">
			<url RA="231.387614" DEC="-37.626702" SR="0.00001"
				VERB="1">cone/scs.xml</url>
			<code>
				self.assertXpath("v:RESOURCE/v:INFO[@name='citation'][1]", {
					"value": EqualingRE("http://.*/tableinfo/ppmxl.main"),
					None: EqualingRE("Advice.*")})
			</code>
		</regTest>
	</regSuite>
</resource>
