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