From de965df890bd5e35c374e343a0494ff189206cfa Mon Sep 17 00:00:00 2001 From: Audrey Budlong Date: Wed, 22 Jan 2025 22:06:57 -0800 Subject: [PATCH 1/4] Update documentation --- python/lsst/ip/diffim/getTemplate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/lsst/ip/diffim/getTemplate.py b/python/lsst/ip/diffim/getTemplate.py index 42c86c869..bad78327d 100644 --- a/python/lsst/ip/diffim/getTemplate.py +++ b/python/lsst/ip/diffim/getTemplate.py @@ -492,7 +492,7 @@ class GetDcrTemplateConfig(GetTemplateConfig, default=3, ) effectiveWavelength = pexConfig.Field( - doc="Effective wavelength of the filter.", + doc="Effective wavelength of the filter in nm.", optional=False, dtype=float, ) From e89d6c8402dde7bcecb31b73fd890ca0bea35513 Mon Sep 17 00:00:00 2001 From: Audrey Budlong Date: Thu, 6 Feb 2025 18:40:32 -0800 Subject: [PATCH 2/4] Update getDcrTemplate task --- python/lsst/ip/diffim/getTemplate.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/python/lsst/ip/diffim/getTemplate.py b/python/lsst/ip/diffim/getTemplate.py index bad78327d..39206d9c8 100644 --- a/python/lsst/ip/diffim/getTemplate.py +++ b/python/lsst/ip/diffim/getTemplate.py @@ -558,17 +558,21 @@ def getOverlappingExposures(self, inputs): """ # Check that the patches actually overlap the detector # Exposure's validPolygon would be more accurate + if (wcs := inputs['wcs']) is None: + raise pipeBase.NoWorkFound("Exposure has no WCS; cannot create a template.") + detectorPolygon = geom.Box2D(inputs["bbox"]) overlappingArea = 0 coaddExposureRefList = [] - dataIds = [] + dataIds = collections.defaultdict(list) patchList = dict() + skymap = inputs['skyMap'] for coaddRef in inputs["dcrCoadds"]: dataId = coaddRef.dataId - patchWcs = inputs["skyMap"][dataId['tract']].getWcs() - patchBBox = inputs["skyMap"][dataId['tract']][dataId['patch']].getOuterBBox() + patchWcs = skymap[dataId['tract']].getWcs() + patchBBox = skymap[dataId['tract']][dataId['patch']].getOuterBBox() patchCorners = patchWcs.pixelToSky(geom.Box2D(patchBBox).getCorners()) - patchPolygon = afwGeom.Polygon(inputs["wcs"].skyToPixel(patchCorners)) + patchPolygon = afwGeom.Polygon(wcs.skyToPixel(patchCorners)) if patchPolygon.intersection(detectorPolygon): overlappingArea += patchPolygon.intersectionSingle(detectorPolygon).calculateArea() self.log.info("Using template input tract=%s, patch=%s, subfilter=%s" % @@ -578,14 +582,21 @@ def getOverlappingExposures(self, inputs): patchList[dataId['tract']].append(dataId['patch']) else: patchList[dataId['tract']] = [dataId['patch'], ] - dataIds.append(dataId) + dataIds[dataId['tract']].append(dataId) if not overlappingArea: raise pipeBase.NoWorkFound('No patches overlap detector') self.checkPatchList(patchList) - coaddExposures = self.getDcrModel(patchList, inputs['dcrCoadds'], inputs['visitInfo']) + # coaddExposures = self.getDcrModel(patchList, inputs['dcrCoadds'], inputs['visitInfo']) + coaddExposures = dict() + for dataId['tract'] in patchList: + coaddExposures[dataId['tract']].append(self.getDcrModel(dataId['patch'], + inputs['dcrCoadds'], + inputs['visitInfo'])) + del inputs['visitInfo'] + del inputs['dcrCoadds'] return pipeBase.Struct(coaddExposures=coaddExposures, dataIds=dataIds) From 8efdef7307d666a26478ddea7a1acb5a80fca3f8 Mon Sep 17 00:00:00 2001 From: Ian Sullivan Date: Sat, 8 Feb 2025 16:23:11 -0800 Subject: [PATCH 3/4] Return DcrCoadds as a dict per tract and patch --- python/lsst/ip/diffim/getTemplate.py | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/python/lsst/ip/diffim/getTemplate.py b/python/lsst/ip/diffim/getTemplate.py index 39206d9c8..a22a78121 100644 --- a/python/lsst/ip/diffim/getTemplate.py +++ b/python/lsst/ip/diffim/getTemplate.py @@ -545,11 +545,13 @@ def getOverlappingExposures(self, inputs): A struct with attibutes: ``coaddExposures`` - Coadd exposures that overlap the detector (`list` - [`lsst.afw.image.Exposure`]). + Dict of coadd exposures that overlap the projected bbox, + indexed on tract id + (`dict` [`int`, `list` [`lsst.afw.image.Exposure`] ]). ``dataIds`` - Data IDs of the coadd exposures that overlap the detector - (`list` [`lsst.daf.butler.DataCoordinate`]). + Dict of data IDs of the coadd exposures that overlap the + projected bbox, indexed on tract id + (`dict` [`int`, `list [`lsst.daf.butler.DataCoordinate`] ]). Raises ------ @@ -563,7 +565,6 @@ def getOverlappingExposures(self, inputs): detectorPolygon = geom.Box2D(inputs["bbox"]) overlappingArea = 0 - coaddExposureRefList = [] dataIds = collections.defaultdict(list) patchList = dict() skymap = inputs['skyMap'] @@ -577,7 +578,6 @@ def getOverlappingExposures(self, inputs): overlappingArea += patchPolygon.intersectionSingle(detectorPolygon).calculateArea() self.log.info("Using template input tract=%s, patch=%s, subfilter=%s" % (dataId['tract'], dataId['patch'], dataId["subfilter"])) - coaddExposureRefList.append(coaddRef) if dataId['tract'] in patchList: patchList[dataId['tract']].append(dataId['patch']) else: @@ -589,12 +589,7 @@ def getOverlappingExposures(self, inputs): self.checkPatchList(patchList) - # coaddExposures = self.getDcrModel(patchList, inputs['dcrCoadds'], inputs['visitInfo']) - coaddExposures = dict() - for dataId['tract'] in patchList: - coaddExposures[dataId['tract']].append(self.getDcrModel(dataId['patch'], - inputs['dcrCoadds'], - inputs['visitInfo'])) + coaddExposures = self.getDcrModel(patchList, inputs['dcrCoadds'], inputs['visitInfo']) del inputs['visitInfo'] del inputs['dcrCoadds'] return pipeBase.Struct(coaddExposures=coaddExposures, @@ -639,7 +634,7 @@ def getDcrModel(self, patchList, coaddRefs, visitInfo): coaddExposures : `list` [`lsst.afw.image.Exposure`] Coadd exposures that overlap the detector. """ - coaddExposures = [] + coaddExposures = collections.defaultdict(list) for tract in patchList: for patch in set(patchList[tract]): coaddRefList = [coaddRef for coaddRef in coaddRefs @@ -649,7 +644,7 @@ def getDcrModel(self, patchList, coaddRefs, visitInfo): self.config.effectiveWavelength, self.config.bandwidth, self.config.numSubfilters) - coaddExposures.append(dcrModel.buildMatchedExposure(visitInfo=visitInfo)) + coaddExposures[tract].append(dcrModel.buildMatchedExposure(visitInfo=visitInfo)) return coaddExposures From 4b39a9666bae981a4ff2e5b8fc73bf903e2c7534 Mon Sep 17 00:00:00 2001 From: Audrey Budlong Date: Mon, 24 Feb 2025 19:43:56 -0800 Subject: [PATCH 4/4] Refactor GetDcrTemplateTask to use new interface --- python/lsst/ip/diffim/getTemplate.py | 68 +++++++++++++++++++--------- 1 file changed, 47 insertions(+), 21 deletions(-) diff --git a/python/lsst/ip/diffim/getTemplate.py b/python/lsst/ip/diffim/getTemplate.py index a22a78121..04e9d5ce6 100644 --- a/python/lsst/ip/diffim/getTemplate.py +++ b/python/lsst/ip/diffim/getTemplate.py @@ -513,7 +513,37 @@ class GetDcrTemplateTask(GetTemplateTask): ConfigClass = GetDcrTemplateConfig _DefaultName = "getDcrTemplate" + def runQuantum(self, butlerQC, inputRefs, outputRefs): + inputs = butlerQC.get(inputRefs) + bbox = inputs.pop("bbox") + wcs = inputs.pop("wcs") + dcrCoaddExposureHandles = inputs.pop('dcrCoadds') + skymap = inputs.pop("skyMap") + visitInfo = inputs.pop("visitInfo") + + # This should not happen with a properly configured execution context. + assert not inputs, "runQuantum got more inputs than expected" + + results = self.getExposures(dcrCoaddExposureHandles, bbox, skymap, wcs, visitInfo) + physical_filter = butlerQC.quantum.dataId["physical_filter"] + outputs = self.run(coaddExposures=results.coaddExposures, + bbox=bbox, + wcs=wcs, + dataIds=results.dataIds, + physical_filter=physical_filter) + butlerQC.put(outputs, outputRefs) + + @deprecated(reason="Replaced by getExposures, which uses explicit arguments instead of a kwargs dict. " + "This method will be removed after v29.", + version="v29.0", category=FutureWarning) def getOverlappingExposures(self, inputs): + return self.getExposures(inputs["dcrCoadds"], + inputs["bbox"], + inputs["skyMap"], + inputs["wcs"], + inputs["visitInfo"]) + + def getExposures(self, dcrCoaddExposureHandles, bbox, skymap, wcs, visitInfo): """Return lists of coadds and their corresponding dataIds that overlap the detector. @@ -523,21 +553,20 @@ def getOverlappingExposures(self, inputs): Parameters ---------- - inputs : `dict` of task Inputs, containing: - - coaddExposureRefs : `list` \ + dcrCoaddExposureHandles : `list` \ [`lsst.daf.butler.DeferredDatasetHandle` of \ `lsst.afw.image.Exposure`] - Data references to exposures that might overlap the detector. - - bbox : `lsst.geom.Box2I` - Template Bounding box of the detector geometry onto which to - resample the coaddExposures. - - skyMap : `lsst.skymap.SkyMap` - Input definition of geometry/bbox and projection/wcs for - template exposures. - - wcs : `lsst.afw.geom.SkyWcs` - Template WCS onto which to resample the coaddExposures. - - visitInfo : `lsst.afw.image.VisitInfo` - Metadata for the science image. + Data references to exposures that might overlap the detector. + bbox : `lsst.geom.Box2I` + Template Bounding box of the detector geometry onto which to + resample the coaddExposures. + skymap : `lsst.skymap.SkyMap` + Input definition of geometry/bbox and projection/wcs for + template exposures. + wcs : `lsst.afw.geom.SkyWcs` + Template WCS onto which to resample the coaddExposures. + visitInfo : `lsst.afw.image.VisitInfo` + Metadata for the science image. Returns ------- @@ -555,20 +584,19 @@ def getOverlappingExposures(self, inputs): Raises ------ - NoWorkFound + pipeBase.NoWorkFound Raised if no patches overlatp the input detector bbox. """ # Check that the patches actually overlap the detector # Exposure's validPolygon would be more accurate - if (wcs := inputs['wcs']) is None: + if wcs is None: raise pipeBase.NoWorkFound("Exposure has no WCS; cannot create a template.") - detectorPolygon = geom.Box2D(inputs["bbox"]) + detectorPolygon = geom.Box2D(bbox) overlappingArea = 0 dataIds = collections.defaultdict(list) patchList = dict() - skymap = inputs['skyMap'] - for coaddRef in inputs["dcrCoadds"]: + for coaddRef in dcrCoaddExposureHandles: dataId = coaddRef.dataId patchWcs = skymap[dataId['tract']].getWcs() patchBBox = skymap[dataId['tract']][dataId['patch']].getOuterBBox() @@ -589,9 +617,7 @@ def getOverlappingExposures(self, inputs): self.checkPatchList(patchList) - coaddExposures = self.getDcrModel(patchList, inputs['dcrCoadds'], inputs['visitInfo']) - del inputs['visitInfo'] - del inputs['dcrCoadds'] + coaddExposures = self.getDcrModel(patchList, dcrCoaddExposureHandles, visitInfo) return pipeBase.Struct(coaddExposures=coaddExposures, dataIds=dataIds)