23__all__ = [
'RefMatchConfig',
'RefMatchTask']
34from lsst.utils.timer
import timeMethod
35from .matchPessimisticB
import MatchPessimisticBTask
36from .display
import displayAstrometry
37from .
import makeMatchStatistics
41 matcher = pexConfig.ConfigurableField(
42 target=MatchPessimisticBTask,
43 doc=
"reference object/source matcher",
45 matchDistanceSigma = pexConfig.RangeField(
46 doc=
"the maximum match distance is set to "
47 " mean_match_distance + matchDistanceSigma*std_dev_match_distance; "
48 "ignored if not fitting a WCS",
53 sourceSelector = sourceSelectorRegistry.makeField(
54 doc=
"How to select sources for cross-matching.",
57 referenceSelector = pexConfig.ConfigurableField(
58 target=ReferenceSourceSelectorTask,
59 doc=
"How to select reference objects for cross-matching."
61 sourceFluxType = pexConfig.Field(
63 doc=
"Source flux type to use in source selection.",
78 """Match an input source catalog with objects from a reference catalog.
82 refObjLoader : `lsst.meas.algorithms.ReferenceLoader`
83 A reference object loader object
85 additional keyword arguments for pipe_base `lsst.pipe.base.Task`
87 ConfigClass = RefMatchConfig
88 _DefaultName = "calibrationBaseClass"
91 pipeBase.Task.__init__(self, **kwargs)
97 if self.config.sourceSelector.name ==
'matcher':
98 if self.config.sourceSelector[
'matcher'].sourceFluxType != self.config.sourceFluxType:
99 raise RuntimeError(
"The sourceFluxType in the sourceSelector['matcher'] must match "
100 "the configured sourceFluxType")
102 self.makeSubtask(
"matcher")
103 self.makeSubtask(
"sourceSelector")
104 self.makeSubtask(
"referenceSelector")
107 """Sets the reference object loader for the task
112 An instance of a reference object loader task or class
118 """Load reference objects overlapping an exposure and match to sources
119 detected on that exposure.
124 exposure that the sources overlap
126 catalog of sources detected on the exposure
130 result : `lsst.pipe.base.Struct`
131 Result struct with Components:
133 - ``refCat`` : reference object catalog of objects that overlap the
135 - ``matches`` : Matched sources
and references
137 - ``matchMeta`` : metadata needed to unpersist matches
142 ignores config.matchDistanceSigma
145 raise RuntimeError(
"Running matcher task with no refObjLoader set in __ini__ or setRefObjLoader")
151 sourceSelection = self.sourceSelector.run(sourceCat)
153 sourceFluxField =
"slot_%sFlux_instFlux" % (self.config.sourceFluxType)
158 filterName=expMd.filterName,
162 refSelection = self.referenceSelector.run(loadRes.refCat)
167 filterName=expMd.filterName,
171 matchRes = self.matcher.matchObjectsToSources(
172 refCat=refSelection.sourceCat,
173 sourceCat=sourceSelection.sourceCat,
175 sourceFluxField=sourceFluxField,
176 refFluxField=loadRes.fluxField,
177 match_tolerance=
None,
182 "Found %d matches with scatter = %0.3f +- %0.3f arcsec; ",
183 len(matchRes.matches), distStats.distMean.asArcseconds(), distStats.distStdDev.asArcseconds()
187 frame = int(debug.frame)
189 refCat=refSelection.sourceCat,
190 sourceCat=sourceSelection.sourceCat,
191 matches=matchRes.matches,
198 return pipeBase.Struct(
199 refCat=loadRes.refCat,
200 refSelection=refSelection,
201 sourceSelection=sourceSelection,
202 matches=matchRes.matches,
206 def _computeMatchStatsOnSky(self, matchList):
207 """Compute on-sky radial distance statistics for a match list
212 list of matches between reference object and sources;
213 the distance field
is the only field read
and it must be set to distance
in radians
217 result : `lsst.pipe.base.Struct`
218 Result struct
with components:
220 - ``distMean`` : clipped mean of on-sky radial separation (`float`)
221 - ``distStdDev`` : clipped standard deviation of on-sky radial
223 - ``maxMatchDist`` : distMean + self.config.matchDistanceSigma *
227 distMean = distStatsInRadians.getValue(afwMath.MEANCLIP)*lsst.geom.radians
228 distStdDev = distStatsInRadians.getValue(afwMath.STDEVCLIP)*lsst.geom.radians
229 return pipeBase.Struct(
231 distStdDev=distStdDev,
232 maxMatchDist=distMean + self.config.matchDistanceSigma * distStdDev,
235 def _getExposureMetadata(self, exposure):
236 """Extract metadata from an exposure.
244 result : `lsst.pipe.base.Struct`
245 Result struct with components:
250 - ``filterName`` : name of filter band (`str`)
251 - ``epoch`` : date of exposure (`astropy.time.Time`)
253 filterLabel = exposure.info.getFilter()
254 filterName = filterLabel.bandLabel if filterLabel
is not None else None
256 if exposure.info.hasVisitInfo():
257 epochTaiMjd = exposure.visitInfo.date.get(system=DateTime.MJD, scale=DateTime.TAI)
258 epoch = astropy.time.Time(epochTaiMjd, scale=
"tai", format=
"mjd")
260 return pipeBase.Struct(
261 bbox=exposure.getBBox(),
262 wcs=exposure.info.getWcs(),
263 photoCalib=exposure.info.getPhotoCalib(),
264 filterName=filterName,
A 2-dimensional celestial WCS that transform pixels to ICRS RA/Dec, using the LSST standard for pixel...
A class to contain the data, WCS, and other information needed to describe an image of the sky.
The photometric calibration of an exposure.
Custom catalog class for record/table subclasses that are guaranteed to have an ID,...
Class for storing ordered metadata with comments.
An integer coordinate rectangle.
def _computeMatchStatsOnSky(self, matchList)
def loadAndMatch(self, exposure, sourceCat)
def __init__(self, refObjLoader, **kwargs)
def _getExposureMetadata(self, exposure)
def setRefObjLoader(self, refObjLoader)
Lightweight representation of a geometric match between two records.