23 __all__ = [
'RefMatchConfig',
'RefMatchTask']
31 import lsst.pipe.base
as pipeBase
32 from lsst.meas.algorithms
import ScienceSourceSelectorTask, ReferenceSourceSelectorTask
33 from .matchOptimisticB
import MatchOptimisticBTask
34 from .display
import displayAstrometry
35 from .
import makeMatchStatistics
39 matcher = pexConfig.ConfigurableField(
40 target=MatchOptimisticBTask,
41 doc=
"reference object/source matcher",
43 matchDistanceSigma = pexConfig.RangeField(
44 doc=
"the maximum match distance is set to " 45 " mean_match_distance + matchDistanceSigma*std_dev_match_distance; " +
46 "ignored if not fitting a WCS",
51 sourceSelection = pexConfig.ConfigurableField(target=ScienceSourceSelectorTask,
52 doc=
"Selection of science sources")
53 referenceSelection = pexConfig.ConfigurableField(target=ReferenceSourceSelectorTask,
54 doc=
"Selection of reference sources")
66 """!Match an input source catalog with objects from a reference catalog 70 ConfigClass = RefMatchConfig
71 _DefaultName =
"calibrationBaseClass" 73 def __init__(self, refObjLoader, schema=None, **kwargs):
74 """!Construct a RefMatchTask 76 @param[in] refObjLoader A reference object loader object 77 @param[in] schema ignored; available for compatibility with an older astrometry task 78 @param[in] kwargs additional keyword arguments for pipe_base Task.\_\_init\_\_ 80 pipeBase.Task.__init__(self, **kwargs)
82 self.makeSubtask(
"matcher")
83 self.makeSubtask(
"sourceSelection")
84 self.makeSubtask(
"referenceSelection")
88 """!Load reference objects overlapping an exposure and match to sources detected on that exposure 90 @param[in] exposure exposure that the sources overlap 91 @param[in] sourceCat catalog of sources detected on the exposure (an lsst.afw.table.SourceCatalog) 93 @return an lsst.pipe.base.Struct with these fields: 94 - refCat reference object catalog of objects that overlap the exposure (with some margin) 95 (an lsst::afw::table::SimpleCatalog) 96 - matches a list of lsst.afw.table.ReferenceMatch 97 - matchMeta metadata needed to unpersist matches (an lsst.daf.base.PropertyList) 99 @note ignores config.matchDistanceSigma 106 sourceSelection = self.sourceSelection.run(sourceCat)
111 filterName=expMd.filterName,
115 refSelection = self.referenceSelection.run(loadRes.refCat)
120 filterName=expMd.filterName,
124 matchRes = self.matcher.matchObjectsToSources(
125 refCat=refSelection.sourceCat,
126 sourceCat=sourceSelection.sourceCat,
128 refFluxField=loadRes.fluxField,
129 match_tolerance=
None,
134 "Found %d matches with scatter = %0.3f +- %0.3f arcsec; " %
135 (len(matchRes.matches), distStats.distMean.asArcseconds(), distStats.distStdDev.asArcseconds())
139 frame = int(debug.frame)
141 refCat=refSelection.sourceCat,
142 sourceCat=sourceSelection.sourceCat,
143 matches=matchRes.matches,
150 return pipeBase.Struct(
151 refCat=loadRes.refCat,
152 refSelection=refSelection,
153 sourceSelection=sourceSelection,
154 matches=matchRes.matches,
158 def _computeMatchStatsOnSky(self, matchList):
159 """Compute on-sky radial distance statistics for a match list 161 @param[in] matchList list of matches between reference object and sources; 162 the distance field is the only field read and it must be set to distance in radians 164 @return a pipe_base Struct containing these fields: 165 - distMean clipped mean of on-sky radial separation 166 - distStdDev clipped standard deviation of on-sky radial separation 167 - maxMatchDist distMean + self.config.matchDistanceSigma*distStdDev 170 distMean = distStatsInRadians.getValue(afwMath.MEANCLIP)*lsst.geom.radians
171 distStdDev = distStatsInRadians.getValue(afwMath.STDEVCLIP)*lsst.geom.radians
172 return pipeBase.Struct(
174 distStdDev=distStdDev,
175 maxMatchDist=distMean + self.config.matchDistanceSigma*distStdDev,
178 def _getExposureMetadata(self, exposure):
179 """!Extract metadata from an exposure 181 @return an lsst.pipe.base.Struct containing the following exposure metadata: 182 - bbox: parent bounding box 183 - wcs: WCS (an lsst.afw.geom.Wcs) 184 - calib calibration (an lsst.afw.image.Calib), or None if unknown 185 - filterName: name of filter, or None if unknown 186 - epoch: date of exposure (an astropy.time.Time), or None 188 exposureInfo = exposure.getInfo()
189 filterName = exposureInfo.getFilter().getName()
or None 190 if filterName ==
"_unknown_":
193 if exposure.getInfo().hasVisitInfo():
194 epochTaiMjd = exposure.getInfo().getVisitInfo().getDate().get(system=DateTime.MJD,
196 epoch = astropy.time.Time(epochTaiMjd, scale=
"tai", format=
"mjd")
198 return pipeBase.Struct(
199 bbox=exposure.getBBox(),
200 wcs=exposureInfo.getWcs(),
201 calib=exposureInfo.getCalib()
if exposureInfo.hasCalib()
else None,
202 filterName=filterName,
def _computeMatchStatsOnSky(self, matchList)
def __init__(self, refObjLoader, schema=None, kwargs)
Construct a RefMatchTask.
def _getExposureMetadata(self, exposure)
Extract metadata from an exposure.
Match an input source catalog with objects from a reference catalog.
def displayAstrometry(refCat=None, sourceCat=None, distortedCentroidKey=None, bbox=None, exposure=None, matches=None, frame=1, title="", pause=True)
def loadAndMatch(self, exposure, sourceCat)
Load reference objects overlapping an exposure and match to sources detected on that exposure...