1 from __future__
import division, absolute_import
30 __all__ = [
"GetCoaddAsTemplateTask",
"GetCoaddAsTemplateConfig",
31 "GetCalexpAsTemplateTask",
"GetCalexpAsTemplateConfig"]
34 templateBorderSize = pexConfig.Field(
37 doc =
"Number of pixels to grow the requested template image to account for warping"
39 coaddName = pexConfig.Field(
40 doc =
"coadd name: typically one of deep or goodSeeing",
47 """Subtask to retrieve coadd for use as an image difference template.
49 This is the default getTemplate Task to be run as a subtask by
50 pipe.tasks.ImageDifferenceTask. The main method is run().
51 It assumes that coadds reside in the repository given by sensorRef.
53 ConfigClass = GetCoaddAsTemplateConfig
54 _DefaultName =
"GetCoaddAsTemplateTask"
56 def run(self, exposure, sensorRef, templateIdList=None):
57 """!Retrieve and mosaic a template coadd exposure that overlaps the exposure
59 \param[in] exposure -- an exposure for which to generate an overlapping template
60 \param[in] sensorRef -- a Butler data reference that can be used to obtain coadd data
61 \param[in] templateIdList -- list of data ids (unused)
63 \return a pipeBase.Struct
64 - exposure: a template coadd exposure assembled out of patches
65 - sources: None for this subtask
67 skyMap = sensorRef.get(datasetType=self.config.coaddName +
"Coadd_skyMap")
68 expWcs = exposure.getWcs()
70 expBoxD.grow(self.config.templateBorderSize)
71 ctrSkyPos = expWcs.pixelToSky(expBoxD.getCenter())
72 tractInfo = skyMap.findTract(ctrSkyPos)
73 self.log.info(
"Using skyMap tract %s" % (tractInfo.getId(),))
74 skyCorners = [expWcs.pixelToSky(pixPos)
for pixPos
in expBoxD.getCorners()]
75 patchList = tractInfo.findPatchList(skyCorners)
78 raise RuntimeError(
"No suitable tract found")
79 self.log.info(
"Assembling %s coadd patches" % (len(patchList),))
82 coaddWcs = tractInfo.getWcs()
84 for skyPos
in skyCorners:
85 coaddBBox.include(coaddWcs.skyToPixel(skyPos))
87 self.log.info(
"exposure dimensions=%s; coadd dimensions=%s" %
88 (exposure.getDimensions(), coaddBBox.getDimensions()))
91 coaddExposure = afwImage.ExposureF(coaddBBox, coaddWcs)
92 coaddExposure.getMaskedImage().set(numpy.nan, afwImage.MaskU.getPlaneBitMask(
"NO_DATA"), numpy.nan)
96 for patchInfo
in patchList:
97 patchSubBBox = patchInfo.getOuterBBox()
98 patchSubBBox.clip(coaddBBox)
100 datasetType=self.config.coaddName +
"Coadd_sub",
102 tract=tractInfo.getId(),
103 patch=
"%s,%s" % (patchInfo.getIndex()[0], patchInfo.getIndex()[1]),
105 if patchSubBBox.isEmpty():
106 self.log.info(
"skip tract=%(tract)s, patch=%(patch)s; no overlapping pixels" % patchArgDict)
108 if not sensorRef.datasetExists(**patchArgDict):
109 self.log.warn(
"%(datasetType)s, tract=%(tract)s, patch=%(patch)s does not exist"
114 self.log.info(
"Reading patch %s" % patchArgDict)
115 coaddPatch = sensorRef.get(**patchArgDict)
116 coaddExposure.getMaskedImage().assign(coaddPatch.getMaskedImage(), coaddPatch.getBBox())
117 if coaddFilter
is None:
118 coaddFilter = coaddPatch.getFilter()
121 if coaddPsf
is None and coaddPatch.hasPsf():
122 coaddPsf = coaddPatch.getPsf()
124 if nPatchesFound == 0:
125 raise RuntimeError(
"No patches found!")
128 raise RuntimeError(
"No coadd Psf found!")
130 coaddExposure.setPsf(coaddPsf)
131 coaddExposure.setFilter(coaddFilter)
132 return pipeBase.Struct(exposure = coaddExposure,
137 doAddCalexpBackground = pexConfig.Field(
140 doc=
"Add background to calexp before processing it."
145 """Subtask to retrieve calexp of the same ccd number as the science image SensorRef
146 for use as an image difference template.
148 To be run as a subtask by pipe.tasks.ImageDifferenceTask.
149 Intended for use with simulations and surveys that repeatedly visit the same pointing.
150 This code was originally part of Winter2013ImageDifferenceTask.
153 ConfigClass = GetCalexpAsTemplateConfig
154 _DefaultName =
"GetCalexpAsTemplateTask"
156 def run(self, exposure, sensorRef, templateIdList):
157 """!Return a calexp exposure with based on input sensorRef.
159 Construct a dataId based on the sensorRef.dataId combined
160 with the specifications from the first dataId in templateIdList
162 \param[in] exposure -- exposure (unused)
163 \param[in] sensorRef -- a Butler data reference
164 \param[in] templateIdList -- list of data ids, which should contain a single item.
165 If there are multiple items, only the first is used.
167 \return a pipeBase.Struct
168 - exposure: a template calexp
169 - sources: source catalog measured on the template
172 if len(templateIdList) == 0:
173 raise RuntimeError(
"No template supplied! Please supply a template visit id.")
174 if len(templateIdList) > 1:
175 self.log.warn(
"Multiple template visits supplied. Getting template from first visit: %s" %
176 (templateIdList[0][
'visit']))
178 templateId = sensorRef.dataId.copy()
179 templateId.update(templateIdList[0])
181 self.log.info(
"Fetching calexp (%s) as template." % (templateId))
183 butler = sensorRef.getButler()
184 template = butler.get(datasetType=
"calexp", dataId=templateId)
185 if self.config.doAddCalexpBackground:
186 templateBg = butler.get(datasetType=
"calexpBackground", dataId=templateId)
187 mi = template.getMaskedImage()
188 mi += templateBg.getImage()
190 if not template.hasPsf():
191 raise pipeBase.TaskError(
"Template has no psf")
193 templateSources = butler.get(datasetType=
"src", dataId=templateId)
194 return pipeBase.Struct(exposure = template,
195 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.