90 def __init__(self, refObjLoader=None, **kwargs):
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")
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,
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,
207 """Compute on-sky radial distance statistics for a match list
211 matchList : `list` of `lsst.afw.table.ReferenceMatch`
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 *
226 distStatsInRadians = makeMatchStatistics(matchList, afwMath.MEANCLIP | afwMath.STDEVCLIP)
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,
236 """Extract metadata from an exposure.
240 exposure : `lsst.afw.image.Exposure`
244 result : `lsst.pipe.base.Struct`
245 Result struct with components:
247 - ``bbox`` : parent bounding box (`lsst.geom.Box2I`)
248 - ``wcs`` : exposure WCS (`lsst.afw.geom.SkyWcs`)
249 - ``photoCalib`` : photometric calibration (`lsst.afw.image.PhotoCalib`)
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,