1 from __future__
import absolute_import, division, print_function
3 __all__ = [
"matchOptimisticB",
"MatchOptimisticBTask",
"MatchOptimisticBConfig",
6 from builtins
import range
7 from builtins
import object
12 from lsst.afw.table
import Point2DKey
13 import lsst.pex.config
as pexConfig
14 import lsst.pipe.base
as pipeBase
15 from lsst.meas.algorithms.sourceSelector
import sourceSelectorRegistry
17 from ..setMatchDistance
import setMatchDistance
18 from .
import matchOptimisticB, MatchOptimisticBControl
22 """ Stores match tolerances for use in AstrometryTask and later 23 iterations of the matcher. 27 maxMatchDist : lsst.afw.geom.Angle 31 """ MatchOptimsiticBTask relies on a maximum distance for matching 32 set by either the default in MatchOptimisticBConfig or the 2 sigma 33 scatter found after AstrometryTask has fit for a wcs. 39 """Configuration for MatchOptimisticBTask 41 maxMatchDistArcSec = pexConfig.RangeField(
42 doc=
"Maximum separation between reference objects and sources " 43 "beyond which they will not be considered a match (arcsec)",
48 numBrightStars = pexConfig.RangeField(
49 doc=
"Number of bright stars to use",
54 minMatchedPairs = pexConfig.RangeField(
55 doc=
"Minimum number of matched pairs; see also minFracMatchedPairs",
60 minFracMatchedPairs = pexConfig.RangeField(
61 doc=
"Minimum number of matched pairs as a fraction of the smaller of " 62 "the number of reference stars or the number of good sources; " 63 "the actual minimum is the smaller of this value or minMatchedPairs",
69 maxOffsetPix = pexConfig.RangeField(
70 doc=
"Maximum allowed shift of WCS, due to matching (pixel)",
75 maxRotationDeg = pexConfig.RangeField(
76 doc=
"Rotation angle allowed between sources and position reference objects (degrees)",
81 allowedNonperpDeg = pexConfig.RangeField(
82 doc=
"Allowed non-perpendicularity of x and y (degree)",
87 numPointsForShape = pexConfig.Field(
88 doc=
"number of points to define a shape for matching",
92 maxDeterminant = pexConfig.Field(
93 doc=
"maximum determinant of linear transformation matrix for a usable solution",
97 sourceSelector = sourceSelectorRegistry.makeField(
98 doc=
"How to select sources for cross-matching",
104 sourceSelector.setDefaults()
117 """!Match sources to reference objects 119 @anchor MatchOptimisticBTask_ 121 @section meas_astrom_matchOptimisticB_Contents Contents 123 - @ref meas_astrom_matchOptimisticB_Purpose 124 - @ref meas_astrom_matchOptimisticB_Initialize 125 - @ref meas_astrom_matchOptimisticB_IO 126 - @ref meas_astrom_matchOptimisticB_Config 127 - @ref meas_astrom_matchOptimisticB_Example 128 - @ref meas_astrom_matchOptimisticB_Debug 130 @section meas_astrom_matchOptimisticB_Purpose Description 132 Match sources to reference objects. This is often done as a preliminary step to fitting an astrometric 133 or photometric solution. For details about the matching algorithm see matchOptimisticB.h 135 @section meas_astrom_matchOptimisticB_Initialize Task initialisation 137 @copydoc \_\_init\_\_ 139 @section meas_astrom_matchOptimisticB_IO Invoking the Task 141 @copydoc matchObjectsToSources 143 @section meas_astrom_matchOptimisticB_Config Configuration parameters 145 See @ref MatchOptimisticBConfig 147 To modify how usable sources are selected, specify a different source 148 selector in `config.sourceSelector`. 150 @section meas_astrom_matchOptimisticB_Example A complete example of using MatchOptimisticBTask 152 MatchOptimisticBTask is a subtask of AstrometryTask, which is called by PhotoCalTask. 153 See \ref pipe_tasks_photocal_Example. 155 @section meas_astrom_matchOptimisticB_Debug Debug variables 157 The @link lsst.pipe.base.cmdLineTask.CmdLineTask command line task@endlink interface supports a 158 flag @c -d to import @b debug.py from your @c PYTHONPATH; see @ref baseDebug for more about 161 The available variables in MatchOptimisticBTask are: 163 <DT> @c verbose (bool) 164 <DD> If True then the matcher prints debug messages to stdout 167 To investigate the @ref meas_astrom_matchOptimisticB_Debug, put something like 171 debug = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would call us recursively 172 if name == "lsst.pipe.tasks.astrometry": 177 lsstDebug.Info = DebugInfo 179 into your debug.py file and run this task with the @c --debug flag. 181 ConfigClass = MatchOptimisticBConfig
182 _DefaultName =
"matchObjectsToSources" 185 pipeBase.Task.__init__(self, **kwargs)
186 self.makeSubtask(
"sourceSelector")
189 """Extra filtering pass; subclass if desired 195 match_tolerance=None):
196 """!Match sources to position reference stars 198 @param[in] refCat catalog of reference objects that overlap the exposure; reads fields for: 200 - the specified flux field 201 @param[in] sourceCat catalog of sources found on an exposure; reads fields for: 206 - aperture flux, if found, else PSF flux 207 @param[in] wcs estimated WCS 208 @param[in] refFluxField field of refCat to use for flux 209 @param[in] match_tolerance a MatchTolerance object for specifying 210 tolerances. Must at minimum contain a lsst.afw.geom.Angle 211 called maxMatchDist that communicates state between AstrometryTask 212 and the matcher Task. 213 @return an lsst.pipe.base.Struct with fields: 214 - matches a list of matches, each instance of lsst.afw.table.ReferenceMatch 215 - usableSourcCat a catalog of sources potentially usable for matching. 216 For this fitter usable sources include unresolved sources not too near the edge. 217 It includes saturated sources, even those these are removed from the final match list, 218 because saturated sources may be used to determine the match list. 221 debug = lsstDebug.Info(__name__)
223 preNumObj = len(refCat)
225 numRefObj = len(refCat)
228 self.log.info(
"filterStars purged %d reference stars, leaving %d stars" %
229 (preNumObj - numRefObj, numRefObj))
231 if match_tolerance
is None:
235 numSources = len(sourceCat)
236 selectedSources = self.sourceSelector.selectSources(sourceCat)
237 usableSourceCat = selectedSources.sourceCat
238 numUsableSources = len(usableSourceCat)
239 self.log.info(
"Purged %d unusable sources, leaving %d usable sources" %
240 (numSources - numUsableSources, numUsableSources))
242 if len(usableSourceCat) == 0:
243 raise pipeBase.TaskError(
"No sources are usable")
247 minMatchedPairs = min(self.config.minMatchedPairs,
248 int(self.config.minFracMatchedPairs * min([len(refCat), len(usableSourceCat)])))
253 sourceCat=usableSourceCat,
255 refFluxField=refFluxField,
256 numUsableSources=numUsableSources,
257 minMatchedPairs=minMatchedPairs,
258 maxMatchDist=match_tolerance.maxMatchDist,
259 sourceFluxField=self.sourceSelector.fluxField,
260 verbose=debug.verbose,
266 for match
in usableMatches:
269 matches.append(match)
271 self.log.debug(
"Found %d usable matches, of which %d had good sources",
272 len(usableMatches), len(matches))
274 if len(matches) == 0:
275 raise RuntimeError(
"Unable to match sources")
277 self.log.info(
"Matched %d sources" % len(matches))
278 if len(matches) < minMatchedPairs:
279 self.log.warn(
"Number of matches is smaller than request")
281 return pipeBase.Struct(
283 usableSourceCat=usableSourceCat,
284 match_tolerance=match_tolerance,
287 def _getIsGoodKeys(self, schema):
288 self.
edgeKey = schema[
"base_PixelFlags_flag_edge"].asKey()
292 def _isGoodTest(self, source):
294 This is a hard coded version of the isGood flag from the old SourceInfo class that used to be 295 part of this class. This is done current as the API for sourceSelector does not currently 298 return (
not source.get(self.
edgeKey)
and 303 def _doMatch(self, refCat, sourceCat, wcs, refFluxField, numUsableSources, minMatchedPairs,
304 maxMatchDist, sourceFluxField, verbose):
305 """!Implementation of matching sources to position reference stars 307 Unlike matchObjectsToSources, this method does not check if the sources are suitable. 309 @param[in] refCat catalog of position reference stars that overlap an exposure 310 @param[in] sourceCat catalog of sources found on the exposure 311 @param[in] wcs estimated WCS of exposure 312 @param[in] refFluxField field of refCat to use for flux 313 @param[in] numUsableSources number of usable sources (sources with known centroid 314 that are not near the edge, but may be saturated) 315 @param[in] minMatchedPairs minimum number of matches 316 @param[in] maxMatchDist maximum on-sky distance between reference objects and sources 317 (an lsst.afw.geom.Angle); if specified then the smaller of config.maxMatchDistArcSec or 318 maxMatchDist is used; if None then config.maxMatchDistArcSec is used 319 @param[in] sourceFluxField Name of flux field in source catalog 320 @param[in] verbose true to print diagnostic information to std::cout 322 @return a list of matches, an instance 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)
330 configMatchDistPix = maxMatchDistArcSec/wcs.pixelScale().asArcseconds()
332 matchControl = MatchOptimisticBControl()
333 matchControl.refFluxField = refFluxField
334 matchControl.sourceFluxField = sourceFluxField
335 matchControl.numBrightStars = self.config.numBrightStars
336 matchControl.minMatchedPairs = self.config.minMatchedPairs
337 matchControl.maxOffsetPix = self.config.maxOffsetPix
338 matchControl.numPointsForShape = self.config.numPointsForShape
339 matchControl.maxDeterminant = self.config.maxDeterminant
341 for maxRotInd
in range(4):
342 matchControl.maxRotationDeg = self.config.maxRotationDeg * math.pow(2.0, 0.5*maxRotInd)
343 for matchRadInd
in range(3):
344 matchControl.matchingAllowancePix = configMatchDistPix * math.pow(1.25, matchRadInd)
346 for angleDiffInd
in range(3):
347 matchControl.allowedNonperpDeg = self.config.allowedNonperpDeg*(angleDiffInd+1)
356 if matches
is not None and len(matches) > 0:
def _isGoodTest(self, source)
def _doMatch(self, refCat, sourceCat, wcs, refFluxField, numUsableSources, minMatchedPairs, maxMatchDist, sourceFluxField, verbose)
Implementation of matching sources to position reference stars.
lsst::afw::table::ReferenceMatchVector matchOptimisticB(lsst::afw::table::SimpleCatalog const &posRefCat, lsst::afw::table::SourceCatalog const &sourceCat, MatchOptimisticBControl const &control, afw::image::Wcs const &wcs, int posRefBegInd=0, bool verbose=false)
Match sources to stars in a position reference catalog using optimistic pattern matching B...
def filterStars(self, refCat)
def __init__(self, kwargs)
def setMatchDistance(matches)
def __init__(self, maxMatchDist=None)
def matchObjectsToSources(self, refCat, sourceCat, wcs, refFluxField, match_tolerance=None)
Match sources to position reference stars.
Match sources to reference objects.
def _getIsGoodKeys(self, schema)