def testRegularizeModelIter(self): """Test that large amplitude changes between iterations are restricted. This also tests that noise-like pixels are not regularized. """ modelClampFactor = 2. regularizationWidth = 2 subfilter = 0 dcrModels = DcrModel(modelImages=self.makeTestImages(), effectiveWavelength=self.effectiveWavelength, bandwidth=self.bandwidth) oldModel = dcrModels[0] xSize, ySize = self.bbox.getDimensions() newModel = oldModel.clone() newModel.array[:] += self.rng.rand(ySize, xSize) * np.max( oldModel.array) newModelRef = newModel.clone() dcrModels.regularizeModelIter(subfilter, newModel, self.bbox, modelClampFactor, regularizationWidth) # Make sure the test parameters do reduce the outliers self.assertGreater(np.max(newModelRef.array), np.max(newModel.array - oldModel.array)) # Check that all of the outliers are clipped highThreshold = oldModel.array * modelClampFactor highPix = newModel.array > highThreshold highPix = ndimage.morphology.binary_opening( highPix, iterations=regularizationWidth) self.assertFalse(np.all(highPix)) lowThreshold = oldModel.array / modelClampFactor lowPix = newModel.array < lowThreshold lowPix = ndimage.morphology.binary_opening( lowPix, iterations=regularizationWidth) self.assertFalse(np.all(lowPix))
def testRegularizationSidelobes(self): """Test that artificial chromatic sidelobes are suppressed. """ clampFrequency = 2. regularizationWidth = 2 noiseLevel = 0.1 sourceAmplitude = 100. modelImages = self.makeTestImages(seed=5, nSrc=5, psfSize=3., noiseLevel=noiseLevel, detectionSigma=5., sourceSigma=sourceAmplitude, fluxRange=2.) templateImage = np.mean([model.array for model in modelImages], axis=0) sidelobeImages = self.makeTestImages(seed=5, nSrc=5, psfSize=1.5, noiseLevel=noiseLevel/10., detectionSigma=5., sourceSigma=sourceAmplitude*5., fluxRange=2.) statsCtrl = self.prepareStats() signList = [-1., 0., 1.] sidelobeShift = (0., 4.) for model, sidelobe, sign in zip(modelImages, sidelobeImages, signList): sidelobe.array *= sign model.array += applyDcr(sidelobe.array, sidelobeShift, useInverse=False) model.array += applyDcr(sidelobe.array, sidelobeShift, useInverse=True) dcrModels = DcrModel(modelImages=modelImages, mask=self.mask) refModels = [dcrModels[subfilter].clone() for subfilter in range(self.dcrNumSubfilters)] dcrModels.regularizeModelFreq(modelImages, self.bbox, statsCtrl, clampFrequency, regularizationWidth=regularizationWidth) for model, refModel, sign in zip(modelImages, refModels, signList): # Make sure the test parameters do reduce the outliers self.assertGreater(np.sum(np.abs(refModel.array - templateImage)), np.sum(np.abs(model.array - templateImage)))
def testRegularizationSmallClamp(self): """Test that large variations between model planes are reduced. This also tests that noise-like pixels are not regularized. """ clampFrequency = 2 regularizationWidth = 2 fluxRange = 10. modelImages = self.makeTestImages(fluxRange=fluxRange) dcrModels = DcrModel(modelImages=modelImages, mask=self.mask, effectiveWavelength=self.effectiveWavelength, bandwidth=self.bandwidth) newModels = [model.clone() for model in dcrModels] templateImage = dcrModels.getReferenceImage(self.bbox) statsCtrl = self.prepareStats() dcrModels.regularizeModelFreq(newModels, self.bbox, statsCtrl, clampFrequency, regularizationWidth) for model, refModel in zip(newModels, dcrModels): # Make sure the test parameters do reduce the outliers self.assertGreater(np.max(refModel.array - templateImage), np.max(model.array - templateImage)) highThreshold = templateImage * clampFrequency highPix = model.array > highThreshold highPix = ndimage.morphology.binary_opening( highPix, iterations=regularizationWidth) self.assertFalse(np.all(highPix)) lowThreshold = templateImage / clampFrequency lowPix = model.array < lowThreshold lowPix = ndimage.morphology.binary_opening( lowPix, iterations=regularizationWidth) self.assertFalse(np.all(lowPix))
def testRegularizeModelIter(self): """Test that large amplitude changes between iterations are restricted. This also tests that noise-like pixels are not regularized. """ modelClampFactor = 2. regularizationWidth = 2 subfilter = 0 dcrModels = DcrModel(modelImages=self.makeTestImages()) oldModel = dcrModels[0] xSize, ySize = self.bbox.getDimensions() newModel = oldModel.clone() newModel.array[:] += self.rng.rand(ySize, xSize)*np.max(oldModel.array) newModelRef = newModel.clone() dcrModels.regularizeModelIter(subfilter, newModel, self.bbox, modelClampFactor, regularizationWidth) # Make sure the test parameters do reduce the outliers self.assertGreater(np.max(newModelRef.array), np.max(newModel.array - oldModel.array)) # Check that all of the outliers are clipped highThreshold = oldModel.array*modelClampFactor highPix = newModel.array > highThreshold highPix = ndimage.morphology.binary_opening(highPix, iterations=regularizationWidth) self.assertFalse(np.all(highPix)) lowThreshold = oldModel.array/modelClampFactor lowPix = newModel.array < lowThreshold lowPix = ndimage.morphology.binary_opening(lowPix, iterations=regularizationWidth) self.assertFalse(np.all(lowPix))
def testRegularizationSidelobes(self): """Test that artificial chromatic sidelobes are suppressed. """ clampFrequency = 2. regularizationWidth = 2 noiseLevel = 0.1 sourceAmplitude = 100. modelImages = self.makeTestImages(seed=5, nSrc=5, psfSize=3., noiseLevel=noiseLevel, detectionSigma=5., sourceSigma=sourceAmplitude, fluxRange=2.) templateImage = np.mean([model.array for model in modelImages], axis=0) sidelobeImages = self.makeTestImages(seed=5, nSrc=5, psfSize=1.5, noiseLevel=noiseLevel/10., detectionSigma=5., sourceSigma=sourceAmplitude*5., fluxRange=2.) statsCtrl = self.prepareStats() signList = [-1., 0., 1.] sidelobeShift = (0., 4.) for model, sidelobe, sign in zip(modelImages, sidelobeImages, signList): sidelobe.array *= sign model.array += applyDcr(sidelobe.array, sidelobeShift, useInverse=False) model.array += applyDcr(sidelobe.array, sidelobeShift, useInverse=True) dcrModels = DcrModel(modelImages=modelImages, mask=self.mask) refModels = [dcrModels[subfilter].clone() for subfilter in range(self.dcrNumSubfilters)] dcrModels.regularizeModelFreq(modelImages, self.bbox, statsCtrl, clampFrequency, regularizationWidth=regularizationWidth) for model, refModel, sign in zip(modelImages, refModels, signList): # Make sure the test parameters do reduce the outliers self.assertGreater(np.sum(np.abs(refModel.array - templateImage)), np.sum(np.abs(model.array - templateImage)))
def testRegularizationSmallClamp(self): """Test that large variations between model planes are reduced. This also tests that noise-like pixels are not regularized. """ clampFrequency = 2 regularizationWidth = 2 fluxRange = 10. modelImages = self.makeTestImages(fluxRange=fluxRange) dcrModels = DcrModel(modelImages=modelImages, mask=self.mask) newModels = [model.clone() for model in dcrModels] templateImage = dcrModels.getReferenceImage(self.bbox) statsCtrl = self.prepareStats() dcrModels.regularizeModelFreq(newModels, self.bbox, statsCtrl, clampFrequency, regularizationWidth) for model, refModel in zip(newModels, dcrModels): # Make sure the test parameters do reduce the outliers self.assertGreater(np.max(refModel.array - templateImage), np.max(model.array - templateImage)) highThreshold = templateImage*clampFrequency highPix = model.array > highThreshold highPix = ndimage.morphology.binary_opening(highPix, iterations=regularizationWidth) self.assertFalse(np.all(highPix)) lowThreshold = templateImage/clampFrequency lowPix = model.array < lowThreshold lowPix = ndimage.morphology.binary_opening(lowPix, iterations=regularizationWidth) self.assertFalse(np.all(lowPix))
def testConditionDcrModelNoChangeHighGain(self): """Conditioning should not change the model if it equals the reference. """ modelImages = self.makeTestImages() dcrModels = DcrModel(modelImages=modelImages, mask=self.mask) newModels = [model.clone() for model in dcrModels] dcrModels.conditionDcrModel(newModels, self.bbox, gain=3.) for refModel, newModel in zip(dcrModels, newModels): self.assertFloatsAlmostEqual(refModel.array, newModel.array)
def testConditionDcrModelNoChangeHighGain(self): """Conditioning should not change the model if it equals the reference. """ modelImages = self.makeTestImages() dcrModels = DcrModel(modelImages=modelImages, mask=self.mask) newModels = [model.clone() for model in dcrModels] dcrModels.conditionDcrModel(newModels, self.bbox, gain=3.) for refModel, newModel in zip(dcrModels, newModels): self.assertFloatsAlmostEqual(refModel.array, newModel.array)
def testConditionDcrModelNoChange(self): """Conditioning should not change the model if it equals the reference. """ modelImages = self.makeTestImages() dcrModels = DcrModel(modelImages=modelImages, mask=self.mask, effectiveWavelength=self.effectiveWavelength, bandwidth=self.bandwidth) newModels = [model.clone() for model in dcrModels] dcrModels.conditionDcrModel(newModels, self.bbox, gain=1.) for refModel, newModel in zip(dcrModels, newModels): self.assertFloatsAlmostEqual(refModel.array, newModel.array)
def testConditionDcrModelWithChange(self): """Verify conditioning when the model changes by a known amount. """ modelImages = self.makeTestImages() dcrModels = DcrModel(modelImages=modelImages, mask=self.mask) newModels = [model.clone() for model in dcrModels] for model in newModels: model.array[:] *= 3. dcrModels.conditionDcrModel(newModels, self.bbox, gain=1.) for refModel, newModel in zip(dcrModels, newModels): refModel.array[:] *= 2. self.assertFloatsAlmostEqual(refModel.array, newModel.array)
def testConditionDcrModelWithChange(self): """Verify conditioning when the model changes by a known amount. """ modelImages = self.makeTestImages() dcrModels = DcrModel(modelImages=modelImages, mask=self.mask) newModels = [model.clone() for model in dcrModels] for model in newModels: model.array[:] *= 3. dcrModels.conditionDcrModel(newModels, self.bbox, gain=1.) for refModel, newModel in zip(dcrModels, newModels): refModel.array[:] *= 2. self.assertFloatsAlmostEqual(refModel.array, newModel.array)
def getDcrModel(self, patchList, coaddRefs, visitInfo): """Build DCR-matched coadds from a list of exposure references. Parameters ---------- patchList : `dict` Dict of the patches containing valid data for each tract coaddRefs : `list` of elements of type `lsst.daf.butler.DeferredDatasetHandle` of `lsst.afw.image.Exposure` Data references to DcrModels that overlap the detector. visitInfo : `lsst.afw.image.VisitInfo` Metadata for the science image. Returns ------- `list` of elements of type `lsst.afw.image.Exposure` Coadd exposures that overlap the detector. """ coaddExposureList = [] for tract in patchList: for patch in set(patchList[tract]): coaddRefList = [ coaddRef for coaddRef in coaddRefs if _selectDataRef(coaddRef, tract, patch) ] dcrModel = DcrModel.fromQuantum( coaddRefList, self.config.effectiveWavelength, self.config.bandwidth, self.config.numSubfilters) coaddExposureList.append( dcrModel.buildMatchedExposure(visitInfo=visitInfo)) return coaddExposureList
def testIterateModel(self): """Test that the DcrModel is iterable, and has the right values. """ testModels = self.makeTestImages() refVals = [np.sum(model.array) for model in testModels] dcrModels = DcrModel(modelImages=testModels) for refVal, model in zip(refVals, dcrModels): self.assertFloatsEqual(refVal, np.sum(model.array)) # Negative indices are allowed, so check that those return models from the end. self.assertFloatsEqual(refVals[-1], np.sum(dcrModels[-1].array))
def run(self, exposure, sensorRef, templateIdList=None): """Retrieve and mosaic a template coadd exposure that overlaps the exposure Parameters ---------- exposure: `lsst.afw.image.Exposure` an exposure for which to generate an overlapping template sensorRef : TYPE a Butler data reference that can be used to obtain coadd data templateIdList : TYPE, optional list of data ids (unused) Returns ------- result : `struct` return a pipeBase.Struct: - ``exposure`` : a template coadd exposure assembled out of patches - ``sources`` : None for this subtask """ skyMap = sensorRef.get(datasetType=self.config.coaddName + "Coadd_skyMap") expWcs = exposure.getWcs() expBoxD = afwGeom.Box2D(exposure.getBBox()) expBoxD.grow(self.config.templateBorderSize) ctrSkyPos = expWcs.pixelToSky(expBoxD.getCenter()) tractInfo = skyMap.findTract(ctrSkyPos) self.log.info("Using skyMap tract %s" % (tractInfo.getId(),)) skyCorners = [expWcs.pixelToSky(pixPos) for pixPos in expBoxD.getCorners()] patchList = tractInfo.findPatchList(skyCorners) if not patchList: raise RuntimeError("No suitable tract found") self.log.info("Assembling %s coadd patches" % (len(patchList),)) # compute coadd bbox coaddWcs = tractInfo.getWcs() coaddBBox = afwGeom.Box2D() for skyPos in skyCorners: coaddBBox.include(coaddWcs.skyToPixel(skyPos)) coaddBBox = afwGeom.Box2I(coaddBBox) self.log.info("exposure dimensions=%s; coadd dimensions=%s" % (exposure.getDimensions(), coaddBBox.getDimensions())) # assemble coadd exposure from subregions of patches coaddExposure = afwImage.ExposureF(coaddBBox, coaddWcs) coaddExposure.maskedImage.set(np.nan, afwImage.Mask.getPlaneBitMask("NO_DATA"), np.nan) nPatchesFound = 0 coaddFilter = None coaddPsf = None for patchInfo in patchList: patchSubBBox = patchInfo.getOuterBBox() patchSubBBox.clip(coaddBBox) patchArgDict = dict( datasetType=self.getCoaddDatasetName() + "_sub", bbox=patchSubBBox, tract=tractInfo.getId(), patch="%s,%s" % (patchInfo.getIndex()[0], patchInfo.getIndex()[1]), numSubfilters=self.config.numSubfilters, ) if patchSubBBox.isEmpty(): self.log.info("skip tract=%(tract)s, patch=%(patch)s; no overlapping pixels" % patchArgDict) continue if self.config.coaddName == 'dcr': if not sensorRef.datasetExists(subfilter=0, **patchArgDict): self.log.warn("%(datasetType)s, tract=%(tract)s, patch=%(patch)s," " numSubfilters=%(numSubfilters)s, subfilter=0 does not exist" % patchArgDict) continue self.log.info("Constructing DCR-matched template for patch %s" % patchArgDict) dcrModel = DcrModel.fromDataRef(sensorRef, **patchArgDict) coaddPatch = dcrModel.buildMatchedExposure(bbox=patchSubBBox, wcs=coaddWcs, visitInfo=exposure.getInfo().getVisitInfo()) else: if not sensorRef.datasetExists(**patchArgDict): self.log.warn("%(datasetType)s, tract=%(tract)s, patch=%(patch)s does not exist" % patchArgDict) continue self.log.info("Reading patch %s" % patchArgDict) coaddPatch = sensorRef.get(**patchArgDict) nPatchesFound += 1 coaddExposure.maskedImage.assign(coaddPatch.maskedImage, coaddPatch.getBBox()) if coaddFilter is None: coaddFilter = coaddPatch.getFilter() # Retrieve the PSF for this coadd tract, if not already retrieved if coaddPsf is None and coaddPatch.hasPsf(): coaddPsf = coaddPatch.getPsf() if nPatchesFound == 0: raise RuntimeError("No patches found!") if coaddPsf is None: raise RuntimeError("No coadd Psf found!") coaddExposure.setPsf(coaddPsf) coaddExposure.setFilter(coaddFilter) return pipeBase.Struct(exposure=coaddExposure, sources=None)
def run(self, tractInfo, patchList, skyCorners, availableCoaddRefs, sensorRef=None, visitInfo=None): """Gen2 and gen3 shared code: determination of exposure dimensions and copying of pixels from overlapping patch regions. Parameters ---------- skyMap : `lsst.skymap.BaseSkyMap` SkyMap object that corresponds to the template coadd. tractInfo : `lsst.skymap.TractInfo` The selected tract. patchList : iterable of `lsst.skymap.patchInfo.PatchInfo` Patches to consider for making the template exposure. skyCorners : list of `lsst.geom.SpherePoint` Sky corner coordinates to be covered by the template exposure. availableCoaddRefs : `dict` [`int`] Dictionary of spatially relevant retrieved coadd patches, indexed by their sequential patch number. In Gen3 mode, values are `lsst.daf.butler.DeferredDatasetHandle` and ``.get()`` is called, in Gen2 mode, ``sensorRef.get(**coaddef)`` is called to retrieve the coadd. sensorRef : `lsst.daf.persistence.ButlerDataRef`, Gen2 only Butler data reference to get coadd data. Must be `None` for Gen3. visitInfo : `lsst.afw.image.VisitInfo`, Gen2 only VisitInfo to make dcr model. Returns ------- templateExposure: `lsst.afw.image.ExposureF` The created template exposure. """ coaddWcs = tractInfo.getWcs() # compute coadd bbox coaddBBox = geom.Box2D() for skyPos in skyCorners: coaddBBox.include(coaddWcs.skyToPixel(skyPos)) coaddBBox = geom.Box2I(coaddBBox) self.log.info("coadd dimensions=%s", coaddBBox.getDimensions()) coaddExposure = afwImage.ExposureF(coaddBBox, coaddWcs) coaddExposure.maskedImage.set(np.nan, afwImage.Mask.getPlaneBitMask("NO_DATA"), np.nan) nPatchesFound = 0 coaddFilterLabel = None coaddPsf = None coaddPhotoCalib = None for patchInfo in patchList: patchNumber = tractInfo.getSequentialPatchIndex(patchInfo) patchSubBBox = patchInfo.getOuterBBox() patchSubBBox.clip(coaddBBox) if patchNumber not in availableCoaddRefs: self.log.warning( "skip patch=%d; patch does not exist for this coadd", patchNumber) continue if patchSubBBox.isEmpty(): if isinstance(availableCoaddRefs[patchNumber], DeferredDatasetHandle): tract = availableCoaddRefs[patchNumber].dataId['tract'] else: tract = availableCoaddRefs[patchNumber]['tract'] self.log.info("skip tract=%d patch=%d; no overlapping pixels", tract, patchNumber) continue if self.config.coaddName == 'dcr': patchInnerBBox = patchInfo.getInnerBBox() patchInnerBBox.clip(coaddBBox) if np.min(patchInnerBBox.getDimensions() ) <= 2 * self.config.templateBorderSize: self.log.info( "skip tract=%(tract)s, patch=%(patch)s; too few pixels.", availableCoaddRefs[patchNumber]) continue self.log.info("Constructing DCR-matched template for patch %s", availableCoaddRefs[patchNumber]) dcrModel = DcrModel.fromQuantum( availableCoaddRefs[patchNumber], self.config.effectiveWavelength, self.config.bandwidth) # The edge pixels of the DcrCoadd may contain artifacts due to missing data. # Each patch has significant overlap, and the contaminated edge pixels in # a new patch will overwrite good pixels in the overlap region from # previous patches. # Shrink the BBox to remove the contaminated pixels, # but make sure it is only the overlap region that is reduced. dcrBBox = geom.Box2I(patchSubBBox) dcrBBox.grow(-self.config.templateBorderSize) dcrBBox.include(patchInnerBBox) coaddPatch = dcrModel.buildMatchedExposure(bbox=dcrBBox, visitInfo=visitInfo) else: if sensorRef is None: # Gen3 coaddPatch = availableCoaddRefs[patchNumber].get() else: # Gen2 coaddPatch = sensorRef.get( **availableCoaddRefs[patchNumber]) nPatchesFound += 1 # Gen2 get() seems to clip based on bbox kwarg but we removed bbox # calculation from caller code. Gen3 also does not do this. overlapBox = coaddPatch.getBBox() overlapBox.clip(coaddBBox) coaddExposure.maskedImage.assign( coaddPatch.maskedImage[overlapBox], overlapBox) if coaddFilterLabel is None: coaddFilterLabel = coaddPatch.getFilter() # Retrieve the PSF for this coadd tract, if not already retrieved if coaddPsf is None and coaddPatch.hasPsf(): coaddPsf = coaddPatch.getPsf() # Retrieve the calibration for this coadd tract, if not already retrieved if coaddPhotoCalib is None: coaddPhotoCalib = coaddPatch.getPhotoCalib() if coaddPhotoCalib is None: raise RuntimeError("No coadd PhotoCalib found!") if nPatchesFound == 0: raise RuntimeError("No patches found!") if coaddPsf is None: raise RuntimeError("No coadd Psf found!") coaddExposure.setPhotoCalib(coaddPhotoCalib) coaddExposure.setPsf(coaddPsf) coaddExposure.setFilter(coaddFilterLabel) return coaddExposure
def run(self, exposure, sensorRef, templateIdList=None): """Retrieve and mosaic a template coadd exposure that overlaps the exposure Parameters ---------- exposure: `lsst.afw.image.Exposure` an exposure for which to generate an overlapping template sensorRef : TYPE a Butler data reference that can be used to obtain coadd data templateIdList : TYPE, optional list of data ids (unused) Returns ------- result : `struct` return a pipeBase.Struct: - ``exposure`` : a template coadd exposure assembled out of patches - ``sources`` : None for this subtask """ skyMap = sensorRef.get(datasetType=self.config.coaddName + "Coadd_skyMap") expWcs = exposure.getWcs() expBoxD = afwGeom.Box2D(exposure.getBBox()) expBoxD.grow(self.config.templateBorderSize) ctrSkyPos = expWcs.pixelToSky(expBoxD.getCenter()) tractInfo = skyMap.findTract(ctrSkyPos) self.log.info("Using skyMap tract %s" % (tractInfo.getId(),)) skyCorners = [expWcs.pixelToSky(pixPos) for pixPos in expBoxD.getCorners()] patchList = tractInfo.findPatchList(skyCorners) if not patchList: raise RuntimeError("No suitable tract found") self.log.info("Assembling %s coadd patches" % (len(patchList),)) # compute coadd bbox coaddWcs = tractInfo.getWcs() coaddBBox = afwGeom.Box2D() for skyPos in skyCorners: coaddBBox.include(coaddWcs.skyToPixel(skyPos)) coaddBBox = afwGeom.Box2I(coaddBBox) self.log.info("exposure dimensions=%s; coadd dimensions=%s" % (exposure.getDimensions(), coaddBBox.getDimensions())) # assemble coadd exposure from subregions of patches coaddExposure = afwImage.ExposureF(coaddBBox, coaddWcs) coaddExposure.maskedImage.set(np.nan, afwImage.Mask.getPlaneBitMask("NO_DATA"), np.nan) nPatchesFound = 0 coaddFilter = None coaddPsf = None for patchInfo in patchList: patchSubBBox = patchInfo.getOuterBBox() patchSubBBox.clip(coaddBBox) patchArgDict = dict( datasetType=self.getCoaddDatasetName() + "_sub", bbox=patchSubBBox, tract=tractInfo.getId(), patch="%s,%s" % (patchInfo.getIndex()[0], patchInfo.getIndex()[1]), numSubfilters=self.config.numSubfilters, ) if patchSubBBox.isEmpty(): self.log.info("skip tract=%(tract)s, patch=%(patch)s; no overlapping pixels" % patchArgDict) continue if self.config.coaddName == 'dcr': if not sensorRef.datasetExists(subfilter=0, **patchArgDict): self.log.warn("%(datasetType)s, tract=%(tract)s, patch=%(patch)s," " numSubfilters=%(numSubfilters)s, subfilter=0 does not exist" % patchArgDict) continue self.log.info("Constructing DCR-matched template for patch %s" % patchArgDict) dcrModel = DcrModel.fromDataRef(sensorRef, **patchArgDict) # The edge pixels of the DcrCoadd may contain artifacts due to missing data. # Each patch has significant overlap, and the contaminated edge pixels in # a new patch will overwrite good pixels in the overlap region from # previous patches. # Shrink the BBox to remove the contaminated pixels, # but make sure it is only the overlap region that is reduced. patchInnerBBox = patchInfo.getInnerBBox() patchInnerBBox.clip(coaddBBox) dcrBBox = afwGeom.Box2I(patchSubBBox) dcrBBox.grow(-self.config.templateBorderSize) dcrBBox.include(patchInnerBBox) coaddPatch = dcrModel.buildMatchedExposure(bbox=dcrBBox, wcs=coaddWcs, visitInfo=exposure.getInfo().getVisitInfo()) else: if not sensorRef.datasetExists(**patchArgDict): self.log.warn("%(datasetType)s, tract=%(tract)s, patch=%(patch)s does not exist" % patchArgDict) continue self.log.info("Reading patch %s" % patchArgDict) coaddPatch = sensorRef.get(**patchArgDict) nPatchesFound += 1 coaddExposure.maskedImage.assign(coaddPatch.maskedImage, coaddPatch.getBBox()) if coaddFilter is None: coaddFilter = coaddPatch.getFilter() # Retrieve the PSF for this coadd tract, if not already retrieved if coaddPsf is None and coaddPatch.hasPsf(): coaddPsf = coaddPatch.getPsf() if nPatchesFound == 0: raise RuntimeError("No patches found!") if coaddPsf is None: raise RuntimeError("No coadd Psf found!") coaddExposure.setPsf(coaddPsf) coaddExposure.setFilter(coaddFilter) return pipeBase.Struct(exposure=coaddExposure, sources=None)