LSSTApplications  1.1.2+25,10.0+13,10.0+132,10.0+133,10.0+224,10.0+41,10.0+8,10.0-1-g0f53050+14,10.0-1-g4b7b172+19,10.0-1-g61a5bae+98,10.0-1-g7408a83+3,10.0-1-gc1e0f5a+19,10.0-1-gdb4482e+14,10.0-11-g3947115+2,10.0-12-g8719d8b+2,10.0-15-ga3f480f+1,10.0-2-g4f67435,10.0-2-gcb4bc6c+26,10.0-28-gf7f57a9+1,10.0-3-g1bbe32c+14,10.0-3-g5b46d21,10.0-4-g027f45f+5,10.0-4-g86f66b5+2,10.0-4-gc4fccf3+24,10.0-40-g4349866+2,10.0-5-g766159b,10.0-5-gca2295e+25,10.0-6-g462a451+1
LSSTDataManagementBasePackage
assembleCoadd.py
Go to the documentation of this file.
1 from __future__ import division, absolute_import
2 #
3 # LSST Data Management System
4 # Copyright 2008, 2009, 2010, 2011, 2012 LSST Corporation.
5 #
6 # This product includes software developed by the
7 # LSST Project (http://www.lsst.org/).
8 #
9 # This program is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the LSST License Statement and
20 # the GNU General Public License along with this program. If not,
21 # see <http://www.lsstcorp.org/LegalNotices/>.
22 #
23 import numpy
24 import lsst.pex.config as pexConfig
25 import lsst.afw.geom as afwGeom
26 import lsst.afw.image as afwImage
27 import lsst.afw.math as afwMath
28 import lsst.coadd.utils as coaddUtils
29 import lsst.pipe.base as pipeBase
30 import lsst.meas.algorithms as measAlg
31 from .coaddBase import CoaddBaseTask, SelectDataIdContainer
32 from .interpImage import InterpImageTask
33 from .matchBackgrounds import MatchBackgroundsTask
34 from .scaleZeroPoint import ScaleZeroPointTask
35 from .coaddHelpers import groupPatchExposures, getGroupDataRef
36 
37 __all__ = ["AssembleCoaddTask"]
38 
39 class AssembleCoaddConfig(CoaddBaseTask.ConfigClass):
40  subregionSize = pexConfig.ListField(
41  dtype = int,
42  doc = "Width, height of stack subregion size; " \
43  "make small enough that a full stack of images will fit into memory at once.",
44  length = 2,
45  default = (2000, 2000),
46  )
47  doSigmaClip = pexConfig.Field(
48  dtype = bool,
49  doc = "Perform sigma clipped outlier rejection? If False then compute a simple mean.",
50  default = True,
51  )
52  sigmaClip = pexConfig.Field(
53  dtype = float,
54  doc = "Sigma for outlier rejection; ignored if doSigmaClip false.",
55  default = 3.0,
56  )
57  clipIter = pexConfig.Field(
58  dtype = int,
59  doc = "Number of iterations of outlier rejection; ignored if doSigmaClip false.",
60  default = 2,
61  )
62  scaleZeroPoint = pexConfig.ConfigurableField(
63  target = ScaleZeroPointTask,
64  doc = "Task to adjust the photometric zero point of the coadd temp exposures",
65  )
66  doInterp = pexConfig.Field(
67  doc = "Interpolate over NaN pixels? Also extrapolate, if necessary, but the results are ugly.",
68  dtype = bool,
69  default = True,
70  )
71  interpImage = pexConfig.ConfigurableField(
72  target = InterpImageTask,
73  doc = "Task to interpolate (and extrapolate) over NaN pixels",
74  )
75  matchBackgrounds = pexConfig.ConfigurableField(
76  target = MatchBackgroundsTask,
77  doc = "Task to match backgrounds",
78  )
79  maxMatchResidualRatio = pexConfig.Field(
80  doc = "Maximum ratio of the mean squared error of the background matching model to the variance " \
81  "of the difference in backgrounds",
82  dtype = float,
83  default = 1.1
84  )
85  maxMatchResidualRMS = pexConfig.Field(
86  doc = "Maximum RMS of residuals of the background offset fit in matchBackgrounds.",
87  dtype = float,
88  default = 1.0
89  )
90  doWrite = pexConfig.Field(
91  doc = "Persist coadd?",
92  dtype = bool,
93  default = True,
94  )
95  doMatchBackgrounds = pexConfig.Field(
96  doc = "Match backgrounds of coadd temp exposures before coadding them? " \
97  "If False, the coadd temp expsosures must already have been background subtracted or matched",
98  dtype = bool,
99  default = True,
100  )
101  autoReference = pexConfig.Field(
102  doc = "Automatically select the coadd temp exposure to use as a reference for background matching? " \
103  "Ignored if doMatchBackgrounds false. " \
104  "If False you must specify the reference temp exposure as the data Id",
105  dtype = bool,
106  default = True,
107  )
108  badMaskPlanes = pexConfig.ListField(
109  dtype = str,
110  doc = "Mask planes that, if set, the associated pixel should not be included in the coaddTempExp.",
111  default = ("EDGE",),
112  )
113 
114 
115 class AssembleCoaddTask(CoaddBaseTask):
116  """Assemble a coadd from a set of coaddTempExp
117  """
118  ConfigClass = AssembleCoaddConfig
119  _DefaultName = "assembleCoadd"
120 
121  def __init__(self, *args, **kwargs):
122  CoaddBaseTask.__init__(self, *args, **kwargs)
123  self.makeSubtask("interpImage")
124  self.makeSubtask("matchBackgrounds")
125  self.makeSubtask("scaleZeroPoint")
126 
127  @pipeBase.timeMethod
128  def run(self, dataRef, selectDataList=[]):
129  """Assemble a coadd from a set of coaddTempExp
130 
131  The coadd is computed as a mean with optional outlier rejection.
132 
133  assembleCoaddTask only works on the dataset type 'coaddTempExp', which are 'coadd temp exposures'.
134  Each coaddTempExp is the size of a patch and contains data for one run, visit or
135  (for a non-mosaic camera it will contain data for a single exposure).
136 
137  coaddTempExps, by default, will have backgrounds in them and will require
138  config.doMatchBackgrounds = True. However, makeCoaddTempExp.py can optionally create background-
139  subtracted coaddTempExps which can be coadded here by setting
140  config.doMatchBackgrounds = False.
141 
142  @param dataRef: data reference for a coadd patch (of dataType 'Coadd') OR a data reference
143  for a coadd temp exposure (of dataType 'Coadd_tempExp') which serves as the reference visit
144  if config.doMatchBackgrounds true and config.autoReference false)
145  If supplying a coadd patch: Must include keys "tract", "patch",
146  plus the camera-specific filter key (e.g. "filter")
147  Used to access the following data products (depending on the config):
148  - [in] self.config.coaddName + "Coadd_tempExp"
149  - [out] self.config.coaddName + "Coadd"
150 
151  @return: a pipeBase.Struct with fields:
152  - coaddExposure: coadd exposure
153  """
154  skyInfo = self.getSkyInfo(dataRef)
155  calExpRefList = self.selectExposures(dataRef, skyInfo, selectDataList=selectDataList)
156  if len(calExpRefList) == 0:
157  self.log.warn("No exposures to coadd")
158  return
159  self.log.info("Coadding %d exposures" % len(calExpRefList))
160 
161  butler = dataRef.getButler()
162  groupData = groupPatchExposures(dataRef, calExpRefList, self.getCoaddDatasetName(),
163  self.getTempExpDatasetName())
164  tempExpRefList = [getGroupDataRef(butler, self.getTempExpDatasetName(), g, groupData.keys) for
165  g in groupData.groups.keys()]
166  inputData = self.prepareInputs(tempExpRefList)
167  tempExpRefList = inputData.tempExpRefList
168  self.log.info("Found %d %s" % (len(inputData.tempExpRefList), self.getTempExpDatasetName()))
169  if len(inputData.tempExpRefList) == 0:
170  self.log.warn("No coadd temporary exposures found")
171  return
172  if self.config.doMatchBackgrounds:
173  refImageScaler = self.getBackgroundReferenceScaler(dataRef)
174  inputData = self.backgroundMatching(inputData, dataRef, refImageScaler)
175  if len(inputData.tempExpRefList) == 0:
176  self.log.warn("No valid background models")
177  return
178 
179  coaddExp = self.assemble(skyInfo, inputData.tempExpRefList, inputData.imageScalerList,
180  inputData.weightList,
181  inputData.backgroundInfoList if self.config.doMatchBackgrounds else None)
182  if self.config.doMatchBackgrounds:
183  self.addBackgroundMatchingMetadata(coaddExp, inputData.tempExpRefList,
184  inputData.backgroundInfoList)
185 
186  if self.config.doInterp:
187  self.interpImage.interpolateOnePlane(
188  maskedImage = coaddExp.getMaskedImage(),
189  planeName = "EDGE",
190  )
191 
192  if self.config.doWrite:
193  self.writeCoaddOutput(dataRef, coaddExp)
194 
195  return pipeBase.Struct(coaddExposure=coaddExp)
196 
197 
198  def getBackgroundReferenceScaler(self, dataRef):
199  """Construct an image scaler for the background reference frame
200 
201  If there is no reference frame ('autoReference'), then this is a no-op
202  and None is returned
203 
204  @param dataRef: Data reference for the background reference frame, or None
205  @return image scaler, or None
206  """
207  if self.config.autoReference:
208  return None
209 
210  # We've been given the data reference
211  dataset = self.getTempExpDatasetName()
212  if not dataRef.datasetExists(dataset):
213  raise RuntimeError("Could not find reference exposure %s %s." % (dataset, dataRef.dataId))
214 
215  refExposure = dataRef.get(self.getTempExpDatasetName(), immediate=True)
216  refImageScaler = self.scaleZeroPoint.computeImageScaler(
217  exposure = refExposure,
218  dataRef = dataRef,
219  )
220  return refImageScaler
221 
222 
223  def prepareInputs(self, refList):
224  """Prepare the input warps for coaddition
225 
226  This involves measuring weights and constructing image scalers
227  for each of the inputs.
228 
229  @param refList: List of data references to tempExp
230  @return Struct:
231  - tempExprefList: List of data references to tempExp
232  - weightList: List of weightings
233  - imageScalerList: List of image scalers
234  """
235  statsCtrl = afwMath.StatisticsControl()
236  statsCtrl.setNumSigmaClip(self.config.sigmaClip)
237  statsCtrl.setNumIter(self.config.clipIter)
238  statsCtrl.setAndMask(self.getBadPixelMask())
239  statsCtrl.setNanSafe(True)
240 
241  # compute tempExpRefList: a list of tempExpRef that actually exist
242  # and weightList: a list of the weight of the associated coadd tempExp
243  # and imageScalerList: a list of scale factors for the associated coadd tempExp
244  tempExpRefList = []
245  weightList = []
246  imageScalerList = []
247  tempExpName = self.getTempExpDatasetName()
248  for tempExpRef in refList:
249  if not tempExpRef.datasetExists(tempExpName):
250  self.log.warn("Could not find %s %s; skipping it" % (tempExpName, tempExpRef.dataId))
251  continue
252 
253  tempExp = tempExpRef.get(tempExpName, immediate=True)
254  maskedImage = tempExp.getMaskedImage()
255  imageScaler = self.scaleZeroPoint.computeImageScaler(
256  exposure = tempExp,
257  dataRef = tempExpRef,
258  )
259  try:
260  imageScaler.scaleMaskedImage(maskedImage)
261  except Exception, e:
262  self.log.warn("Scaling failed for %s (skipping it): %s" % (tempExpRef.dataId, e))
263  continue
264  statObj = afwMath.makeStatistics(maskedImage.getVariance(), maskedImage.getMask(),
265  afwMath.MEANCLIP, statsCtrl)
266  meanVar, meanVarErr = statObj.getResult(afwMath.MEANCLIP);
267  weight = 1.0 / float(meanVar)
268  if not numpy.isfinite(weight):
269  self.log.warn("Non-finite weight for %s: skipping" % (tempExpRef.dataId,))
270  continue
271  self.log.info("Weight of %s %s = %0.3f" % (tempExpName, tempExpRef.dataId, weight))
272 
273  del maskedImage
274  del tempExp
275 
276  tempExpRefList.append(tempExpRef)
277  weightList.append(weight)
278  imageScalerList.append(imageScaler)
279 
280  return pipeBase.Struct(tempExpRefList=tempExpRefList, weightList=weightList,
281  imageScalerList=imageScalerList)
282 
283 
284  def backgroundMatching(self, inputData, refExpDataRef=None, refImageScaler=None):
285  """Perform background matching on the prepared inputs
286 
287  If no reference is provided, the background matcher will select one.
288 
289  This method returns a new inputData Struct that can replace the original.
290 
291  @param inputData: Struct from prepareInputs() with tempExpRefList, weightList, imageScalerList
292  @param refExpDataRef: Data reference for background reference tempExp, or None
293  @param refImageScaler: Image scaler for background reference tempExp, or None
294  @return Struct:
295  - tempExprefList: List of data references to tempExp
296  - weightList: List of weightings
297  - imageScalerList: List of image scalers
298  - backgroundInfoList: result from background matching
299  """
300  try:
301  backgroundInfoList = self.matchBackgrounds.run(
302  expRefList = inputData.tempExpRefList,
303  imageScalerList = inputData.imageScalerList,
304  refExpDataRef = refExpDataRef if not self.config.autoReference else None,
305  refImageScaler = refImageScaler,
306  expDatasetType = self.getTempExpDatasetName(),
307  ).backgroundInfoList
308  except Exception, e:
309  self.log.fatal("Cannot match backgrounds: %s" % (e))
310  raise pipeBase.TaskError("Background matching failed.")
311 
312  newWeightList = []
313  newTempExpRefList = []
314  newBackgroundStructList = []
315  newScaleList = []
316  # the number of good backgrounds may be < than len(tempExpList)
317  # sync these up and correct the weights
318  for tempExpRef, bgInfo, scaler, weight in zip(inputData.tempExpRefList, backgroundInfoList,
319  inputData.imageScalerList, inputData.weightList):
320  if not bgInfo.isReference:
321  # skip exposure if it has no backgroundModel
322  # or if fit was bad
323  if (bgInfo.backgroundModel is None):
324  self.log.info("No background offset model available for %s: skipping"%(
325  tempExpRef.dataId))
326  continue
327  try:
328  varianceRatio = bgInfo.matchedMSE / bgInfo.diffImVar
329  except Exception, e:
330  self.log.info("MSE/Var ratio not calculable (%s) for %s: skipping" %
331  (e, tempExpRef.dataId,))
332  continue
333  if not numpy.isfinite(varianceRatio):
334  self.log.info("MSE/Var ratio not finite (%.2f / %.2f) for %s: skipping" %
335  (bgInfo.matchedMSE, bgInfo.diffImVar,
336  tempExpRef.dataId,))
337  continue
338  elif (varianceRatio > self.config.maxMatchResidualRatio):
339  self.log.info("Bad fit. MSE/Var ratio %.2f > %.2f for %s: skipping" % (
340  varianceRatio, self.config.maxMatchResidualRatio, tempExpRef.dataId,))
341  continue
342  elif ( bgInfo.fitRMS > self.config.maxMatchResidualRMS):
343  self.log.info("Bad fit. RMS %.2f > %.2f for %s: skipping" % (
344  bgInfo.fitRMS, self.config.maxMatchResidualRMS, tempExpRef.dataId,))
345  continue
346  newWeightList.append(1 / (1 / weight + bgInfo.fitRMS**2))
347  newTempExpRefList.append(tempExpRef)
348  newBackgroundStructList.append(bgInfo)
349  newScaleList.append(scaler)
350 
351  return pipeBase.Struct(tempExpRefList=newTempExpRefList, weightList=newWeightList,
352  imageScalerList=newScaleList, backgroundInfoList=newBackgroundStructList)
353 
354  def assemble(self, skyInfo, tempExpRefList, imageScalerList, weightList, bgInfoList=None):
355  """Assemble a coadd from input warps
356 
357  The assembly is performed over small areas on the image at a time, to
358  conserve memory usage.
359 
360  @param skyInfo: Patch geometry information, from getSkyInfo
361  @param tempExpRefList: List of data references to tempExp
362  @param imageScalerList: List of image scalers
363  @param weightList: List of weights
364  @param bgInfoList: List of background data from background matching
365  @return coadded exposure
366  """
367  tempExpName = self.getTempExpDatasetName()
368  self.log.info("Assembling %s %s" % (len(tempExpRefList), tempExpName))
369 
370  statsCtrl = afwMath.StatisticsControl()
371  statsCtrl.setNumSigmaClip(self.config.sigmaClip)
372  statsCtrl.setNumIter(self.config.clipIter)
373  statsCtrl.setAndMask(self.getBadPixelMask())
374  statsCtrl.setNanSafe(True)
375  statsCtrl.setCalcErrorFromInputVariance(True)
376 
377  if self.config.doSigmaClip:
378  statsFlags = afwMath.MEANCLIP
379  else:
380  statsFlags = afwMath.MEAN
381 
382  if bgInfoList is None:
383  bgInfoList = [None]*len(tempExpRefList)
384 
385  coaddExposure = afwImage.ExposureF(skyInfo.bbox, skyInfo.wcs)
386  coaddExposure.setCalib(self.scaleZeroPoint.getCalib())
387  coaddExposure.getInfo().setCoaddInputs(self.inputRecorder.makeCoaddInputs())
388  self.assembleMetadata(coaddExposure, tempExpRefList, weightList)
389  coaddMaskedImage = coaddExposure.getMaskedImage()
390  subregionSizeArr = self.config.subregionSize
391  subregionSize = afwGeom.Extent2I(subregionSizeArr[0], subregionSizeArr[1])
392  for subBBox in _subBBoxIter(skyInfo.bbox, subregionSize):
393  try:
394  self.assembleSubregion(coaddExposure, subBBox, tempExpRefList, imageScalerList,
395  weightList, bgInfoList, statsFlags, statsCtrl)
396  except Exception, e:
397  self.log.fatal("Cannot compute coadd %s: %s" % (subBBox, e,))
398 
399  coaddUtils.setCoaddEdgeBits(coaddMaskedImage.getMask(), coaddMaskedImage.getVariance())
400 
401  return coaddExposure
402 
403  def assembleMetadata(self, coaddExposure, tempExpRefList, weightList):
404  """Set the metadata for the coadd
405 
406  This basic implementation simply sets the filter from the
407  first input.
408 
409  @param coaddExposure: The target image for the coadd
410  @param tempExpRefList: List of data references to tempExp
411  @param weightList: List of weights
412  """
413  tempExpName = self.getTempExpDatasetName()
414  # We load a single pixel of each coaddTempExp, because we just want to get at the metadata
415  # (and we need more than just the PropertySet that contains the header). See #2777.
417  first = True
418  coaddInputs = coaddExposure.getInfo().getCoaddInputs()
419  for tempExpRef, weight in zip(tempExpRefList, weightList):
420  tempExp = tempExpRef.get(tempExpName + "_sub", bbox=bbox, imageOrigin="LOCAL", immediate=True)
421  if first:
422  coaddExposure.setFilter(tempExp.getFilter())
423  first = False
424  self.inputRecorder.addVisitToCoadd(coaddInputs, tempExp, weight)
425  coaddInputs.visits.sort()
426  if self.config.doPsfMatch:
427  psf = self.config.modelPsf.apply()
428  else:
429  psf = measAlg.CoaddPsf(coaddInputs.ccds, coaddExposure.getWcs())
430  coaddExposure.setPsf(psf)
431 
432  def assembleSubregion(self, coaddExposure, bbox, tempExpRefList, imageScalerList, weightList,
433  bgInfoList, statsFlags, statsCtrl):
434  """Assemble the coadd for a sub-region
435 
436  @param coaddExposure: The target image for the coadd
437  @param bbox: Sub-region to coadd
438  @param tempExpRefList: List of data reference to tempExp
439  @param imageScalerList: List of image scalers
440  @param weightList: List of weights
441  @param bgInfoList: List of background data from background matching
442  @param statsFlags: Statistic for coadd
443  @param statsCtrl: Statistics control object for coadd
444  """
445  self.log.info("Computing coadd over %s" % bbox)
446  tempExpName = self.getTempExpDatasetName()
447  coaddMaskedImage = coaddExposure.getMaskedImage()
448  coaddView = afwImage.MaskedImageF(coaddMaskedImage, bbox, afwImage.PARENT, False)
449  maskedImageList = afwImage.vectorMaskedImageF() # [] is rejected by afwMath.statisticsStack
450  for tempExpRef, imageScaler, bgInfo in zip(tempExpRefList, imageScalerList, bgInfoList):
451  exposure = tempExpRef.get(tempExpName + "_sub", bbox=bbox)
452  maskedImage = exposure.getMaskedImage()
453  imageScaler.scaleMaskedImage(maskedImage)
454 
455  if self.config.doMatchBackgrounds and not bgInfo.isReference:
456  backgroundModel = bgInfo.backgroundModel
457  backgroundImage = backgroundModel.getImage() if \
458  self.matchBackgrounds.config.usePolynomial else \
459  backgroundModel.getImageF()
460  backgroundImage.setXY0(coaddMaskedImage.getXY0())
461  maskedImage += backgroundImage.Factory(backgroundImage, bbox, afwImage.PARENT, False)
462  var = maskedImage.getVariance()
463  var += (bgInfo.fitRMS)**2
464 
465  maskedImageList.append(maskedImage)
466 
467  with self.timer("stack"):
468  coaddSubregion = afwMath.statisticsStack(
469  maskedImageList, statsFlags, statsCtrl, weightList)
470 
471  coaddView <<= coaddSubregion
472 
473 
474  def addBackgroundMatchingMetadata(self, coaddExposure, tempExpRefList, backgroundInfoList):
475  """Add metadata from the background matching to the coadd
476 
477  @param coaddExposure: Coadd
478  @param backgroundInfoList: List of background info, results from background matching
479  """
480  self.log.info("Adding exposure information to metadata")
481  metadata = coaddExposure.getMetadata()
482  metadata.addString("CTExp_SDQA1_DESCRIPTION",
483  "Background matching: Ratio of matchedMSE / diffImVar")
484  for ind, (tempExpRef, backgroundInfo) in enumerate(zip(tempExpRefList, backgroundInfoList)):
485  tempExpStr = '&'.join('%s=%s' % (k,v) for k,v in tempExpRef.dataId.items())
486  if backgroundInfo.isReference:
487  metadata.addString("ReferenceExp_ID", tempExpStr)
488  else:
489  metadata.addString("CTExp_ID_%d" % (ind), tempExpStr)
490  metadata.addDouble("CTExp_SDQA1_%d" % (ind),
491  backgroundInfo.matchedMSE/backgroundInfo.diffImVar)
492  metadata.addDouble("CTExp_SDQA2_%d" % (ind),
493  backgroundInfo.fitRMS)
494  @classmethod
496  """Create an argument parser
497  """
498  parser = pipeBase.ArgumentParser(name=cls._DefaultName)
499  parser.add_id_argument("--id", cls.ConfigClass().coaddName + "Coadd_tempExp",
500  help="data ID, e.g. --id tract=12345 patch=1,2",
501  ContainerClass=AssembleCoaddDataIdContainer)
502  parser.add_id_argument("--selectId", "calexp", help="data ID, e.g. --selectId visit=6789 ccd=0..9",
503  ContainerClass=SelectDataIdContainer)
504  return parser
505 
506 
507 
508 def _subBBoxIter(bbox, subregionSize):
509  """Iterate over subregions of a bbox
510 
511  @param[in] bbox: bounding box over which to iterate: afwGeom.Box2I
512  @param[in] subregionSize: size of sub-bboxes
513 
514  @return subBBox: next sub-bounding box of size subregionSize or smaller;
515  each subBBox is contained within bbox, so it may be smaller than subregionSize at the edges of bbox,
516  but it will never be empty
517  """
518  if bbox.isEmpty():
519  raise RuntimeError("bbox %s is empty" % (bbox,))
520  if subregionSize[0] < 1 or subregionSize[1] < 1:
521  raise RuntimeError("subregionSize %s must be nonzero" % (subregionSize,))
522 
523  for rowShift in range(0, bbox.getHeight(), subregionSize[1]):
524  for colShift in range(0, bbox.getWidth(), subregionSize[0]):
525  subBBox = afwGeom.Box2I(bbox.getMin() + afwGeom.Extent2I(colShift, rowShift), subregionSize)
526  subBBox.clip(bbox)
527  if subBBox.isEmpty():
528  raise RuntimeError("Bug: empty bbox! bbox=%s, subregionSize=%s, colShift=%s, rowShift=%s" % \
529  (bbox, subregionSize, colShift, rowShift))
530  yield subBBox
531 
532 
533 
534 class AssembleCoaddDataIdContainer(pipeBase.DataIdContainer):
535  """A version of lsst.pipe.base.DataIdContainer specialized for assembleCoadd.
536  """
537  def makeDataRefList(self, namespace):
538  """Make self.refList from self.idList.
539 
540  Interpret the config.doMatchBackgrounds, config.autoReference,
541  and whether a visit/run supplied.
542  If a visit/run is supplied, config.autoReference is automatically set to False.
543  if config.doMatchBackgrounds == false, then a visit/run will be ignored if accidentally supplied.
544 
545  """
546  keysCoadd = namespace.butler.getKeys(datasetType=namespace.config.coaddName + "Coadd",
547  level=self.level)
548  keysCoaddTempExp = namespace.butler.getKeys(datasetType=namespace.config.coaddName + "Coadd_tempExp",
549  level=self.level)
550 
551  if namespace.config.doMatchBackgrounds:
552  if namespace.config.autoReference: #matcher will pick it's own reference image
553  datasetType = namespace.config.coaddName + "Coadd"
554  validKeys = keysCoadd
555  else:
556  datasetType = namespace.config.coaddName + "Coadd_tempExp"
557  validKeys = keysCoaddTempExp
558  else: #bkg subtracted coadd
559  datasetType = namespace.config.coaddName + "Coadd"
560  validKeys = keysCoadd
561 
562  for dataId in self.idList:
563  # tract and patch are required
564  for key in validKeys:
565  if key not in dataId:
566  raise RuntimeError("--id must include " + key)
567 
568  for key in dataId: # check if users supplied visit/run
569  if (key not in keysCoadd) and (key in keysCoaddTempExp): #user supplied a visit/run
570  if namespace.config.autoReference:
571  # user probably meant: autoReference = False
572  namespace.config.autoReference = False
573  datasetType = namespace.config.coaddName + "Coadd_tempExp"
574  print "Switching config.autoReference to False; applies only to background Matching."
575  break
576 
577  dataRef = namespace.butler.dataRef(
578  datasetType = datasetType,
579  dataId = dataId,
580  )
581  self.refList.append(dataRef)
582 
void setCoaddEdgeBits(lsst::afw::image::Mask< lsst::afw::image::MaskPixel > &coaddMask, lsst::afw::image::Image< WeightPixelT > const &weightMap)
set edge bits of coadd mask based on weight map
An integer coordinate rectangle.
Definition: Box.h:53
Pass parameters to a Statistics objectA class to pass parameters which control how the stats are calc...
Definition: Statistics.h:92
CoaddPsf is the Psf derived to be used for non-PSF-matched Coadd images.
Definition: CoaddPsf.h:44
Statistics makeStatistics(afwImage::Mask< afwImage::MaskPixel > const &msk, int const flags, StatisticsControl const &sctrl)
Specialization to handle Masks.
Definition: Statistics.cc:1023
lsst::afw::image::MaskedImage< PixelT >::Ptr statisticsStack(lsst::afw::image::MaskedImage< PixelT > const &image, Property flags, char dimension, StatisticsControl const &sctrl=StatisticsControl())
A function to compute statistics on the rows or columns of an image.