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