Source code for lsst.validate.drp.calcsrd.adx

# LSST Data Management System
# Copyright 2016 AURA/LSST.
#
# This product includes software developed by the
# LSST Project (http://www.lsst.org/).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the LSST License Statement and
# the GNU General Public License along with this program.  If not,
# see <https://www.lsstcorp.org/LegalNotices/>.

from __future__ import print_function, absolute_import

import numpy as np

from ..base import MeasurementBase, Metric


[docs]class ADxMeasurement(MeasurementBase): """Measurement of AFx (x=1,2,3): The maximum fraction of astrometric distances which deviate by more than ADx milliarcsec (see AMx) (%). Parameters ---------- x : int Variant of AMx metric (x=1, 2, 3), which in turn sets the radius of the annulus for selecting pairs of stars. matchedDataset : lsst.validate.drp.matchreduce.MatchedMultiVisitDataset amx : :class:`lsst.validate.drp.calcsrd.AMxMeasurement` And AMx measurement, providing the median astrometric scatter in the annulus. bandpass : str Bandpass (filter name) used in this measurement (e.g., `'r'`). specName : str Name of a specification level to measure against (e.g., design, minimum, stretch). verbose : bool, optional Output additional information on the analysis steps. job : :class:`lsst.validate.drp.base.Job`, optional If provided, the measurement will register itself with the Job object. linkedBlobs : dict, optional A `dict` of additional blobs (subclasses of BlobBase) that can provide additional context to the measurement, though aren't direct dependencies of the computation (e.g., `matchedDataset). Raises ------ ValueError If `x` isn't in [1, 2, 3]. Notes ----- This table below is provided ``validate_drp``\ 's :file:`metrics.yaml`. LPM-17 dated 2011-07-06 Specification: The rms of the astrometric distance distribution for stellar pairs with separation of D arcmin (repeatability) will not exceed AMx milliarcsec (median distribution for a large number of sources). No more than AFx % of the sample will deviate by more than ADx milliarcsec from the median. AMx, AFx, and ADx are specified for D=5, 20 and 200 arcmin for x= 1, 2, and 3, in the same order (Table 18). The three selected characteristic distances reflect the size of an individual sensor, a raft, and the camera. The required median astrometric precision is driven by the desire to achieve a proper motion accuracy of 0.2 mas/yr and parallax accuracy of 1.0 mas over the course of the survey. These two requirements correspond to relative astrometric precision for a single image of 10 mas (per coordinate). ========================= ====== ======= ======= Astrometric Repeatability Specification ------------------------- ---------------------- Metric Design Minimum Stretch ========================= ====== ======= ======= AM1 (milliarcsec) 10 20 5 AF1 (%) 10 20 5 AD1 (milliarcsec) 20 40 10 AM2 (milliarcsec) 10 20 5 AF2 (%) 10 20 5 AD2 (milliarcsec) 20 40 10 AM3 (milliarcsec) 15 30 10 AF3 (%) 10 20 5 AD3 (milliarcsec) 30 50 20 ========================= ====== ======= ======= Table 18: The specifications for astrometric precision. The three blocks of values correspond to D=5, 20 and 200 arcmin, and to astrometric measurements performed in the r and i bands. """ metric = None value = None units = '' label = 'ADx' def __init__(self, x, matchedDataset, amx, bandpass, specName, verbose=False, job=None, linkedBlobs=None, metricYamlDoc=None, metricYamlPath=None): MeasurementBase.__init__(self) if x not in [1, 2, 3]: raise ValueError('ADx x should be 1, 2, or 3.') self.label = 'AD{0:d}'.format(x) self.bandpass = bandpass self.specName = specName self.metric = Metric.fromYaml(self.label, yamlDoc=metricYamlDoc, yamlPath=metricYamlPath) # register input parameters for serialization # note that matchedDataset is treated as a blob, separately self.registerParameter('D', datum=amx.parameters['D']) self.registerParameter('annulus', datum=amx.parameters['annulus']) self.registerParameter('magRange', datum=amx.parameters['magRange']) self.registerParameter('AMx', datum=amx.datum) self.matchedDataset = matchedDataset # Add external blobs so that links will be persisted with # the measurement if linkedBlobs is not None: for name, blob in linkedBlobs.items(): setattr(self, name, blob) afx = getattr(self.metric.getSpec(specName, bandpass=self.bandpass), 'AF{0:d}'.format(x))\ .getSpec(specName, bandpass=self.bandpass) self.registerParameter('AFx', datum=afx.datum) if amx.value: # No more than AFx of values will deviate by more than the # AMx (50th) + AFx percentiles # To compute ADx, use measured AMx and spec for AFx. percentileAtAfx = np.percentile(amx.rmsDistMas, 100. - self.AFx) percentileAtAmx = np.percentile(amx.rmsDistMas, amx.value) self.value = percentileAtAfx - percentileAtAmx else: # FIXME previously would raise ValidateErrorNoStars self.value = None if job: job.registerMeasurement(self)