22 from __future__
import absolute_import, division, print_function
26 import lsst.pex.config
as pexConfig
27 import lsst.pipe.base
as pipeBase
28 import lsst.afw.geom
as afwGeom
29 import lsst.afw.image
as afwImage
31 __all__ = [
"GetCoaddAsTemplateTask",
"GetCoaddAsTemplateConfig",
32 "GetCalexpAsTemplateTask",
"GetCalexpAsTemplateConfig"]
36 templateBorderSize = pexConfig.Field(
39 doc=
"Number of pixels to grow the requested template image to account for warping" 41 coaddName = pexConfig.Field(
42 doc=
"coadd name: typically one of deep or goodSeeing",
46 warpType = pexConfig.Field(
47 doc=
"Warp type of the coadd template: one of 'direct' or 'psfMatched'",
54 """Subtask to retrieve coadd for use as an image difference template. 56 This is the default getTemplate Task to be run as a subtask by 57 pipe.tasks.ImageDifferenceTask. The main method is run(). 58 It assumes that coadds reside in the repository given by sensorRef. 60 ConfigClass = GetCoaddAsTemplateConfig
61 _DefaultName =
"GetCoaddAsTemplateTask" 63 def run(self, exposure, sensorRef, templateIdList=None):
64 """!Retrieve and mosaic a template coadd exposure that overlaps the exposure 66 \param[in] exposure -- an exposure for which to generate an overlapping template 67 \param[in] sensorRef -- a Butler data reference that can be used to obtain coadd data 68 \param[in] templateIdList -- list of data ids (unused) 70 \return a pipeBase.Struct 71 - exposure: a template coadd exposure assembled out of patches 72 - sources: None for this subtask 74 skyMap = sensorRef.get(datasetType=self.config.coaddName +
"Coadd_skyMap")
75 expWcs = exposure.getWcs()
76 expBoxD = afwGeom.Box2D(exposure.getBBox())
77 expBoxD.grow(self.config.templateBorderSize)
78 ctrSkyPos = expWcs.pixelToSky(expBoxD.getCenter())
79 tractInfo = skyMap.findTract(ctrSkyPos)
80 self.log.info(
"Using skyMap tract %s" % (tractInfo.getId(),))
81 skyCorners = [expWcs.pixelToSky(pixPos)
for pixPos
in expBoxD.getCorners()]
82 patchList = tractInfo.findPatchList(skyCorners)
85 raise RuntimeError(
"No suitable tract found")
86 self.log.info(
"Assembling %s coadd patches" % (len(patchList),))
89 coaddWcs = tractInfo.getWcs()
90 coaddBBox = afwGeom.Box2D()
91 for skyPos
in skyCorners:
92 coaddBBox.include(coaddWcs.skyToPixel(skyPos))
93 coaddBBox = afwGeom.Box2I(coaddBBox)
94 self.log.info(
"exposure dimensions=%s; coadd dimensions=%s" %
95 (exposure.getDimensions(), coaddBBox.getDimensions()))
98 coaddExposure = afwImage.ExposureF(coaddBBox, coaddWcs)
99 coaddExposure.getMaskedImage().set(np.nan, afwImage.Mask\
100 .getPlaneBitMask(
"NO_DATA"), np.nan)
104 for patchInfo
in patchList:
105 patchSubBBox = patchInfo.getOuterBBox()
106 patchSubBBox.clip(coaddBBox)
110 tract=tractInfo.getId(),
111 patch=
"%s,%s" % (patchInfo.getIndex()[0], patchInfo.getIndex()[1]),
113 if patchSubBBox.isEmpty():
114 self.log.info(
"skip tract=%(tract)s, patch=%(patch)s; no overlapping pixels" % patchArgDict)
116 if not sensorRef.datasetExists(**patchArgDict):
117 self.log.warn(
"%(datasetType)s, tract=%(tract)s, patch=%(patch)s does not exist" 122 self.log.info(
"Reading patch %s" % patchArgDict)
123 coaddPatch = sensorRef.get(**patchArgDict)
124 coaddExposure.getMaskedImage().assign(coaddPatch.getMaskedImage(), coaddPatch.getBBox())
125 if coaddFilter
is None:
126 coaddFilter = coaddPatch.getFilter()
129 if coaddPsf
is None and coaddPatch.hasPsf():
130 coaddPsf = coaddPatch.getPsf()
132 if nPatchesFound == 0:
133 raise RuntimeError(
"No patches found!")
136 raise RuntimeError(
"No coadd Psf found!")
138 coaddExposure.setPsf(coaddPsf)
139 coaddExposure.setFilter(coaddFilter)
140 return pipeBase.Struct(exposure=coaddExposure,
144 """Return coadd name for given task config 148 CoaddDatasetName : `string` 150 TODO: This nearly duplicates a method in CoaddBaseTask (DM-11985) 152 warpType = self.config.warpType
153 suffix =
"" if warpType ==
"direct" else warpType[0].upper() + warpType[1:]
154 return self.config.coaddName +
"Coadd" + suffix
158 doAddCalexpBackground = pexConfig.Field(
161 doc=
"Add background to calexp before processing it." 166 """Subtask to retrieve calexp of the same ccd number as the science image SensorRef 167 for use as an image difference template. 169 To be run as a subtask by pipe.tasks.ImageDifferenceTask. 170 Intended for use with simulations and surveys that repeatedly visit the same pointing. 171 This code was originally part of Winter2013ImageDifferenceTask. 174 ConfigClass = GetCalexpAsTemplateConfig
175 _DefaultName =
"GetCalexpAsTemplateTask" 177 def run(self, exposure, sensorRef, templateIdList):
178 """!Return a calexp exposure with based on input sensorRef. 180 Construct a dataId based on the sensorRef.dataId combined 181 with the specifications from the first dataId in templateIdList 183 \param[in] exposure -- exposure (unused) 184 \param[in] sensorRef -- a Butler data reference 185 \param[in] templateIdList -- list of data ids, which should contain a single item. 186 If there are multiple items, only the first is used. 188 \return a pipeBase.Struct 189 - exposure: a template calexp 190 - sources: source catalog measured on the template 193 if len(templateIdList) == 0:
194 raise RuntimeError(
"No template supplied! Please supply a template visit id.")
195 if len(templateIdList) > 1:
196 self.log.warn(
"Multiple template visits supplied. Getting template from first visit: %s" %
197 (templateIdList[0][
'visit']))
199 templateId = sensorRef.dataId.copy()
200 templateId.update(templateIdList[0])
202 self.log.info(
"Fetching calexp (%s) as template." % (templateId))
204 butler = sensorRef.getButler()
205 template = butler.get(datasetType=
"calexp", dataId=templateId)
206 if self.config.doAddCalexpBackground:
207 templateBg = butler.get(datasetType=
"calexpBackground", dataId=templateId)
208 mi = template.getMaskedImage()
209 mi += templateBg.getImage()
211 if not template.hasPsf():
212 raise pipeBase.TaskError(
"Template has no psf")
214 templateSources = butler.get(datasetType=
"src", dataId=templateId)
215 return pipeBase.Struct(exposure=template,
216 sources=templateSources)
def getCoaddDatasetName(self)
def run(self, exposure, sensorRef, templateIdList)
Return a calexp exposure with based on input sensorRef.
def run(self, exposure, sensorRef, templateIdList=None)
Retrieve and mosaic a template coadd exposure that overlaps the exposure.