31import lsst.pipe.base
as pipeBase
32from lsst.skymap
import BaseSkyMap
33from lsst.daf.butler
import DeferredDatasetHandle
35from lsst.meas.algorithms
import CoaddPsf, CoaddPsfConfig
37__all__ = [
"GetCoaddAsTemplateTask",
"GetCoaddAsTemplateConfig",
38 "GetCalexpAsTemplateTask",
"GetCalexpAsTemplateConfig",
39 "GetMultiTractCoaddTemplateTask",
"GetMultiTractCoaddTemplateConfig"]
43 templateBorderSize = pexConfig.Field(
46 doc=
"Number of pixels to grow the requested template image to account for warping"
48 coaddName = pexConfig.Field(
49 doc=
"coadd name: typically one of 'deep', 'goodSeeing', or 'dcr'",
53 numSubfilters = pexConfig.Field(
54 doc=
"Number of subfilters in the DcrCoadd. Used only if ``coaddName``='dcr'",
58 effectiveWavelength = pexConfig.Field(
59 doc=
"Effective wavelength of the filter. Used only if ``coaddName``='dcr'",
63 bandwidth = pexConfig.Field(
64 doc=
"Bandwidth of the physical filter. Used only if ``coaddName``='dcr'",
68 warpType = pexConfig.Field(
69 doc=
"Warp type of the coadd template: one of 'direct' or 'psfMatched'",
77 raise ValueError(
"The effective wavelength and bandwidth of the physical filter "
78 "must be set in the getTemplate config for DCR coadds. "
79 "Required until transmission curves are used in DM-13668.")
83 """Subtask to retrieve coadd for use as an image difference template.
85 This is the default getTemplate Task to be run
as a subtask by
86 ``pipe.tasks.ImageDifferenceTask``. The main methods are ``
run()``
and
91 From the given skymap, the closest tract
is selected; multiple tracts are
92 not supported. The assembled template inherits the WCS of the selected
93 skymap tract
and the resolution of the template exposures. Overlapping box
94 regions of the input template patches are pixel by pixel copied into the
95 assembled template image. There
is no warping
or pixel resampling.
97 Pixels
with no overlap of any available input patches are set to ``nan`` value
98 and ``NO_DATA`` flagged.
101 ConfigClass = GetCoaddAsTemplateConfig
102 _DefaultName = "GetCoaddAsTemplateTask"
104 def runDataRef(self, exposure, sensorRef, templateIdList=None):
105 """Gen2 task entry point. Retrieve and mosaic a template coadd exposure
106 that overlaps the science exposure.
111 an exposure for which to generate an overlapping template
113 a Butler data reference that can be used to obtain coadd data
114 templateIdList : TYPE, optional
115 list of data ids, unused here,
in the case of coadd template
119 result : `lsst.pipe.base.Struct`
120 - ``exposure`` : `lsst.afw.image.ExposureF`
121 a template coadd exposure assembled out of patches
122 - ``sources`` :
None for this subtask
124 skyMap = sensorRef.get(datasetType=self.config.coaddName + "Coadd_skyMap")
125 tractInfo, patchList, skyCorners = self.
getOverlapPatchListgetOverlapPatchList(exposure, skyMap)
127 availableCoaddRefs = dict()
128 for patchInfo
in patchList:
129 patchNumber = tractInfo.getSequentialPatchIndex(patchInfo)
132 bbox=patchInfo.getOuterBBox(),
133 tract=tractInfo.getId(),
134 patch=
"%s,%s" % (patchInfo.getIndex()[0], patchInfo.getIndex()[1]),
136 numSubfilters=self.config.numSubfilters,
139 if sensorRef.datasetExists(**patchArgDict):
140 self.log.info(
"Reading patch %s", patchArgDict)
141 availableCoaddRefs[patchNumber] = patchArgDict
143 templateExposure = self.
runrun(
144 tractInfo, patchList, skyCorners, availableCoaddRefs,
145 sensorRef=sensorRef, visitInfo=exposure.getInfo().getVisitInfo()
147 return pipeBase.Struct(exposure=templateExposure, sources=
None)
149 def runQuantum(self, exposure, butlerQC, skyMapRef, coaddExposureRefs):
150 """Gen3 task entry point. Retrieve and mosaic a template coadd exposure
151 that overlaps the science exposure.
156 The science exposure to define the sky region of the template coadd.
157 butlerQC : `lsst.pipe.base.ButlerQuantumContext`
158 Butler like object that supports getting data by DatasetRef.
159 skyMapRef : `lsst.daf.butler.DatasetRef`
160 Reference to SkyMap object that corresponds to the template coadd.
161 coaddExposureRefs : iterable of `lsst.daf.butler.DeferredDatasetRef`
162 Iterable of references to the available template coadd patches.
166 result : `lsst.pipe.base.Struct`
167 - ``exposure`` : `lsst.afw.image.ExposureF`
168 a template coadd exposure assembled out of patches
169 - ``sources`` : `None`
for this subtask
171 skyMap = butlerQC.get(skyMapRef)
172 coaddExposureRefs = butlerQC.get(coaddExposureRefs)
173 tracts = [ref.dataId['tract']
for ref
in coaddExposureRefs]
174 if tracts.count(tracts[0]) == len(tracts):
175 tractInfo = skyMap[tracts[0]]
177 raise RuntimeError(
"Templates constructed from multiple Tracts not supported by this task. "
178 "Use GetMultiTractCoaddTemplateTask instead.")
180 detectorBBox = exposure.getBBox()
181 detectorWcs = exposure.getWcs()
182 detectorCorners = detectorWcs.pixelToSky(
geom.Box2D(detectorBBox).getCorners())
183 validPolygon = exposure.getInfo().getValidPolygon()
184 detectorPolygon = validPolygon
if validPolygon
else geom.Box2D(detectorBBox)
186 availableCoaddRefs = dict()
188 for coaddRef
in coaddExposureRefs:
189 dataId = coaddRef.dataId
190 patchWcs = skyMap[dataId[
'tract']].getWcs()
191 patchBBox = skyMap[dataId[
'tract']][dataId[
'patch']].getOuterBBox()
192 patchCorners = patchWcs.pixelToSky(
geom.Box2D(patchBBox).getCorners())
193 patchPolygon = afwGeom.Polygon(detectorWcs.skyToPixel(patchCorners))
194 if patchPolygon.intersection(detectorPolygon):
195 overlappingArea += patchPolygon.intersectionSingle(detectorPolygon).calculateArea()
196 if self.config.coaddName ==
'dcr':
197 self.log.info(
"Using template input tract=%s, patch=%s, subfilter=%s",
198 dataId[
'tract'], dataId[
'patch'], dataId[
'subfilter'])
199 if dataId[
'patch']
in availableCoaddRefs:
200 availableCoaddRefs[dataId[
'patch']].append(coaddRef)
202 availableCoaddRefs[dataId[
'patch']] = [coaddRef, ]
204 self.log.info(
"Using template input tract=%s, patch=%s",
205 dataId[
'tract'], dataId[
'patch'])
206 availableCoaddRefs[dataId[
'patch']] = coaddRef
208 if overlappingArea == 0:
209 templateExposure =
None
211 self.log.warning(
"No overlapping template patches found")
213 patchList = [tractInfo[patch]
for patch
in availableCoaddRefs.keys()]
214 templateExposure = self.
runrun(tractInfo, patchList, detectorCorners, availableCoaddRefs,
215 visitInfo=exposure.getInfo().getVisitInfo())
218 pixNoData = np.count_nonzero(templateExposure.mask.array
219 & templateExposure.mask.getPlaneBitMask(
'NO_DATA'))
220 pixGood = templateExposure.getBBox().getArea() - pixNoData
221 self.log.info(
"template has %d good pixels (%.1f%%)", pixGood,
222 100*pixGood/templateExposure.getBBox().getArea())
223 return pipeBase.Struct(exposure=templateExposure, sources=
None, area=pixGood)
226 """Select the relevant tract and its patches that overlap with the science exposure.
231 The science exposure to define the sky region of the template coadd.
233 skyMap : `lsst.skymap.BaseSkyMap`
234 SkyMap object that corresponds to the template coadd.
239 - ``tractInfo`` : `lsst.skymap.TractInfo`
241 - ``patchList`` : `list` of `lsst.skymap.PatchInfo`
242 List of all overlap patches of the selected tract.
244 Corners of the exposure in the sky
in the order given by `lsst.geom.Box2D.getCorners`.
246 expWcs = exposure.getWcs()
248 expBoxD.grow(self.config.templateBorderSize)
249 ctrSkyPos = expWcs.pixelToSky(expBoxD.getCenter())
250 tractInfo = skyMap.findTract(ctrSkyPos)
251 self.log.info("Using skyMap tract %s", tractInfo.getId())
252 skyCorners = [expWcs.pixelToSky(pixPos)
for pixPos
in expBoxD.getCorners()]
253 patchList = tractInfo.findPatchList(skyCorners)
256 raise RuntimeError(
"No suitable tract found")
258 self.log.info(
"Assembling %d coadd patches", len(patchList))
259 self.log.info(
"exposure dimensions=%s", exposure.getDimensions())
261 return (tractInfo, patchList, skyCorners)
263 def run(self, tractInfo, patchList, skyCorners, availableCoaddRefs,
264 sensorRef=None, visitInfo=None):
265 """Gen2 and gen3 shared code: determination of exposure dimensions and
266 copying of pixels from overlapping patch regions.
270 skyMap : `lsst.skymap.BaseSkyMap`
271 SkyMap object that corresponds to the template coadd.
272 tractInfo : `lsst.skymap.TractInfo`
274 patchList : iterable of `lsst.skymap.patchInfo.PatchInfo`
275 Patches to consider
for making the template exposure.
277 Sky corner coordinates to be covered by the template exposure.
278 availableCoaddRefs : `dict` [`int`]
279 Dictionary of spatially relevant retrieved coadd patches,
280 indexed by their sequential patch number. In Gen3 mode, values are
281 `lsst.daf.butler.DeferredDatasetHandle`
and ``.get()``
is called,
282 in Gen2 mode, ``sensorRef.get(**coaddef)``
is called to retrieve the coadd.
283 sensorRef : `lsst.daf.persistence.ButlerDataRef`, Gen2 only
284 Butler data reference to get coadd data.
285 Must be `
None`
for Gen3.
287 VisitInfo to make dcr model.
291 templateExposure: `lsst.afw.image.ExposureF`
292 The created template exposure.
294 coaddWcs = tractInfo.getWcs()
298 for skyPos
in skyCorners:
299 coaddBBox.include(coaddWcs.skyToPixel(skyPos))
301 self.log.info(
"coadd dimensions=%s", coaddBBox.getDimensions())
303 coaddExposure = afwImage.ExposureF(coaddBBox, coaddWcs)
304 coaddExposure.maskedImage.set(np.nan, afwImage.Mask.getPlaneBitMask(
"NO_DATA"), np.nan)
306 coaddFilterLabel =
None
308 coaddPhotoCalib =
None
309 for patchInfo
in patchList:
310 patchNumber = tractInfo.getSequentialPatchIndex(patchInfo)
311 patchSubBBox = patchInfo.getOuterBBox()
312 patchSubBBox.clip(coaddBBox)
313 if patchNumber
not in availableCoaddRefs:
314 self.log.warning(
"skip patch=%d; patch does not exist for this coadd", patchNumber)
316 if patchSubBBox.isEmpty():
317 if isinstance(availableCoaddRefs[patchNumber], DeferredDatasetHandle):
318 tract = availableCoaddRefs[patchNumber].dataId[
'tract']
320 tract = availableCoaddRefs[patchNumber][
'tract']
321 self.log.info(
"skip tract=%d patch=%d; no overlapping pixels", tract, patchNumber)
324 if self.config.coaddName ==
'dcr':
325 patchInnerBBox = patchInfo.getInnerBBox()
326 patchInnerBBox.clip(coaddBBox)
327 if np.min(patchInnerBBox.getDimensions()) <= 2*self.config.templateBorderSize:
328 self.log.info(
"skip tract=%(tract)s, patch=%(patch)s; too few pixels.",
329 availableCoaddRefs[patchNumber])
331 self.log.info(
"Constructing DCR-matched template for patch %s",
332 availableCoaddRefs[patchNumber])
335 dcrModel = DcrModel.fromDataRef(sensorRef,
336 self.config.effectiveWavelength,
337 self.config.bandwidth,
338 **availableCoaddRefs[patchNumber])
340 dcrModel = DcrModel.fromQuantum(availableCoaddRefs[patchNumber],
341 self.config.effectiveWavelength,
342 self.config.bandwidth)
350 dcrBBox.grow(-self.config.templateBorderSize)
351 dcrBBox.include(patchInnerBBox)
352 coaddPatch = dcrModel.buildMatchedExposure(bbox=dcrBBox,
355 if sensorRef
is None:
357 coaddPatch = availableCoaddRefs[patchNumber].get()
360 coaddPatch = sensorRef.get(**availableCoaddRefs[patchNumber])
365 overlapBox = coaddPatch.getBBox()
366 overlapBox.clip(coaddBBox)
367 coaddExposure.maskedImage.assign(coaddPatch.maskedImage[overlapBox], overlapBox)
369 if coaddFilterLabel
is None:
370 coaddFilterLabel = coaddPatch.getFilterLabel()
373 if coaddPsf
is None and coaddPatch.hasPsf():
374 coaddPsf = coaddPatch.getPsf()
377 if coaddPhotoCalib
is None:
378 coaddPhotoCalib = coaddPatch.getPhotoCalib()
380 if coaddPhotoCalib
is None:
381 raise RuntimeError(
"No coadd PhotoCalib found!")
382 if nPatchesFound == 0:
383 raise RuntimeError(
"No patches found!")
385 raise RuntimeError(
"No coadd Psf found!")
387 coaddExposure.setPhotoCalib(coaddPhotoCalib)
388 coaddExposure.setPsf(coaddPsf)
389 coaddExposure.setFilterLabel(coaddFilterLabel)
393 """Return coadd name for given task config
397 CoaddDatasetName : `string`
399 TODO: This nearly duplicates a method in CoaddBaseTask (DM-11985)
401 warpType = self.config.warpType
402 suffix = "" if warpType ==
"direct" else warpType[0].upper() + warpType[1:]
403 return self.config.coaddName +
"Coadd" + suffix
407 doAddCalexpBackground = pexConfig.Field(
410 doc=
"Add background to calexp before processing it."
415 """Subtask to retrieve calexp of the same ccd number as the science image SensorRef
416 for use
as an image difference template. Only gen2 supported.
418 To be run
as a subtask by pipe.tasks.ImageDifferenceTask.
419 Intended
for use
with simulations
and surveys that repeatedly visit the same pointing.
420 This code was originally part of Winter2013ImageDifferenceTask.
423 ConfigClass = GetCalexpAsTemplateConfig
424 _DefaultName = "GetCalexpAsTemplateTask"
426 def run(self, exposure, sensorRef, templateIdList):
427 """Return a calexp exposure with based on input sensorRef.
429 Construct a dataId based on the sensorRef.dataId combined
430 with the specifications
from the first dataId
in templateIdList
436 sensorRef : `list` of `lsst.daf.persistence.ButlerDataRef`
437 Data reference of the calexp(s) to subtract
from.
438 templateIdList : `list` of `lsst.daf.persistence.ButlerDataRef`
439 Data reference of the template calexp to be subtraced.
440 Can be incomplete, fields are initialized
from `sensorRef`.
441 If there are multiple items, only the first one
is used.
447 return a pipeBase.Struct:
449 - ``exposure`` : a template calexp
450 - ``sources`` : source catalog measured on the template
453 if len(templateIdList) == 0:
454 raise RuntimeError(
"No template data reference supplied.")
455 if len(templateIdList) > 1:
456 self.log.warning(
"Multiple template data references supplied. Using the first one only.")
458 templateId = sensorRef.dataId.copy()
459 templateId.update(templateIdList[0])
461 self.log.info(
"Fetching calexp (%s) as template.", templateId)
463 butler = sensorRef.getButler()
464 template = butler.get(datasetType=
"calexp", dataId=templateId)
465 if self.config.doAddCalexpBackground:
466 templateBg = butler.get(datasetType=
"calexpBackground", dataId=templateId)
467 mi = template.getMaskedImage()
468 mi += templateBg.getImage()
470 if not template.hasPsf():
471 raise pipeBase.TaskError(
"Template has no psf")
473 templateSources = butler.get(datasetType=
"src", dataId=templateId)
474 return pipeBase.Struct(exposure=template,
475 sources=templateSources)
478 return self.
runrun(*args, **kwargs)
481 raise NotImplementedError(
"Calexp template is not supported with gen3 middleware")
485 dimensions=(
"instrument",
"visit",
"detector",
"skymap"),
486 defaultTemplates={
"coaddName":
"goodSeeing",
487 "warpTypeSuffix":
"",
489 bbox = pipeBase.connectionTypes.Input(
490 doc=
"BBoxes of calexp used determine geometry of output template",
491 name=
"{fakesType}calexp.bbox",
492 storageClass=
"Box2I",
493 dimensions=(
"instrument",
"visit",
"detector"),
495 wcs = pipeBase.connectionTypes.Input(
496 doc=
"WCSs of calexps that we want to fetch the template for",
497 name=
"{fakesType}calexp.wcs",
499 dimensions=(
"instrument",
"visit",
"detector"),
501 skyMap = pipeBase.connectionTypes.Input(
502 doc=
"Input definition of geometry/bbox and projection/wcs for template exposures",
503 name=BaseSkyMap.SKYMAP_DATASET_TYPE_NAME,
504 dimensions=(
"skymap", ),
505 storageClass=
"SkyMap",
509 coaddExposures = pipeBase.connectionTypes.Input(
510 doc=
"Input template to match and subtract from the exposure",
511 dimensions=(
"tract",
"patch",
"skymap",
"band"),
512 storageClass=
"ExposureF",
513 name=
"{fakesType}{coaddName}Coadd{warpTypeSuffix}",
517 outputExposure = pipeBase.connectionTypes.Output(
518 doc=
"Warped template used to create `subtractedExposure`.",
519 dimensions=(
"instrument",
"visit",
"detector"),
520 storageClass=
"ExposureF",
521 name=
"{fakesType}{coaddName}Diff_templateExp{warpTypeSuffix}",
526 pipelineConnections=GetMultiTractCoaddTemplateConnections):
527 warp = pexConfig.ConfigField(
528 dtype=afwMath.Warper.ConfigClass,
529 doc=
"warper configuration",
531 coaddPsf = pexConfig.ConfigField(
532 doc=
"Configuration for CoaddPsf",
533 dtype=CoaddPsfConfig,
536 def setDefaults(self):
537 self.warp.warpingKernelName =
'lanczos5'
538 self.coaddPsf.warpingKernelName =
'lanczos5'
541class GetMultiTractCoaddTemplateTask(pipeBase.PipelineTask):
542 ConfigClass = GetMultiTractCoaddTemplateConfig
543 _DefaultName =
"getMultiTractCoaddTemplateTask"
545 def __init__(self, *args, **kwargs):
546 super().__init__(*args, **kwargs)
547 self.warper = afwMath.Warper.fromConfig(self.config.warp)
549 def runQuantum(self, butlerQC, inputRefs, outputRefs):
551 inputs = butlerQC.get(inputRefs)
552 inputs[
'coaddExposures'] = self.getOverlappingExposures(inputs)
555 outputs = self.run(**inputs)
556 butlerQC.put(outputs, outputRefs)
558 def getOverlappingExposures(self, inputs):
559 """Return list of coaddExposure DeferredDatasetHandles that overlap detector
561 The spatial index in the registry has generous padding
and often supplies
562 patches near, but
not directly overlapping the detector.
563 Filters inputs so that we don
't have to read in all input coadds.
567 inputs : `dict` of task Inputs
571 coaddExposures : list of elements of type
572 `lsst.daf.butler.DeferredDatasetHandle` of
578 Raised if no patches overlap the input detector bbox
584 coaddExposureList = []
585 for coaddRef
in inputs[
'coaddExposures']:
586 dataId = coaddRef.dataId
587 patchWcs = inputs[
'skyMap'][dataId[
'tract']].getWcs()
588 patchBBox = inputs[
'skyMap'][dataId[
'tract']][dataId[
'patch']].getOuterBBox()
589 patchCorners = patchWcs.pixelToSky(
geom.Box2D(patchBBox).getCorners())
590 patchPolygon = afwGeom.Polygon(inputs[
'wcs'].skyToPixel(patchCorners))
591 if patchPolygon.intersection(detectorPolygon):
592 overlappingArea += patchPolygon.intersectionSingle(detectorPolygon).calculateArea()
593 self.log.info(
"Using template input tract=%s, patch=%s" %
594 (dataId[
'tract'], dataId[
'patch']))
595 coaddExposureList.append(coaddRef)
597 if not overlappingArea:
598 raise pipeBase.NoWorkFound(
'No patches overlap detector')
600 return coaddExposureList
602 def run(self, coaddExposures, bbox, wcs):
603 """Warp coadds from multiple tracts to form a template for image diff.
605 Where the tracts overlap, the resulting template image is averaged.
606 The PSF on the template
is created by combining the CoaddPsf on each
607 template image into a meta-CoaddPsf.
612 Coadds to be mosaicked
614 Template Bounding box of the detector geometry onto which to
615 resample the coaddExposures
617 Template WCS onto which to resample the coaddExposures
622 return a pipeBase.Struct:
623 - ``outputExposure`` : a template coadd exposure assembled out of patches
629 Raised
if no patches overlatp the input detector bbox
633 tractsSchema = afwTable.ExposureTable.makeMinimalSchema()
634 tractKey = tractsSchema.addField(
'tract', type=np.int32, doc=
'Which tract')
635 patchKey = tractsSchema.addField(
'patch', type=np.int32, doc=
'Which patch')
636 weightKey = tractsSchema.addField(
'weight', type=float, doc=
'Weight for each tract, should be 1')
637 tractsCatalog = afwTable.ExposureCatalog(tractsSchema)
640 bbox.grow(self.config.templateBorderSize)
647 for coaddExposure
in coaddExposures:
648 coaddPatch = coaddExposure.get()
651 warped = self.warper.warpExposure(finalWcs, coaddPatch, maxBBox=finalBBox)
654 if not np.any(np.isfinite(warped.image.array)):
655 self.log.info(
"No overlap for warped %s. Skipping" % coaddExposure.ref.dataId)
658 exp = afwImage.ExposureF(finalBBox, finalWcs)
659 exp.maskedImage.set(np.nan, afwImage.Mask.getPlaneBitMask(
"NO_DATA"), np.nan)
660 exp.maskedImage.assign(warped.maskedImage, warped.getBBox())
662 maskedImageList.append(exp.maskedImage)
664 record = tractsCatalog.addNew()
665 record.setPsf(coaddPatch.getPsf())
666 record.setWcs(coaddPatch.getWcs())
667 record.setPhotoCalib(coaddPatch.getPhotoCalib())
668 record.setBBox(coaddPatch.getBBox())
669 record.setValidPolygon(afwGeom.Polygon(
geom.Box2D(coaddPatch.getBBox()).getCorners()))
670 record.set(tractKey, coaddExposure.ref.dataId[
'tract'])
671 record.set(patchKey, coaddExposure.ref.dataId[
'patch'])
672 record.set(weightKey, 1.)
675 if nPatchesFound == 0:
676 raise pipeBase.NoWorkFound(
"No patches found to overlap detector")
681 statsCtrl.setNanSafe(
True)
682 statsCtrl.setWeighted(
True)
683 statsCtrl.setCalcErrorFromInputVariance(
True)
685 templateExposure = afwImage.ExposureF(finalBBox, finalWcs)
686 templateExposure.maskedImage.set(np.nan, afwImage.Mask.getPlaneBitMask(
"NO_DATA"), np.nan)
687 xy0 = templateExposure.getXY0()
690 weightList, clipped=0, maskMap=[])
691 templateExposure.maskedImage.setXY0(xy0)
695 boolmask = templateExposure.mask.array & templateExposure.mask.getPlaneBitMask(
'NO_DATA') == 0
697 centerCoord = afwGeom.SpanSet.fromMask(maskx, 1).computeCentroid()
699 ctrl = self.config.coaddPsf.makeControl()
700 coaddPsf = CoaddPsf(tractsCatalog, finalWcs, centerCoord, ctrl.warpingKernelName, ctrl.cacheSize)
702 raise RuntimeError(
"CoaddPsf could not be constructed")
704 templateExposure.setPsf(coaddPsf)
705 templateExposure.setFilterLabel(coaddPatch.getFilterLabel())
706 templateExposure.setPhotoCalib(coaddPatch.getPhotoCalib())
707 return pipeBase.Struct(outputExposure=templateExposure)
def runDataRef(self, *args, **kwargs)
def runQuantum(self, **kwargs)
def run(self, exposure, sensorRef, templateIdList)
def runDataRef(self, exposure, sensorRef, templateIdList=None)
def getCoaddDatasetName(self)
def getOverlapPatchList(self, exposure, skyMap)
def run(self, tractInfo, patchList, skyCorners, availableCoaddRefs, sensorRef=None, visitInfo=None)
def runQuantum(self, exposure, butlerQC, skyMapRef, coaddExposureRefs)
std::shared_ptr< lsst::afw::image::Image< PixelT > > statisticsStack(std::vector< std::shared_ptr< lsst::afw::image::Image< PixelT > > > &images, Property flags, StatisticsControl const &sctrl=StatisticsControl(), std::vector< lsst::afw::image::VariancePixel > const &wvector=std::vector< lsst::afw::image::VariancePixel >(0))
Property stringToStatisticsProperty(std::string const property)
def run(self, coaddExposures, bbox, wcs)