lsst.ip.diffim  14.0-10-g81837af
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 from __future__ import absolute_import, division, print_function
23 
24 from builtins import input
25 from builtins import object
26 import numpy as np
27 
28 from lsst.afw.table import SourceCatalog
29 from lsst.pipe.base import Struct
30 import lsst.pex.config as pexConfig
31 import lsst.afw.display.ds9 as ds9
32 import lsst.meas.algorithms as measAlg
33 
34 __all__ = ["DiaCatalogSourceSelectorConfig", "DiaCatalogSourceSelectorTask"]
35 
36 
37 class DiaCatalogSourceSelectorConfig(measAlg.BaseStarSelectorConfig):
38  # Selection cuts on the input source catalog
39  fluxLim = pexConfig.Field(
40  doc="specify the minimum psfFlux for good Kernel Candidates",
41  dtype=float,
42  default=0.0,
43  check=lambda x: x >= 0.0,
44  )
45  fluxMax = pexConfig.Field(
46  doc="specify the maximum psfFlux for good Kernel Candidates (ignored if == 0)",
47  dtype=float,
48  default=0.0,
49  check=lambda x: x >= 0.0,
50  )
51  # Selection cuts on the reference catalog
52  selectStar = pexConfig.Field(
53  doc="Select objects that are flagged as stars",
54  dtype=bool,
55  default=True
56  )
57  selectGalaxy = pexConfig.Field(
58  doc="Select objects that are flagged as galaxies",
59  dtype=bool,
60  default=False
61  )
62  includeVariable = pexConfig.Field(
63  doc="Include objects that are known to be variable",
64  dtype=bool,
65  default=False
66  )
67  grMin = pexConfig.Field(
68  doc="Minimum g-r color for selection (inclusive)",
69  dtype=float,
70  default=0.0
71  )
72  grMax = pexConfig.Field(
73  doc="Maximum g-r color for selection (inclusive)",
74  dtype=float,
75  default=3.0
76  )
77 
78  def setDefaults(self):
79  measAlg.BaseStarSelectorConfig.setDefaults(self)
80  self.badFlags = [
81  "base_PixelFlags_flag_edge",
82  "base_PixelFlags_flag_interpolatedCenter",
83  "base_PixelFlags_flag_saturatedCenter",
84  "slot_Centroid_flag",
85  ]
86 
87 
88 class CheckSource(object):
89  """A functor to check whether a source has any flags set that should cause it to be labeled bad."""
90 
91  def __init__(self, table, fluxLim, fluxMax, badFlags):
92  self.keys = [table.getSchema().find(name).key for name in badFlags]
93  self.fluxLim = fluxLim
94  self.fluxMax = fluxMax
95 
96  def __call__(self, source):
97  for k in self.keys:
98  if source.get(k):
99  return False
100  if self.fluxLim is not None and source.getPsfFlux() < self.fluxLim: # ignore faint objects
101  return False
102  if self.fluxMax != 0.0 and source.getPsfFlux() > self.fluxMax: # ignore bright objects
103  return False
104  return True
105 
106 
112 
113 
114 class DiaCatalogSourceSelectorTask(measAlg.BaseStarSelectorTask):
115  """!Select sources for Kernel candidates
116 
117  @anchor DiaCatalogSourceSelectorTask_
118 
119  @section ip_diffim_diaCatalogSourceSelector_Contents Contents
120 
121  - @ref ip_diffim_diaCatalogSourceSelector_Purpose
122  - @ref ip_diffim_diaCatalogSourceSelector_Initialize
123  - @ref ip_diffim_diaCatalogSourceSelector_IO
124  - @ref ip_diffim_diaCatalogSourceSelector_Config
125  - @ref ip_diffim_diaCatalogSourceSelector_Debug
126 
127  @section ip_diffim_diaCatalogSourceSelector_Purpose Description
128 
129  A naive star selector based on second moments. Use with caution.
130 
131  @section ip_diffim_diaCatalogSourceSelector_Initialize Task initialisation
132 
133  @copydoc \_\_init\_\_
134 
135  @section ip_diffim_diaCatalogSourceSelector_IO Invoking the Task
136 
137  Like all star selectors, the main method is `run`.
138 
139  @section ip_diffim_diaCatalogSourceSelector_Config Configuration parameters
140 
141  See @ref DiaCatalogSourceSelectorConfig
142 
143  @section ip_diffim_diaCatalogSourceSelector_Debug Debug variables
144 
145  DiaCatalogSourceSelectorTask has a debug dictionary with the following keys:
146  <dl>
147  <dt>display
148  <dd>bool; if True display debug information
149  <dt>displayExposure
150  <dd>bool; if True display exposure
151  <dt>pauseAtEnd
152  <dd>bool; if True wait after displaying everything and wait for user input
153  </dl>
154 
155  For example, put something like:
156  @code{.py}
157  import lsstDebug
158  def DebugInfo(name):
159  di = lsstDebug.getInfo(name) # N.b. lsstDebug.Info(name) would call us recursively
160  if name.endswith("catalogStarSelector"):
161  di.display = True
162 
163  return di
164 
165  lsstDebug.Info = DebugInfo
166  @endcode
167  into your `debug.py` file and run your task with the `--debug` flag.
168  """
169  ConfigClass = DiaCatalogSourceSelectorConfig
170  usesMatches = True # selectStars uses (requires) its matches argument
171 
172  def selectStars(self, exposure, sourceCat, matches=None):
173  """Select sources for Kernel candidates
174 
175  @param[in] exposure the exposure containing the sources
176  @param[in] sourceCat catalog of sources that may be stars (an lsst.afw.table.SourceCatalog)
177  @param[in] matches a match vector as produced by meas_astrom; required
178  (defaults to None to match the StarSelector API and improve error handling)
179 
180  @return an lsst.pipe.base.Struct containing:
181  - starCat a list of sources to be used as kernel candidates
182  """
183  import lsstDebug
184  display = lsstDebug.Info(__name__).display
185  displayExposure = lsstDebug.Info(__name__).displayExposure
186  pauseAtEnd = lsstDebug.Info(__name__).pauseAtEnd
187 
188  if matches is None:
189  raise RuntimeError("DiaCatalogSourceSelector requires matches")
190 
191  mi = exposure.getMaskedImage()
192 
193  if display:
194  if displayExposure:
195  ds9.mtv(mi, title="Kernel candidates", frame=lsstDebug.frame)
196  #
197  # Look for flags in each Source
198  #
199  isGoodSource = CheckSource(sourceCat, self.config.fluxLim, self.config.fluxMax, self.config.badFlags)
200 
201  #
202  # Go through and find all the acceptable candidates in the catalogue
203  #
204  starCat = SourceCatalog(sourceCat.schema)
205 
206  if display and displayExposure:
207  symbs = []
208  ctypes = []
209 
210  doColorCut = True
211 
212  refSchema = matches[0][0].schema
213  rRefFluxField = measAlg.getRefFluxField(refSchema, "r")
214  gRefFluxField = measAlg.getRefFluxField(refSchema, "g")
215  for ref, source, d in matches:
216  if not isGoodSource(source):
217  if display and displayExposure:
218  symbs.append("+")
219  ctypes.append(ds9.RED)
220  else:
221  isStar = not ref.get("resolved")
222  isVar = not ref.get("photometric")
223  gMag = None
224  rMag = None
225  if doColorCut:
226  try:
227  gMag = -2.5 * np.log10(ref.get(gRefFluxField))
228  rMag = -2.5 * np.log10(ref.get(rRefFluxField))
229  except KeyError:
230  self.log.warn("Cannot cut on color info; fields 'g' and 'r' do not exist")
231  doColorCut = False
232  isRightColor = True
233  else:
234  isRightColor = (gMag-rMag) >= self.config.grMin and (gMag-rMag) <= self.config.grMax
235 
236  isRightType = (self.config.selectStar and isStar) or (self.config.selectGalaxy and not isStar)
237  isRightVar = (self.config.includeVariable) or (self.config.includeVariable is isVar)
238  if isRightType and isRightVar and isRightColor:
239  starCat.append(source)
240  if display and displayExposure:
241  symbs.append("+")
242  ctypes.append(ds9.GREEN)
243  elif display and displayExposure:
244  symbs.append("o")
245  ctypes.append(ds9.BLUE)
246 
247  if display and displayExposure:
248  with ds9.Buffering():
249  for (ref, source, d), symb, ctype in zip(matches, symbs, ctypes):
250  if display and displayExposure:
251  ds9.dot(symb, source.getX() - mi.getX0(), source.getY() - mi.getY0(),
252  size=4, ctype=ctype, frame=lsstDebug.frame)
253 
254  if display:
255  lsstDebug.frame += 1
256  if pauseAtEnd:
257  input("Continue? y[es] p[db] ")
258 
259  return Struct(
260  starCat=starCat,
261  )
262 
263 measAlg.starSelectorRegistry.register("diacatalog", DiaCatalogSourceSelectorTask)
def __init__(self, table, fluxLim, fluxMax, badFlags)