1 from __future__
import division, absolute_import
31 from .coaddBase
import CoaddBaseTask
32 from .warpAndPsfMatch
import WarpAndPsfMatchTask
33 from .coaddHelpers
import groupPatchExposures, getGroupDataRef
35 __all__ = [
"MakeCoaddTempExpTask"]
39 """Config for MakeCoaddTempExpTask
41 warpAndPsfMatch = pexConfig.ConfigurableField(
42 target=WarpAndPsfMatchTask,
43 doc=
"Task to warp and PSF-match calexp",
45 doWrite = pexConfig.Field(
46 doc=
"persist <coaddName>Coadd_tempExp",
50 doOverwrite = pexConfig.Field(
51 doc=
"overwrite <coaddName>Coadd_tempExp; If False, continue if the file exists on disk",
55 bgSubtracted = pexConfig.Field(
56 doc=
"Work with a background subtracted calexp?",
63 """Task to produce <coaddName>Coadd_tempExp images
65 ConfigClass = MakeCoaddTempExpConfig
66 _DefaultName =
"makeCoaddTempExp"
69 CoaddBaseTask.__init__(self, *args, **kwargs)
70 self.makeSubtask(
"warpAndPsfMatch")
73 def run(self, patchRef, selectDataList=[]):
74 """Produce <coaddName>Coadd_tempExp images
76 <coaddName>Coadd_tempExp are produced by PSF-matching (optional) and warping.
78 @param[in] patchRef: data reference for sky map patch. Must include keys "tract", "patch",
79 plus the camera-specific filter key (e.g. "filter" or "band")
80 @return: dataRefList: a list of data references for the new <coaddName>Coadd_tempExp
82 @warning: this task assumes that all exposures in a coaddTempExp have the same filter.
84 @warning: this task sets the Calib of the coaddTempExp to the Calib of the first calexp
85 with any good pixels in the patch. For a mosaic camera the resulting Calib should be ignored
86 (assembleCoadd should determine zeropoint scaling without referring to it).
88 skyInfo = self.getSkyInfo(patchRef)
90 calExpRefList = self.selectExposures(patchRef, skyInfo, selectDataList=selectDataList)
91 if len(calExpRefList) == 0:
92 self.log.warn(
"No exposures to coadd for patch %s", patchRef.dataId)
94 self.log.info(
"Selected %d calexps for patch %s", len(calExpRefList), patchRef.dataId)
95 calExpRefList = [calExpRef
for calExpRef
in calExpRefList
if calExpRef.datasetExists(
"calexp")]
96 self.log.info(
"Processing %d existing calexps for patch %s", len(calExpRefList), patchRef.dataId)
99 self.getTempExpDatasetName())
100 self.log.info(
"Processing %d tempExps for patch %s", len(groupData.groups), patchRef.dataId)
103 for i, (tempExpTuple, calexpRefList)
in enumerate(groupData.groups.items()):
104 tempExpRef =
getGroupDataRef(patchRef.getButler(), self.getTempExpDatasetName(),
105 tempExpTuple, groupData.keys)
106 if not self.config.doOverwrite
and tempExpRef.datasetExists(datasetType=self.getTempExpDatasetName()):
107 self.log.info(
"tempCoaddExp %s exists; skipping", tempExpRef.dataId)
108 dataRefList.append(tempExpRef)
110 self.log.info(
"Processing tempExp %d/%d: id=%s", i, len(groupData.groups), tempExpRef.dataId)
116 visitId = int(tempExpRef.dataId[
"visit"])
117 except (KeyError, ValueError):
122 dataRefList.append(tempExpRef)
123 if self.config.doWrite:
124 self.writeCoaddOutput(tempExpRef, exp,
"tempExp")
126 self.log.warn(
"tempExp %s could not be created", tempExpRef.dataId)
130 """Create a tempExp from inputs
132 We iterate over the multiple calexps in a single exposure to construct
133 the warp ("tempExp") of that exposure to the supplied tract/patch.
135 Pixels that receive no pixels are set to NAN; this is not correct
136 (violates LSST algorithms group policy), but will be fixed up by
137 interpolating after the coaddition.
139 @param calexpRefList: List of data references for calexps that (may)
140 overlap the patch of interest
141 @param skyInfo: Struct from CoaddBaseTask.getSkyInfo() with geometric
142 information about the patch
143 @param visitId: integer identifier for visit, for the table that will
145 @return warped exposure, or None if no pixels overlap
147 inputRecorder = self.inputRecorder.makeCoaddTempExpRecorder(visitId, len(calexpRefList))
148 coaddTempExp = afwImage.ExposureF(skyInfo.bbox, skyInfo.wcs)
149 coaddTempExp.getMaskedImage().set(numpy.nan, afwImage.MaskU.getPlaneBitMask(
"NO_DATA"), numpy.inf)
151 didSetMetadata =
False
152 modelPsf = self.config.modelPsf.apply()
if self.config.doPsfMatch
else None
153 for calExpInd, calExpRef
in enumerate(calexpRefList):
154 self.log.info(
"Processing calexp %d of %d for this tempExp: id=%s",
155 calExpInd+1, len(calexpRefList), calExpRef.dataId)
157 ccdId = calExpRef.get(
"ccdExposureId", immediate=
True)
165 calExpRef = calExpRef.butlerSubset.butler.dataRef(
"calexp", dataId=calExpRef.dataId,
166 tract=skyInfo.tractInfo.getId())
167 calExp = self.getCalExp(calExpRef, bgSubtracted=self.config.bgSubtracted)
168 exposure = self.warpAndPsfMatch.run(calExp, modelPsf=modelPsf, wcs=skyInfo.wcs,
169 maxBBox=skyInfo.bbox).exposure
171 mimg = exposure.getMaskedImage()
172 mimg *= (coaddTempExp.getCalib().getFluxMag0()[0] / exposure.getCalib().getFluxMag0()[0])
175 coaddTempExp.getMaskedImage(), exposure.getMaskedImage(), self.getBadPixelMask())
176 totGoodPix += numGoodPix
177 self.log.debug(
"Calexp %s has %d good pixels in this patch (%.1f%%)",
178 calExpRef.dataId, numGoodPix, 100.0*numGoodPix/skyInfo.bbox.getArea())
179 if numGoodPix > 0
and not didSetMetadata:
180 coaddTempExp.setCalib(exposure.getCalib())
181 coaddTempExp.setFilter(exposure.getFilter())
182 didSetMetadata =
True
183 except Exception
as e:
184 self.log.warn(
"Error processing calexp %s; skipping it: %s", calExpRef.dataId, e)
186 inputRecorder.addCalExp(calExp, ccdId, numGoodPix)
188 inputRecorder.finish(coaddTempExp, totGoodPix)
189 if totGoodPix > 0
and didSetMetadata:
190 coaddTempExp.setPsf(modelPsf
if self.config.doPsfMatch
else
191 CoaddPsf(inputRecorder.coaddInputs.ccds, skyInfo.wcs))
193 self.log.info(
"coaddTempExp has %d good pixels (%.1f%%)",
194 totGoodPix, 100.0*totGoodPix/skyInfo.bbox.getArea())
195 return coaddTempExp
if totGoodPix > 0
and didSetMetadata
else None
Fit spatial kernel using approximate fluxes for candidates, and solving a linear system of equations...
CoaddPsf is the Psf derived to be used for non-PSF-matched Coadd images.
int copyGoodPixels(lsst::afw::image::MaskedImage< ImagePixelT, lsst::afw::image::MaskPixel, lsst::afw::image::VariancePixel > &destImage, lsst::afw::image::MaskedImage< ImagePixelT, lsst::afw::image::MaskPixel, lsst::afw::image::VariancePixel > const &srcImage, lsst::afw::image::MaskPixel const badPixelMask)
copy good pixels from one masked image to another