26 import lsst.pex.config 
as pexConfig
 
   27 from .sourceSelector 
import BaseSourceSelectorConfig, BaseSourceSelectorTask, sourceSelectorRegistry
 
   32     sourceFluxType = pexConfig.Field(
 
   33         doc=
"Type of source flux; typically one of Ap or Psf",
 
   37     minSnr = pexConfig.Field(
 
   39         doc=
"Minimum allowed signal-to-noise ratio for sources used for matching " 
   40         "(in the flux specified by sourceFluxType); <= 0 for no limit",
 
   43     excludePixelFlags = pexConfig.Field(
 
   45         doc=
"Exclude objects that have saturated, interpolated, or edge " 
   46             "pixels using PixelFlags. For matchOptimisticB set this to False " 
   47             "to recover previous matcher selector behavior.",
 
   52 @pexConfig.registerConfigurable(
"matcher", sourceSelectorRegistry)
 
   54     """Select sources that are useful for matching. 
   56     Good matching sources have high signal/noise, are non-blended. They need not 
   57     be PSF sources, just have reliable centroids. 
   59     Distinguished from astrometrySourceSelector because it is more lenient 
   60     (i.e. not checking footprints or bad flags). 
   62     ConfigClass = MatcherSourceSelectorConfig
 
   65         BaseSourceSelectorTask.__init__(self, *args, **kwargs)
 
   68         """Return a selection of sources that are useful for matching. 
   72         sourceCat : `lsst.afw.table.SourceCatalog` 
   73             Catalog of sources to select from. 
   74             This catalog must be contiguous in memory. 
   75         matches : `list` of `lsst.afw.table.ReferenceMatch` or None 
   76             Ignored in this SourceSelector. 
   77         exposure : `lsst.afw.image.Exposure` or None 
   78             The exposure the catalog was built from; used for debug display. 
   82         struct : `lsst.pipe.base.Struct` 
   83             The struct contains the following data: 
   85             - selected : `array` of `bool`` 
   86                 Boolean array of sources that were selected, same length as 
   92         if self.config.excludePixelFlags:
 
   93             good = good & self.
_isGood(sourceCat)
 
   94         return Struct(selected=good)
 
   96     def _getSchemaKeys(self, schema):
 
   97         """Extract and save the necessary keys from schema with asKey.""" 
  103         fluxPrefix = 
"slot_%sFlux_" % (self.config.sourceFluxType,)
 
  105         self.
fluxKey = schema[fluxPrefix + 
"instFlux"].asKey()
 
  109         self.
edgeKey = schema[
"base_PixelFlags_flag_edge"].asKey()
 
  113     def _isParent(self, sourceCat):
 
  114         """Return True for each source that is the parent source.""" 
  115         test = (sourceCat.get(self.
parentKey) == 0)
 
  118     def _hasCentroid(self, sourceCat):
 
  119         """Return True for each source that has a valid centroid""" 
  124     def _goodSN(self, sourceCat):
 
  125         """Return True for each source that has Signal/Noise > config.minSnr.""" 
  126         if self.config.minSnr <= 0:
 
  129             with np.errstate(invalid=
"ignore"):  
 
  130                 return sourceCat.get(self.
fluxKey)/sourceCat.get(self.
fluxErrKey) > self.config.minSnr
 
  132     def _isUsable(self, sourceCat):
 
  134         Return True for each source that is usable for matching, even if it may 
  135         have a poor centroid. 
  137         For a source to be usable it must: 
  138         - have a valid centroid 
  140         - have a valid instFlux (of the type specified in this object's constructor) 
  141         - have adequate signal-to-noise 
  148     def _isGood(self, sourceCat):
 
  150         Return True for each source that is usable for matching, even if it may 
  151         have a poor centroid. 
  153         For a source to be usable it must: 
  154         - Not be on a CCD edge. 
  155         - Not have an interpolated pixel within 3x3 around their centroid. 
  156         - Not have a saturated pixel in their footprint. 
  158         return ~sourceCat.get(self.
edgeKey) & \