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