1 from __future__
import absolute_import, division, print_function
9 from .setMatchDistance
import setMatchDistance
10 from .astromLib
import matchOptimisticB, MatchOptimisticBControl
12 __all__ = [
"MatchOptimisticBTask",
"MatchOptimisticBConfig",
"SourceInfo"]
15 """Configuration for MatchOptimisticBTask
17 sourceFluxType = pexConfig.Field(
18 doc =
"Type of source flux; typically one of Ap or Psf",
22 maxMatchDistArcSec = pexConfig.RangeField(
23 doc =
"Maximum separation between reference objects and sources "
24 "beyond which they will not be considered a match (arcsec)",
29 numBrightStars = pexConfig.RangeField(
30 doc =
"Number of bright stars to use",
35 minMatchedPairs = pexConfig.RangeField(
36 doc =
"Minimum number of matched pairs; see also minFracMatchedPairs",
41 minFracMatchedPairs = pexConfig.RangeField(
42 doc =
"Minimum number of matched pairs as a fraction of the smaller of "
43 "the number of reference stars or the number of good sources; "
44 "the actual minimum is the smaller of this value or minMatchedPairs",
50 maxOffsetPix = pexConfig.RangeField(
51 doc =
"Maximum allowed shift of WCS, due to matching (pixel)",
56 maxRotationDeg = pexConfig.RangeField(
57 doc =
"Rotation angle allowed between sources and position reference objects (degrees)",
62 allowedNonperpDeg = pexConfig.RangeField(
63 doc =
"Allowed non-perpendicularity of x and y (degree)",
68 numPointsForShape = pexConfig.Field(
69 doc =
"number of points to define a shape for matching",
73 maxDeterminant = pexConfig.Field(
74 doc =
"maximum determinant of linear transformation matrix for a usable solution",
80 """Provide usability tests and catalog keys for sources in a source catalog
83 - centroidKey key for centroid
84 - centroidFlagKey key for flag that is True if centroid is valid
85 - edgeKey key for field that is True if source is near an edge
86 - saturatedKey key for field that is True if source has any saturated pixels
87 - interpolatedCenterKey key for field that is True if center pixels have interpolated values;
88 interpolation is triggered by saturation, cosmic rays and bad pixels, and possibly other reasons
89 - fluxField name of flux field
91 @throw RuntimeError if schema version unsupported or a needed field is not found
94 """Construct a SourceInfo
96 @param[in] schema source catalog schema
97 @param[in] fluxType flux type: typically one of "Ap" or "Psf"
99 @throw RuntimeError if the flux field is not found
103 self.
edgeKey = schema[
"base_PixelFlags_flag_edge"].asKey()
111 raise RuntimeError(
"Could not find flux field %s in source schema" % (self.
fluxField,))
114 """Return True if source is likely multiple sources
118 footprint = source.getFootprint()
119 return footprint
is not None and len(footprint.getPeaks()) > 1
122 """Return True if the source has a valid centroid
125 return np.all(np.isfinite(centroid))
and not source.getCentroidFlag()
128 """Return True if the source is usable for matching, even if possibly saturated
130 For a source to be usable it must:
131 - have a valid centroid
132 - be not too near the edge
137 """Return True if source is usable for matching (as per isUsable) and likely has a good centroid
139 For a source to have a good centroid it should not be interpolated in the center;
140 this includes saturated sources so we don't have to test separately for that.
154 """!Match sources to reference objects
156 @anchor MatchOptimisticBTask_
158 @section meas_astrom_matchOptimisticB_Contents Contents
160 - @ref meas_astrom_matchOptimisticB_Purpose
161 - @ref meas_astrom_matchOptimisticB_Initialize
162 - @ref meas_astrom_matchOptimisticB_IO
163 - @ref meas_astrom_matchOptimisticB_Config
164 - @ref meas_astrom_matchOptimisticB_Example
165 - @ref meas_astrom_matchOptimisticB_Debug
167 @section meas_astrom_matchOptimisticB_Purpose Description
169 Match sources to reference objects. This is often done as a preliminary step to fitting an astrometric
170 or photometric solution. For details about the matching algorithm see matchOptimisticB.h
172 @section meas_astrom_matchOptimisticB_Initialize Task initialisation
174 @copydoc \_\_init\_\_
176 @section meas_astrom_matchOptimisticB_IO Invoking the Task
178 @copydoc matchObjectsToSources
180 @section meas_astrom_matchOptimisticB_Config Configuration parameters
182 See @ref MatchOptimisticBConfig
184 To modify the tests for usable sources and good sources, subclass SourceInfo and
185 set MatchOptimisticBTask.SourceInfoClass to your subclass.
187 @section meas_astrom_matchOptimisticB_Example A complete example of using MatchOptimisticBTask
189 MatchOptimisticBTask is a subtask of AstrometryTask, which is called by PhotoCalTask.
190 See \ref meas_photocal_photocal_Example.
192 @section meas_astrom_matchOptimisticB_Debug Debug variables
194 The @link lsst.pipe.base.cmdLineTask.CmdLineTask command line task@endlink interface supports a
195 flag @c -d to import @b debug.py from your @c PYTHONPATH; see @ref baseDebug for more about
198 The available variables in MatchOptimisticBTask are:
200 <DT> @c verbose (bool)
201 <DD> If True then the matcher prints debug messages to stdout
204 To investigate the @ref meas_astrom_matchOptimisticB_Debug, put something like
208 debug = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would call us recursively
209 if name == "lsst.pipe.tasks.astrometry":
214 lsstDebug.Info = DebugInfo
216 into your debug.py file and run this task with the @c --debug flag.
218 ConfigClass = MatchOptimisticBConfig
219 _DefaultName =
"matchObjectsToSources"
220 SourceInfoClass = SourceInfo
223 """Extra filtering pass; subclass if desired
229 """!Match sources to position reference stars
231 @param[in] refCat catalog of reference objects that overlap the exposure; reads fields for:
233 - the specified flux field
234 @param[in] sourceCat catalog of sources found on an exposure; reads fields for:
239 - aperture flux, if found, else PSF flux
240 @param[in] wcs estimated WCS
241 @param[in] refFluxField field of refCat to use for flux
242 @param[in] maxMatchDist maximum on-sky distance between reference objects and sources
243 (an lsst.afw.geom.Angle); if specified then the smaller of config.maxMatchDistArcSec or
244 maxMatchDist is used; if None then config.maxMatchDistArcSec is used
245 @return an lsst.pipe.base.Struct with fields:
246 - matches a list of matches, each instance of lsst.afw.table.ReferenceMatch
247 - usableSourcCat a catalog of sources potentially usable for matching.
248 For this fitter usable sources include unresolved sources not too near the edge.
249 It includes saturated sources, even those these are removed from the final match list,
250 because saturated sources may be used to determine the match list.
255 preNumObj = len(refCat)
257 numRefObj = len(refCat)
259 if self.log: self.log.info(
"filterStars purged %d reference stars, leaving %d stars" % \
260 (preNumObj - numRefObj, numRefObj))
263 schema = sourceCat.schema,
264 fluxType = self.config.sourceFluxType,
268 numSources = len(sourceCat)
270 usableSourceCat.extend(s
for s
in sourceCat
if sourceInfo.isUsable(s))
271 numUsableSources = len(usableSourceCat)
272 self.log.info(
"Purged %d unusable sources, leaving %d usable sources" % \
273 (numSources - numUsableSources, numUsableSources))
275 if len(usableSourceCat) == 0:
276 raise pipeBase.TaskError(
"No sources are usable")
280 minMatchedPairs = min(self.config.minMatchedPairs,
281 int(self.config.minFracMatchedPairs * min([len(refCat), len(usableSourceCat)])))
286 sourceCat = usableSourceCat,
288 refFluxField = refFluxField,
289 numUsableSources = numUsableSources,
290 minMatchedPairs = minMatchedPairs,
291 maxMatchDist = maxMatchDist,
292 sourceInfo = sourceInfo,
293 verbose = debug.verbose,
298 for match
in usableMatches:
299 if sourceInfo.isGood(match.second):
300 matches.append(match)
302 self.log.logdebug(
"Found %d usable matches, of which %d had good sources" %
303 (len(usableMatches), len(matches)))
305 if len(matches) == 0:
306 raise RuntimeError(
"Unable to match sources")
308 self.log.info(
"Matched %d sources" % len(matches))
309 if len(matches) < minMatchedPairs:
310 self.log.warn(
"Number of matches is smaller than request")
312 return pipeBase.Struct(
314 usableSourceCat = usableSourceCat,
318 def _doMatch(self, refCat, sourceCat, wcs, refFluxField, numUsableSources, minMatchedPairs,
319 maxMatchDist, sourceInfo, verbose):
320 """!Implementation of matching sources to position reference stars
322 Unlike matchObjectsToSources, this method does not check if the sources are suitable.
324 @param[in] refCat catalog of position reference stars that overlap an exposure
325 @param[in] sourceCat catalog of sources found on the exposure
326 @param[in] wcs estimated WCS of exposure
327 @param[in] refFluxField field of refCat to use for flux
328 @param[in] numUsableSources number of usable sources (sources with known centroid
329 that are not near the edge, but may be saturated)
330 @param[in] minMatchedPairs minimum number of matches
331 @param[in] maxMatchDist maximum on-sky distance between reference objects and sources
332 (an lsst.afw.geom.Angle); if specified then the smaller of config.maxMatchDistArcSec or
333 maxMatchDist is used; if None then config.maxMatchDistArcSec is used
334 @param[in] sourceInfo SourceInfo for the sourceCat
335 @param[in] verbose true to print diagnostic information to std::cout
337 @return a list of matches, an instance of lsst.afw.table.ReferenceMatch
339 numSources = len(sourceCat)
340 posRefBegInd = numUsableSources - numSources
341 if maxMatchDist
is None:
342 maxMatchDistArcSec = self.config.maxMatchDistArcSec
344 maxMatchDistArcSec = min(maxMatchDist.asArcseconds(), self.config.maxMatchDistArcSec)
345 configMatchDistPix = maxMatchDistArcSec/wcs.pixelScale().asArcseconds()
348 matchControl.refFluxField = refFluxField
349 matchControl.sourceFluxField = sourceInfo.fluxField
350 matchControl.numBrightStars = self.config.numBrightStars
351 matchControl.minMatchedPairs = self.config.minMatchedPairs
352 matchControl.maxOffsetPix = self.config.maxOffsetPix
353 matchControl.numPointsForShape = self.config.numPointsForShape
354 matchControl.maxDeterminant = self.config.maxDeterminant
356 for maxRotInd
in range(4):
357 matchControl.maxRotationDeg = self.config.maxRotationDeg * math.pow(2.0, 0.5*maxRotInd)
358 for matchRadInd
in range(3):
359 matchControl.matchingAllowancePix = configMatchDistPix * math.pow(1.25, matchRadInd)
361 for angleDiffInd
in range(3):
362 matchControl.allowedNonperpDeg = self.config.allowedNonperpDeg*(angleDiffInd+1)
371 if matches
is not None and len(matches) > 0:
Match sources to reference objects.
def matchObjectsToSources
Match 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)
def _doMatch
Implementation of matching sources to position reference stars.
Custom catalog class for record/table subclasses that are guaranteed to have an ID, and should generally be sorted by that ID.