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