152 matchTolerance=None, bbox=None):
153 """Match sources to position reference stars.
157 refCat : `lsst.afw.table.SimpleCatalog`
158 Reference catalog to match.
159 sourceCat : `lsst.afw.table.SourceCatalog`
160 Catalog of sources found on an exposure. This should already be
161 down-selected to "good"/"usable" sources in the calling Task.
162 wcs : `lsst.afw.geom.SkyWcs`
163 Current WCS of the exposure containing the sources.
164 sourceFluxField : `str`
165 Field of the sourceCat to use for flux
167 Field of the refCat to use for flux
168 matchTolerance : `lsst.meas.astrom.MatchTolerance`
169 Object containing information from previous
170 `lsst.meas.astrom.AstrometryTask` match/fit cycles for use in
171 matching. If `None` is config defaults.
172 bbox : `lsst.geom.Box2I`, optional
173 Bounding box of the exposure for evaluating the local pixelScale
174 (defaults to the Sky Origin of the ``wcs`` provided if ``bbox``
179 matchResult : `lsst.pipe.base.Struct`
180 Result struct with components
182 - ``matches`` : List of matches with distance below the maximum match
183 distance (`list` of `lsst.afw.table.ReferenceMatch`).
184 - ``useableSourceCat`` : Catalog of sources matched and suited for
185 WCS fitting (`lsst.afw.table.SourceCatalog`).
186 - ``matchTolerance`` : MatchTolerance object updated from this
187 match iteration (`lsst.meas.astrom.MatchTolerance`).
192 preNumObj = len(refCat)
194 numRefObj = len(refCat)
197 self.
log.info(
"filterStars purged %d reference stars, leaving %d stars",
198 preNumObj - numRefObj, numRefObj)
200 if matchTolerance
is None:
205 usableSourceCat = sourceCat
207 numUsableSources = len(usableSourceCat)
209 if len(usableSourceCat) == 0:
210 raise pipeBase.TaskError(
"No sources are usable")
212 minMatchedPairs = min(self.config.minMatchedPairs,
213 int(self.config.minFracMatchedPairs * min([len(refCat), len(usableSourceCat)])))
218 sourceCat=usableSourceCat,
220 refFluxField=refFluxField,
221 numUsableSources=numUsableSources,
222 minMatchedPairs=minMatchedPairs,
223 maxMatchDist=matchTolerance.maxMatchDist,
224 sourceFluxField=sourceFluxField,
225 verbose=debug.verbose,
232 for match
in usableMatches:
235 matches.append(match)
237 self.
log.debug(
"Found %d usable matches, of which %d had good sources",
238 len(usableMatches), len(matches))
240 if len(matches) == 0:
241 raise RuntimeError(
"Unable to match sources")
243 self.
log.info(
"Matched %d sources", len(matches))
244 if len(matches) < minMatchedPairs:
245 self.
log.warning(
"Number of matches is smaller than request")
247 return pipeBase.Struct(
249 usableSourceCat=usableSourceCat,
250 matchTolerance=matchTolerance,
287 def _doMatch(self, refCat, sourceCat, wcs, refFluxField, numUsableSources, minMatchedPairs,
288 maxMatchDist, sourceFluxField, verbose, bbox=None):
289 """Implementation of matching sources to position reference stars.
291 Unlike matchObjectsToSources, this method does not check if the sources
296 refCat : `lsst.afw.table.SimpleCatalog`
297 Catalog of reference objects.
298 sourceCat : `lsst.afw.table.SourceCatalog`
299 Catalog of detected sources.
300 wcs : `lsst.afw.geom.SkyWcs`
301 Current best WCS of the image.
302 refFluxFioeld : `str`
303 Name of flux field in refCat to use.
304 numUsableSources : `int`
305 Total number of source usable for matching.
306 mintMatchPairs : `int`
307 Minimum number of objects to match between the refCat and sourceCat
308 to consider a valid match.
309 maxMatchDist : `lsst.geom.Angle`
310 Maximum separation to considering a reference and a source a match.
311 sourceFluxField : `str`
312 Name of source catalog flux field.
314 Print diagnostic information std::cout
315 bbox : `lsst.geom.Box2I`, optional
316 Bounding box of the exposure for evaluating the local pixelScale
317 (defaults to the Sky Origin of the ``wcs`` provided if ``bbox``
322 matches : `list` of `lsst.afw.table.ReferenceMatch`
324 numSources = len(sourceCat)
325 posRefBegInd = numUsableSources - numSources
326 if maxMatchDist
is None:
327 maxMatchDistArcSec = self.config.maxMatchDistArcSec
329 maxMatchDistArcSec = min(maxMatchDist.asArcseconds(), self.config.maxMatchDistArcSec)
332 pixelScale = wcs.getPixelScale(bbox.getCenter()).asArcseconds()
334 pixelScale = wcs.getPixelScale().asArcseconds()
336 configMatchDistPix = maxMatchDistArcSec/pixelScale
339 matchControl.refFluxField = refFluxField
340 matchControl.sourceFluxField = sourceFluxField
341 matchControl.numBrightStars = self.config.numBrightStars
342 matchControl.minMatchedPairs = self.config.minMatchedPairs
343 matchControl.maxOffsetPix = self.config.maxOffsetPix
344 matchControl.numPointsForShape = self.config.numPointsForShape
345 matchControl.maxDeterminant = self.config.maxDeterminant
347 for maxRotInd
in range(4):
348 matchControl.maxRotationDeg = self.config.maxRotationDeg * math.pow(2.0, 0.5*maxRotInd)
349 for matchRadInd
in range(3):
350 matchControl.matchingAllowancePix = configMatchDistPix * math.pow(1.25, matchRadInd)
352 for angleDiffInd
in range(3):
353 matchControl.allowedNonperpDeg = self.config.allowedNonperpDeg*(angleDiffInd+1)
354 matches = matchOptimisticB(
362 if matches
is not None and len(matches) > 0:
363 setMatchDistance(matches)