2 __all__ = [
"MatchOptimisticBTask",
"MatchOptimisticBConfig",
10 from .setMatchDistance
import setMatchDistance
11 from .matchOptimisticB
import matchOptimisticB, MatchOptimisticBControl
15 """Stores match tolerances for use in `lsst.meas.astrom.AstrometryTask` and 16 later iterations of the matcher. 18 MatchOptimsiticBTask relies on a maximum distance for matching 19 set by either the default in MatchOptimisticBConfig or the 2 sigma 20 scatter found after AstrometryTask has fit for a wcs. 24 maxMatchDist : `lsst.geom.Angle` 25 Current maximum distance to consider a match. 33 """Configuration for MatchOptimisticBTask 35 maxMatchDistArcSec = pexConfig.RangeField(
36 doc=
"Maximum separation between reference objects and sources " 37 "beyond which they will not be considered a match (arcsec)",
42 numBrightStars = pexConfig.RangeField(
43 doc=
"Number of bright stars to use",
48 minMatchedPairs = pexConfig.RangeField(
49 doc=
"Minimum number of matched pairs; see also minFracMatchedPairs",
54 minFracMatchedPairs = pexConfig.RangeField(
55 doc=
"Minimum number of matched pairs as a fraction of the smaller of " 56 "the number of reference stars or the number of good sources; " 57 "the actual minimum is the smaller of this value or minMatchedPairs",
63 maxOffsetPix = pexConfig.RangeField(
64 doc=
"Maximum allowed shift of WCS, due to matching (pixel). " 65 "When changing this value, the LoadReferenceObjectsConfig.pixelMargin should also be updated.",
70 maxRotationDeg = pexConfig.RangeField(
71 doc=
"Rotation angle allowed between sources and position reference objects (degrees)",
76 allowedNonperpDeg = pexConfig.RangeField(
77 doc=
"Allowed non-perpendicularity of x and y (degree)",
82 numPointsForShape = pexConfig.Field(
83 doc=
"number of points to define a shape for matching",
87 maxDeterminant = pexConfig.Field(
88 doc=
"maximum determinant of linear transformation matrix for a usable solution",
104 """Match sources to reference objects using the Optimistic Pattern Matcher 105 B algorithm of Tabur 2007. 107 ConfigClass = MatchOptimisticBConfig
108 _DefaultName =
"matchObjectsToSources" 111 pipeBase.Task.__init__(self, **kwargs)
114 """Extra filtering pass; subclass if desired. 118 refCat : `lsst.afw.table.SimpleCatalog` 119 Catalog of reference objects. 123 trimmedRefCat : `lsst.afw.table.SimpleCatalog` 124 Reference catalog with some filtering applied. Currently no 125 filtering is applied. 131 match_tolerance=None):
132 """Match sources to position reference stars. 136 refCat : `lsst.afw.table.SimpleCatalog` 137 Reference catalog to match. 138 sourceCat : `lsst.afw.table.SourceCatalog` 139 Catalog of sources found on an exposure. This should already be 140 down-selected to "good"/"usable" sources in the calling Task. 141 wcs : `lsst.afw.geom.SkyWcs` 142 Current WCS of the exposure containing the sources. 143 sourceFluxField : `str` 144 Field of the sourceCat to use for flux 146 Field of the refCat to use for flux 147 match_tolerance : `lsst.meas.astrom.MatchTolerance` 148 Object containing information from previous 149 `lsst.meas.astrom.AstrometryTask` match/fit cycles for use in 150 matching. If `None` is config defaults. 154 matchResult : `lsst.pipe.base.Struct` 155 Result struct with components 157 - ``matches`` : List of matches with distance below the maximum match 158 distance (`list` of `lsst.afw.table.ReferenceMatch`). 159 - ``useableSourceCat`` : Catalog of sources matched and suited for 160 WCS fitting (`lsst.afw.table.SourceCatalog`). 161 - ``match_tolerance`` : MatchTolerance object updated from this 162 match iteration (`lsst.meas.astrom.MatchTolerance`). 167 preNumObj = len(refCat)
169 numRefObj = len(refCat)
172 self.log.
info(
"filterStars purged %d reference stars, leaving %d stars" %
173 (preNumObj - numRefObj, numRefObj))
175 if match_tolerance
is None:
180 usableSourceCat = sourceCat
182 numUsableSources = len(usableSourceCat)
184 if len(usableSourceCat) == 0:
185 raise pipeBase.TaskError(
"No sources are usable")
187 minMatchedPairs =
min(self.config.minMatchedPairs,
188 int(self.config.minFracMatchedPairs *
min([len(refCat), len(usableSourceCat)])))
193 sourceCat=usableSourceCat,
195 refFluxField=refFluxField,
196 numUsableSources=numUsableSources,
197 minMatchedPairs=minMatchedPairs,
198 maxMatchDist=match_tolerance.maxMatchDist,
199 sourceFluxField=sourceFluxField,
200 verbose=debug.verbose,
206 for match
in usableMatches:
209 matches.append(match)
211 self.log.
debug(
"Found %d usable matches, of which %d had good sources",
212 len(usableMatches), len(matches))
214 if len(matches) == 0:
215 raise RuntimeError(
"Unable to match sources")
217 self.log.
info(
"Matched %d sources" % len(matches))
218 if len(matches) < minMatchedPairs:
219 self.log.
warn(
"Number of matches is smaller than request")
221 return pipeBase.Struct(
223 usableSourceCat=usableSourceCat,
224 match_tolerance=match_tolerance,
227 def _getIsGoodKeys(self, schema):
228 """Retrieve the keys needed for the isGoodTest from the source catalog 233 schema : `lsst.afw.table.Schema` 234 Source schema to retrieve `lsst.afw.table.Key` s from. 236 self.
edgeKey = schema[
"base_PixelFlags_flag_edge"].asKey()
240 def _isGoodTest(self, source):
241 """Test that an object is good for use in the WCS fitter. 243 This is a hard coded version of the isGood flag from the old SourceInfo 244 class that used to be part of this class. 248 source : `lsst.afw.table.SourceRecord` 254 Source passes CCD edge and saturated tests. 256 return (
not source.get(self.
edgeKey)
and 261 def _doMatch(self, refCat, sourceCat, wcs, refFluxField, numUsableSources, minMatchedPairs,
262 maxMatchDist, sourceFluxField, verbose):
263 """Implementation of matching sources to position reference stars. 265 Unlike matchObjectsToSources, this method does not check if the sources 270 refCat : `lsst.afw.table.SimpleCatalog` 271 Catalog of reference objects. 272 sourceCat : `lsst.afw.table.SourceCatalog` 273 Catalog of detected sources. 274 wcs : `lsst.afw.geom.SkyWcs` 275 Current best WCS of the image. 276 refFluxFioeld : `str` 277 Name of flux field in refCat to use. 278 numUsableSources : `int` 279 Total number of source usable for matching. 280 mintMatchPairs : `int` 281 Minimum number of objects to match between the refCat and sourceCat 282 to consider a valid match. 283 maxMatchDist : `lsst.geom.Angle` 284 Maximum separation to considering a reference and a source a match. 285 sourceFluxField : `str` 286 Name of source catalog flux field. 288 Print diagnostic information std::cout 292 matches : `list` of `lsst.afw.table.ReferenceMatch` 294 numSources = len(sourceCat)
295 posRefBegInd = numUsableSources - numSources
296 if maxMatchDist
is None:
297 maxMatchDistArcSec = self.config.maxMatchDistArcSec
299 maxMatchDistArcSec =
min(maxMatchDist.asArcseconds(), self.config.maxMatchDistArcSec)
300 configMatchDistPix = maxMatchDistArcSec/wcs.getPixelScale().asArcseconds()
302 matchControl = MatchOptimisticBControl()
303 matchControl.refFluxField = refFluxField
304 matchControl.sourceFluxField = sourceFluxField
305 matchControl.numBrightStars = self.config.numBrightStars
306 matchControl.minMatchedPairs = self.config.minMatchedPairs
307 matchControl.maxOffsetPix = self.config.maxOffsetPix
308 matchControl.numPointsForShape = self.config.numPointsForShape
309 matchControl.maxDeterminant = self.config.maxDeterminant
311 for maxRotInd
in range(4):
312 matchControl.maxRotationDeg = self.config.maxRotationDeg * math.pow(2.0, 0.5*maxRotInd)
313 for matchRadInd
in range(3):
314 matchControl.matchingAllowancePix = configMatchDistPix * math.pow(1.25, matchRadInd)
316 for angleDiffInd
in range(3):
317 matchControl.allowedNonperpDeg = self.config.allowedNonperpDeg*(angleDiffInd+1)
326 if matches
is not None and len(matches) > 0:
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)
def matchObjectsToSources(self, refCat, sourceCat, wcs, sourceFluxField, refFluxField, match_tolerance=None)