23 from __future__
import absolute_import, division, print_function
28 import lsst.pex.config
as pexConfig
29 from .sourceSelector
import BaseSourceSelectorConfig, BaseSourceSelectorTask, sourceSelectorRegistry
30 from lsst.pipe.base
import Struct
31 from functools
import reduce
35 sourceFluxType = pexConfig.Field(
36 doc=
"Type of source flux; typically one of Ap or Psf",
40 minSnr = pexConfig.Field(
42 doc=
"Minimum allowed signal-to-noise ratio for sources used for matching "
43 "(in the flux specified by sourceFluxType); <= 0 for no limit",
50 !Select sources that are useful for astrometry.
52 Good astrometry sources have high signal/noise, are non-blended, and
53 did not have certain "bad" flags set during source extraction. They need not
54 be PSF sources, just have reliable centroids.
56 ConfigClass = AstrometrySourceSelectorConfig
59 BaseSourceSelectorTask.__init__(self, *args, **kwargs)
63 !Return a catalog of sources: a subset of sourceCat.
65 If sourceCat is cotiguous in memory, will use vectorized tests for ~100x
66 execution speed advantage over non-contiguous catalogs. This would be
67 even faster if we didn't have to check footprints for multiple peaks.
69 @param[in] sourceCat catalog of sources that may be sources
70 (an lsst.afw.table.SourceCatalog)
72 @return a pipeBase.Struct containing:
73 - sourceCat a catalog of sources
77 if sourceCat.isContiguous():
78 bad = reduce(
lambda x, y: np.logical_or(x, sourceCat.get(y)), self.config.badFlags,
False)
80 result = sourceCat[good & ~bad]
82 result = table.SourceCatalog(sourceCat.table)
83 for i, source
in enumerate(sourceCat):
84 if self.
_isGood(source)
and not self._isBad(source):
86 return Struct(sourceCat=result)
88 def _getSchemaKeys(self, schema):
89 """Extract and save the necessary keys from schema with asKey."""
96 self.
edgeKey = schema[
"base_PixelFlags_flag_edge"].asKey()
98 self.
saturatedKey = schema[
"base_PixelFlags_flag_saturated"].asKey()
100 fluxPrefix =
"slot_%sFlux_" % (self.config.sourceFluxType,)
101 self.
fluxKey = schema[fluxPrefix +
"flux"].asKey()
105 def _isMultiple_vector(self, sourceCat):
106 """Return True for each source that is likely multiple sources."""
109 for i, cat
in enumerate(sourceCat):
110 footprint = cat.getFootprint()
111 test[i] |= (footprint
is not None)
and (len(footprint.getPeaks()) > 1)
114 def _isMultiple(self, source):
115 """Return True if source is likely multiple sources."""
118 footprint = source.getFootprint()
119 return footprint
is not None and len(footprint.getPeaks()) > 1
121 def _hasCentroid_vector(self, sourceCat):
122 """Return True for each source that has a valid centroid"""
127 def _hasCentroid(self, source):
128 """Return True if the source has a valid centroid"""
129 centroid = source.getCentroid()
130 return np.all(np.isfinite(centroid))
and not source.getCentroidFlag()
132 def _goodSN_vector(self, sourceCat):
133 """Return True for each source that has Signal/Noise > config.minSnr."""
134 if self.config.minSnr <= 0:
139 def _goodSN(self, source):
140 """Return True if source has Signal/Noise > config.minSnr."""
141 return (self.config.minSnr <= 0
or
144 def _isUsable_vector(self, sourceCat):
146 Return True for each source that is usable for matching, even if it may
147 have a poor centroid.
149 For a source to be usable it must:
150 - have a valid centroid
152 - have a valid flux (of the type specified in this object's constructor)
153 - have adequate signal-to-noise
161 def _isUsable(self, source):
163 Return True if the source is usable for matching, even if it may have a
166 For a source to be usable it must:
167 - have a valid centroid
169 - have a valid flux (of the type specified in this object's constructor)
170 - have adequate signal-to-noise
177 def _isGood_vector(self, sourceCat):
179 Return True for each source that is usable for matching and likely has a
182 The additional tests for a good centroid, beyond isUsable, are:
183 - not interpolated in the center
193 def _isGood(self, source):
195 Return True if source is usable for matching and likely has a good centroid.
197 The additional tests for a good centroid, beyond isUsable, are:
198 - not interpolated in the center
205 and not source.get(self.
edgeKey)
208 sourceSelectorRegistry.register(
"astrometry", AstrometrySourceSelectorTask)