23 __all__ = [
'RefMatchConfig',
'RefMatchTask']
34 from lsst.utils.timer
import timeMethod
35 from .matchPessimisticB
import MatchPessimisticBTask
36 from .display
import displayAstrometry
37 from .
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.",
69 self.
sourceSelectorsourceSelector[
'science'].fluxLimit.fluxField = \
71 self.
sourceSelectorsourceSelector[
'science'].signalToNoise.fluxField = \
73 self.
sourceSelectorsourceSelector[
'science'].signalToNoise.errField = \
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.
123 exposure : `lsst.afw.image.Exposure`
124 exposure that the sources overlap
125 sourceCat : `lsst.afw.table.SourceCatalog.`
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
134 exposure (`lsst.afw.table.SimpleCatalog`)
135 - ``matches`` : Matched sources and references
136 (`list` of `lsst.afw.table.ReferenceMatch`)
137 - ``matchMeta`` : metadata needed to unpersist matches
138 (`lsst.daf.base.PropertyList`)
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,
159 photoCalib=expMd.photoCalib,
163 refSelection = self.referenceSelector.
run(loadRes.refCat)
165 matchMeta = self.
refObjLoaderrefObjLoader.getMetadataBox(
168 filterName=expMd.filterName,
169 photoCalib=expMd.photoCalib,
173 matchRes = self.matcher.matchObjectsToSources(
174 refCat=refSelection.sourceCat,
175 sourceCat=sourceSelection.sourceCat,
177 sourceFluxField=sourceFluxField,
178 refFluxField=loadRes.fluxField,
179 match_tolerance=
None,
184 "Found %d matches with scatter = %0.3f +- %0.3f arcsec; ",
185 len(matchRes.matches), distStats.distMean.asArcseconds(), distStats.distStdDev.asArcseconds()
189 frame = int(debug.frame)
191 refCat=refSelection.sourceCat,
192 sourceCat=sourceSelection.sourceCat,
193 matches=matchRes.matches,
200 return pipeBase.Struct(
201 refCat=loadRes.refCat,
202 refSelection=refSelection,
203 sourceSelection=sourceSelection,
204 matches=matchRes.matches,
208 def _computeMatchStatsOnSky(self, matchList):
209 """Compute on-sky radial distance statistics for a match list
213 matchList : `list` of `lsst.afw.table.ReferenceMatch`
214 list of matches between reference object and sources;
215 the distance field is the only field read and it must be set to distance in radians
219 result : `lsst.pipe.base.Struct`
220 Result struct with components:
222 - ``distMean`` : clipped mean of on-sky radial separation (`float`)
223 - ``distStdDev`` : clipped standard deviation of on-sky radial
225 - ``maxMatchDist`` : distMean + self.config.matchDistanceSigma *
229 distMean = distStatsInRadians.getValue(afwMath.MEANCLIP)*lsst.geom.radians
230 distStdDev = distStatsInRadians.getValue(afwMath.STDEVCLIP)*lsst.geom.radians
231 return pipeBase.Struct(
233 distStdDev=distStdDev,
234 maxMatchDist=distMean + self.config.matchDistanceSigma * distStdDev,
237 def _getExposureMetadata(self, exposure):
238 """Extract metadata from an exposure.
242 exposure : `lsst.afw.image.Exposure`
246 result : `lsst.pipe.base.Struct`
247 Result struct with components:
249 - ``bbox`` : parent bounding box (`lsst.geom.Box2I`)
250 - ``wcs`` : exposure WCS (`lsst.afw.geom.SkyWcs`)
251 - ``photoCalib`` : photometric calibration (`lsst.afw.image.PhotoCalib`)
252 - ``filterName`` : name of filter band (`str`)
253 - ``epoch`` : date of exposure (`astropy.time.Time`)
256 exposureInfo = exposure.getInfo()
257 filterLabel = exposureInfo.getFilterLabel()
258 filterName = filterLabel.bandLabel
if filterLabel
is not None else None
260 if exposure.getInfo().hasVisitInfo():
261 epochTaiMjd = exposure.getInfo().getVisitInfo().getDate().get(system=DateTime.MJD,
263 epoch = astropy.time.Time(epochTaiMjd, scale=
"tai", format=
"mjd")
265 return pipeBase.Struct(
266 bbox=exposure.getBBox(),
267 wcs=exposureInfo.getWcs(),
268 photoCalib=exposureInfo.getPhotoCalib(),
269 filterName=filterName,
def _computeMatchStatsOnSky(self, matchList)
def loadAndMatch(self, exposure, sourceCat)
def __init__(self, refObjLoader, **kwargs)
def _getExposureMetadata(self, exposure)
def setRefObjLoader(self, refObjLoader)
def run(self, coaddExposures, bbox, wcs)
Fit spatial kernel using approximate fluxes for candidates, and solving a linear system of equations.
def displayAstrometry(refCat=None, sourceCat=None, distortedCentroidKey=None, bbox=None, exposure=None, matches=None, frame=1, title="", pause=True)