lsst.coadd.utils  16.0-4-g8a0f11a+22
coadd.py
Go to the documentation of this file.
1 #
2 # LSST Data Management System
3 # Copyright 2008, 2009, 2010, 2011, 2012 LSST Corporation.
4 #
5 # This product includes software developed by the
6 # LSST Project (http://www.lsst.org/).
7 #
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the LSST License Statement and
19 # the GNU General Public License along with this program. If not,
20 # see <http://www.lsstcorp.org/LegalNotices/>.
21 #
22 __all__ = ["Coadd"]
23 
24 import math
25 
26 import lsst.pex.config as pexConfig
27 from lsst.log import Log
28 import lsst.afw.image as afwImage
29 import lsst.afw.math as afwMath
30 from . import addToCoadd, setCoaddEdgeBits
31 
32 
33 class CoaddConfig(pexConfig.Config):
34  """Config for Coadd
35  """
36  badMaskPlanes = pexConfig.ListField(
37  dtype=str,
38  doc="mask planes that, if set, the associated pixel should not be included in the coadd",
39  default=("NO_DATA", "SAT"),
40  )
41 
42 
43 class Coadd:
44  """Coadd by weighted addition
45 
46  This class may be subclassed to implement other coadd techniques.
47  Typically this is done by overriding addExposure.
48  """
49  ConfigClass = CoaddConfig
50 
51  def __init__(self, bbox, wcs, badMaskPlanes, logName="coadd.utils.Coadd"):
52  """Create a coadd
53 
54  @param[in] bbox: bounding box of coadd Exposure with respect to parent (lsst.afw.geom.Box2I):
55  coadd dimensions = bbox.getDimensions(); xy0 = bbox.getMin()
56  @param[in] wcs: WCS of coadd exposure (lsst.afw.geom.SKyWcs)
57  @param[in] badMaskPlanes: mask planes to pay attention to when rejecting masked pixels.
58  Specify as a collection of names.
59  badMaskPlanes should always include "NO_DATA".
60  @param[in] logName: name by which messages are logged
61  """
62  self._log = Log.getLogger(logName)
63  self._bbox = bbox
64  self._wcs = wcs
65  self._badPixelMask = afwImage.Mask.getPlaneBitMask(badMaskPlanes)
66  self._coadd = afwImage.ExposureF(bbox, wcs)
67  self._weightMap = afwImage.ImageF(bbox)
68  self._filterDict = dict() # dict of filter name: filter object for all filters seen so far
69 
70  self._statsControl = afwMath.StatisticsControl()
71  self._statsControl.setNumSigmaClip(3.0)
72  self._statsControl.setNumIter(2)
73  self._statsControl.setAndMask(self._badPixelMask)
74 
75  @classmethod
76  def fromConfig(cls, bbox, wcs, config, logName="coadd.utils.Coadd"):
77  """Create a coadd
78 
79  @param[in] bbox: bounding box of coadd Exposure with respect to parent (lsst.afw.geom.Box2I):
80  coadd dimensions = bbox.getDimensions(); xy0 = bbox.getMin()
81  @param[in] wcs: WCS of coadd exposure (lsst.afw.geom.SKyWcs)
82  @param[in] config: coadd config; an instance of CoaddConfig
83  @param[in] logName: name by which messages are logged
84  """
85  return cls(
86  bbox=bbox,
87  wcs=wcs,
88  badMaskPlanes=config.badMaskPlanes,
89  logName=logName,
90  )
91 
92  def addExposure(self, exposure, weightFactor=1.0):
93  """Add an Exposure to the coadd
94 
95  @param[in] exposure: Exposure to add to coadd; this should be:
96  - background-subtracted or background-matched to the other images being coadded
97  - psf-matched to the desired PSF model (optional)
98  - warped to match the coadd
99  - photometrically scaled to the desired flux magnitude
100  @param[in] weightFactor: extra weight factor for this exposure
101 
102  @return
103  - overlapBBox: region of overlap between exposure and coadd in parent coordinates (afwGeom.Box2I)
104  - weight: weight with which exposure was added to coadd; weight = weightFactor / clipped mean variance
105 
106  Subclasses may override to preprocess the exposure or change the way it is added to the coadd.
107  """
108  maskedImage = exposure.getMaskedImage()
109 
110  # compute the weight
111  statObj = afwMath.makeStatistics(maskedImage.getVariance(), maskedImage.getMask(),
112  afwMath.MEANCLIP, self._statsControl)
113  meanVar = statObj.getResult(afwMath.MEANCLIP)[0]
114  weight = weightFactor / float(meanVar)
115  if math.isnan(weight):
116  raise RuntimeError("Weight is NaN (weightFactor=%s; mean variance=%s)" % (weightFactor, meanVar))
117 
118  # save filter info
119  filter = exposure.getFilter()
120  self._filterDict.setdefault(filter.getName(), filter)
121 
122  self._log.info("Add exposure to coadd with weight=%0.3g", weight)
123 
124  overlapBBox = addToCoadd(self._coadd.getMaskedImage(), self._weightMap,
125  maskedImage, self._badPixelMask, weight)
126 
127  return overlapBBox, weight
128 
129  def getCoadd(self):
130  """Get the coadd exposure for all exposures you have coadded so far
131 
132  If all exposures in this coadd have the same-named filter then that filter is set in the coadd.
133  Otherwise the coadd will have the default unknown filter.
134 
135  @warning: the Calib is not be set.
136  """
137  # make a deep copy so I can scale it
138  coaddMaskedImage = self._coadd.getMaskedImage()
139  scaledMaskedImage = coaddMaskedImage.Factory(coaddMaskedImage, True)
140 
141  # set the edge pixels
142  setCoaddEdgeBits(scaledMaskedImage.getMask(), self._weightMap)
143 
144  # scale non-edge pixels by weight map
145  scaledMaskedImage /= self._weightMap
146 
147  scaledExposure = afwImage.makeExposure(scaledMaskedImage, self._wcs)
148  if len(self._filterDict) == 1:
149  scaledExposure.setFilter(list(self._filterDict.values())[0])
150  return scaledExposure
151 
152  def getFilters(self):
153  """Return a collection of all the filters seen so far in in addExposure
154  """
155  return list(self._filterDict.values())
156 
157  def getBadPixelMask(self):
158  """Return the bad pixel mask
159  """
160  return self._badPixelMask
161 
162  def getBBox(self):
163  """Return the bounding box of the coadd
164  """
165  return self._bbox
166 
167  def getWcs(self):
168  """Return the wcs of the coadd
169  """
170  return self._wcs
171 
172  def getWeightMap(self):
173  """Return the weight map for all exposures you have coadded so far
174 
175  The weight map is a float Image of the same dimensions as the coadd; the value of each pixel
176  is the sum of the weights of all exposures that contributed to that pixel.
177  """
178  return self._weightMap
std::shared_ptr< Exposure< ImagePixelT, MaskPixelT, VariancePixelT > > makeExposure(MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > &mimage, std::shared_ptr< geom::SkyWcs const > wcs=std::shared_ptr< geom::SkyWcs const >())
def addExposure(self, exposure, weightFactor=1.0)
Definition: coadd.py:92
def fromConfig(cls, bbox, wcs, config, logName="coadd.utils.Coadd")
Definition: coadd.py:76
def __init__(self, bbox, wcs, badMaskPlanes, logName="coadd.utils.Coadd")
Definition: coadd.py:51