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