lsst.meas.algorithms  13.0-23-gb99accf
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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 from __future__ import absolute_import, division, print_function
24 
25 import numpy as np
26 
27 from lsst.afw import table
28 import lsst.pex.config as pexConfig
29 from .sourceSelector import BaseSourceSelectorConfig, BaseSourceSelectorTask, sourceSelectorRegistry
30 from lsst.pipe.base import Struct
31 
32 
33 class MatcherSourceSelectorConfig(BaseSourceSelectorConfig):
34  sourceFluxType = pexConfig.Field(
35  doc="Type of source flux; typically one of Ap or Psf",
36  dtype=str,
37  default="Ap",
38  )
39  minSnr = pexConfig.Field(
40  dtype=float,
41  doc="Minimum allowed signal-to-noise ratio for sources used for matching "
42  "(in the flux specified by sourceFluxType); <= 0 for no limit",
43  default=40,
44  )
45 
46 
47 class MatcherSourceSelectorTask(BaseSourceSelectorTask):
48  """
49  !Select sources that are useful for matching.
50 
51  Good matching sources have high signal/noise, are non-blended. They need not
52  be PSF sources, just have reliable centroids.
53  """
54  ConfigClass = MatcherSourceSelectorConfig
55 
56  def __init__(self, *args, **kwargs):
57  BaseSourceSelectorTask.__init__(self, *args, **kwargs)
58 
59  def selectSources(self, sourceCat, matches=None):
60  """
61  !Return a catalog of sources: a subset of sourceCat.
62 
63  If sourceCat is cotiguous in memory, will use vectorized tests for ~100x
64  execution speed advantage over non-contiguous catalogs. This would be
65  even faster if we didn't have to check footprints for multiple peaks.
66 
67  @param[in] sourceCat catalog of sources that may be sources
68  (an lsst.afw.table.SourceCatalog)
69 
70  @return a pipeBase.Struct containing:
71  - sourceCat a catalog of sources
72  """
73  self._getSchemaKeys(sourceCat.schema)
74 
75  if sourceCat.isContiguous():
76  good = self._isUsable_vector(sourceCat)
77  result = sourceCat[good]
78  else:
79  result = table.SourceCatalog(sourceCat.table)
80  for i, source in enumerate(sourceCat):
81  if self._isUsable(source):
82  result.append(source)
83  return Struct(sourceCat=result)
84 
85  def _getSchemaKeys(self, schema):
86  """Extract and save the necessary keys from schema with asKey."""
87  self.parentKey = schema["parent"].asKey()
88  self.centroidXKey = schema["slot_Centroid_x"].asKey()
89  self.centroidYKey = schema["slot_Centroid_y"].asKey()
90  self.centroidFlagKey = schema["slot_Centroid_flag"].asKey()
91 
92  fluxPrefix = "slot_%sFlux_" % (self.config.sourceFluxType,)
93  self.fluxField = fluxPrefix + "flux"
94  self.fluxKey = schema[fluxPrefix + "flux"].asKey()
95  self.fluxFlagKey = schema[fluxPrefix + "flag"].asKey()
96  self.fluxSigmaKey = schema[fluxPrefix + "fluxSigma"].asKey()
97 
98  def _isParent_vector(self, sourceCat):
99  """Return True for each source that is the parent source."""
100  test = (sourceCat.get(self.parentKey) == 0)
101  return test
102 
103  def _isParent(self, source):
104  """Return True if source is the parent source."""
105  if (source.get(self.parentKey) == 0):
106  return True
107  return False
108 
109  def _hasCentroid_vector(self, sourceCat):
110  """Return True for each source that has a valid centroid"""
111  return np.isfinite(sourceCat.get(self.centroidXKey)) \
112  & np.isfinite(sourceCat.get(self.centroidYKey)) \
113  & ~sourceCat.get(self.centroidFlagKey)
114 
115  def _hasCentroid(self, source):
116  """Return True if the source has a valid centroid"""
117  centroid = source.getCentroid()
118  return np.all(np.isfinite(centroid)) and not source.getCentroidFlag()
119 
120  def _goodSN_vector(self, sourceCat):
121  """Return True for each source that has Signal/Noise > config.minSnr."""
122  if self.config.minSnr <= 0:
123  return True
124  else:
125  return sourceCat.get(self.fluxKey)/sourceCat.get(self.fluxSigmaKey) > self.config.minSnr
126 
127  def _goodSN(self, source):
128  """Return True if source has Signal/Noise > config.minSnr."""
129  return (self.config.minSnr <= 0 or
130  (source.get(self.fluxKey)/source.get(self.fluxSigmaKey) > self.config.minSnr))
131 
132  def _isUsable_vector(self, sourceCat):
133  """
134  Return True for each source that is usable for matching, even if it may
135  have a poor centroid.
136 
137  For a source to be usable it must:
138  - have a valid centroid
139  - not be deblended
140  - have a valid flux (of the type specified in this object's constructor)
141  - have adequate signal-to-noise
142  """
143  return self._hasCentroid_vector(sourceCat) \
144  & self._isParent_vector(sourceCat) \
145  & self._goodSN_vector(sourceCat) \
146  & ~sourceCat.get(self.fluxFlagKey)
147 
148  def _isUsable(self, source):
149  """
150  Return True if the source is usable for matching, even if it may have a
151  poor centroid.
152 
153  For a source to be usable it must:
154  - have a valid centroid
155  - not be deblended
156  - have a valid flux (of the type specified in this object's constructor)
157  - have adequate signal-to-noise
158  """
159  return self._hasCentroid(source) \
160  and self._isParent(source) \
161  and not source.get(self.fluxFlagKey) \
162  and self._goodSN(source)
163 
164 
166  """
167  !Select sources that are useful for matching.
168 
169  Good matching sources have high signal/noise, are non-blended. They need not
170  be PSF sources, just have reliable centroids. This inherited class adds
171  the removal of saturated, interpolated, and edge_key objects to the set of
172  bad flags. It is a temporary addition designed preserve the source selction
173  used in matchOptimisticB. Once matchPessimisticB is adopted as the default
174  source selector the class will be removed and the saturated, interpoalted, and
175  edge_key flags will be added to the matcherSourceSelector class.
176 
177  TODO: Once DM-10399 is complete an RFC will be filed to make matchPessimisticB
178  the default matcher this class will replace matcherSourceSelector with this source
179  selector resulting in only one matcherSourceSeletor. The ticket describing
180  this work is DM-10800.
181  """
182  def _getSchemaKeys(self, schema):
183  """Extract and save the necessary keys from schema with asKey."""
184  MatcherSourceSelectorTask._getSchemaKeys(self, schema)
185 
186  self.edgeKey = schema["base_PixelFlags_flag_edge"].asKey()
187  self.interpolatedCenterKey = schema["base_PixelFlags_flag_interpolatedCenter"].asKey()
188  self.saturatedKey = schema["base_PixelFlags_flag_saturated"].asKey()
189 
190  def _isUsable_vector(self, sourceCat):
191  """
192  Return True for each source that is usable for matching, even if it may
193  have a poor centroid.
194 
195  For a source to be usable it must:
196  - have a valid centroid
197  - not be deblended
198  - have a valid flux (of the type specified in this object's constructor)
199  - have adequate signal-to-noise
200  """
201  result = MatcherSourceSelectorTask._isUsable_vector(self, sourceCat)
202 
203  return result \
204  & ~sourceCat.get(self.edgeKey) \
205  & ~sourceCat.get(self.interpolatedCenterKey) \
206  & ~sourceCat.get(self.saturatedKey)
207 
208  def _isUsable(self, source):
209  """
210  Return True if the source is usable for matching, even if it may have a
211  poor centroid.
212 
213  For a source to be usable it must:
214  - have a valid centroid
215  - not be deblended
216  - have a valid flux (of the type specified in this object's constructor)
217  - have adequate signal-to-noise
218  """
219  result = MatcherSourceSelectorTask._isUsable(self, source)
220 
221  return result \
222  and not source.get(self.edgeKey) \
223  and not source.get(self.interpolatedCenterKey) \
224  and not source.get(self.saturatedKey)
225 
226 
227 sourceSelectorRegistry.register("matcher", MatcherSourceSelectorTask)
228 sourceSelectorRegistry.register("matcherPessimistic",
229  MatcherPessimisticSourceSelectorTask)
Definition: CR.h:34