LSSTApplications  11.0-13-gbb96280,12.1.rc1,12.1.rc1+1,12.1.rc1+2,12.1.rc1+5,12.1.rc1+8,12.1.rc1-1-g06d7636+1,12.1.rc1-1-g253890b+5,12.1.rc1-1-g3d31b68+7,12.1.rc1-1-g3db6b75+1,12.1.rc1-1-g5c1385a+3,12.1.rc1-1-g83b2247,12.1.rc1-1-g90cb4cf+6,12.1.rc1-1-g91da24b+3,12.1.rc1-2-g3521f8a,12.1.rc1-2-g39433dd+4,12.1.rc1-2-g486411b+2,12.1.rc1-2-g4c2be76,12.1.rc1-2-gc9c0491,12.1.rc1-2-gda2cd4f+6,12.1.rc1-3-g3391c73+2,12.1.rc1-3-g8c1bd6c+1,12.1.rc1-3-gcf4b6cb+2,12.1.rc1-4-g057223e+1,12.1.rc1-4-g19ed13b+2,12.1.rc1-4-g30492a7
LSSTDataManagementBasePackage
coaddBase.py
Go to the documentation of this file.
1 from __future__ import division, absolute_import
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 <http://www.lsstcorp.org/LegalNotices/>.
22 #
23 import numpy
24 
25 import lsst.pex.config as pexConfig
26 import lsst.afw.geom as afwGeom
27 import lsst.afw.image as afwImage
28 import lsst.pipe.base as pipeBase
29 import lsst.meas.algorithms as measAlg
30 
31 from lsst.afw.fits import FitsError
32 from lsst.coadd.utils import CoaddDataIdContainer
33 from .selectImages import WcsSelectImagesTask, SelectStruct
34 from .coaddInputRecorder import CoaddInputRecorderTask
35 
36 try:
37  from lsst.meas.mosaic import applyMosaicResults
38 except ImportError:
39  applyMosaicResults = None
40 
41 __all__ = ["CoaddBaseTask", "getSkyInfo"]
42 
43 class CoaddBaseConfig(pexConfig.Config):
44  """Config for CoaddBaseTask
45  """
46  coaddName = pexConfig.Field(
47  doc = "Coadd name: typically one of deep or goodSeeing.",
48  dtype = str,
49  default = "deep",
50  )
51  select = pexConfig.ConfigurableField(
52  doc = "Image selection subtask.",
53  target = WcsSelectImagesTask,
54  )
55  badMaskPlanes = pexConfig.ListField(
56  dtype = str,
57  doc = "Mask planes that, if set, the associated pixel should not be included in the coaddTempExp.",
58  default = ("NO_DATA",),
59  )
60  inputRecorder = pexConfig.ConfigurableField(
61  doc = "Subtask that helps fill CoaddInputs catalogs added to the final Exposure",
62  target = CoaddInputRecorderTask
63  )
64  doPsfMatch = pexConfig.Field(dtype=bool, doc="Match to modelPsf?", default=False)
65  modelPsf = measAlg.GaussianPsfFactory.makeField(doc = "Model Psf factory")
66  doApplyUberCal = pexConfig.Field(
67  dtype = bool,
68  doc = "Apply meas_mosaic ubercal results to input calexps?",
69  default = False
70  )
71 
72 class CoaddTaskRunner(pipeBase.TaskRunner):
73  @staticmethod
74  def getTargetList(parsedCmd, **kwargs):
75  return pipeBase.TaskRunner.getTargetList(parsedCmd, selectDataList=parsedCmd.selectId.dataList,
76  **kwargs)
77 
78 class CoaddBaseTask(pipeBase.CmdLineTask):
79  """Base class for coaddition.
80 
81  Subclasses must specify _DefaultName
82  """
83  ConfigClass = CoaddBaseConfig
84  RunnerClass = CoaddTaskRunner
85 
86  def __init__(self, *args, **kwargs):
87  pipeBase.Task.__init__(self, *args, **kwargs)
88  self.makeSubtask("select")
89  self.makeSubtask("inputRecorder")
90 
91  def selectExposures(self, patchRef, skyInfo=None, selectDataList=[]):
92  """!
93  \brief Select exposures to coadd
94 
95  Get the corners of the bbox supplied in skyInfo using \ref afwGeom.Box2D and convert the pixel
96  positions of the bbox corners to sky coordinates using \ref skyInfo.wcs.pixelToSky. Use the
97  \ref WcsSelectImagesTask_ "WcsSelectImagesTask" to select exposures that lie inside the patch
98  indicated by the dataRef.
99 
100  \param[in] patchRef data reference for sky map patch. Must include keys "tract", "patch",
101  plus the camera-specific filter key (e.g. "filter" or "band")
102  \param[in] skyInfo geometry for the patch; output from getSkyInfo
103  \return a list of science exposures to coadd, as butler data references
104  """
105  if skyInfo is None:
106  skyInfo = self.getSkyInfo(patchRef)
107  cornerPosList = afwGeom.Box2D(skyInfo.bbox).getCorners()
108  coordList = [skyInfo.wcs.pixelToSky(pos) for pos in cornerPosList]
109  return self.select.runDataRef(patchRef, coordList, selectDataList=selectDataList).dataRefList
110 
111  def getSkyInfo(self, patchRef):
112  """!
113  \brief Use \ref getSkyinfo to return the skyMap, tract and patch information, wcs and the outer bbox
114  of the patch.
115 
116  \param[in] patchRef data reference for sky map. Must include keys "tract" and "patch"
117 
118  \return pipe_base Struct containing:
119  - skyMap: sky map
120  - tractInfo: information for chosen tract of sky map
121  - patchInfo: information about chosen patch of tract
122  - wcs: WCS of tract
123  - bbox: outer bbox of patch, as an afwGeom Box2I
124  """
125  return getSkyInfo(coaddName=self.config.coaddName, patchRef=patchRef)
126 
127  def getCalExp(self, dataRef, bgSubtracted):
128  """!Return one "calexp" calibrated exposure
129 
130  @param[in] dataRef a sensor-level data reference
131  @param[in] bgSubtracted return calexp with background subtracted? If False get the
132  calexp's background background model and add it to the calexp.
133  @return calibrated exposure
134 
135  If config.doApplyUberCal, meas_mosaic calibrations will be applied to
136  the returned exposure using applyMosaicResults.
137  """
138  exposure = dataRef.get("calexp", immediate=True)
139  if not bgSubtracted:
140  background = dataRef.get("calexpBackground", immediate=True)
141  mi = exposure.getMaskedImage()
142  mi += background.getImage()
143  del mi
144  if not self.config.doApplyUberCal:
145  return exposure
146  if applyMosaicResults is None:
147  raise RuntimeError(
148  "Cannot use improved calibrations for %s because meas_mosaic could not be imported."
149  % dataRef.dataId
150  )
151  else:
152  applyMosaicResults(dataRef, calexp=exposure)
153  return exposure
154 
156  return self.config.coaddName + "Coadd"
157 
159  return self.config.coaddName + "Coadd_tempExp"
160 
161  @classmethod
163  """Create an argument parser
164  """
165  parser = pipeBase.ArgumentParser(name=cls._DefaultName)
166  parser.add_id_argument("--id", "deepCoadd", help="data ID, e.g. --id tract=12345 patch=1,2",
167  ContainerClass=CoaddDataIdContainer)
168  parser.add_id_argument("--selectId", "calexp", help="data ID, e.g. --selectId visit=6789 ccd=0..9",
169  ContainerClass=SelectDataIdContainer)
170  return parser
171 
172  def _getConfigName(self):
173  """Return the name of the config dataset
174  """
175  return "%s_%s_config" % (self.config.coaddName, self._DefaultName)
176 
177  def _getMetadataName(self):
178  """Return the name of the metadata dataset
179  """
180  return "%s_%s_metadata" % (self.config.coaddName, self._DefaultName)
181 
182  def getBadPixelMask(self):
183  """!
184  \brief Convenience method to provide the bitmask from the mask plane names
185  """
186  return afwImage.MaskU.getPlaneBitMask(self.config.badMaskPlanes)
187 
188  def writeCoaddOutput(self, dataRef, obj, suffix=None):
189  """!
190  \brief Write a coadd product through the butler
191 
192  \param[in] dataRef data reference for coadd
193  \param[in,out] obj coadd product to write
194  \param[in] suffix suffix to apply to coadd dataset name
195  """
196  objName = self.getCoaddDatasetName()
197  if suffix is not None:
198  objName += "_" + suffix
199  self.log.info("Persisting %s" % objName)
200  dataRef.put(obj, objName)
201 
202 class SelectDataIdContainer(pipeBase.DataIdContainer):
203  """!
204  \brief A dataId container for inputs to be selected.
205 
206  Read the header (including the size and Wcs) for all specified
207  inputs and pass those along, ultimately for the SelectImagesTask.
208  This is most useful when used with multiprocessing, as input headers are
209  only read once.
210  """
211  def makeDataRefList(self, namespace):
212  """Add a dataList containing useful information for selecting images"""
213  super(SelectDataIdContainer, self).makeDataRefList(namespace)
214  self.dataList = []
215  for ref in self.refList:
216  try:
217  md = ref.get("calexp_md", immediate=True)
218  wcs = afwImage.makeWcs(md)
219  data = SelectStruct(dataRef=ref, wcs=wcs, dims=(md.get("NAXIS1"), md.get("NAXIS2")))
220  except FitsError as e:
221  namespace.log.warn("Unable to construct Wcs from %s" % (ref.dataId))
222  continue
223  self.dataList.append(data)
224 
225 def getSkyInfo(coaddName, patchRef):
226  """!
227  \brief Return the SkyMap, tract and patch information, wcs, and outer bbox of the patch to be coadded.
228 
229  \param[in] coaddName coadd name; typically one of deep or goodSeeing
230  \param[in] patchRef data reference for sky map. Must include keys "tract" and "patch"
231 
232  \return pipe_base Struct containing:
233  - skyMap: sky map
234  - tractInfo: information for chosen tract of sky map
235  - patchInfo: information about chosen patch of tract
236  - wcs: WCS of tract
237  - bbox: outer bbox of patch, as an afwGeom Box2I
238  """
239  skyMap = patchRef.get(coaddName + "Coadd_skyMap")
240  tractId = patchRef.dataId["tract"]
241  tractInfo = skyMap[tractId]
242 
243  # patch format is "xIndex,yIndex"
244  patchIndex = tuple(int(i) for i in patchRef.dataId["patch"].split(","))
245  patchInfo = tractInfo.getPatchInfo(patchIndex)
246 
247  return pipeBase.Struct(
248  skyMap = skyMap,
249  tractInfo = tractInfo,
250  patchInfo = patchInfo,
251  wcs = tractInfo.getWcs(),
252  bbox = patchInfo.getOuterBBox(),
253  )
254 
255 def scaleVariance(maskedImage, maskPlanes, log=None):
256  """!
257  \brief Scale the variance in a maskedImage
258 
259  The variance plane in a convolved or warped image (or a coadd derived
260  from warped images) does not accurately reflect the noise properties of
261  the image because variance has been lost to covariance. This function
262  attempts to correct for this by scaling the variance plane to match
263  the observed variance in the image. This is not perfect (because we're
264  not tracking the covariance) but it's simple and is often good enough.
265 
266  @param maskedImage MaskedImage to operate on; variance will be scaled
267  @param maskPlanes List of mask planes for pixels to reject
268  @param log Log for reporting the renormalization factor; or None
269  @return renormalisation factor
270  """
271  variance = maskedImage.getVariance()
272  sigNoise = maskedImage.getImage().getArray()/numpy.sqrt(variance.getArray())
273  maskVal = maskedImage.getMask().getPlaneBitMask(maskPlanes)
274  good = (maskedImage.getMask().getArray() & maskVal) == 0
275  # Robust measurement of stdev
276  q1, q3 = numpy.percentile(sigNoise[good], (25, 75))
277  stdev = 0.74*(q3 - q1)
278  ratio = stdev**2
279  if log:
280  log.info("Renormalizing variance by %f" % (ratio,))
281  variance *= ratio
282  return ratio
def getBadPixelMask
Convenience method to provide the bitmask from the mask plane names.
Definition: coaddBase.py:182
A dataId container for inputs to be selected.
Definition: coaddBase.py:202
def getCalExp
Return one &quot;calexp&quot; calibrated exposure.
Definition: coaddBase.py:127
def scaleVariance
Scale the variance in a maskedImage.
Definition: coaddBase.py:255
def selectExposures
Select exposures to coadd.
Definition: coaddBase.py:91
boost::shared_ptr< Wcs > makeWcs(coord::Coord const &crval, geom::Point2D const &crpix, double CD11, double CD12, double CD21, double CD22)
Create a Wcs object from crval, crpix, CD, using CD elements (useful from python) ...
Definition: makeWcs.cc:138
def writeCoaddOutput
Write a coadd product through the butler.
Definition: coaddBase.py:188
def getSkyInfo
Use getSkyinfo to return the skyMap, tract and patch information, wcs and the outer bbox of the patch...
Definition: coaddBase.py:111
def getSkyInfo
Return the SkyMap, tract and patch information, wcs, and outer bbox of the patch to be coadded...
Definition: coaddBase.py:225
A floating-point coordinate rectangle geometry.
Definition: Box.h:271