LSST Applications  21.0.0+04719a4bac,21.0.0-1-ga51b5d4+f5e6047307,21.0.0-11-g2b59f77+a9c1acf22d,21.0.0-11-ga42c5b2+86977b0b17,21.0.0-12-gf4ce030+76814010d2,21.0.0-13-g1721dae+760e7a6536,21.0.0-13-g3a573fe+768d78a30a,21.0.0-15-g5a7caf0+f21cbc5713,21.0.0-16-g0fb55c1+b60e2d390c,21.0.0-19-g4cded4ca+71a93a33c0,21.0.0-2-g103fe59+bb20972958,21.0.0-2-g45278ab+04719a4bac,21.0.0-2-g5242d73+3ad5d60fb1,21.0.0-2-g7f82c8f+8babb168e8,21.0.0-2-g8f08a60+06509c8b61,21.0.0-2-g8faa9b5+616205b9df,21.0.0-2-ga326454+8babb168e8,21.0.0-2-gde069b7+5e4aea9c2f,21.0.0-2-gecfae73+1d3a86e577,21.0.0-2-gfc62afb+3ad5d60fb1,21.0.0-25-g1d57be3cd+e73869a214,21.0.0-3-g357aad2+ed88757d29,21.0.0-3-g4a4ce7f+3ad5d60fb1,21.0.0-3-g4be5c26+3ad5d60fb1,21.0.0-3-g65f322c+e0b24896a3,21.0.0-3-g7d9da8d+616205b9df,21.0.0-3-ge02ed75+a9c1acf22d,21.0.0-4-g591bb35+a9c1acf22d,21.0.0-4-g65b4814+b60e2d390c,21.0.0-4-gccdca77+0de219a2bc,21.0.0-4-ge8a399c+6c55c39e83,21.0.0-5-gd00fb1e+05fce91b99,21.0.0-6-gc675373+3ad5d60fb1,21.0.0-64-g1122c245+4fb2b8f86e,21.0.0-7-g04766d7+cd19d05db2,21.0.0-7-gdf92d54+04719a4bac,21.0.0-8-g5674e7b+d1bd76f71f,master-gac4afde19b+a9c1acf22d,w.2021.13
LSST Data Management Base Package
matcherSourceSelector.py
Go to the documentation of this file.
1 #
2 # LSST Data Management System
3 #
4 # Copyright 2008-2017 AURA/LSST.
5 #
6 # This product includes software developed by the
7 # LSST Project (http://www.lsst.org/).
8 #
9 # This program is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the LSST License Statement and
20 # the GNU General Public License along with this program. If not,
21 # see <https://www.lsstcorp.org/LegalNotices/>.
22 #
23 
24 import numpy as np
25 
26 import lsst.pex.config as pexConfig
27 from .sourceSelector import BaseSourceSelectorConfig, BaseSourceSelectorTask, sourceSelectorRegistry
28 from lsst.pipe.base import Struct
29 
30 
32  sourceFluxType = pexConfig.Field(
33  doc="Type of source flux; typically one of Ap or Psf",
34  dtype=str,
35  default="Ap",
36  )
37  minSnr = pexConfig.Field(
38  dtype=float,
39  doc="Minimum allowed signal-to-noise ratio for sources used for matching "
40  "(in the flux specified by sourceFluxType); <= 0 for no limit",
41  default=40,
42  )
43  excludePixelFlags = pexConfig.Field(
44  dtype=bool,
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.",
48  default=True,
49  )
50 
51 
52 @pexConfig.registerConfigurable("matcher", sourceSelectorRegistry)
54  """Select sources that are useful for matching.
55 
56  Good matching sources have high signal/noise, are non-blended. They need not
57  be PSF sources, just have reliable centroids.
58 
59  Distinguished from astrometrySourceSelector because it is more lenient
60  (i.e. not checking footprints or bad flags).
61  """
62  ConfigClass = MatcherSourceSelectorConfig
63 
64  def __init__(self, *args, **kwargs):
65  BaseSourceSelectorTask.__init__(self, *args, **kwargs)
66 
67  def selectSources(self, sourceCat, matches=None, exposure=None):
68  """Return a selection of sources that are useful for matching.
69 
70  Parameters:
71  -----------
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.
79 
80  Return
81  ------
82  struct : `lsst.pipe.base.Struct`
83  The struct contains the following data:
84 
85  - selected : `array` of `bool``
86  Boolean array of sources that were selected, same length as
87  sourceCat.
88  """
89  self._getSchemaKeys_getSchemaKeys(sourceCat.schema)
90 
91  good = self._isUsable_isUsable(sourceCat)
92  if self.config.excludePixelFlags:
93  good = good & self._isGood_isGood(sourceCat)
94  return Struct(selected=good)
95 
96  def _getSchemaKeys(self, schema):
97  """Extract and save the necessary keys from schema with asKey.
98  """
99  self.parentKeyparentKey = schema["parent"].asKey()
100  self.centroidXKeycentroidXKey = schema["slot_Centroid_x"].asKey()
101  self.centroidYKeycentroidYKey = schema["slot_Centroid_y"].asKey()
102  self.centroidFlagKeycentroidFlagKey = schema["slot_Centroid_flag"].asKey()
103 
104  fluxPrefix = "slot_%sFlux_" % (self.config.sourceFluxType,)
105  self.fluxFieldfluxField = fluxPrefix + "instFlux"
106  self.fluxKeyfluxKey = schema[fluxPrefix + "instFlux"].asKey()
107  self.fluxFlagKeyfluxFlagKey = schema[fluxPrefix + "flag"].asKey()
108  self.fluxErrKeyfluxErrKey = schema[fluxPrefix + "instFluxErr"].asKey()
109 
110  self.edgeKeyedgeKey = schema["base_PixelFlags_flag_edge"].asKey()
111  self.interpolatedCenterKeyinterpolatedCenterKey = schema["base_PixelFlags_flag_interpolatedCenter"].asKey()
112  self.saturatedKeysaturatedKey = schema["base_PixelFlags_flag_saturated"].asKey()
113 
114  def _isParent(self, sourceCat):
115  """Return True for each source that is the parent source.
116  """
117  test = (sourceCat.get(self.parentKeyparentKey) == 0)
118  return test
119 
120  def _hasCentroid(self, sourceCat):
121  """Return True for each source that has a valid centroid
122  """
123  return np.isfinite(sourceCat.get(self.centroidXKeycentroidXKey)) \
124  & np.isfinite(sourceCat.get(self.centroidYKeycentroidYKey)) \
125  & ~sourceCat.get(self.centroidFlagKeycentroidFlagKey)
126 
127  def _goodSN(self, sourceCat):
128  """Return True for each source that has Signal/Noise > config.minSnr.
129  """
130  if self.config.minSnr <= 0:
131  return True
132  else:
133  with np.errstate(invalid="ignore"): # suppress NAN warnings
134  return sourceCat.get(self.fluxKeyfluxKey)/sourceCat.get(self.fluxErrKeyfluxErrKey) > self.config.minSnr
135 
136  def _isUsable(self, sourceCat):
137  """
138  Return True for each source that is usable for matching, even if it may
139  have a poor centroid.
140 
141  For a source to be usable it must:
142  - have a valid centroid
143  - not be deblended
144  - have a valid instFlux (of the type specified in this object's constructor)
145  - have adequate signal-to-noise
146  """
147  return self._hasCentroid_hasCentroid(sourceCat) \
148  & self._isParent_isParent(sourceCat) \
149  & self._goodSN_goodSN(sourceCat) \
150  & ~sourceCat.get(self.fluxFlagKeyfluxFlagKey)
151 
152  def _isGood(self, sourceCat):
153  """
154  Return True for each source that is usable for matching, even if it may
155  have a poor centroid.
156 
157  For a source to be usable it must:
158  - Not be on a CCD edge.
159  - Not have an interpolated pixel within 3x3 around their centroid.
160  - Not have a saturated pixel in their footprint.
161  """
162  return ~sourceCat.get(self.edgeKeyedgeKey) & \
163  ~sourceCat.get(self.interpolatedCenterKeyinterpolatedCenterKey) & \
164  ~sourceCat.get(self.saturatedKeysaturatedKey)
def selectSources(self, sourceCat, matches=None, exposure=None)