<resource schema="lotsspol" resdir=".">
	<meta name="creationDate">2022-06-07T12:30:55Z</meta>
	<meta name="schema-rank">100</meta>

	<meta name="title">
		Rotation Measures from the LOFAR Two Meter Sky Survey LoTSS DR2
	</meta>
	<meta name="description" format="rst">
		The LOFAR Two Meter Sky Survey LoTSS DR2
		(:bibcode:`2022A&amp;A...659A...1S`) obtained radio data from 27% of the
		northern sky between 120 and 168 MHz in the year 2014 through 2020.  This
		service publishes polarization spectra of extragalactic radio sources
		(radio galaxies and blazars) and the rotation measures derived from them.
		We also give redshifts for all sources.  The data has a spatial resolution
		of 20 arcsec.
	</meta>
	<meta name="subject">radio-galaxies</meta>
	<meta name="subject">spectropolarimetry</meta>
	<meta name="subject">blazars</meta>

	<meta name="creator">O'Sullivan, S.;
		Shimwell, T. W.; Hardcastle, M. J.; Tasse, C.; Heald, G.; Carretti, E.;
		Brüggen, M.; Vacca, V.; Sobey, C.; C. L. Van Eck; Horellou, C.; Beck, R.;
		Bilicki, M.; Bourke, S.; Botteon, A.; Croston, J. H.; Drabent, A.; Duncan,
		K.; Heesen, V.; Ideguchi, S.; Kirwan, M.; Lawlor, L.; Mingo, B.; Nikiel,
		B.; Wroczyński, J.; Piotrowska, J.; Scaife, A. M. M.; van Weeren, R. J.
	</meta>
	<meta name="instrument">TPDP</meta>
	<meta name="facility">LOFAR</meta>

	<meta name="source">2023arXiv230107697O</meta>
	<meta name="contentLevel">Research</meta>
	<meta name="type">Catalog</meta>

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

	<meta name="ssap.dataSource">pointed</meta>
	<meta name="ssap.creationType">archival</meta>
	<meta name="productType">spectrum</meta>
	<meta name="ssap.testQuery">MAXREC=1</meta>

	<table id="rmtable" onDisk="True" adql="True">
		<meta name="description" format="rst">A table of rotation measures derived
		from the content of \schema.spectra.  This is supposed to be in line with
		RMTable version 1, https://github.com/CIRADA-Tools/RMTable.</meta>

		<meta name="_associatedDatalinkService">
			<meta name="serviceId">sdl</meta>
			<meta name="idColumn">cat_id</meta>
		</meta>

		<column name="cat_id" type="smallint" required="True"
			ucd="meta.id;meta.main"
			tablehead="Cat. #"
			description="Source ID in catalog"
			verbLevel="1"/>
		<column name="ra" type="double precision"
			unit="deg" ucd="pos.eq.ra;meta.main"
			tablehead="RA"
			description="Right Ascension [ICRS] of the polarised emission at epoch
				(this will often be an one extremity of the radio source)."
			displayHint="type=hms,sf=0" verbLevel="1"/>
		<column name="dec" type="double precision"
			unit="deg" ucd="pos.eq.dec;meta.main"
			tablehead="Dec"
			description="Declination [ICRS] of the polarised emission at epoch
				(this will often be an one extremity of the radio source)."
			displayHint="type=dms,sf=0" verbLevel="1"/>
		<column name="datalink" type="text"
			ucd="meta.ref.url"
			tablehead="Spectrum"
			description="Datalink for the spectrum"
			displayHint="type=url" verbLevel="1">
		 <property name="targetType"
			>application/x-votable+xml;content=datalink</property>
			<property name="targetTitle">Datalink</property>
		</column>

		<column name="rm" type="real"
			unit="rad.m**-2" ucd="phys.polarization.rotMeasure;meta.main"
			tablehead="Rot. Meas."
			description="Rotation measure"
			displayHint="sf=3" verbLevel="1"/>
		<column name="rm_err" type="double precision"
			unit="rad.m**-2" ucd="stat.error;phys.polarization.rotMeasure"
			description="Total error in RM"
			tablehead="Err. RM"
			displayHint="sf=4" verbLevel="15"/>
		<column name="rm_err_snr" type="double precision"
			unit="rad.m**-2" ucd="stat.error;phys.polarization.rotMeasure"
			description="Error in RM from signal to noise ratio only"
			verbLevel="25"/>

		<column name="polint" type="double precision"
			unit="Jy" ucd="phot.flux.density;phys.polarization.linear"
			tablehead="Pol. intens."
			description="Polarized intensity"
			displayHint="sf=3" verbLevel="1"/>
		<column name="polint_err" type="real"
			unit="Jy" ucd="stat.error;phot.flux.density;phys.polarization.linear"
			tablehead="Err. Pol.Int."
			description="Error in Polarised Intensity"
			displayHint="sf=3" verbLevel="15"/>

		<column name="fracpol" type="double precision"
			unit="" ucd="phys.polarization.linear"
			description="Fractional (linear) polarization"
			verbLevel="1"/>
		<column name="fracpol_err" type="real"
			unit="" ucd="stat.error;phys.polarization.linear"
			description="Error in fractional polarization"
			verbLevel="15"/>
		<column name="rmsf_fwhm" type="real"
			unit="rad.m**-2" ucd="instr.rmsf;stat.fwhm"
			description="Full-width at half maximum of the RMSF"
			verbLevel="15"/>

		<column name="reffreq_pol" type="real"
			unit="Hz" ucd="em.freq;phys.polarization"
			description="Reference frequency for polarization"
			verbLevel="15"/>
		<column name="l" type="double precision"
			unit="deg" ucd="pos.galactic.lon"
			description="Galactic Longitude"
			verbLevel="25"/>
		<column name="b" type="double precision"
			unit="deg" ucd="pos.galactic.lat"
			description="Galactic Latitude"
			verbLevel="25"/>

		<column name="pos_err" type="double precision"
			unit="deg" ucd="stat.error;pos"
			description="Position uncertainty"
			verbLevel="15"/>
		<column name="beamdist" type="real"
			unit="deg" ucd="pos.angDistance;instr.beam"
			description="Distance from beam centre (taken as centre of tile)"
			verbLevel="25"/>
		<column name="catname" type="text"
			ucd="meta.note"
			description="Name of catalog this was taken from."
			verbLevel="30"/>
		<column name="complex_flag" type="char"
			ucd="meta.code"
			description="Faraday complexity flag"
			verbLevel="15">
			<values nullLiteral="_"/>
		</column>
		<column name="complex_test" type="text"
			ucd="meta.note"
			description="Faraday complexity metric"
			verbLevel="25"/>
		<column name="rm_method" type="text"
			ucd="meta.note"
			description="RM determination method"
			verbLevel="30"/>
		<column name="ionosphere" type="text"
			ucd="meta.note"
			description="Ionospheric correction method"
			verbLevel="30"/>
		<column name="pol_bias" type="text"
			ucd="meta.note"
			description="Polarization bias correction method"
			verbLevel="30"/>
		<column name="flux_type" type="text"
			ucd="meta.note"
			description="Stokes extraction method"
			verbLevel="30"/>
		<column name="beam_maj" type="real"
			unit="deg" ucd="pos.angResolution;instr.beam;phys.angSize.smajAxis"
			description="Beam major axis"
			verbLevel="15"/>
		<column name="beam_min" type="real"
			unit="deg" ucd="pos.angResolution;instr.beam;phys.angSize.sminAxis"
			description="Beam minor axis"
			verbLevel="15"/>
		<column name="beam_pa" type="real"
			unit="deg" ucd="pos.angResolution;instr.beam;pos.posAng"
			description="Beam position angle"
			verbLevel="15"/>
		<column name="reffreq_beam" type="real"
			unit="Hz" ucd="em.freq;instr.beam"
			description="Reference frequency for beam"
			verbLevel="15"/>
		<column name="minfreq" type="real"
			unit="Hz" ucd="em.freq;stat.min"
			description="Lowest frequency"
			verbLevel="1"/>
		<column name="maxfreq" type="real"
			unit="Hz" ucd="em.freq;stat.max"
			description="Highest frequency"
			verbLevel="1"/>
		<column name="channelwidth" type="real"
			unit="Hz" ucd="em.freq;instr.bandwidth"
			description="Typical channel width"
			verbLevel="30"/>
		<column name="noise_chan" type="real"
			unit="Jy" ucd="stat.error;instr.det.noise"
			description="Typical per-channel noise in Q;U"
			verbLevel="15"/>
		<column name="telescope" type="text"
			ucd="instr.tel"
			description="Name of Telescope(s)"
			verbLevel="30"/>
		<column name="int_time" type="real"
			unit="s" ucd="time.duration;obs.exposure"
			description="Integration time"
			verbLevel="25"/>
		<column name="epoch_mjd" type="double precision"
			unit="d" ucd="time.epoch"
			description="Median epoch of observation"
			verbLevel="1"/>
		<column name="obs_interval" type="real"
			unit="d" ucd="time.interval"
			description="Interval of observation"
			verbLevel="30"/>
		<column name="leakage" type="real"
			unit="" ucd="phys.polarization.linear"
			description="Instrumental leakage estimate"
			verbLevel="30"/>
		<column name="dataref" type="text"
			ucd="meta.bib.bibcode"
			description="Data references"
			displayHint="type=bibcode" verbLevel="15"/>
		<column name="notes" type="text"
			ucd="meta.note"
			description="Notes"
			verbLevel="15"/>
		<column name="reffreq_i" type="real"
			unit="Hz" ucd="em.freq;phys.polarization.stokes.I"
			description="Reference frequency for Stokes I"
			verbLevel="15"/>

		<column name="field" type="text"
			ucd="meta.id;obs.field"
			tablehead="LoTSS pointing"
			description="LoTSS observation pointing name"
			verbLevel="1"/>
		<column name="x" type="smallint" required="True"
			unit="pixel" ucd="pos.cartesian.x;instr.det"
			description="x-pixel coordinate within an individual LoTSS field,
				ranging from 0 to 3200, for a pixel width of 4.5 arcsec"
			verbLevel="20"/>
		<column name="y" type="smallint" required="True"
			unit="pixel" ucd="pos.cartesian.y;instr.det"
			description="y-pixel coordinate within an individual LoTSS field, ranging
				from 0 to 3200, for a pixel height of 4.5 arcsec"
			verbLevel="20"/>
		<column name="snr_rmtools_mad" type="double precision"
			unit="" ucd="stat.snr;phot.flux;phys.polarization"
			description="Signal to noise ratio based the peak polarized intensity
				divided by the estimated noise in the Faraday depth spectrum (where the
				noise is computed using the median deviation from the median of the
				polarized intensity, and then correcting to be equivalent to a Gaussian
				sigma)."
			verbLevel="25"/>

		<column name="ra_nvss" type="double precision"
			unit="deg" ucd="pos.eq.ra"
			description="RA of the object in NVSS"
			verbLevel="20"/>
		<column name="dec_nvss" type="double precision"
			unit="deg" ucd="pos.eq.dec"
			description="Dec of the object in NVSS"
			verbLevel="20"/>
		<column name="nvss_rm" type="real"
			unit="rad.m**-2" ucd="phys.polarization.rotMeasure"
			description="Rotation measure of the object in NVSS"
			verbLevel="20"/>
		<column name="nvss_rm_err" type="real"
			unit="rad.m**-2" ucd="stat.error;phys.polarization.rotMeasure"
			description="Error in rotation measure of the object in NVSS"
			verbLevel="25"/>
		<column name="i_nvss" type="real"
			unit="mJy" ucd="phot.flux;phys.polarization.stokes.I"
			description="Integrated Stokes I flux density from NVSS"
			verbLevel="30"/>
		<column name="p_nvss" type="real"
			unit="mJy" ucd="phot.flux;phys.polarization.stokes.I"
			description="Average peak polarized intensity from NVSS"
			verbLevel="30"/>
		<column name="pi_nvss" type="real"
			unit="" ucd="phys.polarization;arith.ratio"
			description="Percent polarization from NVSS"
			verbLevel="30"/>
		<column name="separation_nvss" type="double precision"
			unit="arcsec" ucd="pos.angDistance"
			description="Difference between NVSS position and LoTSS DR2 position"
			verbLevel="30"/>

		<column name="lgz_size" type="double precision"
			unit="arcsec" ucd="phys.angsize;stat.max"
			description="Largest angular size of the source"
			verbLevel="30"/>
		<column name="zphot" type="double precision"
			unit="" ucd="src.redshift.phot"
			description="Photometric redshift derived here from archive photometry
				(WISE, PanSTARRS, etc; cf. 2021A&amp;A...648A...4D)."
			verbLevel="5"/>
		<column name="zphot_err" type="double precision"
			unit="" ucd="stat.error;src.redshift.phot"
			description="Error in zphot"
			verbLevel="15"/>

		<column name="phot_spec_z_best" type="smallint" required="True"
			ucd="meta.code;src.redshift"
			description="Nature of z_best: 0: phot, 1: spec"
			verbLevel="10"/>
		<column name="lgz_ra_deg" type="double precision"
			unit="deg" ucd="pos.eq.ra"
			description="RA of the host galaxy, mainly from NED."
			verbLevel="25"/>
		<column name="lgz_dec_deg" type="double precision"
			unit="deg" ucd="pos.eq.dec"
			description="Dec of the host galaxy, mainly from NED."
			verbLevel="25"/>
		<column name="z_best" type="double precision"
			unit="" ucd="src.redshift"
			description="Best redshift available from the literature, typically
				from NED."
			verbLevel="1"/>

		<column name="num_in_field" type="smallint" required="True"
			ucd="meta.number;src"
			description="Number of polarized sources in the originating pointing."
			verbLevel="25"/>
		<column name="medrm" type="real"
			unit="rad.m**-2" ucd="phys.polarization.rotMeasure;stat.median"
			description="Median RM in the originating pointing."
			verbLevel="25"/>
		<column name="madrm" type="real"
			unit="rad.m**-2" ucd="stat.mad;phys.polarization.rotMeasure"
			description="Median absolute deviation of RM in the originating
				pointing."
			verbLevel="25"/>
		<column name="medfpol" type="real"
			unit="" ucd="phys.polarization;stat.median"
			description="Median degree of polarization in the originating pointing
				(percent)."
			verbLevel="25"/>
		<column name="madfpol" type="real"
			unit="" ucd="stat.mad;phys.polarization"
			description="Median absolute deviation of degree of polarization in the
				originating pointing (percent)."
			verbLevel="25"/>
		<column name="ra_centre" type="double precision"
			unit="deg" ucd="pos.eq.ra;obs.field"
			description="RA of field centre"
			verbLevel="25"/>
		<column name="dec_centre" type="double precision"
			unit="deg" ucd="pos.eq.dec;obs.field"
			description="Dec of field centre"
			verbLevel="25"/>

		<column name="nchan" type="integer"
			ucd="meta.number;em.bin"
			description="Number of channels used in RM derivation"
			verbLevel="15">
			<values nullLiteral="-1"/>
		</column>

		<column name="source_name_dr2" type="text"
			ucd="meta.id"
			tablehead="ILT name"
			description="Official source name assigned by the International
				LOFAR Telescope ILT."
			verbLevel="1"/>
		<column name="ra_dr2" type="double precision"
			unit="deg" ucd="pos.eq.ra"
			description="LoTSS DR2 RA of the centroid of the total radio intensity
				using pyBDSF."
			verbLevel="1"/>
		<column name="dec_dr2" type="double precision"
			unit="deg" ucd="pos.eq.dec"
			description="LoTSS DR2 Dec of the centroid of the total radio intensity
				using pyBDSF."
			verbLevel="1"/>
		<column name="e_ra_dr2" type="double precision"
			unit="deg" ucd="stat.error;pos.eq.ra"
			description="Error in ra_dr2"
			verbLevel="15"/>
		<column name="e_dec_dr2" type="double precision"
			unit="deg" ucd="stat.error;pos.eq.dec"
			description="Error in dec_dr2"
			verbLevel="15"/>
		<column name="total_flux_dr2" type="double precision"
			unit="Jy" ucd="phot.flux;em.radio"
			description="Total radio flux at 144 MHz from pyBDSF."
			verbLevel="1"/>
		<column name="e_total_flux_dr2" type="double precision"
			unit="Jy" ucd="stat.error;phot.flux;em.radio"
			description="Error in total_flux_dr2"
			verbLevel="15"/>
		<column name="maj_dr2" type="double precision"
			unit="arcsec" ucd="phys.angSize.smajAxis"
			description="Semimajor axis of the radio emission"
			verbLevel="15"/>
		<column name="min_dr2" type="double precision"
			unit="arcsec" ucd="phys.angSize.sminAxis"
			description="Semiminor axis of the radio emission"
			verbLevel="15"/>
		<column name="pa_dr2" type="double precision"
			unit="deg" ucd="pos.posAng"
			description="Position angle of the radio emission, north over west"
			verbLevel="15"/>
		<column name="l144" type="double precision"
			unit="W.Hz**-1" ucd="phys.luminosity"
			description="Spectral luminosity at 144 MHz in the rest frame of the
				source"
			verbLevel="15"/>
		<column name="linearsize_kpc" type="double precision"
			unit="kpc" ucd="phys.size"
			description="Projected largest linear size"
			verbLevel="15"/>

		<column name="rrm" type="double precision"
			unit="rad.m**-2" ucd="phys.polarization.rotMeasure;src.net"
			description="The residual RM after subtraction of the average Galactic
				RM within an aperture of radius 1 degree (see the grm column)."
			verbLevel="15" note="galm"/>
		<column name="grm" type="double precision"
			unit="rad.m**-2" ucd="phys.polarization.rotMeasure"
			description="Average Galactic RM within an aperture of radius 1 degree
				from the Garching Faraday rotation sky v2."
			verbLevel="15" note="galm"/>
		<column name="grmerr" type="double precision"
			unit="rad.m**-2" ucd="stat.error;phys.polarization.rotMeasure"
			description="Error in grm."
			verbLevel="25" note="galm"/>

		<column name="bzcat_name" type="text"
			ucd="meta.id.cross"
			description="Blazar source name in the ROMA-BZCAT catalogue
				(2015Ap&amp;SS.357...75M)"
			verbLevel="25"/>

		<meta name="note" tag="galm">
			This is using Version 2 of the Galactic Faraday rotation sky at
			https://wwwmpa.mpa-garching.mpg.de/ ̃ensslin/research/data/faraday2020.html.
		</meta>
	</table>

	<data id="import_cat">
		<sources pattern="*data*/*RMTable.fits"/>
		<fitsTableGrammar nanIsNULL="True" lowerKeys="True"/>
		<make table="rmtable">
			<rowmaker idmaps="*"
				simplemaps="catname: catalog,
					obs_interval: interval,
					num_in_field: num,
					rrm: rrm2022_1deg,
					grm: grm2022_1deg,
					grmerr: grmerr2022_1deg">
				<map key="epoch_mjd" source="epoch"/>
				<map key="datalink">makeAbsoluteURL(
					"\rdId/sdl/dlmeta?ID=\resdir/{:06d}".format(@cat_id))</map>
			</rowmaker>
		</make>
	</data>

	<table id="spectra" onDisk="True" adql="True"
			namePath="//ssap#instance">
		<meta name="description">Spectrally resolved polarisation; for
			pre-derived rotation measures, see \schema.rmtable.  The spectral
			behaviour of the LoTSS Stokes I data are presently unreliable and not
			included here. However, one can use the stokes_i column in
			\schema.rmtable in combination with an assumed radio spectral index to
			produce fractional polarization spectra.
		</meta>
		<LOOP listItems="ssa_location ssa_dateObs ssa_dstitle
			ssa_specstart ssa_specend
			ssa_length ssa_timeExt ssa_targclass">
			<events>
				<column original="\item"/>
			</events>
		</LOOP>

		<mixin>//products#table</mixin>
		<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"/>

		<column name="cat_id" type="bigint" required="True"
			ucd="meta.id;meta.main"
			description="Running number of the source"
			verbLevel="1"/>
		<column name="freq" type="double precision[]"
			unit="Hz" ucd="em.freq"
			description="The spectral coordinate"
			verbLevel="1"/>

		<LOOP listItems="i q u">
			<events>
				<column name="stokes\item" type="double precision[]"
					unit="mJy/beam" ucd="phys.polarization.stokes.\upper{\item}"	
					description="Per-frequency Stokes polarization coefficients
						\upper{\item}"
					verbLevel="1"/>
				<column name="stokes\item\+_error" type="double precision[]"
					unit="mJy/beam" ucd="stat.error;phys.polarization.stokes.\upper{\item}"	
					description="Error in stokes\item"
					verbLevel="15"/>
			</events>
		</LOOP>

		<column name="galactic_location" type="spoint"
			ucd="pos;pos.galactic"
			tablehead="Galactic"
			description="ssa_location expressed in galactic coordinates (do not
				use for querying: there's no index on this)."
			verbLevel="25"/>
	</table>

	<data id="import_spec">
		<recreateAfter>make_view</recreateAfter>
		<sources
			pattern="data/*PolSpectra.fits"/>

		<fitsTableGrammar>
			<rowfilter name="add_accref">
				<setup>
						<par name="pathPattern"
							>makeAbsoluteURL("\rdId/sdl/dlget?ID={}")</par>
				</setup>
				<code>
					@cat_id = @source_number
					@accref = "\resdir/{:06d}".format(@cat_id)
					@path = pathPattern.format(@accref)
					yield row
				</code>
			</rowfilter>

			<rowfilter procDef="//products#define">
				<bind key="accref">@accref</bind>
				<bind key="table">"\schema.spectra"</bind>
				<bind key="path">@path</bind>
				<bind key="fsize">100000</bind>
				<bind key="datalink">"\rdId#sdl"</bind>
				<bind key="mime">"application/x-votable+xml"</bind>
				<bind key="preview">makeAbsoluteURL(
					"\rdId/preview/qp/{}".format(@cat_id))</bind>
				<bind key="preview_mime">"image/png"</bind>
			</rowfilter>
		</fitsTableGrammar>

		<make table="spectra">
			<rowmaker idmaps="*">
				<apply name="add_metadata_from_rmtable">
					<!-- this assumes import_cat has run before us and will crash
					badly if not.  It's ok if it ran in the same transaction, though.
					That's also why we're only reading the metadata late: we
					need the connection of the target table, and setup/code doesn't
					have that.
					-->
					<setup>
						<code>
							def read_meta(conn):
								res = conn.query(
									"select cat_id, epoch_mjd, int_time from \schema.rmtable")
								return dict((cat_id, {"epoch_mjd": epoch, "int_time": int_time})
									for cat_id, epoch, int_time in res)
						</code>
					</setup>
					<code>
						if not hasattr(targetTable, "from_cat"):
							targetTable.from_cat = read_meta(targetTable.connection)
						vars.update(targetTable.from_cat[@cat_id])
					</code>
				</apply>

				<apply procDef="//ssap#fill-plainlocation">
					<bind key="ra">@ra</bind>
					<bind key="dec">@dec</bind>
					<bind key="aperture">1/180.</bind>
				</apply>

				<apply name="clean_arrays">
					<!-- for some reason, there are NaNs on the spectral axis
					in quite a few records.  We  can't have them, but we then
					need to fix the other arrays, too. -->
					<code>
						mask = numpy.isnan(vars["freq"])
						for key in ["freq",
								"stokesI", "stokesI_error",
								"stokesQ", "stokesQ_error",
								"stokesU", "stokesU_error"]:
							if vars[key] is not None:
								vars[key] = vars[key][~mask]
					</code>
				</apply>

				<apply name="infer_targclass">
					<!-- Shane: 'In terms of radio classifications, if "bzcat_name" has
					an entry, then it is a "blazar", otherwise it is a "radio galaxy".

					I'm just assuming the rmtable has already been imported; perhaps
					DaCHS should have a mechanism to ensure that.
					-->
					<setup imports="functools">
						<code>
							@functools.cache
							def get_bznames(conn):
								return dict(
									conn.query("SELECT cat_id, bzcat_name"
									" FROM \schema.rmtable"))
						</code>
					</setup>
					<code>
						if get_bznames(targetTable.connection)[@cat_id]:
							@ssa_targclass = "blazar"
						else:
							@ssa_targclass = "radio-g"
					</code>
				</apply>

				<map key="galactic_location">pgsphere.SPoint.fromDegrees(
					float(@l), float(@b))</map>

				<map key="ssa_dateObs">None</map>
				<map key="ssa_dstitle">"LoTSS {}".format(@cat_id)</map>
				<map key="ssa_specstart">LIGHT_C/@freq[-1]</map>
				<map key="ssa_specend">LIGHT_C/@freq[0]</map>
				<map key="ssa_length">@Nchan</map>
				<map key="ssa_timeExt">@int_time</map>
				<map key="ssa_dateObs">@epoch_mjd</map>

				<LOOP listItems="i q u">
					<events>
						<map key="stokes\item" source="stokes\upper{\item}"/>
						<map key="stokes\item\+_error"
							source="stokes\upper{\item}\+_error"/>
					</events>
				</LOOP>
			</rowmaker>
		</make>
	</data>


	<table id="ssameta" onDisk="True" adql="hidden">
		<!-- the SSA table (on which the service is based -->

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

		<mixin
			sourcetable="spectra"
			copiedcolumns="ssa_*"
			ssa_specres="0.002"
			ssa_aperture="1/180."
			ssa_fluxunit="'Jy'"
			ssa_spectralunit="'Hz'"
			ssa_bandpass="'Radio'"
			ssa_collection="'LoTSS DR2'"
			ssa_fluxcalib="'RELATIVE'"
			ssa_fluxucd="'phys.polarization.stokes'"
			ssa_speccalib="'ABSOLUTE'"
			ssa_spectralucd="'em.freq'"
		>//ssap#view</mixin>

		<mixin
			calibLevel="2"
			coverage="ssa_region"
			sResolution="ssa_spaceRes"
			oUCD="ssa_fluxucd"
			emUCD="ssa_spectralucd"
			>//obscore#publishSSAPMIXC</mixin>
	</table>

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

	<coverage>
		<updater sourceTable="ssameta"/>
	</coverage>

	<table id="instance" onDisk="False">
		<meta name="description">The polarization coefficients for a LoTSS DR2
			source.  The spectral behaviour of the LoTSS Stokes I data are
			presently unreliable and not included here. However, one can use the
			stokes_i column in \schema.rmtable in combination with an assumed radio
			spectral index to produce fractional polarization spectra.
		</meta>
		<mixin ssaTable="ssameta"
			spectralDescription="Frequency"
			fluxDescription="Total flux obtained as sqrt(Q^2 + U^2)"
			>//ssap#sdm-instance</mixin>

		<LOOP listItems="q i u">
			<events>
				<column name="stokes\item" type="double precision"
					ucd="phys.polarization.stokes.\upper{\item}" unit="Jy"
					description="Per-frequency Stokes polarization coefficients
						\upper{\item}"
					verbLevel="1"/>
				<column name="stokes\item\+_error" type="double precision"
					ucd="stat.error;phys.polarization.stokes.\upper{\item}"	 unit="Jy"
					description="Error in stokes\item"
					verbLevel="1"/>
			</events>
		</LOOP>

	</table>

	<data id="build_spectrum">
		<embeddedGrammar>
			<iterator>
				<setup>
					<par name="colnames">("freq", "stokesq", "stokesq_error",
						"stokesi", "stokesi_error", "stokesu", "stokesu_error")</par>
				</setup>
				<code>
				with base.getTableConn() as conn:
					res = list(conn.query(
						"select {}"
						" from \schema.spectra"
						" where accref=%(accref)s".format(", ".join(colnames)),
						self.sourceToken))
					if not res:
						raise UnknownURI("'{}' is not an accref we know here".format(
							self.sourceToken["accref"]))

					# we have to rename a few columns in the spectrum vs. the
					# database
					fieldnames = ("spectral", )+colnames[1:]
					for rec in zip(*(res[0])):
						vals = dict(zip(fieldnames, rec))
						vals["flux"] = math.sqrt(vals["stokesq"]**2+vals["stokesu"]**2)
						yield vals
				</code>
			</iterator>
		</embeddedGrammar>
		<make table="instance">
			<parmaker>
				<apply procDef="//ssap#feedSSAToSDM"/>
			</parmaker>
		</make>
	</data>

	<coverage>
		<spectral>7.95128418E-26 1.1131797852E-25</spectral>
		<updater spaceTable="rmtable" timeTable="rmtable"/>
	</coverage>

	<service id="sdl" allowed="dlget,dlmeta">
		<meta name="title">LoTSS DR2 Datalink Service</meta>
		<datalinkCore>
			<descriptorGenerator procDef="//soda#sdm_genDesc">
				<bind key="ssaTD">"\rdId#ssameta"</bind>
			</descriptorGenerator>
			<dataFunction procDef="//soda#sdm_genData">
				<bind key="builder">"\rdId#build_spectrum"</bind>
			</dataFunction>
			<FEED source="//soda#sdm_plainfluxcalib"/>
			<FEED source="//soda#sdm_cutout"/>
			<FEED source="//soda#sdm_format"/>
		</datalinkCore>
	</service>

	<service id="preview" allowed="qp">
		<meta name="title">LoTSS DR2 spectra preview maker</meta>
		<property name="queryField">cat_id</property>
		<pythonCore>
			<inputTable>
				<inputKey name="cat_id" type="integer" required="True"
					description="Lotss DR2 source number to preview"/>
			</inputTable>
			<coreProc>
				<setup imports="gavo.svcs, numpy, gavo.helpers.processing,
					matplotlib, matplotlib.figure, io">
					<code>

					</code>
				</setup>
				<code>
					with base.getTableConn() as conn:
						res = list(conn.query("SELECT freq, stokesi, stokesq, stokesu"
							" FROM \schema.spectra"
							" WHERE cat_id=%(cat_id)s",
							inputTable.args))

					if not res:
						raise svcs.UnknownURI("No data for this id known here")
					freq, stokesi, stokesq, stokesu = res[0]
					x = 3e8/(numpy.array(freq)**2)

					fig = figure.Figure((1, 0.4), 200)
					ax = fig.add_axes([0,0,1,1], frameon=False)
					# once there's stokes I data, re-enable this:
					#	ax.scatter(x, stokesi, s=0.2, color="green")
					ax.scatter(x, stokesq, s=0.2, color="blue")
					ax.scatter(x, stokesu, s=0.2, color="red")

					rendered = io.BytesIO()
					fig.savefig(rendered, format="png")
					return ("image/png", rendered.getvalue())
				</code>
			</coreProc>
		</pythonCore>
	</service>

	<service id="web" defaultRenderer="form">
		<meta name="shortName">\schema Web</meta>

		<dbCore queriedTable="ssameta">
			<condDesc buildFrom="ssa_location"/>
			<condDesc buildFrom="ssa_dateObs"/>
		</dbCore>

		<outputTable>
			<autoCols>accref, mime, ssa_targname,
				ssa_aperture, ssa_dateObs</autoCols>
			<FEED source="//ssap#atomicCoords"/>
			<outputField original="ssa_specstart" displayHint="spectralUnit=MHz"/>
			<outputField original="ssa_specend" displayHint="spectralUnit=MHz"/>
		</outputTable>
	</service>

	<service id="ssa" allowed="form,ssap.xml">
		<meta name="title">LoTSS DR2 Polarization spectra</meta>
		<meta name="shortName">\schema SSAP</meta>
		<meta name="ssap.complianceLevel">full</meta>

		<publish render="ssap.xml" sets="ivo_managed"/>
		<publish render="form" sets="ivo_managed,local" service="web"/>

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

	<service id="cone" allowed="form,scs.xml">
		<meta name="title">LoTSS DR2 Rotation Measures</meta>
		<meta name="shortName">\schema SCS</meta>
		<publish render="form" sets="ivo_managed, local"/>
		<publish render="scs.xml" sets="ivo_managed"/>

		<meta name="testQuery">
			<meta name="ra">1.2086517</meta>
			<meta name="dec">40.9616903</meta>
			<meta name="sr">0.001</meta>
		</meta>

		<scsCore queriedTable="rmtable">
			<FEED source="//scs#coreDescs"/>
			<condDesc buildFrom="source_name_dr2"/>
			<condDesc buildFrom="rm"/>
			<condDesc buildFrom="field"/>
			<condDesc buildFrom="epoch_mjd"/>
		</scsCore>

	</service>

	<regSuite title="lotsspol regression">
		<regTest title="lotsspol SSAP serves some data">
			<url REQUEST="queryData" POS="0.3857576,24.0423674" SIZE="0.001"
				>ssa/ssap.xml</url>
			<code><![CDATA[
				self.assertHasStrings(
					"/getproduct/lotsspol/003510</TD>",
					"<TD>ivo://org.gavo.dc/~?lotsspol/003510</TD>",
					"<TD>0.0055555", # the aperture
					"<TD>24.0423673997" # the split Dec
					)
			]]></code>
		</regTest>

		<regTest title="lotsspol SDM spectrum looks about right.">
			<url httpHonorRedirects="True">/getproduct/lotsspol/003510</url>
			<code><![CDATA[
				self.assertHasStrings(
					'value="0.005555', # the char.spatialaxis...extent
					'value="0.69808',	# spectralaxis...extent
					'value="444"',		 # ssa_length
					'QZysOAf8AB',	 # start of data stream
					)
			]]></code>
		</regTest>

		<regTest title="lotsspol delivers a preview.">
			<url httpHonorRedirects="True">/getproduct/lotsspol/003510?preview=True</url>
			<code><![CDATA[
				self.assertHasStrings("PNG", "ZZX")
			]]></code>
		</regTest>

		<regTest title="lotsspol SCS form (and stats obtained).">
			<url parSet="form" rm="-90 .. -80"
				polint=">0.011">/lotsspol/q/cone/form</url>
			<code>
				self.assertHasStrings("56805.0 ..", # placeholder of epoch
					"-81.269&lt;" # rounded RM
					)
			</code>
		</regTest>

		<regTest title="lotsspol cutout works (i.e., SODA can deal with freq
			spectra).">
			<url ID="lotsspol/003510" BAND="1.8 2.0">sdl/dlget</url>
			<code>
				row1 = self.getFirstVOTableRow(rejectExtras=False)
				self.assertAlmostEqual(row1['spectral'], 150144958.496094)
				self.assertAlmostEqual(row1['stokesu_error'], 0.0032496917534212957)
				self.assertXpath("//v:FIELD[@name='spectral']", {
					"unit": "Hz"})
				self.assertXpath("//v:PARAM[@name='ssa_specend']", {
					"value": "1.9966868085537424"})
			</code>
		</regTest>
	</regSuite>
</resource>
