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