lsst.meas.base  14.0-23-g2010ef9+4
forcedPhotCoadd.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 #
3 # LSST Data Management System
4 # Copyright 2008-2015 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 builtins import zip
24 
25 import lsst.pex.config
26 import lsst.pipe.base
27 import lsst.coadd.utils
28 import lsst.afw.table
29 
30 from .forcedPhotImage import ForcedPhotImageConfig, ForcedPhotImageTask
31 
32 __all__ = ("ForcedPhotCoaddConfig", "ForcedPhotCoaddTask")
33 
34 
36  footprintDatasetName = lsst.pex.config.Field(
37  doc="Dataset (without coadd prefix) that should be used to obtain (Heavy)Footprints for sources. "
38  "Must have IDs that match those of the reference catalog."
39  "If None, Footprints will be generated by transforming the reference Footprints.",
40  dtype=str,
41  default="meas",
42  optional=True
43  )
44 
45  def setDefaults(self):
46  ForcedPhotImageTask.ConfigClass.setDefaults(self)
47  # Copy 'id' and 'parent' columns without renaming them; since these are
48  # the only IDs we have in coadd processing, there's no need to qualify
49  # them with 'object'.
50  self.measurement.copyColumns["id"] = "id"
51  self.measurement.copyColumns["parent"] = "parent"
52  self.references.removePatchOverlaps = False # see validate() for why
53  self.measurement.plugins.names |= ['base_InputCount', 'base_Variance']
54  self.measurement.plugins['base_PixelFlags'].masksFpAnywhere = ['CLIPPED', 'SENSOR_EDGE',
55  'REJECTED', 'INEXACT_PSF']
56  self.measurement.plugins['base_PixelFlags'].masksFpCenter = ['CLIPPED', 'SENSOR_EDGE',
57  'REJECTED', 'INEXACT_PSF']
58 
59  def validate(self):
60  ForcedPhotImageTask.ConfigClass.validate(self)
61  if (self.measurement.doReplaceWithNoise and self.footprintDatasetName is not None
62  and self.references.removePatchOverlaps):
63  raise ValueError("Cannot use removePatchOverlaps=True with deblended footprints, as parent "
64  "sources may be rejected while their children are not.")
65 
66 
72 
73 
74 class ForcedPhotCoaddRunner(lsst.pipe.base.ButlerInitializedTaskRunner):
75  """Get the psfCache setting into ForcedPhotCoaddTask"""
76  @staticmethod
77  def getTargetList(parsedCmd, **kwargs):
78  return lsst.pipe.base.ButlerInitializedTaskRunner.getTargetList(parsedCmd,
79  psfCache=parsedCmd.psfCache)
80 
81 
83  """!
84  A command-line driver for performing forced measurement on coadd images
85 
86  This task is a subclass of ForcedPhotImageTask which is specifically for doing forced
87  measurement on a coadd, using as a reference catalog detections which were made on overlapping
88  coadds (i.e. in other bands).
89 
90  The run method (inherited from ForcedPhotImageTask) takes a lsst.daf.persistence.ButlerDataRef
91  argument that corresponds to a coadd image. This is used to provide all the inputs and outputs
92  for the task:
93  - A "*Coadd_src" (e.g. "deepCoadd_src") dataset is used as the reference catalog. This not loaded
94  directly from the passed dataRef, however; only the patch and tract are used, while the filter
95  is set by the configuration for the references subtask (see CoaddSrcReferencesTask).
96  - A "*Coadd_calexp" (e.g. "deepCoadd_calexp") dataset is used as the measurement image. Note that
97  this means that ProcessCoaddTask must be run on an image before ForcedPhotCoaddTask, in order
98  to generate the "*Coadd_calexp" dataset.
99  - A "*Coadd_forced_src" (e.g. "deepCoadd_forced_src") dataset will be written with the output
100  measurement catalog.
101 
102  In addition to the run method, ForcedPhotCcdTask overrides several methods of ForcedPhotImageTask
103  to specialize it for coadd processing, including makeIdFactory() and fetchReferences(). None of these
104  should be called directly by the user, though it may be useful to override them further in subclasses.
105  """
106 
107  ConfigClass = ForcedPhotCoaddConfig
108  RunnerClass = lsst.pipe.base.ButlerInitializedTaskRunner
109  _DefaultName = "forcedPhotCoadd"
110  dataPrefix = "deepCoadd_"
111 
112  def getExposure(self, dataRef):
113  name = self.config.coaddName + "Coadd_calexp"
114  return dataRef.get(name) if dataRef.datasetExists(name) else None
115 
116  def makeIdFactory(self, dataRef):
117  """Create an object that generates globally unique source IDs from per-CCD IDs and the CCD ID.
118 
119  @param dataRef Data reference from butler. The "CoaddId_bits" and "CoaddId"
120  datasets are accessed. The data ID must have tract and patch keys.
121  """
122  # With the default configuration, this IdFactory doesn't do anything, because
123  # the IDs it generates are immediately overwritten by the ID from the reference
124  # catalog (since that's in config.measurement.copyColumns). But we create one here anyway, to
125  # allow us to revert back to the old behavior of generating new forced source IDs,
126  # just by renaming the ID in config.copyColumns to "object_id".
127  expBits = dataRef.get(self.config.coaddName + "CoaddId_bits")
128  expId = int(dataRef.get(self.config.coaddName + "CoaddId"))
129  return lsst.afw.table.IdFactory.makeSource(expId, 64 - expBits)
130 
131  def getExposureId(self, dataRef):
132  return int(dataRef.get(self.config.coaddName + "CoaddId"))
133 
134  def fetchReferences(self, dataRef, exposure):
135  """Return an iterable of reference sources which overlap the exposure
136 
137  @param dataRef Data reference from butler corresponding to the image to be measured;
138  should have tract, patch, and filter keys.
139  @param exposure lsst.afw.image.Exposure to be measured (not used by this implementation)
140 
141  All work is delegated to the references subtask; see CoaddSrcReferencesTask for information
142  about the default behavior.
143  """
144  skyMap = dataRef.get(self.dataPrefix + "skyMap", immediate=True)
145  tractInfo = skyMap[dataRef.dataId["tract"]]
146  patch = tuple(int(v) for v in dataRef.dataId["patch"].split(","))
147  patchInfo = tractInfo.getPatchInfo(patch)
148  references = lsst.afw.table.SourceCatalog(self.references.schema)
149  references.extend(self.references.fetchInPatches(dataRef, patchList=[patchInfo]))
150  return references
151 
152  def attachFootprints(self, sources, refCat, exposure, refWcs, dataRef):
153  """For coadd forced photometry, we use the deblended HeavyFootprints from the single-band
154  measurements of the same band - because we've guaranteed that the peaks (and hence child sources)
155  will be consistent across all bands before we get to measurement, this should yield reasonable
156  deblending for most sources. It's most likely limitation is that it will not provide good flux
157  upper limits for sources that were not detected in this band but were blended with sources that
158  were.
159  """
160  if self.config.footprintDatasetName is None:
161  return ForcedPhotImageTask.attachFootprints(self, sources, refCat, exposure, refWcs, dataRef)
162  self.log.info("Loading deblended footprints for sources from %s, %s" %
163  (self.config.footprintDatasetName, dataRef.dataId))
164  fpCat = dataRef.get("%sCoadd_%s" % (self.config.coaddName, self.config.footprintDatasetName),
165  immediate=True)
166  for refRecord, srcRecord in zip(refCat, sources):
167  fpRecord = fpCat.find(refRecord.getId())
168  if fpRecord is None:
169  raise LookupError("Cannot find Footprint for source %s; please check that %sCoadd_%s "
170  "IDs are compatible with reference source IDs" %
171  (srcRecord.getId(), self.config.coaddName,
172  self.config.footprintDatasetName))
173  srcRecord.setFootprint(fpRecord.getFootprint())
174 
175  @classmethod
176  def _makeArgumentParser(cls):
177  parser = lsst.pipe.base.ArgumentParser(name=cls._DefaultName)
178  parser.add_id_argument("--id", "deepCoadd_forced_src", help="data ID, with raw CCD keys + tract",
179  ContainerClass=lsst.coadd.utils.CoaddDataIdContainer)
180  parser.add_argument("--psfCache", type=int, default=100, help="Size of CoaddPsf cache")
181  return parser
A base class for command-line forced measurement drivers.
static std::shared_ptr< IdFactory > makeSource(RecordId expId, int reserved)
def attachFootprints(self, sources, refCat, exposure, refWcs, dataRef)
A command-line driver for performing forced measurement on coadd images.
Config class for forced measurement driver task.