LSSTApplications  18.1.0
LSSTDataManagementBasePackage
forcedPhotCoadd.py
Go to the documentation of this file.
1 # This file is part of meas_base.
2 #
3 # Developed for the LSST Data Management System.
4 # This product includes software developed by the LSST Project
5 # (https://www.lsst.org).
6 # See the COPYRIGHT file at the top-level directory of this distribution
7 # for details of code ownership.
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 GNU General Public License
20 # along with this program. If not, see <https://www.gnu.org/licenses/>.
21 
22 import lsst.pex.config
23 import lsst.pipe.base
24 import lsst.coadd.utils
25 import lsst.afw.table
26 
27 from .forcedPhotImage import ForcedPhotImageConfig, ForcedPhotImageTask
28 
29 __all__ = ("ForcedPhotCoaddConfig", "ForcedPhotCoaddTask")
30 
31 
33  footprintDatasetName = lsst.pex.config.Field(
34  doc="Dataset (without coadd prefix) that should be used to obtain (Heavy)Footprints for sources. "
35  "Must have IDs that match those of the reference catalog."
36  "If None, Footprints will be generated by transforming the reference Footprints.",
37  dtype=str,
38  default="meas",
39  optional=True
40  )
41 
43  dtype=bool,
44  default=False,
45  doc="Should be set to True if fake sources have been inserted into the input data."
46  )
47 
48  def setDefaults(self):
49  ForcedPhotImageTask.ConfigClass.setDefaults(self)
50  # Copy 'id' and 'parent' columns without renaming them; since these are
51  # the only IDs we have in coadd processing, there's no need to qualify
52  # them with 'object'.
53  self.measurement.copyColumns["id"] = "id"
54  self.measurement.copyColumns["parent"] = "parent"
55  self.references.removePatchOverlaps = False # see validate() for why
56  self.measurement.plugins.names |= ['base_InputCount', 'base_Variance']
57  self.measurement.plugins['base_PixelFlags'].masksFpAnywhere = ['CLIPPED', 'SENSOR_EDGE',
58  'REJECTED', 'INEXACT_PSF']
59  self.measurement.plugins['base_PixelFlags'].masksFpCenter = ['CLIPPED', 'SENSOR_EDGE',
60  'REJECTED', 'INEXACT_PSF']
61 
62  def validate(self):
63  ForcedPhotImageTask.ConfigClass.validate(self)
64  if (self.measurement.doReplaceWithNoise and self.footprintDatasetName is not None and
65  self.references.removePatchOverlaps):
66  raise ValueError("Cannot use removePatchOverlaps=True with deblended footprints, as parent "
67  "sources may be rejected while their children are not.")
68 
69 
71  """Get the psfCache setting into ForcedPhotCoaddTask"""
72  @staticmethod
73  def getTargetList(parsedCmd, **kwargs):
74  return lsst.pipe.base.ButlerInitializedTaskRunner.getTargetList(parsedCmd,
75  psfCache=parsedCmd.psfCache)
76 
77 
79  """A command-line driver for performing forced measurement on coadd images.
80 
81  Notes
82  -----
83  In addition to the run method, `ForcedPhotCcdTask` overrides several
84  methods of `ForcedPhotImageTask` to specialize it for coadd processing,
85  including `~ForcedPhotImageTask.makeIdFactory` and
86  `~ForcedPhotImageTask.fetchReferences`. None of these should be called
87  directly by the user, though it may be useful to override them further in
88  subclasses.
89  """
90 
91  ConfigClass = ForcedPhotCoaddConfig
93  _DefaultName = "forcedPhotCoadd"
94  dataPrefix = "deepCoadd_"
95 
96  def getExposure(self, dataRef):
97 
98  if self.config.hasFakes:
99  name = "fakes_" + self.config.coaddName + "Coadd_calexp"
100  else:
101  name = self.config.coaddName + "Coadd_calexp"
102 
103  return dataRef.get(name) if dataRef.datasetExists(name) else None
104 
105  def makeIdFactory(self, dataRef):
106  """Create an object that generates globally unique source IDs.
107 
108  Source IDs are created based on a per-CCD ID and the ID of the CCD
109  itself.
110 
111  Parameters
112  ----------
113  dataRef : `lsst.daf.persistence.ButlerDataRef`
114  Butler data reference. The "CoaddId_bits" and "CoaddId" datasets
115  are accessed. The data ID must have tract and patch keys.
116  """
117  # With the default configuration, this IdFactory doesn't do anything,
118  # because the IDs it generates are immediately overwritten by the ID
119  # from the reference catalog (since that's in
120  # config.measurement.copyColumns). But we create one here anyway, to
121  # allow us to revert back to the old behavior of generating new forced
122  # source IDs, just by renaming the ID in config.copyColumns to
123  # "object_id".
124  expBits = dataRef.get(self.config.coaddName + "CoaddId_bits")
125  expId = int(dataRef.get(self.config.coaddName + "CoaddId"))
126  return lsst.afw.table.IdFactory.makeSource(expId, 64 - expBits)
127 
128  def getExposureId(self, dataRef):
129  return int(dataRef.get(self.config.coaddName + "CoaddId"))
130 
131  def fetchReferences(self, dataRef, exposure):
132  """Return an iterable of reference sources which overlap the exposure.
133 
134  Parameters
135  ----------
136  dataRef : `lsst.daf.persistence.ButlerDataRef`
137  Butler data reference corresponding to the image to be measured;
138  should have tract, patch, and filter keys.
139 
140  exposure : `lsst.afw.image.Exposure`
141  Unused.
142 
143  Notes
144  -----
145  All work is delegated to the references subtask; see
146  `CoaddSrcReferencesTask` for information about the default behavior.
147  """
148  skyMap = dataRef.get(self.dataPrefix + "skyMap", immediate=True)
149  tractInfo = skyMap[dataRef.dataId["tract"]]
150  patch = tuple(int(v) for v in dataRef.dataId["patch"].split(","))
151  patchInfo = tractInfo.getPatchInfo(patch)
152  references = lsst.afw.table.SourceCatalog(self.references.schema)
153  references.extend(self.references.fetchInPatches(dataRef, patchList=[patchInfo]))
154  return references
155 
156  def attachFootprints(self, sources, refCat, exposure, refWcs, dataRef):
157  r"""Attach Footprints to source records.
158 
159  For coadd forced photometry, we use the deblended "heavy"
160  `~lsst.afw.detection.Footprint`\ s from the single-band measurements
161  of the same band - because we've guaranteed that the peaks (and hence
162  child sources) will be consistent across all bands before we get to
163  measurement, this should yield reasonable deblending for most sources.
164  It's most likely limitation is that it will not provide good flux
165  upper limits for sources that were not detected in this band but were
166  blended with sources that were.
167  """
168  if self.config.footprintDatasetName is None:
169  return ForcedPhotImageTask.attachFootprints(self, sources, refCat, exposure, refWcs, dataRef)
170  self.log.info("Loading deblended footprints for sources from %s, %s" %
171  (self.config.footprintDatasetName, dataRef.dataId))
172  fpCat = dataRef.get("%sCoadd_%s" % (self.config.coaddName, self.config.footprintDatasetName),
173  immediate=True)
174  for refRecord, srcRecord in zip(refCat, sources):
175  fpRecord = fpCat.find(refRecord.getId())
176  if fpRecord is None:
177  raise LookupError("Cannot find Footprint for source %s; please check that %sCoadd_%s "
178  "IDs are compatible with reference source IDs" %
179  (srcRecord.getId(), self.config.coaddName,
180  self.config.footprintDatasetName))
181  srcRecord.setFootprint(fpRecord.getFootprint())
182 
183  @classmethod
184  def _makeArgumentParser(cls):
186  parser.add_id_argument("--id", "deepCoadd_forced_src", help="data ID, with raw CCD keys + tract",
188  parser.add_argument("--psfCache", type=int, default=100, help="Size of CoaddPsf cache")
189  return parser
static std::shared_ptr< IdFactory > makeSource(RecordId expId, int reserved)
Return an IdFactory that includes another, fixed ID in the higher-order bits.
Definition: IdFactory.cc:72
def attachFootprints(self, sources, refCat, exposure, refWcs, dataRef)