1 from __future__
import division, absolute_import
30 __all__ = [
"GetCoaddAsTemplateTask",
"GetCoaddAsTemplateConfig",
31 "GetCalexpAsTemplateTask",
"GetCalexpAsTemplateConfig"]
35 templateBorderSize = pexConfig.Field(
38 doc=
"Number of pixels to grow the requested template image to account for warping"
40 coaddName = pexConfig.Field(
41 doc=
"coadd name: typically one of deep or goodSeeing",
48 """Subtask to retrieve coadd for use as an image difference template.
50 This is the default getTemplate Task to be run as a subtask by
51 pipe.tasks.ImageDifferenceTask. The main method is run().
52 It assumes that coadds reside in the repository given by sensorRef.
54 ConfigClass = GetCoaddAsTemplateConfig
55 _DefaultName =
"GetCoaddAsTemplateTask"
57 def run(self, exposure, sensorRef, templateIdList=None):
58 """!Retrieve and mosaic a template coadd exposure that overlaps the exposure
60 \param[in] exposure -- an exposure for which to generate an overlapping template
61 \param[in] sensorRef -- a Butler data reference that can be used to obtain coadd data
62 \param[in] templateIdList -- list of data ids (unused)
64 \return a pipeBase.Struct
65 - exposure: a template coadd exposure assembled out of patches
66 - sources: None for this subtask
68 skyMap = sensorRef.get(datasetType=self.config.coaddName +
"Coadd_skyMap")
69 expWcs = exposure.getWcs()
71 expBoxD.grow(self.config.templateBorderSize)
72 ctrSkyPos = expWcs.pixelToSky(expBoxD.getCenter())
73 tractInfo = skyMap.findTract(ctrSkyPos)
74 self.log.info(
"Using skyMap tract %s" % (tractInfo.getId(),))
75 skyCorners = [expWcs.pixelToSky(pixPos)
for pixPos
in expBoxD.getCorners()]
76 patchList = tractInfo.findPatchList(skyCorners)
79 raise RuntimeError(
"No suitable tract found")
80 self.log.info(
"Assembling %s coadd patches" % (len(patchList),))
83 coaddWcs = tractInfo.getWcs()
85 for skyPos
in skyCorners:
86 coaddBBox.include(coaddWcs.skyToPixel(skyPos))
88 self.log.info(
"exposure dimensions=%s; coadd dimensions=%s" %
89 (exposure.getDimensions(), coaddBBox.getDimensions()))
92 coaddExposure = afwImage.ExposureF(coaddBBox, coaddWcs)
93 coaddExposure.getMaskedImage().set(numpy.nan, afwImage.MaskU.getPlaneBitMask(
"NO_DATA"), numpy.nan)
97 for patchInfo
in patchList:
98 patchSubBBox = patchInfo.getOuterBBox()
99 patchSubBBox.clip(coaddBBox)
101 datasetType=self.config.coaddName +
"Coadd_sub",
103 tract=tractInfo.getId(),
104 patch=
"%s,%s" % (patchInfo.getIndex()[0], patchInfo.getIndex()[1]),
106 if patchSubBBox.isEmpty():
107 self.log.info(
"skip tract=%(tract)s, patch=%(patch)s; no overlapping pixels" % patchArgDict)
109 if not sensorRef.datasetExists(**patchArgDict):
110 self.log.warn(
"%(datasetType)s, tract=%(tract)s, patch=%(patch)s does not exist"
115 self.log.info(
"Reading patch %s" % patchArgDict)
116 coaddPatch = sensorRef.get(**patchArgDict)
117 coaddExposure.getMaskedImage().assign(coaddPatch.getMaskedImage(), coaddPatch.getBBox())
118 if coaddFilter
is None:
119 coaddFilter = coaddPatch.getFilter()
122 if coaddPsf
is None and coaddPatch.hasPsf():
123 coaddPsf = coaddPatch.getPsf()
125 if nPatchesFound == 0:
126 raise RuntimeError(
"No patches found!")
129 raise RuntimeError(
"No coadd Psf found!")
131 coaddExposure.setPsf(coaddPsf)
132 coaddExposure.setFilter(coaddFilter)
133 return pipeBase.Struct(exposure=coaddExposure,
138 doAddCalexpBackground = pexConfig.Field(
141 doc=
"Add background to calexp before processing it."
146 """Subtask to retrieve calexp of the same ccd number as the science image SensorRef
147 for use as an image difference template.
149 To be run as a subtask by pipe.tasks.ImageDifferenceTask.
150 Intended for use with simulations and surveys that repeatedly visit the same pointing.
151 This code was originally part of Winter2013ImageDifferenceTask.
154 ConfigClass = GetCalexpAsTemplateConfig
155 _DefaultName =
"GetCalexpAsTemplateTask"
157 def run(self, exposure, sensorRef, templateIdList):
158 """!Return a calexp exposure with based on input sensorRef.
160 Construct a dataId based on the sensorRef.dataId combined
161 with the specifications from the first dataId in templateIdList
163 \param[in] exposure -- exposure (unused)
164 \param[in] sensorRef -- a Butler data reference
165 \param[in] templateIdList -- list of data ids, which should contain a single item.
166 If there are multiple items, only the first is used.
168 \return a pipeBase.Struct
169 - exposure: a template calexp
170 - sources: source catalog measured on the template
173 if len(templateIdList) == 0:
174 raise RuntimeError(
"No template supplied! Please supply a template visit id.")
175 if len(templateIdList) > 1:
176 self.log.warn(
"Multiple template visits supplied. Getting template from first visit: %s" %
177 (templateIdList[0][
'visit']))
179 templateId = sensorRef.dataId.copy()
180 templateId.update(templateIdList[0])
182 self.log.info(
"Fetching calexp (%s) as template." % (templateId))
184 butler = sensorRef.getButler()
185 template = butler.get(datasetType=
"calexp", dataId=templateId)
186 if self.config.doAddCalexpBackground:
187 templateBg = butler.get(datasetType=
"calexpBackground", dataId=templateId)
188 mi = template.getMaskedImage()
189 mi += templateBg.getImage()
191 if not template.hasPsf():
192 raise pipeBase.TaskError(
"Template has no psf")
194 templateSources = butler.get(datasetType=
"src", dataId=templateId)
195 return pipeBase.Struct(exposure=template,
196 sources=templateSources)
An integer coordinate rectangle.
def run
Return a calexp exposure with based on input sensorRef.
A floating-point coordinate rectangle geometry.
def run
Retrieve and mosaic a template coadd exposure that overlaps the exposure.