23"""Select sources that are useful for astrometry.
25Such sources have good signal-to-noise, are well centroided, not blended,
26and not flagged with a handful of "bad" flags.
29__all__ = [
"AstrometrySourceSelectorConfig",
"AstrometrySourceSelectorTask"]
34from .sourceSelector
import BaseSourceSelectorConfig, BaseSourceSelectorTask, sourceSelectorRegistry
35from lsst.pipe.base
import Struct
36from functools
import reduce
40 badFlags = pexConfig.ListField(
41 doc=
"List of flags which cause a source to be rejected as bad",
44 "base_PixelFlags_flag_edge",
45 "base_PixelFlags_flag_interpolatedCenter",
46 "base_PixelFlags_flag_saturatedCenter",
47 "base_PixelFlags_flag_crCenter",
48 "base_PixelFlags_flag_bad",
51 sourceFluxType = pexConfig.Field(
52 doc=
"Type of source flux; typically one of Ap or Psf",
56 minSnr = pexConfig.Field(
58 doc=
"Minimum allowed signal-to-noise ratio for sources used for matching "
59 "(in the flux specified by sourceFluxType); <= 0 for no limit",
64@pexConfig.registerConfigurable("astrometry", sourceSelectorRegistry)
66 """Select sources that are useful for astrometry.
68 Good astrometry sources have high signal/noise, are non-blended, and
69 did
not have certain
"bad" flags set during source extraction. They need
not
70 be PSF sources, just have reliable centroids.
72 ConfigClass = AstrometrySourceSelectorConfig
75 BaseSourceSelectorTask.__init__(self, *args, **kwargs)
78 """Return a selection of sources that are useful for astrometry.
83 Catalog of sources to select from.
84 This catalog must be contiguous
in memory.
86 Ignored
in this SourceSelector.
88 The exposure the catalog was built
from; used
for debug display.
92 struct : `lsst.pipe.base.Struct`
93 The struct contains the following data:
96 Boolean array of sources that were selected, same length
as
97 sourceCat. (`numpy.ndarray` of `bool`)
101 bad = reduce(lambda x, y: np.logical_or(x, sourceCat.get(y)), self.config.badFlags,
False)
103 return Struct(selected=good & ~bad)
105 def _getSchemaKeys(self, schema):
106 """Extract and save the necessary keys from schema with asKey.
116 self.
edgeKey = schema[
"base_PixelFlags_flag_edge"].asKey()
120 fluxPrefix =
"slot_%sFlux_" % (self.config.sourceFluxType,)
125 def _isMultiple(self, sourceCat):
126 """Return True for each source that is likely multiple sources.
130 for i, cat
in enumerate(sourceCat):
131 footprint = cat.getFootprint()
132 test[i] |= (footprint
is not None)
and (len(footprint.getPeaks()) > 1)
135 def _hasCentroid(self, sourceCat):
136 """Return True for each source that has a valid centroid
138 def checkNonfiniteCentroid():
139 """Return True for sources with non-finite centroids.
141 return ~np.isfinite(sourceCat.get(self.
centroidXKey)) | \
143 assert ~checkNonfiniteCentroid().any(), \
144 "Centroids not finite for %d unflagged sources." % (checkNonfiniteCentroid().sum())
149 def _goodSN(self, sourceCat):
150 """Return True for each source that has Signal/Noise > config.minSnr.
152 if self.config.minSnr <= 0:
155 with np.errstate(invalid=
"ignore"):
158 def _isUsable(self, sourceCat):
159 """Return True for each source that is usable for matching, even if it may
160 have a poor centroid.
162 For a source to be usable it must:
163 - have a valid centroid
165 - have a valid flux (of the type specified
in this object
's constructor)
166 - have adequate signal-to-noise
174 def _isGood(self, sourceCat):
175 """Return True for each source that is usable for matching and likely has a
178 The additional tests for a good centroid, beyond isUsable, are:
179 -
not interpolated
in the center
189 def _isBadFlagged(self, source):
190 """Return True if any of config.badFlags are set for this source.
192 return any(source.get(flag)
for flag
in self.config.badFlags)
def _hasCentroid(self, sourceCat)
def _isUsable(self, sourceCat)
def __init__(self, *args, **kwargs)
def selectSources(self, sourceCat, matches=None, exposure=None)
def _isMultiple(self, sourceCat)
def _isGood(self, sourceCat)
def _getSchemaKeys(self, schema)
def _goodSN(self, sourceCat)