lsst.ip.diffim  20.0.0-1-g596936a+10
diaCatalogSourceSelector.py
Go to the documentation of this file.
1 # This file is part of ip_diffim.
2 #
3 # Developed for the LSST Data Management System.
4 # This product includes software developed by the LSST Project
5 # (https://www.lsst.org).
6 # See the COPYRIGHT file at the top-level directory of this distribution
7 # for details of code ownership.
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 GNU General Public License
20 # along with this program. If not, see <https://www.gnu.org/licenses/>.
21 
22 import numpy as np
23 
24 from lsst.pipe.base import Struct
25 import lsst.pex.config as pexConfig
26 import lsst.afw.display as afwDisplay
27 import lsst.meas.algorithms as measAlg
28 
29 __all__ = ["DiaCatalogSourceSelectorConfig", "DiaCatalogSourceSelectorTask"]
30 
31 
32 class DiaCatalogSourceSelectorConfig(measAlg.BaseStarSelectorConfig):
33  # Selection cuts on the input source catalog
34  fluxLim = pexConfig.Field(
35  doc="specify the minimum psfFlux for good Kernel Candidates",
36  dtype=float,
37  default=0.0,
38  check=lambda x: x >= 0.0,
39  )
40  fluxMax = pexConfig.Field(
41  doc="specify the maximum psfFlux for good Kernel Candidates (ignored if == 0)",
42  dtype=float,
43  default=0.0,
44  check=lambda x: x >= 0.0,
45  )
46  # Selection cuts on the reference catalog
47  selectStar = pexConfig.Field(
48  doc="Select objects that are flagged as stars",
49  dtype=bool,
50  default=True
51  )
52  selectGalaxy = pexConfig.Field(
53  doc="Select objects that are flagged as galaxies",
54  dtype=bool,
55  default=False
56  )
57  includeVariable = pexConfig.Field(
58  doc="Include objects that are known to be variable",
59  dtype=bool,
60  default=False
61  )
62  grMin = pexConfig.Field(
63  doc="Minimum g-r color for selection (inclusive)",
64  dtype=float,
65  default=0.0
66  )
67  grMax = pexConfig.Field(
68  doc="Maximum g-r color for selection (inclusive)",
69  dtype=float,
70  default=3.0
71  )
72 
73  def setDefaults(self):
74  measAlg.BaseStarSelectorConfig.setDefaults(self)
75  self.badFlags = [
76  "base_PixelFlags_flag_edge",
77  "base_PixelFlags_flag_interpolatedCenter",
78  "base_PixelFlags_flag_saturatedCenter",
79  "slot_Centroid_flag",
80  ]
81 
82 
83 class CheckSource(object):
84  """A functor to check whether a source has any flags set that should cause it to be labeled bad."""
85 
86  def __init__(self, table, fluxLim, fluxMax, badFlags):
87  self.keys = [table.getSchema().find(name).key for name in badFlags]
88  self.fluxLim = fluxLim
89  self.fluxMax = fluxMax
90 
91  def __call__(self, source):
92  for k in self.keys:
93  if source.get(k):
94  return False
95  if self.fluxLim is not None and source.getPsfInstFlux() < self.fluxLim: # ignore faint objects
96  return False
97  if self.fluxMax != 0.0 and source.getPsfInstFlux() > self.fluxMax: # ignore bright objects
98  return False
99  return True
100 
101 
102 @pexConfig.registerConfigurable("diaCatalog", measAlg.sourceSelectorRegistry)
103 class DiaCatalogSourceSelectorTask(measAlg.BaseSourceSelectorTask):
104  """A task that selects sources for Kernel candidates.
105 
106  A naive star selector based on second moments. Use with caution.
107 
108  Notes
109  -----
110  Debug Variables
111 
112  DiaCatalogSourceSelectorTask has a debug dictionary with the following keys:
113 
114  display : `bool`
115  if True display debug information
116  displayExposure : `bool`
117  if True display exposure
118  pauseAtEnd `bool`
119  if True wait after displaying everything and wait for user input
120 
121  Examples
122  --------
123  For example, put something like:
124 
125  .. code-block:: py
126 
127  import lsstDebug
128  def DebugInfo(name):
129  di = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would call us recursively
130  if name.endswith("diaCatalogSourceSelector"):
131  di.display = True
132 
133  return di
134 
135  lsstDebug.Info = DebugInfo
136 
137  into your `debug.py` file and run your task with the `--debug` flag.
138  """
139  ConfigClass = DiaCatalogSourceSelectorConfig
140  usesMatches = True # selectStars uses (requires) its matches argument
141 
142  def selectSources(self, sourceCat, matches=None, exposure=None):
143  """Return a selection of sources for Kernel candidates.
144 
145  Parameters
146  ----------
147  sourceCat : `lsst.afw.table.SourceCatalog`
148  Catalog of sources to select from.
149  This catalog must be contiguous in memory.
150  matches : `list` of `lsst.afw.table.ReferenceMatch`
151  A match vector as produced by meas_astrom.
152  exposure : `lsst.afw.image.Exposure` or None
153  The exposure the catalog was built from; used for debug display.
154 
155  Returns
156  -------
157  struct : `lsst.pipe.base.Struct`
158  The struct contains the following data:
159 
160  - selected : `array` of `bool``
161  Boolean array of sources that were selected, same length as
162  sourceCat.
163  """
164  import lsstDebug
165  display = lsstDebug.Info(__name__).display
166  displayExposure = lsstDebug.Info(__name__).displayExposure
167  pauseAtEnd = lsstDebug.Info(__name__).pauseAtEnd
168 
169  if matches is None:
170  raise RuntimeError("DiaCatalogSourceSelector requires matches")
171 
172  mi = exposure.getMaskedImage()
173 
174  if display and displayExposure:
175  disp = afwDisplay.Display(frame=lsstDebug.frame)
176  disp.mtv(mi, title="Kernel candidates")
177  #
178  # Look for flags in each Source
179  #
180  isGoodSource = CheckSource(sourceCat, self.config.fluxLim, self.config.fluxMax, self.config.badFlags)
181 
182  # Go through and find all the acceptable candidates in the catalogue
183  selected = np.zeros(len(sourceCat), dtype=bool)
184 
185  if display and displayExposure:
186  symbs = []
187  ctypes = []
188 
189  doColorCut = True
190 
191  refSchema = matches[0][0].schema
192  rRefFluxField = measAlg.getRefFluxField(refSchema, "r")
193  gRefFluxField = measAlg.getRefFluxField(refSchema, "g")
194  for i, (ref, source, d) in enumerate(matches):
195  if not isGoodSource(source):
196  if display and displayExposure:
197  symbs.append("+")
198  ctypes.append(afwDisplay.RED)
199  else:
200  isStar = not ref.get("resolved")
201  isVar = not ref.get("photometric")
202  gMag = None
203  rMag = None
204  if doColorCut:
205  try:
206  gMag = -2.5 * np.log10(ref.get(gRefFluxField))
207  rMag = -2.5 * np.log10(ref.get(rRefFluxField))
208  except KeyError:
209  self.log.warn("Cannot cut on color info; fields 'g' and 'r' do not exist")
210  doColorCut = False
211  isRightColor = True
212  else:
213  isRightColor = (gMag-rMag) >= self.config.grMin and (gMag-rMag) <= self.config.grMax
214 
215  isRightType = (self.config.selectStar and isStar) or (self.config.selectGalaxy and not isStar)
216  isRightVar = (self.config.includeVariable) or (self.config.includeVariable is isVar)
217  if isRightType and isRightVar and isRightColor:
218  selected[i] = True
219  if display and displayExposure:
220  symbs.append("+")
221  ctypes.append(afwDisplay.GREEN)
222  elif display and displayExposure:
223  symbs.append("o")
224  ctypes.append(afwDisplay.BLUE)
225 
226  if display and displayExposure:
227  disp = afwDisplay.Display(frame=lsstDebug.frame)
228  with disp.Buffering():
229  for (ref, source, d), symb, ctype in zip(matches, symbs, ctypes):
230  disp.dot(symb, source.getX() - mi.getX0(), source.getY() - mi.getY0(),
231  size=4, ctype=ctype)
232 
233  if display:
234  lsstDebug.frame += 1
235  if pauseAtEnd:
236  input("Continue? y[es] p[db] ")
237 
238  return Struct(selected=selected)
lsst::ip::diffim.diaCatalogSourceSelector.CheckSource.keys
keys
Definition: diaCatalogSourceSelector.py:87
lsst::ip::diffim.diaCatalogSourceSelector.DiaCatalogSourceSelectorConfig.setDefaults
def setDefaults(self)
Definition: diaCatalogSourceSelector.py:73
lsst::ip::diffim.diaCatalogSourceSelector.CheckSource.fluxLim
fluxLim
Definition: diaCatalogSourceSelector.py:88
lsst::afw::display
lsst::ip::diffim.diaCatalogSourceSelector.CheckSource
Definition: diaCatalogSourceSelector.py:83
lsst::ip::diffim.diaCatalogSourceSelector.DiaCatalogSourceSelectorConfig.badFlags
badFlags
Definition: diaCatalogSourceSelector.py:75
lsst::ip::diffim.diaCatalogSourceSelector.CheckSource.fluxMax
fluxMax
Definition: diaCatalogSourceSelector.py:89
lsst::ip::diffim.diaCatalogSourceSelector.DiaCatalogSourceSelectorTask
Definition: diaCatalogSourceSelector.py:103
lsstDebug::Info
lsst::ip::diffim.diaCatalogSourceSelector.CheckSource.__init__
def __init__(self, table, fluxLim, fluxMax, badFlags)
Definition: diaCatalogSourceSelector.py:86
lsst::ip::diffim.diaCatalogSourceSelector.DiaCatalogSourceSelectorTask.selectSources
def selectSources(self, sourceCat, matches=None, exposure=None)
Definition: diaCatalogSourceSelector.py:142
lsst::ip::diffim.diaCatalogSourceSelector.CheckSource.__call__
def __call__(self, source)
Definition: diaCatalogSourceSelector.py:91
lsst::ip::diffim.diaCatalogSourceSelector.DiaCatalogSourceSelectorConfig
Definition: diaCatalogSourceSelector.py:32