lsst.pipe.tasks  13.0-66-gfbf2f2ce+5
coaddBase.py
Go to the documentation of this file.
1 #
2 # LSST Data Management System
3 # Copyright 2008-2015 AURA/LSST.
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 from __future__ import absolute_import, division, print_function
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 
44 class CoaddBaseConfig(pexConfig.Config):
45  """!Configuration parameters for CoaddBaseTask
46 
47  \anchor CoaddBaseConfig_
48 
49  \brief Configuration parameters shared between MakeCoaddTempExp and AssembleCoadd
50  """
51  coaddName = pexConfig.Field(
52  doc="Coadd name: typically one of deep or goodSeeing.",
53  dtype=str,
54  default="deep",
55  )
56  select = pexConfig.ConfigurableField(
57  doc="Image selection subtask.",
58  target=WcsSelectImagesTask,
59  )
60  badMaskPlanes = pexConfig.ListField(
61  dtype=str,
62  doc="Mask planes that, if set, the associated pixel should not be included in the coaddTempExp.",
63  default=("NO_DATA",),
64  )
65  inputRecorder = pexConfig.ConfigurableField(
66  doc="Subtask that helps fill CoaddInputs catalogs added to the final Exposure",
67  target=CoaddInputRecorderTask
68  )
69  doPsfMatch = pexConfig.Field(
70  dtype=bool,
71  doc="Match to modelPsf? Deprecated. Sets makePsfMatched=True, makeDirect=False",
72  default=False
73  )
74  modelPsf = measAlg.GaussianPsfFactory.makeField(doc="Model Psf factory")
75  doApplyUberCal = pexConfig.Field(
76  dtype=bool,
77  doc="Apply meas_mosaic ubercal results to input calexps?",
78  default=False
79  )
80 
81 
82 class CoaddTaskRunner(pipeBase.TaskRunner):
83 
84  @staticmethod
85  def getTargetList(parsedCmd, **kwargs):
86  return pipeBase.TaskRunner.getTargetList(parsedCmd, selectDataList=parsedCmd.selectId.dataList,
87  **kwargs)
88 
89 
90 class CoaddBaseTask(pipeBase.CmdLineTask):
91  """!Base class for coaddition.
92 
93  Subclasses must specify _DefaultName
94  """
95  ConfigClass = CoaddBaseConfig
96  RunnerClass = CoaddTaskRunner
97 
98  def __init__(self, *args, **kwargs):
99  pipeBase.Task.__init__(self, *args, **kwargs)
100  self.makeSubtask("select")
101  self.makeSubtask("inputRecorder")
102 
103  def selectExposures(self, patchRef, skyInfo=None, selectDataList=[]):
104  """!
105  \brief Select exposures to coadd
106 
107  Get the corners of the bbox supplied in skyInfo using \ref afwGeom.Box2D and convert the pixel
108  positions of the bbox corners to sky coordinates using \ref skyInfo.wcs.pixelToSky. Use the
109  \ref WcsSelectImagesTask_ "WcsSelectImagesTask" to select exposures that lie inside the patch
110  indicated by the dataRef.
111 
112  \param[in] patchRef data reference for sky map patch. Must include keys "tract", "patch",
113  plus the camera-specific filter key (e.g. "filter" or "band")
114  \param[in] skyInfo geometry for the patch; output from getSkyInfo
115  \return a list of science exposures to coadd, as butler data references
116  """
117  if skyInfo is None:
118  skyInfo = self.getSkyInfo(patchRef)
119  cornerPosList = afwGeom.Box2D(skyInfo.bbox).getCorners()
120  coordList = [skyInfo.wcs.pixelToSky(pos) for pos in cornerPosList]
121  return self.select.runDataRef(patchRef, coordList, selectDataList=selectDataList).dataRefList
122 
123  def getSkyInfo(self, patchRef):
124  """!
125  \brief Use \ref getSkyinfo to return the skyMap, tract and patch information, wcs and the outer bbox
126  of the patch.
127 
128  \param[in] patchRef data reference for sky map. Must include keys "tract" and "patch"
129 
130  \return pipe_base Struct containing:
131  - skyMap: sky map
132  - tractInfo: information for chosen tract of sky map
133  - patchInfo: information about chosen patch of tract
134  - wcs: WCS of tract
135  - bbox: outer bbox of patch, as an afwGeom Box2I
136  """
137  return getSkyInfo(coaddName=self.config.coaddName, patchRef=patchRef)
138 
139  def getCalExp(self, dataRef, bgSubtracted):
140  """!Return one "calexp" calibrated exposure
141 
142  @param[in] dataRef a sensor-level data reference
143  @param[in] bgSubtracted return calexp with background subtracted? If False get the
144  calexp's background background model and add it to the calexp.
145  @return calibrated exposure
146 
147  If config.doApplyUberCal, meas_mosaic calibrations will be applied to
148  the returned exposure using applyMosaicResults.
149  """
150  exposure = dataRef.get("calexp", immediate=True)
151  if not bgSubtracted:
152  background = dataRef.get("calexpBackground", immediate=True)
153  mi = exposure.getMaskedImage()
154  mi += background.getImage()
155  del mi
156  if not self.config.doApplyUberCal:
157  return exposure
158  if applyMosaicResults is None:
159  raise RuntimeError(
160  "Cannot use improved calibrations for %s because meas_mosaic could not be imported."
161  % dataRef.dataId
162  )
163  else:
164  applyMosaicResults(dataRef, calexp=exposure)
165  return exposure
166 
167  def getCoaddDatasetName(self, warpType="direct"):
168  """Return coadd name for given warpType and task config
169 
170  Parameters
171  ----------
172  warpType : string
173  Either 'direct' or 'psfMatched'
174 
175  Returns
176  -------
177  CoaddDatasetName : `string`
178  """
179  suffix = "" if warpType == "direct" else warpType[0].upper() + warpType[1:]
180  return self.config.coaddName + "Coadd" + suffix
181 
182  def getTempExpDatasetName(self, warpType="direct"):
183  """Return warp name for given warpType and task config
184 
185  Parameters
186  ----------
187  warpType : string
188  Either 'direct' or 'psfMatched'
189 
190  Returns
191  -------
192  WarpDatasetName : `string`
193  """
194  return self.config.coaddName + "Coadd_" + warpType + "Warp"
195 
196  @classmethod
197  def _makeArgumentParser(cls):
198  """Create an argument parser
199  """
200  parser = pipeBase.ArgumentParser(name=cls._DefaultName)
201  parser.add_id_argument("--id", "deepCoadd", help="data ID, e.g. --id tract=12345 patch=1,2",
202  ContainerClass=CoaddDataIdContainer)
203  parser.add_id_argument("--selectId", "calexp", help="data ID, e.g. --selectId visit=6789 ccd=0..9",
204  ContainerClass=SelectDataIdContainer)
205  return parser
206 
207  def _getConfigName(self):
208  """Return the name of the config dataset
209  """
210  return "%s_%s_config" % (self.config.coaddName, self._DefaultName)
211 
212  def _getMetadataName(self):
213  """Return the name of the metadata dataset
214  """
215  return "%s_%s_metadata" % (self.config.coaddName, self._DefaultName)
216 
217  def getBadPixelMask(self):
218  """!
219  \brief Convenience method to provide the bitmask from the mask plane names
220  """
221  return afwImage.Mask.getPlaneBitMask(self.config.badMaskPlanes)
222 
223 
224 class SelectDataIdContainer(pipeBase.DataIdContainer):
225  """!
226  \brief A dataId container for inputs to be selected.
227 
228  Read the header (including the size and Wcs) for all specified
229  inputs and pass those along, ultimately for the SelectImagesTask.
230  This is most useful when used with multiprocessing, as input headers are
231  only read once.
232  """
233 
234  def makeDataRefList(self, namespace):
235  """Add a dataList containing useful information for selecting images"""
236  super(SelectDataIdContainer, self).makeDataRefList(namespace)
237  self.dataList = []
238  for ref in self.refList:
239  try:
240  md = ref.get("calexp_md", immediate=True)
241  wcs = afwImage.makeWcs(md)
242  data = SelectStruct(dataRef=ref, wcs=wcs, bbox=afwImage.bboxFromMetadata(md))
243  except FitsError as e:
244  namespace.log.warn("Unable to construct Wcs from %s" % (ref.dataId))
245  continue
246  self.dataList.append(data)
247 
248 
249 def getSkyInfo(coaddName, patchRef):
250  """!
251  \brief Return the SkyMap, tract and patch information, wcs, and outer bbox of the patch to be coadded.
252 
253  \param[in] coaddName coadd name; typically one of deep or goodSeeing
254  \param[in] patchRef data reference for sky map. Must include keys "tract" and "patch"
255 
256  \return pipe_base Struct containing:
257  - skyMap: sky map
258  - tractInfo: information for chosen tract of sky map
259  - patchInfo: information about chosen patch of tract
260  - wcs: WCS of tract
261  - bbox: outer bbox of patch, as an afwGeom Box2I
262  """
263  skyMap = patchRef.get(coaddName + "Coadd_skyMap")
264  tractId = patchRef.dataId["tract"]
265  tractInfo = skyMap[tractId]
266 
267  # patch format is "xIndex,yIndex"
268  patchIndex = tuple(int(i) for i in patchRef.dataId["patch"].split(","))
269  patchInfo = tractInfo.getPatchInfo(patchIndex)
270 
271  return pipeBase.Struct(
272  skyMap=skyMap,
273  tractInfo=tractInfo,
274  patchInfo=patchInfo,
275  wcs=tractInfo.getWcs(),
276  bbox=patchInfo.getOuterBBox(),
277  )
278 
279 
280 def scaleVariance(maskedImage, maskPlanes, log=None):
281  """!
282  \brief Scale the variance in a maskedImage
283 
284  The variance plane in a convolved or warped image (or a coadd derived
285  from warped images) does not accurately reflect the noise properties of
286  the image because variance has been lost to covariance. This function
287  attempts to correct for this by scaling the variance plane to match
288  the observed variance in the image. This is not perfect (because we're
289  not tracking the covariance) but it's simple and is often good enough.
290 
291  @param maskedImage MaskedImage to operate on; variance will be scaled
292  @param maskPlanes List of mask planes for pixels to reject
293  @param log Log for reporting the renormalization factor; or None
294  @return renormalisation factor
295  """
296  variance = maskedImage.getVariance()
297  sigNoise = maskedImage.getImage().getArray()/numpy.sqrt(variance.getArray())
298  maskVal = maskedImage.getMask().getPlaneBitMask(maskPlanes)
299  good = (maskedImage.getMask().getArray() & maskVal) == 0
300  # Robust measurement of stdev
301  q1, q3 = numpy.percentile(sigNoise[good], (25, 75))
302  stdev = 0.74*(q3 - q1)
303  ratio = stdev**2
304  if log:
305  log.info("Renormalizing variance by %f" % (ratio,))
306  variance *= ratio
307  return ratio
def getCoaddDatasetName(self, warpType="direct")
Definition: coaddBase.py:167
Base class for coaddition.
Definition: coaddBase.py:90
Configuration parameters for CoaddBaseTask.
Definition: coaddBase.py:44
A dataId container for inputs to be selected.
Definition: coaddBase.py:224
def __init__(self, args, kwargs)
Definition: coaddBase.py:98
def getSkyInfo(self, patchRef)
Use getSkyinfo to return the skyMap, tract and patch information, wcs and the outer bbox of the patch...
Definition: coaddBase.py:123
def getTempExpDatasetName(self, warpType="direct")
Definition: coaddBase.py:182
def getBadPixelMask(self)
Convenience method to provide the bitmask from the mask plane names.
Definition: coaddBase.py:217
def getTargetList(parsedCmd, kwargs)
Definition: coaddBase.py:85
def selectExposures(self, patchRef, skyInfo=None, selectDataList=[])
Select exposures to coadd.
Definition: coaddBase.py:103
def getCalExp(self, dataRef, bgSubtracted)
Return one "calexp" calibrated exposure.
Definition: coaddBase.py:139
def scaleVariance(maskedImage, maskPlanes, log=None)
Scale the variance in a maskedImage.
Definition: coaddBase.py:280
def getSkyInfo(coaddName, patchRef)
Return the SkyMap, tract and patch information, wcs, and outer bbox of the patch to be coadded...
Definition: coaddBase.py:249