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