23 """Select sources that are useful for astrometry. 25 Such sources have good signal-to-noise, are well centroided, not blended, 26 and not flagged with a handful of "bad" flags. 32 from .sourceSelector
import BaseSourceSelectorConfig, BaseSourceSelectorTask, sourceSelectorRegistry
34 from functools
import reduce
38 badFlags = pexConfig.ListField(
39 doc=
"List of flags which cause a source to be rejected as bad",
42 "base_PixelFlags_flag_edge",
43 "base_PixelFlags_flag_interpolatedCenter",
44 "base_PixelFlags_flag_saturatedCenter",
45 "base_PixelFlags_flag_crCenter",
46 "base_PixelFlags_flag_bad",
49 sourceFluxType = pexConfig.Field(
50 doc=
"Type of source flux; typically one of Ap or Psf",
54 minSnr = pexConfig.Field(
56 doc=
"Minimum allowed signal-to-noise ratio for sources used for matching " 57 "(in the flux specified by sourceFluxType); <= 0 for no limit",
62 @pexConfig.registerConfigurable(
"astrometry", sourceSelectorRegistry)
64 """Select sources that are useful for astrometry. 66 Good astrometry sources have high signal/noise, are non-blended, and 67 did not have certain "bad" flags set during source extraction. They need not 68 be PSF sources, just have reliable centroids. 70 ConfigClass = AstrometrySourceSelectorConfig
73 BaseSourceSelectorTask.__init__(self, *args, **kwargs)
76 """Return a selection of sources that are useful for astrometry. 80 sourceCat : `lsst.afw.table.SourceCatalog` 81 Catalog of sources to select from. 82 This catalog must be contiguous in memory. 83 matches : `list` of `lsst.afw.table.ReferenceMatch` or None 84 Ignored in this SourceSelector. 85 exposure : `lsst.afw.image.Exposure` or None 86 The exposure the catalog was built from; used for debug display. 90 struct : `lsst.pipe.base.Struct` 91 The struct contains the following data: 93 - selected : `array` of `bool`` 94 Boolean array of sources that were selected, same length as 99 bad = reduce(
lambda x, y: np.logical_or(x, sourceCat.get(y)), self.config.badFlags,
False)
101 return Struct(selected=good & ~bad)
103 def _getSchemaKeys(self, schema):
104 """Extract and save the necessary keys from schema with asKey.""" 113 self.
edgeKey = schema[
"base_PixelFlags_flag_edge"].asKey()
117 fluxPrefix =
"slot_%sFlux_" % (self.config.sourceFluxType,)
122 def _isMultiple(self, sourceCat):
123 """Return True for each source that is likely multiple sources.""" 126 for i, cat
in enumerate(sourceCat):
127 footprint = cat.getFootprint()
128 test[i] |= (footprint
is not None)
and (len(footprint.getPeaks()) > 1)
131 def _hasCentroid(self, sourceCat):
132 """Return True for each source that has a valid centroid""" 133 def checkNonfiniteCentroid():
134 """Return True for sources with non-finite centroids.""" 135 return ~np.isfinite(sourceCat.get(self.
centroidXKey)) | \
137 assert ~checkNonfiniteCentroid().
any(), \
138 "Centroids not finite for %d unflagged sources." % (checkNonfiniteCentroid().sum())
143 def _goodSN(self, sourceCat):
144 """Return True for each source that has Signal/Noise > config.minSnr.""" 145 if self.config.minSnr <= 0:
148 with np.errstate(invalid=
"ignore"):
151 def _isUsable(self, sourceCat):
153 Return True for each source that is usable for matching, even if it may 154 have a poor centroid. 156 For a source to be usable it must: 157 - have a valid centroid 159 - have a valid flux (of the type specified in this object's constructor) 160 - have adequate signal-to-noise 168 def _isGood(self, sourceCat):
170 Return True for each source that is usable for matching and likely has a 173 The additional tests for a good centroid, beyond isUsable, are: 174 - not interpolated in the center 184 def _isBadFlagged(self, source):
185 """Return True if any of config.badFlags are set for this source.""" 186 return any(source.get(flag)
for flag
in self.config.badFlags)
def _isGood(self, sourceCat)
def __init__(self, args, kwargs)
def _isUsable(self, sourceCat)
def _goodSN(self, sourceCat)
bool any(CoordinateExpr< N > const &expr) noexcept
Return true if any elements are true.
def _hasCentroid(self, sourceCat)
def _isMultiple(self, sourceCat)
def selectSources(self, sourceCat, matches=None, exposure=None)
def _getSchemaKeys(self, schema)