23 __all__ = [
'RefMatchConfig',
'RefMatchTask']
30 import lsst.pex.config
as pexConfig
34 from .matchPessimisticB
import MatchPessimisticBTask
35 from .display
import displayAstrometry
36 from .
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. 122 exposure : `lsst.afw.image.Exposure` 123 exposure that the sources overlap 124 sourceCat : `lsst.afw.table.SourceCatalog.` 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 133 exposure (`lsst.afw.table.SimpleCatalog`) 134 - ``matches`` : Matched sources and references 135 (`list` of `lsst.afw.table.ReferenceMatch`) 136 - ``matchMeta`` : metadata needed to unpersist matches 137 (`lsst.daf.base.PropertyList`) 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,
161 refSelection = self.referenceSelector.
run(loadRes.refCat)
166 filterName=expMd.filterName,
167 photoCalib=expMd.photoCalib,
170 matchRes = self.matcher.matchObjectsToSources(
171 refCat=refSelection.sourceCat,
172 sourceCat=sourceSelection.sourceCat,
174 sourceFluxField=sourceFluxField,
175 refFluxField=loadRes.fluxField,
176 match_tolerance=
None,
181 "Found %d matches with scatter = %0.3f +- %0.3f arcsec; " %
182 (len(matchRes.matches), distStats.distMean.asArcseconds(), distStats.distStdDev.asArcseconds())
186 frame = int(debug.frame)
188 refCat=refSelection.sourceCat,
189 sourceCat=sourceSelection.sourceCat,
190 matches=matchRes.matches,
197 return pipeBase.Struct(
198 refCat=loadRes.refCat,
199 refSelection=refSelection,
200 sourceSelection=sourceSelection,
201 matches=matchRes.matches,
205 def _computeMatchStatsOnSky(self, matchList):
206 """Compute on-sky radial distance statistics for a match list 210 matchList : `list` of `lsst.afw.table.ReferenceMatch` 211 list of matches between reference object and sources; 212 the distance field is the only field read and it must be set to distance in radians 216 result : `lsst.pipe.base.Struct` 217 Result struct with components: 219 - ``distMean`` : clipped mean of on-sky radial separation (`float`) 220 - ``distStdDev`` : clipped standard deviation of on-sky radial 222 - ``maxMatchDist`` : distMean + self.config.matchDistanceSigma * 226 distMean = distStatsInRadians.getValue(afwMath.MEANCLIP)*lsst.geom.radians
227 distStdDev = distStatsInRadians.getValue(afwMath.STDEVCLIP)*lsst.geom.radians
228 return pipeBase.Struct(
230 distStdDev=distStdDev,
231 maxMatchDist=distMean + self.config.matchDistanceSigma * distStdDev,
234 def _getExposureMetadata(self, exposure):
235 """Extract metadata from an exposure. 239 exposure : `lsst.afw.image.Exposure` 243 result : `lsst.pipe.base.Struct` 244 Result struct with components: 246 - ``bbox`` : parent bounding box (`lsst.geom.Box2I`) 247 - ``wcs`` : exposure WCS (`lsst.afw.geom.SkyWcs`) 248 - ``photoCalib`` : photometric calibration (`lsst.afw.image.PhotoCalib`) 249 - ``filterName`` : name of filter (`str`) 250 - ``epoch`` : date of exposure (`astropy.time.Time`) 253 exposureInfo = exposure.getInfo()
254 filterName = exposureInfo.getFilter().getName()
or None 255 if filterName ==
"_unknown_":
258 if exposure.getInfo().hasVisitInfo():
259 epochTaiMjd = exposure.getInfo().getVisitInfo().getDate().get(system=DateTime.MJD,
261 epoch = astropy.time.Time(epochTaiMjd, scale=
"tai", format=
"mjd")
263 return pipeBase.Struct(
264 bbox=exposure.getBBox(),
265 wcs=exposureInfo.getWcs(),
266 photoCalib=exposureInfo.getPhotoCalib(),
267 filterName=filterName,
def _computeMatchStatsOnSky(self, matchList)
def _getExposureMetadata(self, exposure)
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)
def setRefObjLoader(self, refObjLoader)
def run(self, skyInfo, tempExpRefList, imageScalerList, weightList, altMaskList=None, mask=None, supplementaryData=None)
def loadAndMatch(self, exposure, sourceCat)
def __init__(self, refObjLoader, kwargs)