23__all__ = [
'RefMatchConfig',
'RefMatchTask']
32from lsst.meas.algorithms
import ReferenceSourceSelectorTask
33from lsst.meas.algorithms.sourceSelector
import sourceSelectorRegistry
34from .matchPessimisticB
import MatchPessimisticBTask
35from .display
import displayAstrometry
36from .
import makeMatchStatistics
40 matcher = pexConfig.ConfigurableField(
41 target=MatchPessimisticBTask,
42 doc=
"reference object/source matcher",
44 matchDistanceSigma = pexConfig.RangeField(
45 doc=
"the maximum match distance is set to "
46 " mean_match_distance + matchDistanceSigma*std_dev_match_distance; "
47 "ignored if not fitting a WCS",
52 sourceSelector = sourceSelectorRegistry.makeField(
53 doc=
"How to select sources for cross-matching.",
56 referenceSelector = pexConfig.ConfigurableField(
57 target=ReferenceSourceSelectorTask,
58 doc=
"How to select reference objects for cross-matching."
60 sourceFluxType = pexConfig.Field(
62 doc=
"Source flux type to use in source selection.",
77 """Match an input source catalog with objects from a reference catalog.
81 refObjLoader : `lsst.meas.algorithms.ReferenceLoader`
82 A reference object loader object
84 additional keyword arguments for pipe_base `lsst.pipe.base.Task`
86 ConfigClass = RefMatchConfig
87 _DefaultName = "calibrationBaseClass"
90 pipeBase.Task.__init__(self, **kwargs)
96 if self.config.sourceSelector.name ==
'matcher':
97 if self.config.sourceSelector[
'matcher'].sourceFluxType != self.config.sourceFluxType:
98 raise RuntimeError(
"The sourceFluxType in the sourceSelector['matcher'] must match "
99 "the configured sourceFluxType")
101 self.makeSubtask(
"matcher")
102 self.makeSubtask(
"sourceSelector")
103 self.makeSubtask(
"referenceSelector")
106 """Sets the reference object loader for the task
111 An instance of a reference object loader task or class
117 """Load reference objects overlapping an exposure and match to sources
118 detected on that exposure.
123 exposure that the sources overlap
125 catalog of sources detected on the exposure
129 result : `lsst.pipe.base.Struct`
130 Result struct with Components:
132 - ``refCat`` : reference object catalog of objects that overlap the
134 - ``matches`` : Matched sources
and references
136 - ``matchMeta`` : metadata needed to unpersist matches
141 ignores config.matchDistanceSigma
144 raise RuntimeError(
"Running matcher task with no refObjLoader set in __ini__ or setRefObjLoader")
150 sourceSelection = self.sourceSelector.run(sourceCat)
152 sourceFluxField =
"slot_%sFlux_instFlux" % (self.config.sourceFluxType)
157 filterName=expMd.filterName,
158 photoCalib=expMd.photoCalib,
162 refSelection = self.referenceSelector.run(loadRes.refCat)
167 filterName=expMd.filterName,
168 photoCalib=expMd.photoCalib,
172 matchRes = self.matcher.matchObjectsToSources(
173 refCat=refSelection.sourceCat,
174 sourceCat=sourceSelection.sourceCat,
176 sourceFluxField=sourceFluxField,
177 refFluxField=loadRes.fluxField,
178 match_tolerance=
None,
183 "Found %d matches with scatter = %0.3f +- %0.3f arcsec; " %
184 (len(matchRes.matches), distStats.distMean.asArcseconds(), distStats.distStdDev.asArcseconds())
188 frame = int(debug.frame)
190 refCat=refSelection.sourceCat,
191 sourceCat=sourceSelection.sourceCat,
192 matches=matchRes.matches,
199 return pipeBase.Struct(
200 refCat=loadRes.refCat,
201 refSelection=refSelection,
202 sourceSelection=sourceSelection,
203 matches=matchRes.matches,
207 def _computeMatchStatsOnSky(self, matchList):
208 """Compute on-sky radial distance statistics for a match list
213 list of matches between reference object and sources;
214 the distance field
is the only field read
and it must be set to distance
in radians
218 result : `lsst.pipe.base.Struct`
219 Result struct
with components:
221 - ``distMean`` : clipped mean of on-sky radial separation (`float`)
222 - ``distStdDev`` : clipped standard deviation of on-sky radial
224 - ``maxMatchDist`` : distMean + self.config.matchDistanceSigma *
228 distMean = distStatsInRadians.getValue(afwMath.MEANCLIP)*lsst.geom.radians
229 distStdDev = distStatsInRadians.getValue(afwMath.STDEVCLIP)*lsst.geom.radians
230 return pipeBase.Struct(
232 distStdDev=distStdDev,
233 maxMatchDist=distMean + self.config.matchDistanceSigma * distStdDev,
236 def _getExposureMetadata(self, exposure):
237 """Extract metadata from an exposure.
245 result : `lsst.pipe.base.Struct`
246 Result struct with components:
251 - ``filterName`` : name of filter band (`str`)
252 - ``epoch`` : date of exposure (`astropy.time.Time`)
255 exposureInfo = exposure.getInfo()
256 filterLabel = exposureInfo.getFilterLabel()
257 filterName = filterLabel.bandLabel if filterLabel
is not None else None
259 if exposure.getInfo().hasVisitInfo():
260 epochTaiMjd = exposure.getInfo().getVisitInfo().getDate().get(system=DateTime.MJD,
262 epoch = astropy.time.Time(epochTaiMjd, scale=
"tai", format=
"mjd")
264 return pipeBase.Struct(
265 bbox=exposure.getBBox(),
266 wcs=exposureInfo.getWcs(),
267 photoCalib=exposureInfo.getPhotoCalib(),
268 filterName=filterName,
def _computeMatchStatsOnSky(self, matchList)
def loadAndMatch(self, exposure, sourceCat)
def __init__(self, refObjLoader, **kwargs)
def _getExposureMetadata(self, exposure)
def setRefObjLoader(self, refObjLoader)