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 matching.
52 Good matching sources have high signal/noise, are non-blended. They need not
53 be PSF sources, just have reliable centroids.
55 ConfigClass = MatcherSourceSelectorConfig
58 BaseSourceSelectorTask.__init__(self, *args, **kwargs)
62 !Return a catalog of sources: a subset of sourceCat.
64 If sourceCat is cotiguous in memory, will use vectorized tests for ~100x
65 execution speed advantage over non-contiguous catalogs. This would be
66 even faster if we didn't have to check footprints for multiple peaks.
68 @param[in] sourceCat catalog of sources that may be sources
69 (an lsst.afw.table.SourceCatalog)
71 @return a pipeBase.Struct containing:
72 - sourceCat a catalog of sources
76 if sourceCat.isContiguous():
78 result = sourceCat[good]
80 result = table.SourceCatalog(sourceCat.table)
81 for i, source
in enumerate(sourceCat):
84 return Struct(sourceCat=result)
86 def _getSchemaKeys(self, schema):
87 """Extract and save the necessary keys from schema with asKey."""
93 fluxPrefix =
"slot_%sFlux_" % (self.config.sourceFluxType,)
95 self.
fluxKey = schema[fluxPrefix +
"flux"].asKey()
99 def _isParent_vector(self, sourceCat):
100 """Return True for each source that is the parent source."""
101 test = (sourceCat.get(self.
parentKey) == 0)
104 def _isParent(self, source):
105 """Return True if source is the parent source."""
110 def _hasCentroid_vector(self, sourceCat):
111 """Return True for each source that has a valid centroid"""
116 def _hasCentroid(self, source):
117 """Return True if the source has a valid centroid"""
118 centroid = source.getCentroid()
119 return np.all(np.isfinite(centroid))
and not source.getCentroidFlag()
121 def _goodSN_vector(self, sourceCat):
122 """Return True for each source that has Signal/Noise > config.minSnr."""
123 if self.config.minSnr <= 0:
128 def _goodSN(self, source):
129 """Return True if source has Signal/Noise > config.minSnr."""
130 return (self.config.minSnr <= 0
or
133 def _isUsable_vector(self, sourceCat):
135 Return True for each source that is usable for matching, even if it may
136 have a poor centroid.
138 For a source to be usable it must:
139 - have a valid centroid
141 - have a valid flux (of the type specified in this object's constructor)
142 - have adequate signal-to-noise
149 def _isUsable(self, source):
151 Return True if the source is usable for matching, even if it may have a
154 For a source to be usable it must:
155 - have a valid centroid
157 - have a valid flux (of the type specified in this object's constructor)
158 - have adequate signal-to-noise
165 sourceSelectorRegistry.register(
"matcher", MatcherSourceSelectorTask)