24from deprecated.sphinx
import deprecated
26import lsst.afw.image
as afwImage
38from lsst.utils.timer
import timeMethod
44 "GetDcrTemplateConfig",
49 pipeBase.PipelineTaskConnections,
50 dimensions=(
"instrument",
"visit",
"detector",
"skymap"),
51 defaultTemplates={
"coaddName":
"goodSeeing",
"warpTypeSuffix":
"",
"fakesType":
""},
53 bbox = pipeBase.connectionTypes.Input(
54 doc=
"Bounding box of exposure to determine the geometry of the output template.",
55 name=
"{fakesType}calexp.bbox",
57 dimensions=(
"instrument",
"visit",
"detector"),
59 wcs = pipeBase.connectionTypes.Input(
60 doc=
"WCS of the exposure that we will construct the template for.",
61 name=
"{fakesType}calexp.wcs",
63 dimensions=(
"instrument",
"visit",
"detector"),
65 skyMap = pipeBase.connectionTypes.Input(
66 doc=
"Geometry of the tracts and patches that the coadds are defined on.",
67 name=BaseSkyMap.SKYMAP_DATASET_TYPE_NAME,
68 dimensions=(
"skymap",),
69 storageClass=
"SkyMap",
71 coaddExposures = pipeBase.connectionTypes.Input(
72 doc=
"Coadds that may overlap the desired region, as possible inputs to the template."
73 " Will be restricted to those that directly overlap the projected bounding box.",
74 dimensions=(
"tract",
"patch",
"skymap",
"band"),
75 storageClass=
"ExposureF",
76 name=
"{fakesType}{coaddName}Coadd{warpTypeSuffix}",
79 deferGraphConstraint=
True,
82 template = pipeBase.connectionTypes.Output(
83 doc=
"Warped template, pixel matched to the bounding box and WCS.",
84 dimensions=(
"instrument",
"visit",
"detector"),
85 storageClass=
"ExposureF",
86 name=
"{fakesType}{coaddName}Diff_templateExp{warpTypeSuffix}",
90class GetTemplateConfig(
91 pipeBase.PipelineTaskConfig, pipelineConnections=GetTemplateConnections
93 templateBorderSize = pexConfig.Field(
96 doc=
"Number of pixels to grow the requested template image to account for warping",
98 warp = pexConfig.ConfigField(
99 dtype=afwMath.Warper.ConfigClass,
100 doc=
"warper configuration",
102 coaddPsf = pexConfig.ConfigField(
103 doc=
"Configuration for CoaddPsf",
104 dtype=CoaddPsfConfig,
106 varianceBackground = pexConfig.ConfigurableField(
107 target=SubtractBackgroundTask,
108 doc=
"Task to estimate the background variance.",
110 highVarianceThreshold = pexConfig.RangeField(
114 doc=
"Set the HIGH_VARIANCE mask plane for regions with variance"
115 " greater than the median by this factor.",
118 def setDefaults(self):
121 self.warp.cacheSize = 100000
122 self.coaddPsf.cacheSize = self.warp.cacheSize
125 self.warp.interpLength = 100
126 self.warp.warpingKernelName =
"lanczos3"
127 self.coaddPsf.warpingKernelName = self.warp.warpingKernelName
130 self.varianceBackground.algorithm =
"LINEAR"
131 self.varianceBackground.binSize = 32
132 self.varianceBackground.useApprox =
False
133 self.varianceBackground.statisticsProperty =
"MEDIAN"
134 self.varianceBackground.doFilterSuperPixels =
True
135 self.varianceBackground.ignoredPixelMask = [
"BAD",
143class GetTemplateTask(pipeBase.PipelineTask):
144 ConfigClass = GetTemplateConfig
145 _DefaultName =
"getTemplate"
147 def __init__(self, *args, **kwargs):
148 super().__init__(*args, **kwargs)
149 self.warper = afwMath.Warper.fromConfig(self.config.warp)
150 self.schema = afwTable.ExposureTable.makeMinimalSchema()
151 self.schema.addField(
152 "tract", type=np.int32, doc=
"Which tract this exposure came from."
154 self.schema.addField(
157 doc=
"Which patch in the tract this exposure came from.",
159 self.schema.addField(
162 doc=
"Weight for each exposure, used to make the CoaddPsf; should always be 1.",
164 self.makeSubtask(
"varianceBackground")
166 def runQuantum(self, butlerQC, inputRefs, outputRefs):
167 inputs = butlerQC.get(inputRefs)
168 bbox = inputs.pop(
"bbox")
169 wcs = inputs.pop(
"wcs")
170 coaddExposures = inputs.pop(
"coaddExposures")
171 skymap = inputs.pop(
"skyMap")
174 assert not inputs,
"runQuantum got more inputs than expected"
176 results = self.getExposures(coaddExposures, bbox, skymap, wcs)
177 physical_filter = butlerQC.quantum.dataId[
"physical_filter"]
179 coaddExposureHandles=results.coaddExposures,
182 dataIds=results.dataIds,
183 physical_filter=physical_filter,
185 butlerQC.put(outputs, outputRefs)
188 reason=
"Replaced by getExposures, which uses explicit arguments instead of a kwargs dict. "
189 "This method will be removed after v29.",
191 category=FutureWarning,
193 def getOverlappingExposures(self, inputs):
194 return self.getExposures(
195 inputs[
"coaddExposures"], inputs[
"bbox"], inputs[
"skyMap"], inputs[
"wcs"]
198 def getExposures(self, coaddExposureHandles, bbox, skymap, wcs):
199 """Return a data structure containing the coadds that overlap the
200 specified bbox projected onto the sky, and a corresponding data
201 structure of their dataIds.
202 These are the appropriate inputs to this task's `run` method.
204 The spatial index in the butler registry has generous padding and often
205 supplies patches near, but not directly overlapping the desired region.
206 This method filters the inputs so that `run` does not have to read in
207 all possibly-matching coadd exposures.
211 coaddExposureHandles : `iterable` \
212 [`lsst.daf.butler.DeferredDatasetHandle` of \
213 `lsst.afw.image.Exposure`]
214 Dataset handles to exposures that might overlap the desired
216 bbox : `lsst.geom.Box2I`
217 Template bounding box of the pixel geometry onto which the
218 coaddExposures will be resampled.
219 skymap : `lsst.skymap.SkyMap`
220 Geometry of the tracts and patches the coadds are defined on.
221 wcs : `lsst.afw.geom.SkyWcs`
222 Template WCS onto which the coadds will be resampled.
226 result : `lsst.pipe.base.Struct`
227 A struct with attributes:
230 Dict of coadd exposures that overlap the projected bbox,
232 (`dict` [`int`, `list` [`lsst.daf.butler.DeferredDatasetHandle` of
233 `lsst.afw.image.Exposure`] ]).
235 Dict of data IDs of the coadd exposures that overlap the
236 projected bbox, indexed on tract id
237 (`dict` [`int`, `list [`lsst.daf.butler.DataCoordinate`] ]).
242 Raised if no patches overlap the input detector bbox, or the input
246 raise pipeBase.NoWorkFound(
247 "WCS is None; cannot find overlapping exposures."
253 coaddExposures = collections.defaultdict(list)
254 dataIds = collections.defaultdict(list)
256 for coaddRef
in coaddExposureHandles:
257 dataId = coaddRef.dataId
258 patchWcs = skymap[dataId[
"tract"]].getWcs()
259 patchBBox = skymap[dataId[
"tract"]][dataId[
"patch"]].getOuterBBox()
260 patchCorners = patchWcs.pixelToSky(
geom.Box2D(patchBBox).getCorners())
262 if patchPolygon.intersection(detectorPolygon):
263 overlappingArea += patchPolygon.intersectionSingle(
267 "Using template input tract=%s, patch=%s",
271 coaddExposures[dataId[
"tract"]].append(coaddRef)
272 dataIds[dataId[
"tract"]].append(dataId)
274 if not overlappingArea:
275 raise pipeBase.NoWorkFound(
"No patches overlap detector")
277 return pipeBase.Struct(coaddExposures=coaddExposures, dataIds=dataIds)
280 def run(self, *, coaddExposureHandles, bbox, wcs, dataIds, physical_filter):
281 """Warp coadds from multiple tracts and patches to form a template to
282 subtract from a science image.
284 Tract and patch overlap regions are combined by a variance-weighted
285 average, and the variance planes are combined with the same weights,
286 not added in quadrature; the overlap regions are not statistically
287 independent, because they're derived from the same original data.
288 The PSF on the template is created by combining the CoaddPsf on each
289 template image into a meta-CoaddPsf.
293 coaddExposureHandles : `dict` [`int`, `list` of \
294 [`lsst.daf.butler.DeferredDatasetHandle` of \
295 `lsst.afw.image.Exposure`]]
296 Coadds to be mosaicked, indexed on tract id.
297 bbox : `lsst.geom.Box2I`
298 Template Bounding box of the detector geometry onto which to
299 resample the ``coaddExposureHandles``. Modified in-place to include the
301 wcs : `lsst.afw.geom.SkyWcs`
302 Template WCS onto which to resample the ``coaddExposureHandles``.
303 dataIds : `dict` [`int`, `list` [`lsst.daf.butler.DataCoordinate`]]
304 Record of the tract and patch of each coaddExposure, indexed on
306 physical_filter : `str`
307 Physical filter of the science image.
311 result : `lsst.pipe.base.Struct`
312 A struct with attributes:
315 A template coadd exposure assembled out of patches
316 (`lsst.afw.image.ExposureF`).
321 If no coadds are found with sufficient un-masked pixels.
323 band, photoCalib = self._checkInputs(dataIds, coaddExposureHandles)
325 bbox.grow(self.config.templateBorderSize)
329 for tract
in coaddExposureHandles:
330 maskedImages, catalog, totalBox = self._makeExposureCatalog(
331 coaddExposureHandles[tract], dataIds[tract]
333 warpedBox = computeWarpedBBox(catalog[0].wcs, bbox, wcs)
336 unwarped, count, included = self._merge(
337 maskedImages, warpedBox, catalog[0].wcs
343 "No valid pixels from coadd patches in tract %s; not including in output.",
347 warpedBox.clip(totalBox)
348 potentialInput = self.warper.warpExposure(
349 wcs, unwarped.subset(warpedBox), destBBox=bbox
355 potentialInput.mask.array
356 & potentialInput.mask.getPlaneBitMask(
"NO_DATA")
359 "No overlap from coadd patches in tract %s; not including in output.",
366 tempCatalog.reserve(len(included))
368 tempCatalog.append(catalog[i])
369 catalogs.append(tempCatalog)
370 warped[tract] = potentialInput.maskedImage
373 raise pipeBase.NoWorkFound(
"No patches found to overlap science exposure.")
375 template, count, _ = self._merge(warped, bbox, wcs)
377 raise pipeBase.NoWorkFound(
"No valid pixels in warped template.")
381 catalog.reserve(sum([len(c)
for c
in catalogs]))
386 self.checkHighVariance(template)
387 template.setPsf(self._makePsf(template, catalog, wcs))
389 template.setPhotoCalib(photoCalib)
390 return pipeBase.Struct(template=template)
393 """Set a mask plane for regions with unusually high variance.
397 template : `lsst.afw.image.Exposure`
398 The warped template exposure, which will be modified in place.
400 highVarianceMaskPlaneBit = template.mask.addMaskPlane(
"HIGH_VARIANCE")
401 template.mask.getPlaneBitMask(
"HIGH_VARIANCE")
402 varianceExposure = template.clone()
403 varianceExposure.image.array = varianceExposure.variance.array
404 varianceBackground = self.varianceBackground.run(varianceExposure).background.getImage().array
405 threshold = self.config.highVarianceThreshold*np.nanmedian(varianceBackground)
406 highVariancePix = varianceBackground > threshold
407 template.mask.array[highVariancePix] |= 2**highVarianceMaskPlaneBit
410 def _checkInputs(dataIds, coaddExposures):
411 """Check that the all the dataIds are from the same band and that
412 the exposures all have the same photometric calibration.
416 dataIds : `dict` [`int`, `list` [`lsst.daf.butler.DataCoordinate`]]
417 Record of the tract and patch of each coaddExposure.
418 coaddExposures : `dict` [`int`, `list` of \
419 [`lsst.daf.butler.DeferredDatasetHandle` of \
420 `lsst.afw.image.Exposure` or
421 `lsst.afw.image.Exposure`]]
422 Coadds to be mosaicked.
427 Filter band of all the input exposures.
428 photoCalib : `lsst.afw.image.PhotoCalib`
429 Photometric calibration of all of the input exposures.
434 Raised if the bands or calibrations of the input exposures are not
437 bands = set(dataId[
"band"]
for tract
in dataIds
for dataId
in dataIds[tract])
439 raise RuntimeError(f
"GetTemplateTask called with multiple bands: {bands}")
442 exposure.get(component=
"photoCalib")
443 for exposures
in coaddExposures.values()
444 for exposure
in exposures
446 if not all([photoCalibs[0] == x
for x
in photoCalibs]):
447 msg = f
"GetTemplateTask called with exposures with different photoCalibs: {photoCalibs}"
448 raise RuntimeError(msg)
449 photoCalib = photoCalibs[0]
450 return band, photoCalib
453 """Make an exposure catalog for one tract.
457 exposureRefs : `list` of [`lsst.daf.butler.DeferredDatasetHandle` of \
458 `lsst.afw.image.Exposure`]
459 Exposures to include in the catalog.
460 dataIds : `list` [`lsst.daf.butler.DataCoordinate`]
461 Data ids of each of the included exposures; must have "tract" and
466 images : `dict` [`lsst.afw.image.MaskedImage`]
467 MaskedImages of each of the input exposures, for warping.
468 catalog : `lsst.afw.table.ExposureCatalog`
469 Catalog of metadata for each exposure
470 totalBox : `lsst.geom.Box2I`
471 The union of the bounding boxes of all the input exposures.
474 catalog.reserve(len(exposureRefs))
475 exposures = (exposureRef.get()
for exposureRef
in exposureRefs)
479 for coadd, dataId
in zip(exposures, dataIds):
480 images[dataId] = coadd.maskedImage
481 bbox = coadd.getBBox()
482 totalBox = totalBox.expandedTo(bbox)
483 record = catalog.addNew()
484 record.setPsf(coadd.psf)
485 record.setWcs(coadd.wcs)
486 record.setPhotoCalib(coadd.photoCalib)
489 record.set(
"tract", dataId[
"tract"])
490 record.set(
"patch", dataId[
"patch"])
493 record.set(
"weight", 1)
495 return images, catalog, totalBox
497 def _merge(self, maskedImages, bbox, wcs):
498 """Merge the images that came from one tract into one larger image,
499 ignoring NaN pixels and non-finite variance pixels from individual
504 maskedImages : `dict` [`lsst.afw.image.MaskedImage` or
505 `lsst.afw.image.Exposure`]
506 Images to be merged into one larger bounding box.
507 bbox : `lsst.geom.Box2I`
508 Bounding box defining the image to merge into.
509 wcs : `lsst.afw.geom.SkyWcs`
510 WCS of all of the input images to set on the output image.
514 merged : `lsst.afw.image.MaskedImage`
515 Merged image with all of the inputs at their respective bbox
518 Count of the number of good pixels (those with positive weights)
520 included : `list` [`int`]
521 List of indexes of patches that were included in the merged
522 result, to be used to trim the exposure catalog.
524 merged = afwImage.ExposureF(bbox, wcs)
525 weights = afwImage.ImageF(bbox)
527 for i, (dataId, maskedImage)
in enumerate(maskedImages.items()):
529 clippedBox =
geom.Box2I(maskedImage.getBBox())
530 clippedBox.clip(bbox)
531 if clippedBox.area == 0:
532 self.log.debug(
"%s does not overlap template region.", dataId)
534 maskedImage = maskedImage.subset(clippedBox)
536 good = (maskedImage.variance.array > 0) & (
537 np.isfinite(maskedImage.variance.array)
539 weight = maskedImage.variance.array[good] ** (-0.5)
540 bad = np.isnan(maskedImage.image.array) | ~good
543 maskedImage.image.array[bad] = 0.0
544 maskedImage.variance.array[bad] = 0.0
546 maskedImage.mask.array[bad] = 0
550 maskedImage.image.array[good] *= weight
551 maskedImage.variance.array[good] *= weight
552 weights[clippedBox].array[good] += weight
555 merged.maskedImage[clippedBox] += maskedImage
558 good = weights.array > 0
563 weights = weights.array[good]
564 merged.image.array[good] /= weights
565 merged.variance.array[good] /= weights
567 merged.mask.array[~good] |= merged.mask.getPlaneBitMask(
"NO_DATA")
569 return merged, good.sum(), included
572 """Return a PSF containing the PSF at each of the input regions.
574 Note that although this includes all the exposures from the catalog,
575 the PSF knows which part of the template the inputs came from, so when
576 evaluated at a given position it will not include inputs that never
577 went in to those pixels.
581 template : `lsst.afw.image.Exposure`
582 Generated template the PSF is for.
583 catalog : `lsst.afw.table.ExposureCatalog`
584 Catalog of exposures that went into the template that contains all
586 wcs : `lsst.afw.geom.SkyWcs`
587 WCS of the template, to warp the PSFs to.
591 coaddPsf : `lsst.meas.algorithms.CoaddPsf`
592 The meta-psf constructed from all of the input catalogs.
596 boolmask = template.mask.array & template.mask.getPlaneBitMask(
"NO_DATA") == 0
598 centerCoord = afwGeom.SpanSet.fromMask(maskx, 1).computeCentroid()
600 ctrl = self.config.coaddPsf.makeControl()
602 catalog, wcs, centerCoord, ctrl.warpingKernelName, ctrl.cacheSize
608 GetTemplateConnections,
609 dimensions=(
"instrument",
"visit",
"detector",
"skymap"),
610 defaultTemplates={
"coaddName":
"dcr",
"warpTypeSuffix":
"",
"fakesType":
""},
612 visitInfo = pipeBase.connectionTypes.Input(
613 doc=
"VisitInfo of calexp used to determine observing conditions.",
614 name=
"{fakesType}calexp.visitInfo",
615 storageClass=
"VisitInfo",
616 dimensions=(
"instrument",
"visit",
"detector"),
618 dcrCoadds = pipeBase.connectionTypes.Input(
619 doc=
"Input DCR template to match and subtract from the exposure",
620 name=
"{fakesType}dcrCoadd{warpTypeSuffix}",
621 storageClass=
"ExposureF",
622 dimensions=(
"tract",
"patch",
"skymap",
"band",
"subfilter"),
627 def __init__(self, *, config=None):
628 super().__init__(config=config)
629 self.inputs.remove(
"coaddExposures")
632class GetDcrTemplateConfig(
633 GetTemplateConfig, pipelineConnections=GetDcrTemplateConnections
635 numSubfilters = pexConfig.Field(
636 doc=
"Number of subfilters in the DcrCoadd.",
640 effectiveWavelength = pexConfig.Field(
641 doc=
"Effective wavelength of the filter in nm.",
645 bandwidth = pexConfig.Field(
646 doc=
"Bandwidth of the physical filter.",
652 if self.effectiveWavelength
is None or self.bandwidth
is None:
654 "The effective wavelength and bandwidth of the physical filter "
655 "must be set in the getTemplate config for DCR coadds. "
656 "Required until transmission curves are used in DM-13668."
660class GetDcrTemplateTask(GetTemplateTask):
661 ConfigClass = GetDcrTemplateConfig
662 _DefaultName =
"getDcrTemplate"
664 def runQuantum(self, butlerQC, inputRefs, outputRefs):
665 inputs = butlerQC.get(inputRefs)
666 bbox = inputs.pop(
"bbox")
667 wcs = inputs.pop(
"wcs")
668 dcrCoaddExposureHandles = inputs.pop(
"dcrCoadds")
669 skymap = inputs.pop(
"skyMap")
670 visitInfo = inputs.pop(
"visitInfo")
673 assert not inputs,
"runQuantum got more inputs than expected"
675 results = self.getExposures(
676 dcrCoaddExposureHandles, bbox, skymap, wcs, visitInfo
678 physical_filter = butlerQC.quantum.dataId[
"physical_filter"]
680 coaddExposureHandles=results.coaddExposures,
683 dataIds=results.dataIds,
684 physical_filter=physical_filter,
686 butlerQC.put(outputs, outputRefs)
689 reason=
"Replaced by getExposures, which uses explicit arguments instead of a kwargs dict. "
690 "This method will be removed after v29.",
692 category=FutureWarning,
694 def getOverlappingExposures(self, inputs):
695 return self.getExposures(
703 def getExposures(self, dcrCoaddExposureHandles, bbox, skymap, wcs, visitInfo):
704 """Return lists of coadds and their corresponding dataIds that overlap
707 The spatial index in the registry has generous padding and often
708 supplies patches near, but not directly overlapping the detector.
709 Filters inputs so that we don't have to read in all input coadds.
713 dcrCoaddExposureHandles : `list` \
714 [`lsst.daf.butler.DeferredDatasetHandle` of \
715 `lsst.afw.image.Exposure`]
716 Data references to exposures that might overlap the detector.
717 bbox : `lsst.geom.Box2I`
718 Template Bounding box of the detector geometry onto which to
719 resample the coaddExposures.
720 skymap : `lsst.skymap.SkyMap`
721 Input definition of geometry/bbox and projection/wcs for
723 wcs : `lsst.afw.geom.SkyWcs`
724 Template WCS onto which to resample the coaddExposures.
725 visitInfo : `lsst.afw.image.VisitInfo`
726 Metadata for the science image.
730 result : `lsst.pipe.base.Struct`
731 A struct with attibutes:
734 Dict of coadd exposures that overlap the projected bbox,
736 (`dict` [`int`, `list` [`lsst.afw.image.Exposure`] ]).
738 Dict of data IDs of the coadd exposures that overlap the
739 projected bbox, indexed on tract id
740 (`dict` [`int`, `list [`lsst.daf.butler.DataCoordinate`] ]).
745 Raised if no patches overlatp the input detector bbox.
750 raise pipeBase.NoWorkFound(
"Exposure has no WCS; cannot create a template.")
754 dataIds = collections.defaultdict(list)
756 for coaddRef
in dcrCoaddExposureHandles:
757 dataId = coaddRef.dataId
758 subfilter = dataId[
"subfilter"]
759 patchWcs = skymap[dataId[
"tract"]].getWcs()
760 patchBBox = skymap[dataId[
"tract"]][dataId[
"patch"]].getOuterBBox()
761 patchCorners = patchWcs.pixelToSky(
geom.Box2D(patchBBox).getCorners())
763 if patchPolygon.intersection(detectorPolygon):
764 overlappingArea += patchPolygon.intersectionSingle(
768 "Using template input tract=%s, patch=%s, subfilter=%s"
769 % (dataId[
"tract"], dataId[
"patch"], dataId[
"subfilter"])
771 if dataId[
"tract"]
in patchList:
772 patchList[dataId[
"tract"]].append(dataId[
"patch"])
774 patchList[dataId[
"tract"]] = [
778 dataIds[dataId[
"tract"]].append(dataId)
780 if not overlappingArea:
781 raise pipeBase.NoWorkFound(
"No patches overlap detector")
783 self.checkPatchList(patchList)
785 coaddExposures = self.getDcrModel(patchList, dcrCoaddExposureHandles, visitInfo)
786 return pipeBase.Struct(coaddExposures=coaddExposures, dataIds=dataIds)
789 """Check that all of the DcrModel subfilters are present for each
795 Dict of the patches containing valid data for each tract.
800 If the number of exposures found for a patch does not match the
801 number of subfilters.
803 for tract
in patchList:
804 for patch
in set(patchList[tract]):
805 if patchList[tract].count(patch) != self.config.numSubfilters:
807 "Invalid number of DcrModel subfilters found: %d vs %d expected",
808 patchList[tract].count(patch),
809 self.config.numSubfilters,
813 """Build DCR-matched coadds from a list of exposure references.
818 Dict of the patches containing valid data for each tract.
819 coaddRefs : `list` [`lsst.daf.butler.DeferredDatasetHandle`]
820 Data references to `~lsst.afw.image.Exposure` representing
821 DcrModels that overlap the detector.
822 visitInfo : `lsst.afw.image.VisitInfo`
823 Metadata for the science image.
827 coaddExposures : `list` [`lsst.afw.image.Exposure`]
828 Coadd exposures that overlap the detector.
830 coaddExposures = collections.defaultdict(list)
831 for tract
in patchList:
832 for patch
in set(patchList[tract]):
835 for coaddRef
in coaddRefs
839 dcrModel = DcrModel.fromQuantum(
841 self.config.effectiveWavelength,
842 self.config.bandwidth,
843 self.config.numSubfilters,
845 coaddExposures[tract].append(dcrModel.buildMatchedExposureHandle(visitInfo=visitInfo))
846 return coaddExposures
850 condition = (coaddRef.dataId[
"tract"] == tract) & (
851 coaddRef.dataId[
"patch"] == patch
A group of labels for a filter in an exposure or coadd.
A floating-point coordinate rectangle geometry.
An integer coordinate rectangle.
CoaddPsf is the Psf derived to be used for non-PSF-matched Coadd images.
_selectDataRef(coaddRef, tract, patch)
checkPatchList(self, patchList)
_merge(self, maskedImages, bbox, wcs)
_makeExposureCatalog(self, exposureRefs, dataIds)
run(self, *, coaddExposureHandles, bbox, wcs, dataIds, physical_filter)
getDcrModel(self, patchList, coaddRefs, visitInfo)
checkHighVariance(self, template)
_makePsf(self, template, catalog, wcs)