LSSTApplications  1.1.2+25,10.0+13,10.0+132,10.0+133,10.0+224,10.0+41,10.0+8,10.0-1-g0f53050+14,10.0-1-g4b7b172+19,10.0-1-g61a5bae+98,10.0-1-g7408a83+3,10.0-1-gc1e0f5a+19,10.0-1-gdb4482e+14,10.0-11-g3947115+2,10.0-12-g8719d8b+2,10.0-15-ga3f480f+1,10.0-2-g4f67435,10.0-2-gcb4bc6c+26,10.0-28-gf7f57a9+1,10.0-3-g1bbe32c+14,10.0-3-g5b46d21,10.0-4-g027f45f+5,10.0-4-g86f66b5+2,10.0-4-gc4fccf3+24,10.0-40-g4349866+2,10.0-5-g766159b,10.0-5-gca2295e+25,10.0-6-g462a451+1
LSSTDataManagementBasePackage
processCoadd.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 #
3 # LSST Data Management System
4 # Copyright 2008, 2009, 2010 LSST Corporation.
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 lsst.pex.config as pexConfig
25 import lsst.pipe.base as pipeBase
26 import lsst.afw.geom as afwGeom
27 import lsst.afw.math as afwMath
28 import lsst.afw.table as afwTable
29 from lsst.coadd.utils import CoaddDataIdContainer
30 from .coaddBase import getSkyInfo
31 from .processImage import ProcessImageTask
32 
33 class ProcessCoaddConfig(ProcessImageTask.ConfigClass):
34  """Config for ProcessCoadd"""
35  coaddName = pexConfig.Field(
36  doc = "coadd name: typically one of deep or goodSeeing",
37  dtype = str,
38  default = "deep",
39  )
40  doScaleVariance = pexConfig.Field(dtype=bool, default=True, doc = "Scale variance plane using empirical noise")
41 
42  def setDefaults(self):
43  ProcessImageTask.ConfigClass.setDefaults(self)
44  self.calibrate.background.undersampleStyle = 'REDUCE_INTERP_ORDER'
45  self.calibrate.detection.background.undersampleStyle = 'REDUCE_INTERP_ORDER'
46  self.detection.background.undersampleStyle = 'REDUCE_INTERP_ORDER'
47  self.calibrate.doPsf = False
48  self.calibrate.astrometry.forceKnownWcs = True
49  self.calibrate.repair.doInterpolate = False
50  self.calibrate.repair.doCosmicRay = False
51  self.calibrate.doPhotoCal = False
52  self.detection.isotropicGrow = True
53  self.detection.returnOriginalFootprints = False
55  self.measurement.doReplaceWithNoise = True
56  self.doDeblend = True
57  self.deblend.maxNumberOfPeaks = 20
58 
59 class ProcessCoaddTask(ProcessImageTask):
60  """Process a Coadd image
61 
62  """
63  ConfigClass = ProcessCoaddConfig
64  _DefaultName = "processCoadd"
65 
66  def __init__(self, **kwargs):
67  ProcessImageTask.__init__(self, **kwargs)
68  self.dataPrefix = self.config.coaddName + "Coadd_"
69  self.isPatchInnerKey = self.schema.addField(
70  "detect_isPatchInner", type="Flag",
71  doc="true if source is in the inner region of a coadd patch",
72  )
73  self.isTractInnerKey = self.schema.addField(
74  "detect_isTractInner", type="Flag",
75  doc="true if source is in the inner region of a coadd tract",
76  )
77  self.isPrimaryKey = self.schema.addField(
78  "detect_isPrimary", type="Flag",
79  doc="true if source has no children and is in the inner region of a coadd patch " \
80  + "and is in the inner region of a coadd tract",
81  )
82 
83  @pipeBase.timeMethod
84  def scaleVariance(self, exposure):
86  ctrl.setAndMask(~0x0)
87  var = exposure.getMaskedImage().getVariance()
88  mask = exposure.getMaskedImage().getMask()
89  dstats = afwMath.makeStatistics(exposure.getMaskedImage(), afwMath.VARIANCECLIP, ctrl).getValue(afwMath.VARIANCECLIP)
90  vstats = afwMath.makeStatistics(var, mask, afwMath.MEANCLIP, ctrl).getValue(afwMath.MEANCLIP)
91  vrat = dstats / vstats
92  self.log.info("Renormalising variance by %f" % (vrat))
93  var *= vrat
94 
95  def makeIdFactory(self, dataRef):
96  expBits = dataRef.get(self.config.coaddName + "CoaddId_bits")
97  expId = long(dataRef.get(self.config.coaddName + "CoaddId"))
98  return afwTable.IdFactory.makeSource(expId, 64 - expBits)
99 
100  def getExposureId(self, dataRef):
101  return long(dataRef.get(self.config.coaddName + "CoaddId"))
102 
103  @pipeBase.timeMethod
104  def run(self, dataRef):
105  """Process a coadd image
106 
107  @param dataRef: butler data reference corresponding to coadd patch
108  @return pipe_base Struct containing these fields:
109  - exposure: calibrated exposure (calexp): as computed if config.doCalibrate,
110  else as upersisted and updated if config.doDetection, else None
111  - calib: object returned by calibration process if config.doCalibrate, else None
112  - sources: detected source if config.doDetection, else None
113  """
114  self.log.info("Processing %s" % (dataRef.dataId))
115 
116  # initialize outputs
117  coadd = None
118 
119  skyInfo = getSkyInfo(coaddName=self.config.coaddName, patchRef=dataRef)
120 
121  coadd = dataRef.get(self.config.coaddName + "Coadd")
122  if self.config.doScaleVariance:
123  self.scaleVariance(coadd)
124 
125  # delegate most of the work to ProcessImageTask
126  result = self.process(dataRef, coadd, enableWriteSources=False)
127  result.coadd = coadd
128 
129  if result.sources is not None:
130  self.setIsPrimaryFlag(sources=result.sources, skyInfo=skyInfo)
131 
132  # write sources
133  if self.config.doWriteSources:
134  dataRef.put(result.sources, self.dataPrefix + 'src')
135 
136  return result
137 
138  def setIsPrimaryFlag(self, sources, skyInfo):
139  """Set is-primary and related flags on sources
140 
141  @param[in,out] sources: a SourceTable
142  - reads centroid fields and an nChild field
143  - writes is-patch-inner, is-tract-inner and is-primary flags
144  @param[in] skyInfo: a SkyInfo object as returned by getSkyInfo;
145  reads skyMap, patchInfo, and tractInfo fields
146 
147 
148  @raise RuntimeError if self.config.doDeblend and the nChild key is not found in the table
149  """
150  # Test for the presence of the nchild key instead of checking config.doDeblend because sources
151  # might be unpersisted with deblend info, even if deblending is not run again.
152  nChildKeyName = "deblend_nChild"
153 
154  try:
155  nChildKey = self.schema.find(nChildKeyName).key
156  except Exception:
157  nChildKey = None
158 
159  if self.config.doDeblend and nChildKey is None:
160  # deblending was run but the nChildKey was not found; this suggests a variant deblender
161  # was used that we cannot use the output from, or some obscure error.
162  raise RuntimeError("Ran the deblender but cannot find %r in the source table" % (nChildKeyName,))
163 
164  # set inner flags for each source and set primary flags for sources with no children
165  # (or all sources if deblend info not available)
166  innerFloatBBox = afwGeom.Box2D(skyInfo.patchInfo.getInnerBBox())
167  tractId = skyInfo.tractInfo.getId()
168  for source in sources:
169  if source.getCentroidFlag():
170  # centroid unknown, so leave the inner and primary flags False
171  continue
172 
173  centroidPos = source.getCentroid()
174  isPatchInner = innerFloatBBox.contains(centroidPos)
175  source.setFlag(self.isPatchInnerKey, isPatchInner)
176 
177  skyPos = source.getCoord()
178  sourceInnerTractId = skyInfo.skyMap.findTract(skyPos).getId()
179  isTractInner = sourceInnerTractId == tractId
180  source.setFlag(self.isTractInnerKey, isTractInner)
181 
182  if nChildKey is None or source.get(nChildKey) == 0:
183  source.setFlag(self.isPrimaryKey, isPatchInner and isTractInner)
184 
185  @classmethod
187  parser = pipeBase.ArgumentParser(name=cls._DefaultName)
188  parser.add_id_argument("--id", "deepCoadd", help="data ID, e.g. --id tract=12345 patch=1,2",
189  ContainerClass=CoaddDataIdContainer)
190  return parser
191 
192  def _getConfigName(self):
193  """Return the name of the config dataset
194  """
195  return "%s_processCoadd_config" % (self.config.coaddName,)
196 
197  def _getMetadataName(self):
198  """Return the name of the metadata dataset
199  """
200  return "%s_processCoadd_metadata" % (self.config.coaddName,)
Pass parameters to a Statistics objectA class to pass parameters which control how the stats are calc...
Definition: Statistics.h:92
Statistics makeStatistics(afwImage::Mask< afwImage::MaskPixel > const &msk, int const flags, StatisticsControl const &sctrl)
Specialization to handle Masks.
Definition: Statistics.cc:1023
A floating-point coordinate rectangle geometry.
Definition: Box.h:271