23 __all__ = [
'RefMatchConfig',
'RefMatchTask']
31 import lsst.pipe.base
as pipeBase
32 from lsst.meas.algorithms
import ScienceSourceSelectorTask, ReferenceSourceSelectorTask
33 from .matchPessimisticB
import MatchPessimisticBTask
34 from .display
import displayAstrometry
35 from .
import makeMatchStatistics
39 matcher = pexConfig.ConfigurableField(
40 target=MatchPessimisticBTask,
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")
58 """Match an input source catalog with objects from a reference catalog. 62 refObjLoader : `lsst.meas.algorithms.ReferenceLoader` 63 A reference object loader object 64 schema : `lsst.afw.table.Schema` 65 ignored; available for compatibility with an older astrometry task 67 additional keyword arguments for pipe_base `lsst.pipe.base.Task` 69 ConfigClass = RefMatchConfig
70 _DefaultName =
"calibrationBaseClass" 72 def __init__(self, refObjLoader, schema=None, **kwargs):
73 pipeBase.Task.__init__(self, **kwargs)
78 self.makeSubtask(
"matcher")
79 self.makeSubtask(
"sourceSelection")
80 self.makeSubtask(
"referenceSelection")
83 """Sets the reference object loader for the task 88 An instance of a reference object loader task or class 94 """Load reference objects overlapping an exposure and match to sources 95 detected on that exposure. 99 exposure : `lsst.afw.image.Exposure` 100 exposure that the sources overlap 101 sourceCat : `lsst.afw.table.SourceCatalog.` 102 catalog of sources detected on the exposure 106 result : `lsst.pipe.base.Struct` 107 Result struct with Components: 109 - ``refCat`` : reference object catalog of objects that overlap the 110 exposure (`lsst.afw.table.SimpleCatalog`) 111 - ``matches`` : Matched sources and references 112 (`list` of `lsst.afw.table.ReferenceMatch`) 113 - ``matchMeta`` : metadata needed to unpersist matches 114 (`lsst.daf.base.PropertyList`) 118 ignores config.matchDistanceSigma 121 raise RuntimeError(
"Running matcher task with no refObjLoader set in __ini__ or setRefObjLoader")
127 sourceSelection = self.sourceSelection.run(sourceCat)
132 filterName=expMd.filterName,
136 refSelection = self.referenceSelection.run(loadRes.refCat)
141 filterName=expMd.filterName,
145 matchRes = self.matcher.matchObjectsToSources(
146 refCat=refSelection.sourceCat,
147 sourceCat=sourceSelection.sourceCat,
149 refFluxField=loadRes.fluxField,
150 match_tolerance=
None,
155 "Found %d matches with scatter = %0.3f +- %0.3f arcsec; " %
156 (len(matchRes.matches), distStats.distMean.asArcseconds(), distStats.distStdDev.asArcseconds())
160 frame = int(debug.frame)
162 refCat=refSelection.sourceCat,
163 sourceCat=sourceSelection.sourceCat,
164 matches=matchRes.matches,
171 return pipeBase.Struct(
172 refCat=loadRes.refCat,
173 refSelection=refSelection,
174 sourceSelection=sourceSelection,
175 matches=matchRes.matches,
179 def _computeMatchStatsOnSky(self, matchList):
180 """Compute on-sky radial distance statistics for a match list 184 matchList : `list` of `lsst.afw.table.ReferenceMatch` 185 list of matches between reference object and sources; 186 the distance field is the only field read and it must be set to distance in radians 190 result : `lsst.pipe.base.Struct` 191 Result struct with components: 193 - ``distMean`` : clipped mean of on-sky radial separation (`float`) 194 - ``distStdDev`` : clipped standard deviation of on-sky radial 196 - ``maxMatchDist`` : distMean + self.config.matchDistanceSigma * 200 distMean = distStatsInRadians.getValue(afwMath.MEANCLIP)*lsst.geom.radians
201 distStdDev = distStatsInRadians.getValue(afwMath.STDEVCLIP)*lsst.geom.radians
202 return pipeBase.Struct(
204 distStdDev=distStdDev,
205 maxMatchDist=distMean + self.config.matchDistanceSigma * distStdDev,
208 def _getExposureMetadata(self, exposure):
209 """Extract metadata from an exposure. 213 exposure : `lsst.afw.image.Exposure` 217 result : `lsst.pipe.base.Struct` 218 Result struct with components: 220 - ``bbox`` : parent bounding box (`lsst.geom.Box2I`) 221 - ``wcs`` : exposure WCS (`lsst.afw.geom.SkyWcs`) 222 - ``calib`` : calibration (`lsst.afw.image.Calib`) 223 - ``filterName`` : name of filter (`str`) 224 - ``epoch`` : date of exposure (`astropy.time.Time`) 227 exposureInfo = exposure.getInfo()
228 filterName = exposureInfo.getFilter().getName()
or None 229 if filterName ==
"_unknown_":
232 if exposure.getInfo().hasVisitInfo():
233 epochTaiMjd = exposure.getInfo().getVisitInfo().getDate().get(system=DateTime.MJD,
235 epoch = astropy.time.Time(epochTaiMjd, scale=
"tai", format=
"mjd")
237 return pipeBase.Struct(
238 bbox=exposure.getBBox(),
239 wcs=exposureInfo.getWcs(),
240 calib=exposureInfo.getCalib()
if exposureInfo.hasCalib()
else None,
241 filterName=filterName,
def _computeMatchStatsOnSky(self, matchList)
def __init__(self, refObjLoader, schema=None, kwargs)
def _getExposureMetadata(self, exposure)
def displayAstrometry(refCat=None, sourceCat=None, distortedCentroidKey=None, bbox=None, exposure=None, matches=None, frame=1, title="", pause=True)
def setRefObjLoader(self, refObjLoader)
def loadAndMatch(self, exposure, sourceCat)