LSSTApplications  11.0-13-gbb96280,12.1+18,12.1+7,12.1-1-g14f38d3+72,12.1-1-g16c0db7+5,12.1-1-g5961e7a+84,12.1-1-ge22e12b+23,12.1-11-g06625e2+4,12.1-11-g0d7f63b+4,12.1-19-gd507bfc,12.1-2-g7dda0ab+38,12.1-2-gc0bc6ab+81,12.1-21-g6ffe579+2,12.1-21-gbdb6c2a+4,12.1-24-g941c398+5,12.1-3-g57f6835+7,12.1-3-gf0736f3,12.1-37-g3ddd237,12.1-4-gf46015e+5,12.1-5-g06c326c+20,12.1-5-g648ee80+3,12.1-5-gc2189d7+4,12.1-6-ga608fc0+1,12.1-7-g3349e2a+5,12.1-7-gfd75620+9,12.1-9-g577b946+5,12.1-9-gc4df26a+10
LSSTDataManagementBasePackage
propagateVisitFlags.py
Go to the documentation of this file.
1 from builtins import zip
2 #!/usr/bin/env python
3 #
4 # LSST Data Management System
5 # Copyright 2014-2015 LSST/AURA
6 #
7 # This product includes software developed by the
8 # LSST Project (http://www.lsst.org/).
9 #
10 # This program is free software: you can redistribute it and/or modify
11 # it under the terms of the GNU General Public License as published by
12 # the Free Software Foundation, either version 3 of the License, or
13 # (at your option) any later version.
14 #
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
19 #
20 # You should have received a copy of the LSST License Statement and
21 # the GNU General Public License along with this program. If not,
22 # see <http://www.lsstcorp.org/LegalNotices/>.
23 #
24 
25 import numpy
26 from lsst.pex.config import Config, Field, DictField
27 from lsst.pipe.base import Task
28 import lsst.afw.geom as afwGeom
29 import lsst.afw.table as afwTable
30 
31 
33  """!Configuration for propagating flags to coadd"""
34  flags = DictField(keytype=str, itemtype=float,
35  default={"calib_psfCandidate": 0.2, "calib_psfUsed": 0.2, },
36  doc="Source catalog flags to propagate, with the threshold of relative occurrence.")
37  matchRadius = Field(dtype=float, default=0.2, doc="Source matching radius (arcsec)")
38 
39 
40 ## \addtogroup LSST_task_documentation
41 ## \{
42 ## \page PropagateVisitFlagsTask
43 ## \ref PropagateVisitFlagsTask_ "PropagateVisitFlagsTask"
44 ## \copybrief PropagateVisitFlagsTask
45 ## \}
46 
48  """!Task to propagate flags from single-frame measurements to coadd measurements
49 
50 \anchor PropagateVisitFlagsTask_
51 
52 \brief Propagate flags from individual visit measurements to coadd measurements
53 
54 \section pipe_tasks_propagateVisitFlagsTask_Contents Contents
55 
56  - \ref pipe_tasks_propagateVisitFlagsTask_Description
57  - \ref pipe_tasks_propagateVisitFlagsTask_Initialization
58  - \ref pipe_tasks_propagateVisitFlagsTask_Config
59  - \ref pipe_tasks_propagateVisitFlagsTask_Use
60  - \ref pipe_tasks_propagateVisitFlagsTask_Example
61 
62 \section pipe_tasks_propagateVisitFlagsTask_Description Description
63 
64 \copybrief PropagateVisitFlagsTask
65 
66 We want to be able to set a flag for sources on the coadds using flags
67 that were determined from the individual visits. A common example is sources
68 that were used for PSF determination, since we do not do any PSF determination
69 on the coadd but use the individual visits. This requires matching the coadd
70 source catalog to each of the catalogs from the inputs (see
71 PropagateVisitFlagsConfig.matchRadius), and thresholding on the number of
72 times a source is flagged on the input catalog.
73 
74 An important consideration in this is that the flagging of sources in the
75 individual visits can be somewhat stochastic, e.g., the same stars may not
76 always be used for PSF determination because the field of view moves slightly
77 between visits, or the seeing changed. We there threshold on the relative
78 occurrence of the flag in the visits (see PropagateVisitFlagsConfig.flags).
79 Flagging a source that is always flagged in inputs corresponds to a threshold
80 of 1, while flagging a source that is flagged in any of the input corresponds
81 to a threshold of 0. But neither of these extrema are really useful in
82 practise.
83 
84 Setting the threshold too high means that sources that are not consistently
85 flagged (e.g., due to chip gaps) will not have the flag propagated. Setting
86 that threshold too low means that random sources which are falsely flagged in
87 the inputs will start to dominate. If in doubt, we suggest making this
88 threshold relatively low, but not zero (e.g., 0.1 to 0.2 or so). The more
89 confidence in the quality of the flagging, the lower the threshold can be.
90 
91 The relative occurrence accounts for the edge of the field-of-view of the
92 camera, but does not include chip gaps, bad or saturated pixels, etc.
93 
94 \section pipe_tasks_propagateVisitFlagsTask_Initialization Initialization
95 
96 Beyond the usual Task initialization, PropagateVisitFlagsTask also requires
97 a schema for the catalog that is being constructed.
98 
99 \section pipe_tasks_propagateVisitFlagsTask_Config Configuration parameters
100 
101 See \ref PropagateVisitFlagsConfig
102 
103 \section pipe_tasks_propagateVisitFlagsTask_Use Use
104 
105 The 'run' method (described below) is the entry-point for operations. The
106 'getCcdInputs' staticmethod is provided as a convenience for retrieving the
107 'ccdInputs' (CCD inputs table) from an Exposure.
108 
109 \copydoc run
110 
111 \section pipe_tasks_propagateVisitFlagsTask_Example Example
112 
113 \code{.py}
114 # Requires:
115 # * butler: data butler, for retrieving the CCD catalogs
116 # * coaddCatalog: catalog of source measurements on the coadd (lsst.afw.table.SourceCatalog)
117 # * coaddExposure: coadd (lsst.afw.image.Exposure)
118 from lsst.pipe.tasks.propagateVisitFlags import PropagateVisitFlagsTask, PropagateVisitFlagsConfig
119 config = PropagateVisitFlagsConfig()
120 config.flags["calib.psf.used"] = 0.3 # Relative threshold for this flag
121 config.matchRadius = 0.5 # Matching radius in arcsec
122 task = PropagateVisitFlagsTask(coaddCatalog.schema, config=config)
123 ccdInputs = task.getCcdInputs(coaddExposure)
124 task.run(butler, coaddCatalog, ccdInputs, coaddExposure.getWcs())
125 \endcode
126 """
127  ConfigClass = PropagateVisitFlagsConfig
128 
129  def __init__(self, schema, **kwargs):
130  Task.__init__(self, **kwargs)
131  self.schema = schema
132  self._keys = dict((f, self.schema.addField(f, type="Flag", doc="Propagated from visits")) for
133  f in self.config.flags)
134 
135  @staticmethod
136  def getCcdInputs(coaddExposure):
137  """!Convenience method to retrieve the CCD inputs table from a coadd exposure"""
138  return coaddExposure.getInfo().getCoaddInputs().ccds
139 
140  def run(self, butler, coaddSources, ccdInputs, coaddWcs):
141  """!Propagate flags from individual visit measurements to coadd
142 
143  This requires matching the coadd source catalog to each of the catalogs
144  from the inputs, and thresholding on the number of times a source is
145  flagged on the input catalog. The threshold is made on the relative
146  occurrence of the flag in each source. Flagging a source that is always
147  flagged in inputs corresponds to a threshold of 1, while flagging a
148  source that is flagged in any of the input corresponds to a threshold of
149  0. But neither of these extrema are really useful in practise.
150 
151  Setting the threshold too high means that sources that are not consistently
152  flagged (e.g., due to chip gaps) will not have the flag propagated. Setting
153  that threshold too low means that random sources which are falsely flagged in
154  the inputs will start to dominate. If in doubt, we suggest making this threshold
155  relatively low, but not zero (e.g., 0.1 to 0.2 or so). The more confidence in
156  the quality of the flagging, the lower the threshold can be.
157 
158  The relative occurrence accounts for the edge of the field-of-view of
159  the camera, but does not include chip gaps, bad or saturated pixels, etc.
160 
161  @param[in] butler Data butler, for retrieving the input source catalogs
162  @param[in,out] coaddSources Source catalog from the coadd
163  @param[in] ccdInputs Table of CCDs that contribute to the coadd
164  @param[in] coaddWcs Wcs for coadd
165  """
166  if len(self.config.flags) == 0:
167  return
168 
169  flags = self._keys.keys()
170  visitKey = ccdInputs.schema.find("visit").key
171  ccdKey = ccdInputs.schema.find("ccd").key
172  radius = self.config.matchRadius*afwGeom.arcseconds
173 
174  self.log.info("Propagating flags %s from inputs" % (flags,))
175 
176  counts = dict((f, numpy.zeros(len(coaddSources), dtype=int)) for f in flags)
177  indices = numpy.array([s.getId() for s in coaddSources]) # Allowing for non-contiguous data
178 
179  # Accumulate counts of flags being set
180  for ccdRecord in ccdInputs:
181  v = ccdRecord.get(visitKey)
182  c = ccdRecord.get(ccdKey)
183  ccdSources = butler.get("src", visit=int(v), ccd=int(c), immediate=True)
184  for sourceRecord in ccdSources:
185  sourceRecord.updateCoord(ccdRecord.getWcs())
186  for flag in flags:
187  # We assume that the flags will be relatively rare, so it is more efficient to match
188  # against a subset of the input catalog for each flag than it is to match once against
189  # the entire catalog. It would be best to have built a kd-tree on coaddSources and
190  # keep reusing that for the matching, but we don't have a suitable implementation.
191  matches = afwTable.matchRaDec(coaddSources, ccdSources[ccdSources.get(flag)], radius, False)
192  for m in matches:
193  index = (numpy.where(indices == m.first.getId()))[0][0]
194  counts[flag][index] += 1
195 
196  # Apply threshold
197  for f in flags:
198  key = self._keys[f]
199  for s, num in zip(coaddSources, counts[f]):
200  numOverlaps = len(ccdInputs.subsetContaining(s.getCentroid(), coaddWcs, True))
201  s.setFlag(key, bool(num > numOverlaps*self.config.flags[f]))
202  self.log.info("Propagated %d sources with flag %s" % (sum(s.get(key) for s in coaddSources), f))
std::vector< Match< typename Cat::Record, typename Cat::Record > > matchRaDec(Cat const &cat, Angle radius, bool symmetric)
Task to propagate flags from single-frame measurements to coadd measurements.
Configuration for propagating flags to coadd.
def getCcdInputs
Convenience method to retrieve the CCD inputs table from a coadd exposure.
def run
Propagate flags from individual visit measurements to coadd.