2 __all__ = [
"MatchOptimisticBTask",
"MatchOptimisticBConfig",
8 import lsst.pipe.base
as pipeBase
9 from lsst.meas.algorithms.sourceSelector
import sourceSelectorRegistry
11 from .setMatchDistance
import setMatchDistance
12 from .matchOptimisticB
import matchOptimisticB, MatchOptimisticBControl
16 """Stores match tolerances for use in `lsst.meas.astrom.AstrometryTask` and 17 later iterations of the matcher. 19 MatchOptimsiticBTask relies on a maximum distance for matching 20 set by either the default in MatchOptimisticBConfig or the 2 sigma 21 scatter found after AstrometryTask has fit for a wcs. 25 maxMatchDist : `lsst.geom.Angle` 26 Current maximum distance to consider a match. 34 """Configuration for MatchOptimisticBTask 36 maxMatchDistArcSec = pexConfig.RangeField(
37 doc=
"Maximum separation between reference objects and sources " 38 "beyond which they will not be considered a match (arcsec)",
43 numBrightStars = pexConfig.RangeField(
44 doc=
"Number of bright stars to use",
49 minMatchedPairs = pexConfig.RangeField(
50 doc=
"Minimum number of matched pairs; see also minFracMatchedPairs",
55 minFracMatchedPairs = pexConfig.RangeField(
56 doc=
"Minimum number of matched pairs as a fraction of the smaller of " 57 "the number of reference stars or the number of good sources; " 58 "the actual minimum is the smaller of this value or minMatchedPairs",
64 maxOffsetPix = pexConfig.RangeField(
65 doc=
"Maximum allowed shift of WCS, due to matching (pixel). " 66 "When changing this value, the LoadReferenceObjectsConfig.pixelMargin should also be updated.",
71 maxRotationDeg = pexConfig.RangeField(
72 doc=
"Rotation angle allowed between sources and position reference objects (degrees)",
77 allowedNonperpDeg = pexConfig.RangeField(
78 doc=
"Allowed non-perpendicularity of x and y (degree)",
83 numPointsForShape = pexConfig.Field(
84 doc=
"number of points to define a shape for matching",
88 maxDeterminant = pexConfig.Field(
89 doc=
"maximum determinant of linear transformation matrix for a usable solution",
93 sourceSelector = sourceSelectorRegistry.makeField(
94 doc=
"How to select sources for cross-matching",
100 sourceSelector.setDefaults()
101 sourceSelector.excludePixelFlags =
False 114 """Match sources to reference objects using the Optimistic Pattern Matcher 115 B algorithm of Tabur 2007. 117 ConfigClass = MatchOptimisticBConfig
118 _DefaultName =
"matchObjectsToSources" 121 pipeBase.Task.__init__(self, **kwargs)
122 self.makeSubtask(
"sourceSelector")
125 """Extra filtering pass; subclass if desired. 129 refCat : `lsst.afw.table.SimpleCatalog` 130 Catalog of reference objects. 134 trimmedRefCat : `lsst.afw.table.SimpleCatalog` 135 Reference catalog with some filtering applied. Currently no 136 filtering is applied. 142 match_tolerance=None):
143 """Match sources to position reference stars. 147 refCat : `lsst.afw.table.SimpleCatalog` 148 Reference catalog to match. 149 sourceCat : `lsst.afw.table.SourceCatalog` 150 Source catalog to match. 151 wcs : `lsst.afw.geom.SkyWcs` 152 Current WCS of the exposure containing the sources. 154 Name of the reference catalog filter to use. 155 match_tolerance : `lsst.meas.astrom.MatchTolerance` 156 Object containing information from previous 157 `lsst.meas.astrom.AstrometryTask` match/fit cycles for use in 158 matching. If `None` is config defaults. 162 matchResult : `lsst.pipe.base.Struct` 163 Result struct with components 165 - ``matches`` : List of matches with distance below the maximum match 166 distance (`list` of `lsst.afw.table.ReferenceMatch`). 167 - ``useableSourceCat`` : Catalog of sources matched and suited for 168 WCS fitting (`lsst.afw.table.SourceCatalog`). 169 - ``match_tolerance`` : MatchTolerance object updated from this 170 match iteration (`lsst.meas.astrom.MatchTolerance`). 175 preNumObj = len(refCat)
177 numRefObj = len(refCat)
180 self.log.info(
"filterStars purged %d reference stars, leaving %d stars" %
181 (preNumObj - numRefObj, numRefObj))
183 if match_tolerance
is None:
187 numSources = len(sourceCat)
188 selectedSources = self.sourceSelector.run(sourceCat)
189 usableSourceCat = selectedSources.sourceCat
190 numUsableSources = len(usableSourceCat)
191 self.log.info(
"Purged %d unusable sources, leaving %d usable sources" %
192 (numSources - numUsableSources, numUsableSources))
194 if len(usableSourceCat) == 0:
195 raise pipeBase.TaskError(
"No sources are usable")
199 minMatchedPairs = min(self.config.minMatchedPairs,
200 int(self.config.minFracMatchedPairs * min([len(refCat), len(usableSourceCat)])))
205 sourceCat=usableSourceCat,
207 refFluxField=refFluxField,
208 numUsableSources=numUsableSources,
209 minMatchedPairs=minMatchedPairs,
210 maxMatchDist=match_tolerance.maxMatchDist,
211 sourceFluxField=self.sourceSelector.fluxField,
212 verbose=debug.verbose,
218 for match
in usableMatches:
221 matches.append(match)
223 self.log.debug(
"Found %d usable matches, of which %d had good sources",
224 len(usableMatches), len(matches))
226 if len(matches) == 0:
227 raise RuntimeError(
"Unable to match sources")
229 self.log.info(
"Matched %d sources" % len(matches))
230 if len(matches) < minMatchedPairs:
231 self.log.warn(
"Number of matches is smaller than request")
233 return pipeBase.Struct(
235 usableSourceCat=usableSourceCat,
236 match_tolerance=match_tolerance,
239 def _getIsGoodKeys(self, schema):
240 """Retrieve the keys needed for the isGoodTest from the source catalog 245 schema : `lsst.afw.table.Schema` 246 Source schema to retrieve `lsst.afw.table.Key` s from. 248 self.
edgeKey = schema[
"base_PixelFlags_flag_edge"].asKey()
252 def _isGoodTest(self, source):
253 """Test that an object is good for use in the WCS fitter. 255 This is a hard coded version of the isGood flag from the old SourceInfo 256 class that used to be part of this class. 260 source : `lsst.afw.table.SourceRecord` 266 Source passes CCD edge and saturated tests. 268 return (
not source.get(self.
edgeKey)
and 273 def _doMatch(self, refCat, sourceCat, wcs, refFluxField, numUsableSources, minMatchedPairs,
274 maxMatchDist, sourceFluxField, verbose):
275 """Implementation of matching sources to position reference stars. 277 Unlike matchObjectsToSources, this method does not check if the sources 282 refCat : `lsst.afw.table.SimpleCatalog` 283 Catalog of reference objects. 284 sourceCat : `lsst.afw.table.SourceCatalog` 285 Catalog of detected sources. 286 wcs : `lsst.afw.geom.SkyWcs` 287 Current best WCS of the image. 288 refFluxFioeld : `str` 289 Name of flux field in refCat to use. 290 numUsableSources : `int` 291 Total number of source usable for matching. 292 mintMatchPairs : `int` 293 Minimum number of objects to match between the refCat and sourceCat 294 to consider a valid match. 295 maxMatchDist : `lsst.geom.Angle` 296 Maximum separation to considering a reference and a source a match. 297 sourceFluxField : `str` 298 Name of source catalog flux field. 300 Print diagnostic information std::cout 304 matches : `list` of `lsst.afw.table.ReferenceMatch` 306 numSources = len(sourceCat)
307 posRefBegInd = numUsableSources - numSources
308 if maxMatchDist
is None:
309 maxMatchDistArcSec = self.config.maxMatchDistArcSec
311 maxMatchDistArcSec = min(maxMatchDist.asArcseconds(), self.config.maxMatchDistArcSec)
312 configMatchDistPix = maxMatchDistArcSec/wcs.getPixelScale().asArcseconds()
314 matchControl = MatchOptimisticBControl()
315 matchControl.refFluxField = refFluxField
316 matchControl.sourceFluxField = sourceFluxField
317 matchControl.numBrightStars = self.config.numBrightStars
318 matchControl.minMatchedPairs = self.config.minMatchedPairs
319 matchControl.maxOffsetPix = self.config.maxOffsetPix
320 matchControl.numPointsForShape = self.config.numPointsForShape
321 matchControl.maxDeterminant = self.config.maxDeterminant
323 for maxRotInd
in range(4):
324 matchControl.maxRotationDeg = self.config.maxRotationDeg * math.pow(2.0, 0.5*maxRotInd)
325 for matchRadInd
in range(3):
326 matchControl.matchingAllowancePix = configMatchDistPix * math.pow(1.25, matchRadInd)
328 for angleDiffInd
in range(3):
329 matchControl.allowedNonperpDeg = self.config.allowedNonperpDeg*(angleDiffInd+1)
338 if matches
is not None and len(matches) > 0:
def matchObjectsToSources(self, refCat, sourceCat, wcs, refFluxField, match_tolerance=None)
afw::table::ReferenceMatchVector matchOptimisticB(afw::table::SimpleCatalog const &posRefCat, afw::table::SourceCatalog const &sourceCat, MatchOptimisticBControl const &control, afw::geom::SkyWcs const &wcs, int posRefBegInd=0, bool verbose=false)
Match sources to stars in a position reference catalog using optimistic pattern matching B...
def __init__(self, kwargs)
def _getIsGoodKeys(self, schema)
def __init__(self, maxMatchDist=None)
def filterStars(self, refCat)
def _doMatch(self, refCat, sourceCat, wcs, refFluxField, numUsableSources, minMatchedPairs, maxMatchDist, sourceFluxField, verbose)
def setMatchDistance(matches)
def _isGoodTest(self, source)