<!-- Fields description adapted from Vizier, raw data parsing adapted from
astrometry.net -->

<!-- See doc/HOWTO on how to come up with obspos (raw observed positions
from USNOB)
-->

<resource schema="usnob">
	<meta name="creationDate">2008-01-11T16:27:00Z</meta>
	<meta name="schema-rank">200</meta>

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

	<meta name="title">The USNO-B 1.0 Catalog</meta>
	<meta name="description">The USNO-B catalog is an all-sky catalog
		of about 1e9 objects including their proper motions, based on
		scans of several sky surveys conducted between 1950 and the late
		1990ies.</meta>
	<meta name="source">2003AJ....125..984M</meta>
	<meta name="copyright">This service uses code provided by Astrometry.net.
	For more details visit http://astrometry.net.  The field metadata were,
	in part, taken from CDS' Vizier service.</meta>
	<meta name="_related" title="Plate Data">/usnob/res/plates/pq/form</meta>
	<meta name="_related" title="PPMXL">/browse/ppmxl</meta>

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

	<coverage>
		<spatial>0/1-11</spatial>
		<spectral>2.257e-19 5.369e-19</spectral>
	</coverage>

	<table id="data" onDisk="true" mixin="//scs#q3cindex">
		<adql>True</adql>
		<publish sets="ivo_managed,local"/>
		<meta name="description">The USNO-B 1.0 catalogue with Barron's
			spurious detections removed.</meta>
		<meta name="_longdoc" format="rst">
			This is the data table of USNO-B.  Note that this data set is huge,
			and usually your queries will time out unless you specify a
			spatial region to search in.

			The spurious detections listed by Barron et al (2008),
			http://adsabs.harvard.edu/abs/2008AJ....135..414B, have been
			removed, albeit with somewhat generous match radius, so
			17327425 rows rather than 17224285 were deleted.

			Note that the star/galaxy separation flag frequently is
			>11 and !=19, which should not be the case according to the
			documentation.  We left it this way.

			Surveys have been mappend onto characters, with A being the first
			blue survey.  The survey 9 is mapped to survey 8 (i.e., H).
		</meta>


		<index columns="B1S,B1f"/>
		<index columns="R1S,R1f"/>
		<index columns="B2S,B2f"/>
		<index columns="R2S,R2f"/>
		<index columns="I_S,If"/>

<!-- do we want this?  We'd need to compute it...  For SCS, we'd need a main id...
		<column ucd="meta.id;meta.main" name="id" type="text"/> -->
		<column name="RAJ2000" unit="deg"
			description="Right Ascension at Eq=J2000, Ep=J2000"
			ucd="pos.eq.ra;meta.main" type="double precision"
			tablehead="RA (J2000)" verbLevel="1" displayHint="sf=6"/>
		<column name="DEJ2000" unit="deg"
			description="Declination at Eq=J2000, Ep=J2000"
			ucd="pos.eq.dec;meta.main" type="double precision"
			tablehead="DEC (J2000)" verbLevel="1" displayHint="sf=6"/>
		<column name="e_RAdeg" unit="deg"
			description="Mean error on RAdeg*cos(DEdeg) at Epoch"
			ucd="stat.error;pos.eq.ra"
			tablehead="Err(RA)cos(DEC)" verbLevel="11"/>
		<column name="e_DEdeg" unit="deg"
			description="Mean error on DEdeg at Epoch"
			ucd="stat.error;pos.eq.dec" tablehead="Err(DEC)"
			verbLevel="11"/>
		<column name="Epoch" unit="yr" description="Mean epoch of observation"
			ucd="time.epoch" tablehead="Epoch" verbLevel="5"/>
		<column name="pmRA" unit="deg/yr" displayHint="displayUnit=mas/yr,sf=0"
			description="Proper motion in RA" ucd="pos.pm;pos.eq.ra"
			tablehead="pm(RA)" verbLevel="5"/>
		<column name="pmDE" unit="deg/yr" displayHint="displayUnit=mas/yr,sf=0"
			description="Proper motion in DE"
			ucd="pos.pm;pos.eq.dec" tablehead="pm(DEC)" verbLevel="5"/>
		<column name="muPr" description="Total Proper Motion probability"
			ucd="stat.fit.goodness" tablehead="P(pm)"/>
		<column name="e_pmRA" unit="deg/yr" description="Mean error on pmRA"
			ucd="stat.error;pos.pm;pos.eq.ra" tablehead="Err(pm(RA))"
			verbLevel="15" displayHint="displayUnit=mas/yr,sf=0"/>
		<column name="e_pmDE" unit="deg/yr" description="Mean error on pmDE"
			ucd="stat.error;pos.pm;pos.eq.dec" verbLevel="15"
			tablehead="Err(pm(DEC))" displayHint="displayUnit=mas/yr,sf=0"/>
		<column name="fit_RA" unit="deg" description="Mean error on RA fit"
			ucd="stat.error" tablehead="Mean err RA fit" verbLevel="25"/>
		<column name="fit_DE" unit="deg" description="Mean error on DE fit"
			ucd="stat.error" tablehead="Mean err DEC fit" verbLevel="25"/>
		<column name="Ndet" type="smallint" required="True"
			description="Number of detections"
			ucd="meta.number" tablehead="N_detect"
			verbLevel="21"/>
		<column name="Flags" type="char" description="Flags on object"
				ucd="meta.code" tablehead="Flags" note="*">
			<values nullLiteral=" "/>
		</column>
		<column name="B1mag" unit="mag" description="First blue magnitude (B1)"
			ucd="phot.mag;em.opt.B" tablehead="mag(B1)" verbLevel="20"/>
		<column id="survcol" name="B1S" type="char" description="B1 Survey code"
				ucd="meta.id">
			<values id="fieldvalues" nullLiteral=" ">
				<option>A</option>
				<option>B</option>
				<option>C</option>
				<option>D</option>
			</values>
		</column>
		<column name="B1f" type="smallint"
			description="B1 Field number in survey" ucd="meta.id;obs.field"
			tablehead="B1 field#">
			<values nullLiteral="-1"/>
		</column>
		<column name="B1sg" type="char" ucd="src.class.starGalaxy"
			tablehead="B1 star/gal."
			description="B1 Star/galaxy separation, A=Galaxy, L=Star">
			<values nullLiteral=" "/>
		</column>
		<column name="B1xi" unit="deg" description="B1 Residual in X direction"
			tablehead="xi(B1)"
			ucd="stat.fit.residual;pos.cartesian.x"/>
		<column name="B1eta" unit="deg" description="B1 Residual in Y direction"
			tablehead="eta(B1)"
			ucd="stat.fit.residual;pos.eq.dec;arith.diff"/>
		<column name="R1mag" unit="mag" description="First red magnitude (R1)"
			ucd="phot.mag;em.opt.R" tablehead="mag(R1)" verbLevel="20"/>
		<column name="R1S" original="survcol" description="R1 Survey code"/>
		<column name="R1f" type="smallint"
			description="R1 Field number in survey" ucd="meta.id;obs.field"
			tablehead="R1 field#">
			<values nullLiteral="-1"/>
		</column>
		<column name="R1sg" type="char" ucd="src.class.starGalaxy"
			tablehead="R1 star/gal."
			description="R1 Star/galaxy separation, A=Galaxy, L=Star">
			<values nullLiteral=" "/>
		</column>
		<column name="R1xi" unit="deg" description="R1 Residual in X direction"
			tablehead="xi(R1)"
			ucd="stat.fit.residual;pos.cartesian.x"/>
		<column name="R1eta" unit="deg" description="R1 Residual in Y direction"
			tablehead="eta(R1)"
			ucd="stat.fit.residual;pos.eq.dec;arith.diff"/>
		<column name="B2mag" unit="mag" description="Second blue magnitude (B2)"
			ucd="phot.mag;em.opt.B" tablehead="mag(B2)" verbLevel="20"/>
		<column name="B2S" type="char" description="B2 Survey code"
			ucd="meta.id">
			<values nullLiteral=" "/>
		</column>
		<column name="B2f" type="smallint"
			description="B2 Field number in survey" ucd="meta.id;obs.field"
			tablehead="B2 field#">
			<values nullLiteral="-1"/>
		</column>
		<column name="B2sg" type="char" ucd="src.class.starGalaxy"
			tablehead="B2 star/gal."
			description="B2 Star/galaxy separation, A=Galaxy, L=Star">
			<values nullLiteral=" "/>
		</column>
		<column name="B2xi" unit="deg" description="B2 Residual in X direction"
			tablehead="xi(B2)"
			ucd="stat.fit.residual;pos.cartesian.x"/>
		<column name="B2eta" unit="deg" description="B2 Residual in Y direction"
			tablehead="eta(B2)"
			ucd="stat.fit.residual;pos.eq.dec;arith.diff"/>
		<column name="R2mag" unit="mag" description="Second red magnitude (R2)"
			ucd="phot.mag;em.opt.R" tablehead="mag(R2)" verbLevel="20"/>
		<column name="R2S" type="char" description="R2 Survey code"
			ucd="meta.id">
			<values nullLiteral=" "/>
		</column>
		<column name="R2f" type="smallint"
			description="R2 Field number in survey" ucd="meta.id;obs.field"
			tablehead="R2 field#">
			<values nullLiteral="-1"/>
		</column>
		<column name="R2sg" type="char" ucd="src.class.starGalaxy"
			tablehead="R2 star/gal."
			description="R2 Star/galaxy separation, A=Galaxy, L=Star">
			<values nullLiteral=" "/>
		</column>
		<column name="R2xi" unit="deg" description="R2 Residual in X direction"
			tablehead="xi(R2)"
			ucd="stat.fit.residual;pos.cartesian.x"/>
		<column name="R2eta" unit="deg" description="R2 Residual in Y direction"
			tablehead="eta(R2)"
			ucd="stat.fit.residual;pos.eq.dec;arith.diff"/>
		<column name="Imag" unit="mag" description="Infrared (N) magnitude"
			ucd="phot.mag;em.opt.I" tablehead="mag(I)" verbLevel="20"/>
		<column name="I_S" type="char" description="I Survey code"
			ucd="meta.id">
			<values nullLiteral=" "/>
		</column>
		<column name="If" type="smallint"
			description="I Field number in survey" ucd="meta.id;obs.field"
			tablehead="I field#">
			<values nullLiteral="-1"/>
		</column>
		<column name="Isg" type="char" ucd="src.class.starGalaxy"
			tablehead="I star/gal."
			description="I Star/galaxy separation, A=Galaxy, L=Star">
			<values nullLiteral=" "/>
		</column>
		<column name="Ixi" unit="deg" description="I Residual in X direction"
			tablehead="xi(I)"
			ucd="stat.fit.residual;pos.cartesian.x"/>
		<column name="Ieta" unit="deg" description="I Residual in Y direction"
			tablehead="eta(I)"
			ucd="stat.fit.residual;pos.eq.dec;arith.diff"/>

		<meta name="note" tag="*">
			::

				M = Existence in a proper motion catalog,
				s = object on a diffraction spike,
				Y = Correlation with YS4.0 catalog (Monet, in prep.)
		</meta>
	</table>


<!-- import the main usnob catalogue -->
	<data id="import">
		<sources pattern="USNO-B1/*.cat" recurse="True"/>
		<directGrammar id="booster" type="bin"
			cBooster="res/boosterfunc.c" recordSize="80"/>
		<make table="data">
			<script type="postCreation" lang="SQL" name="Define USNOB matcher">
				CREATE OR REPLACE FUNCTION usnob_getmatch(alpha double precision,
					delta double precision, windowSecs float
				) RETURNS SETOF usnob.data AS $$
				DECLARE
					rec RECORD;
				BEGIN
					FOR rec IN (SELECT * FROM usnob.data WHERE
						q3c_join(alpha, delta, raj2000, dej2000, windowSecs/3600.))
					LOOP
						RETURN NEXT rec;
					END LOOP;
				END;
				$$ LANGUAGE plpgsql;
			</script>


		</make>
	</data>


	<table id="spurious" onDisk="True" adql="True" mixin="//scs#q3cindex">
		<mixin>//scs#pgs-pos-index</mixin>
		<meta name="description">Spurious detections in USNO-B 1.0 as
			established by Barron et al, 2008AJ....135..414B.</meta>
		<publish/>
		<meta name="source">2008AJ....135..414B</meta>
		<column name="RA" type="double precision"
			ucd="pos.eq.ra;meta.main" tablehead="RA" unit="deg"
			description="RA of spurious detection"/>
		<column name="DEC" type="double precision"
			ucd="pos.eq.dec;meta.main" tablehead="Dec" unit="deg"
			description="Dec of spurious detection"/>
	</table>

	<!-- Import spurious sources and remove them from main usnob -->
	<data id="deletespur">
		<sources pattern="spuriousEntries/clean_USNOB_spurious_entries.fits"/>
		<fitsTableGrammar/>
		<make table="spurious">
			<script type="postCreation" lang="SQL" name="Remove bad objects">
				SET enable_seqscan=False;
				delete from usnob.data as w where
					q3c_ang2ipix(w.raj2000, w.dej2000) in (
						select
							q3c_ang2ipix(raj2000, dej2000)
								from usnob.data as d
								join usnob.spurious as s
								on q3c_join(ra, dec, raj2000, dej2000, 0.1/3600.))
			</script>
		</make>
	</data>

	<table id="ppmxcross" onDisk="True" adql="True">
		<meta name="description">A crossmatch between USNO-B 1.0 and PPMX.
		</meta>
		<index columns="ipix"/>
		<index columns="ppmxid"/>

		<column name="ipix" type="bigint" required="True"
			tablehead="USNO ipix"
			ucd="meta.id"
			description="q3c ipix value of USNO-B object"/>
		<column name="ppmxid" type="text" tablehead="PPMX id"
			description="PPMX id of matching object"
			ucd="meta.id;meta.main"/>

	</table>

	<data id="usnobPPMX">
		<!-- a crossmatch between PPMX and USNOB -->
		<nullGrammar/>
		<make table="ppmxcross">
			<script type="preIndex" lang="SQL" name="create USNOB-PPMX crossmatch">
				SET work_mem=512000;
				INSERT INTO usnob.ppmxcross (
					SELECT q3c_ang2ipix(raj2000, dej2000) AS ipix, p.localid
					FROM
						ppmx.data AS p,
						usnob.data AS u
					WHERE q3c_join(p.alphaFloat, p.deltaFloat,
						u.raj2000, u.dej2000, 1.5/3600.))
			</script>
		</make>
	</data>

	<table id="twomasscross" onDisk="True" adql="True">
		<meta name="description">A crossmatch between USNO-B 1.0 and 2MASS.
		</meta>
		<index columns="ipix"/>
		<index columns="twomassid"/>
		<column original="ppmxcross.ipix"/>
		<column name="twomassid" type="text" ucd="meta.id;meta.main"
			description="2MASS id of matching object"
			tablehead="2MASS id"/>

	</table>
		
	<data id="usnob2MASS">
		<!-- a crossmatch between usnob and 2mass -->
		<nullGrammar/>
		<make table="twomasscross">
			<script type="preIndex" lang="SQL" name="create USNOB-2MASS crossmatch">
				SET work_mem=20000000;
				INSERT INTO usnob.twomasscross (
					SELECT
						q3c_ang2ipix(u.raj2000, u.dej2000) as ipix,
						t.mainid as twomassid
					FROM
						usnob.data as u
						join twomass.data as t
						on (q3c_join(u.raj2000, u.dej2000, t.raj2000, t.dej2000, 1/3600.))
				)
			</script>
		</make>
	</data>


	<table id="platecorrs" onDisk="True" adql="True"
			namePath="usnob/res/plates#plates">
		<meta name="description">Plate corrections to USNO-B 1.0 based
			on a crossmatch with PPMX</meta>
		<meta name="title">ICRS Corrections by USNO-B1 Plate</meta>
		<meta name="_longdoc">For each plate and each survey, this table
			gives the mean offsets between the positions of the stars common
			to PPMX and USNO-B 1.0 with USNO-B magnitudes between 12.5 and
			13.5.  To find these, the PPMX positions were brought to the
			epoch of the USNO-B plate using the PPMX proper motions.

			Note that the infrared surveys have not been processed
			since we could not figure out how to map the plate data to
			the survey numbers given in USNO-B 1.0.</meta>

		<column original="survey"/>
		<column original="field"/>
		<column name="da" description="Mean offset in alpha"
			tablehead="d(alpha)" unit="deg" ucd="pos.eq.ra;arith.diff"/>
		<column name="dd" description="Mean offset in delta"
			tablehead="d(delta)" unit="deg" ucd="pos.eq.dec;arith.diff"/>
		<column name="nTotal" type="integer" required="True"
			tablehead="N"
			description="Number of objects in estimate" ucd="meta.number"/>
		
		<publish sets="ivo_managed,local"/>
	</table>
	
	<!-- Plate corrections based on a crossmatch to PPMX -->
	<data id="make_platecorrs" auto="False" updating="true">
		<sources item="ignores"/>
		<nullGrammar/>
		<make table="platecorrs">

			<!-- The function usnob_createorigtable creates a temporary table
			origPos containing the original positions for tSurvey and tField.

			The function usnob_crossmatchPPMX works on this table and crossmatches
			it with ppmx.  Yes, this isn't stellar design.
			-->
			<script type="newSource" lang="SQL" name="Make correction functions">
				CREATE OR REPLACE FUNCTION usnob_createorigtable(tSurvey char,
					tField integer, xicol text, etacol text, magcol text,
					surveycol text, fieldcol text, whereannex text
				) RETURNS void AS $$
				BEGIN
					EXECUTE $cr$CREATE TEMP TABLE origPos AS (
						SELECT q.raj2000, q.dej2000,
							q.pos[0]-xi/cos(q.dej2000/180.*3.1415926536) AS alphaEp,
							q.pos[1]+eta AS deltaEp, q.epoch, mag FROM (
								SELECT a.raj2000, a.dej2000,
									movePm(a.raj2000, a.dej2000, a.pmra, a.pmde,
									'2000-01-01T00:00:00', b.epoch) AS pos, a.$cr$
									|| etacol || ' AS eta, a.'
									|| xicol || ' AS xi, b.epoch, a.'
									|| magcol || ' AS mag
							FROM usnob.data AS a, usnob.plates AS b
							WHERE a.' ||
								quote_ident(surveycol) || '=' || quote_literal(tSurvey)
								|| ' AND a.'
								|| quote_ident(fieldcol) || '=' || quote_literal(tField)
								|| ' AND b.survey=' || quote_literal(tSurvey) ||
								' AND b.field=' || quote_literal(tField) || whereannex ||
							') AS q)';
					EXECUTE 'CREATE INDEX q3c_scratch ON
						origPos (q3c_ang2ipix(raj2000, dej2000))';
					EXECUTE 'CLUSTER q3c_scratch ON origPos';
					EXECUTE 'ANALYZE origPos';
				END
				$$ LANGUAGE plpgsql;

				CREATE OR REPLACE FUNCTION usnob_crossmatchPPMX(
				) RETURNS void AS $$
				BEGIN
				EXECUTE 'DROP TABLE IF EXISTS tmpcross';
				EXECUTE $ctt$ CREATE TEMP TABLE tmpcross AS (
					SELECT raj2000, dej2000, alphaEp, deltaEp, epoch, mag, cmag,
						pos[0] as alphaPPMX, pos[1] as deltaPPMX, localid,
						alpha2000P, delta2000P
					FROM (
						SELECT raj2000, dej2000, alphaEp, deltaEp, epoch, mag, cmag,
						 movePm(alphaFloat, deltaFloat, pmra/3600., pmde/3600.,
							'2000-01-01T00:00:00', epoch) AS pos, localid,
							alphaFloat as alpha2000P, deltaFloat as delta2000P
						FROM origPos as a JOIN ppmx.data as b
						ON q3c_join(a.raj2000, a.dej2000,
							b.alphaFloat, b.deltaFloat, 1.5/3600)
						OFFSET 0)
					AS q
					WHERE cmag BETWEEN 12.5 AND 13.5)$ctt$;
				EXECUTE 'CREATE INDEX q3c_cross ON
					tmpcross (q3c_ang2ipix(alphaEp, deltaEp))';
				EXECUTE 'CLUSTER q3c_cross ON tmpcross';
				EXECUTE 'ANALYZE tmpcross';
				EXECUTE 'DROP TABLE origPos';
				END
				$$ LANGUAGE plpgsql;
			</script>

			<!-- This script calls the computeoffsets function repeatedly for
			all known plates.  It's in python since my PL/pgSQL attempts would
			always hit resource limits -->
			<script type="newSource" lang="python" name="usnob_computeOffsets">
				fieldNames = {
					"A": ("b1xi", "b1eta", "b1f", "b1s", "b1mag"),
					"B": ("r1xi", "r1eta", "r1f", "r1s", "r1mag"),
					"C": ("b2xi", "b2eta", "b2f", "b2s", "b2mag"),
					"D": ("r2xi", "r2eta", "r2f", "r2s", "r2mag"),
					"E": ("b2xi", "b2eta", "b2f", "b2s", "b2mag"),
					"F": ("r1xi", "r1eta", "r1f", "r1s", "r1mag"),
					"G": ("r2xi", "r2eta", "r2f", "r2s", "r2mag"),
					"I": ("ixi", "ieta", "if", "i_s", "imag"),
					"H": ("ixi", "ieta", "if", "i_s", "imag"),
				}  # There's a copy of this in redux.rd!

				def findSingleCorrection(conn, survey, field):
					xicol, etacol, fieldcol, surveycol, magcol = fieldNames[survey]
					conn.execute("SELECT usnob_createorigtable(%(survey)s, %(field)s,"
							" %(xicol)s, %(etacol)s, %(magcol)s, %(surveycol)s, "
							" %(fieldcol)s,"+
							" ' AND %s BETWEEN 11 AND 15 '"%magcol+")",
						locals())
					conn.execute("SELECT usnob_crossmatchPPMX()")
					# ignore (ca. 3) objects crossing the stich line in ra here.
					res = conn.query("SELECT sum(da), sum(dd), count(*) FROM"
						" (SELECT alphaPPMX-alphaEp AS da, deltaPPMX-deltaEp AS dd"
						" FROM tmpcross"
						"   WHERE alphappmx-alphaep BETWEEN -0.1 AND 0.1) AS q")
					dAlpha, dDelta, nTotal = list(res)[0]
					if nTotal:
						return dAlpha/float(nTotal), dDelta/float(nTotal), nTotal
					else:
						return None, None, 0

				def getCorrectionsForSurvey(survey):
					table.query("SET work_mem=8000000")
					existing = set(r[0] for r in table.query(
						"SELECT field FROM usnob.platecorrs"
						" WHERE survey=%(survey)s", locals()))
					res = table.query("SELECT field FROM usnob.plates WHERE"
						" survey=%(survey)s", locals())
					items = list(res)
					for count, (field,) in enumerate(items):
						if field in existing:
							continue
						print(survey, field, "(%d/%d)"%(count, len(items)))
						table.query("BEGIN")
						da, dd, nTotal = findSingleCorrection(
							table.connection, survey, field)
						if nTotal:
							table.query("INSERT INTO usnob.platecorrs (survey, field, da, dd,"
								" nTotal) VALUES (%(survey)s, %(field)s, %(da)s,"
								" %(dd)s, %(nTotal)s)", locals())
							print("  ...%d objects -- %f, %f"%(nTotal, dd, dd))
						table.query("COMMIT")

				for survey in fieldNames:
					getCorrectionsForSurvey(survey)
			</script>
		</make>
	</data>


	<dbCore id="qcore" queriedTable="data">
		<condDesc original="//scs#humanInput"/>
		<condDesc original="//scs#protoInput"/>
		<condDesc buildFrom="RAJ2000"/>
		<condDesc buildFrom="DEJ2000"/>
		<condDesc buildFrom="B1mag"/>
		<condDesc buildFrom="B1f" fixedSQL="B1S='A'"/>
		<condDesc buildFrom="B2f" fixedSQL="B2S='C'"/>
		<condDesc buildFrom="R1f" fixedSQL="R1S='B'"/>
		<condDesc buildFrom="R2f" fixedSQL="R2S='D'"/>
	</dbCore>

	<service id="q" core="qcore">
		<meta name="shortName">usnob_q</meta>
		<meta name="title">USNO-B query</meta>
		<meta name="_intro" format="rst"><![CDATA[
		This is a simple cone-search like interface to
		the USNO-B table.  You probably do not want to use this; for
		a form interface to USNO-B, use
		`VizieR's USNO-B Form <http://vizier.u-strasbg.fr/viz-bin/VizieR?-source=I%2F284>`_,
		for advanced queries, our USNO-B table is exposed to our
		\RSTservicelink{__system__/tap/run/tap}{TAP service}.
		]]></meta>
		<outputTable namePath="data">
			<outputField original="RAJ2000"/>
			<outputField original="DEJ2000"/>
			<outputField original="Epoch"/>
			<outputField original="pmRA"/>
			<outputField original="pmDE"/>
			<outputField original="B1mag"/>
			<outputField original="R1mag"/>
			<outputField original="B2mag"/>
			<outputField original="R2mag"/>
			<outputField original="Imag"/>
		</outputTable>
	</service>
	
	<dbCore id="pccore" queriedTable="platecorrs">
		<condDesc>
			<inputKey original="survey" multiplicity="multiple">
				<values fromdb="survey FROM usnob.platecorrs"/>
			</inputKey>
		</condDesc>
		<condDesc buildFrom="field"/>
		<condDesc buildFrom="nTotal"/>
	</dbCore>

	<service id="pc" core="pccore">
		<meta name="shortName">usnob_platecor</meta>
		<meta name="title">Corrections to USNO-B plates from PPMX</meta>
		<meta name="description">This table contains, for each field
			that went into USNO-B1, a correction derived from matching
			the USNO-B1 positions for that plate with the PPMX ones (used
			as a representation of ICRS) and deriving a mean offset of the
			objects from that particular plate for them.  We did not
			attempt to derive magnitude-dependent corrections (although it is
			known that the true residuals depend on both magnitude and color).
		</meta>
		<outputTable namePath="platecorrs">
			<LOOP listItems="field survey nTotal">
				<events>
					<outputField original="\item"/>
				</events>
			</LOOP>
			<outputField original="da" displayHint="displayUnit=arcsec"/>
			<outputField original="dd" displayHint="displayUnit=arcsec"/>
		</outputTable>
	</service>

	<regSuite title="USNO-B1 regressions">
		<regTest title="USNO-B data plausible">
			<url parSet="TAP" QUERY="SELECT * FROM usnob.data
				WHERE dej2000=-89.85 and r1mag between 15 and 16
				and 1=contains(point('', raj2000, dej2000),
					CIRCLE('', 221, -89.85, 0.01))">/tap/sync</url>
			<code>
				rows = self.getVOTableRows()
				self.assertEqual(len(rows), 1)
				row = rows[0]
				self.assertAlmostEqual(row["e_DEdeg"], 1.1111100093330606e-06)
				self.assertAlmostEqual(row["R2mag"], 15.71000003814697)
				self.assertAlmostEqual(row["pmDE"], -2.77778008239693e-06)
				self.assertAlmostEqual(row["Epoch"], 1986.9000244140625)
				self.assertEqual(row["B2eta"], 0.0)
				self.assertEqual(row["B1eta"], None)
			</code>
		</regTest>

		<regTest title="USNO-B data cleaned up (or not)">
			<url parSet="TAP" QUERY="SELECT raj2000, dej2000 FROM usnob.data
				WHERE 1=contains(point('', raj2000, dej2000),
					CIRCLE('', 115.0902, -89.8655, 0.0005))">/tap/sync</url>
			<code>
				# if there's a : in the host part, this decides we're running
				# a "local" test, where the spurious detections have not been
				# cleaned. Otherwise it's the actual service with a cleaned table.
				local = ":" in self.url.httpURL.split("/")[2]
				rows = self.getVOTableRows()
				if local:
					self.assertEqual(len(rows), 1)
				else:
					self.assertEqual(len(rows), 0)
			</code>
		</regTest>

<!--		<regTest title="Platecorrs present" tags="bigserver">
			<url></url>
			<code>
			</code>
		</regTest>-->
	</regSuite>
</resource>
