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"]
38 """Config for MakeCoaddTempExpTask
40 warpAndPsfMatch = pexConfig.ConfigurableField(
41 target = WarpAndPsfMatchTask,
42 doc =
"Task to warp and PSF-match calexp",
44 doWrite = pexConfig.Field(
45 doc =
"persist <coaddName>Coadd_tempExp",
49 doOverwrite = pexConfig.Field(
50 doc =
"overwrite <coaddName>Coadd_tempExp; If False, continue if the file exists on disk",
54 bgSubtracted = pexConfig.Field(
55 doc =
"Work with a background subtracted calexp?",
62 """Task to produce <coaddName>Coadd_tempExp images
64 ConfigClass = MakeCoaddTempExpConfig
65 _DefaultName =
"makeCoaddTempExp"
68 CoaddBaseTask.__init__(self, *args, **kwargs)
69 self.makeSubtask(
"warpAndPsfMatch")
72 def run(self, patchRef, selectDataList=[]):
73 """Produce <coaddName>Coadd_tempExp images
75 <coaddName>Coadd_tempExp are produced by PSF-matching (optional) and warping.
77 @param[in] patchRef: data reference for sky map patch. Must include keys "tract", "patch",
78 plus the camera-specific filter key (e.g. "filter" or "band")
79 @return: dataRefList: a list of data references for the new <coaddName>Coadd_tempExp
81 @warning: this task assumes that all exposures in a coaddTempExp have the same filter.
83 @warning: this task sets the Calib of the coaddTempExp to the Calib of the first calexp
84 with any good pixels in the patch. For a mosaic camera the resulting Calib should be ignored
85 (assembleCoadd should determine zeropoint scaling without referring to it).
87 skyInfo = self.getSkyInfo(patchRef)
89 calExpRefList = self.selectExposures(patchRef, skyInfo, selectDataList=selectDataList)
90 if len(calExpRefList) == 0:
91 self.log.warn(
"No exposures to coadd for patch %s" % patchRef.dataId)
93 self.log.info(
"Selected %d calexps for patch %s" % (len(calExpRefList), patchRef.dataId))
94 calExpRefList = [calExpRef
for calExpRef
in calExpRefList
if calExpRef.datasetExists(
"calexp")]
95 self.log.info(
"Processing %d existing calexps for patch %s" % (len(calExpRefList), patchRef.dataId))
98 self.getTempExpDatasetName())
99 self.log.info(
"Processing %d tempExps for patch %s" % (len(groupData.groups), patchRef.dataId))
102 for i, (tempExpTuple, calexpRefList)
in enumerate(groupData.groups.iteritems()):
103 tempExpRef =
getGroupDataRef(patchRef.getButler(), self.getTempExpDatasetName(),
104 tempExpTuple, groupData.keys)
105 if not self.config.doOverwrite
and tempExpRef.datasetExists(datasetType=self.getTempExpDatasetName()):
106 self.log.info(
"tempCoaddExp %s exists; skipping" % (tempExpRef.dataId,))
107 dataRefList.append(tempExpRef)
109 self.log.info(
"Processing tempExp %d/%d: id=%s" % (i, len(groupData.groups), tempExpRef.dataId))
115 visitId = long(tempExpRef.dataId[
"visit"])
116 except (KeyError, ValueError):
121 dataRefList.append(tempExpRef)
122 if self.config.doWrite:
123 self.writeCoaddOutput(tempExpRef, exp,
"tempExp")
125 self.log.warn(
"tempExp %s could not be created" % (tempExpRef.dataId,))
129 """Create a tempExp from inputs
131 We iterate over the multiple calexps in a single exposure to construct
132 the warp ("tempExp") of that exposure to the supplied tract/patch.
134 Pixels that receive no pixels are set to NAN; this is not correct
135 (violates LSST algorithms group policy), but will be fixed up by
136 interpolating after the coaddition.
138 @param calexpRefList: List of data references for calexps that (may)
139 overlap the patch of interest
140 @param skyInfo: Struct from CoaddBaseTask.getSkyInfo() with geometric
141 information about the patch
142 @param visitId: integer identifier for visit, for the table that will
144 @return warped exposure, or None if no pixels overlap
146 inputRecorder = self.inputRecorder.makeCoaddTempExpRecorder(visitId)
147 coaddTempExp = afwImage.ExposureF(skyInfo.bbox, skyInfo.wcs)
148 coaddTempExp.getMaskedImage().set(numpy.nan, afwImage.MaskU.getPlaneBitMask(
"NO_DATA"), numpy.inf)
150 didSetMetadata =
False
151 modelPsf = self.config.modelPsf.apply()
if self.config.doPsfMatch
else None
152 for calExpInd, calExpRef
in enumerate(calexpRefList):
153 self.log.info(
"Processing calexp %d of %d for this tempExp: id=%s" %
154 (calExpInd+1, len(calexpRefList), calExpRef.dataId))
156 ccdId = calExpRef.get(
"ccdExposureId", immediate=
True)
164 calExpRef = calExpRef.butlerSubset.butler.dataRef(
"calexp", dataId=calExpRef.dataId,
165 tract=skyInfo.tractInfo.getId())
166 calExp = self.getCalExp(calExpRef, bgSubtracted=self.config.bgSubtracted)
167 exposure = self.warpAndPsfMatch.run(calExp, modelPsf=modelPsf, wcs=skyInfo.wcs,
168 maxBBox=skyInfo.bbox).exposure
170 mimg = exposure.getMaskedImage()
171 mimg *= (coaddTempExp.getCalib().getFluxMag0()[0] / exposure.getCalib().getFluxMag0()[0])
174 coaddTempExp.getMaskedImage(), exposure.getMaskedImage(), self.getBadPixelMask())
175 totGoodPix += numGoodPix
176 self.log.logdebug(
"Calexp %s has %d good pixels in this patch (%.1f%%)" %
177 (calExpRef.dataId, numGoodPix, 100.0*numGoodPix/skyInfo.bbox.getArea()))
178 if numGoodPix > 0
and not didSetMetadata:
179 coaddTempExp.setCalib(exposure.getCalib())
180 coaddTempExp.setFilter(exposure.getFilter())
181 didSetMetadata =
True
183 self.log.warn(
"Error processing calexp %s; skipping it: %s" % (calExpRef.dataId, e))
185 inputRecorder.addCalExp(calExp, ccdId, numGoodPix)
187 inputRecorder.finish(coaddTempExp, totGoodPix)
188 if totGoodPix > 0
and didSetMetadata:
189 coaddTempExp.setPsf(modelPsf
if self.config.doPsfMatch
else
190 CoaddPsf(inputRecorder.coaddInputs.ccds, skyInfo.wcs))
192 self.log.info(
"coaddTempExp has %d good pixels (%.1f%%)" %
193 (totGoodPix, 100.0*totGoodPix/skyInfo.bbox.getArea()))
194 return coaddTempExp
if totGoodPix > 0
and didSetMetadata
else None
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