26 import lsst.pipe.base
as pipeBase
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",
45 warpType = pexConfig.Field(
46 doc=
"Warp type of the coadd template: one of 'direct' or 'psfMatched'",
53 """Subtask to retrieve coadd for use as an image difference template. 55 This is the default getTemplate Task to be run as a subtask by 56 pipe.tasks.ImageDifferenceTask. The main method is run(). 57 It assumes that coadds reside in the repository given by sensorRef. 59 ConfigClass = GetCoaddAsTemplateConfig
60 _DefaultName =
"GetCoaddAsTemplateTask" 62 def run(self, exposure, sensorRef, templateIdList=None):
63 """!Retrieve and mosaic a template coadd exposure that overlaps the exposure 65 @param[in] exposure -- an exposure for which to generate an overlapping template 66 @param[in] sensorRef -- a Butler data reference that can be used to obtain coadd data 67 @param[in] templateIdList -- list of data ids (unused) 69 @return a pipeBase.Struct 70 - exposure: a template coadd exposure assembled out of patches 71 - sources: None for this subtask 73 skyMap = sensorRef.get(datasetType=self.config.coaddName +
"Coadd_skyMap")
74 expWcs = exposure.getWcs()
76 expBoxD.grow(self.config.templateBorderSize)
77 ctrSkyPos = expWcs.pixelToSky(expBoxD.getCenter())
78 tractInfo = skyMap.findTract(ctrSkyPos)
79 self.log.info(
"Using skyMap tract %s" % (tractInfo.getId(),))
80 skyCorners = [expWcs.pixelToSky(pixPos)
for pixPos
in expBoxD.getCorners()]
81 patchList = tractInfo.findPatchList(skyCorners)
84 raise RuntimeError(
"No suitable tract found")
85 self.log.info(
"Assembling %s coadd patches" % (len(patchList),))
88 coaddWcs = tractInfo.getWcs()
90 for skyPos
in skyCorners:
91 coaddBBox.include(coaddWcs.skyToPixel(skyPos))
93 self.log.info(
"exposure dimensions=%s; coadd dimensions=%s" %
94 (exposure.getDimensions(), coaddBBox.getDimensions()))
97 coaddExposure = afwImage.ExposureF(coaddBBox, coaddWcs)
98 coaddExposure.getMaskedImage().set(np.nan, afwImage.Mask.getPlaneBitMask(
"NO_DATA"), np.nan)
102 for patchInfo
in patchList:
103 patchSubBBox = patchInfo.getOuterBBox()
104 patchSubBBox.clip(coaddBBox)
108 tract=tractInfo.getId(),
109 patch=
"%s,%s" % (patchInfo.getIndex()[0], patchInfo.getIndex()[1]),
111 if patchSubBBox.isEmpty():
112 self.log.info(
"skip tract=%(tract)s, patch=%(patch)s; no overlapping pixels" % patchArgDict)
114 if not sensorRef.datasetExists(**patchArgDict):
115 self.log.warn(
"%(datasetType)s, tract=%(tract)s, patch=%(patch)s does not exist" 120 self.log.info(
"Reading patch %s" % patchArgDict)
121 coaddPatch = sensorRef.get(**patchArgDict)
122 coaddExposure.getMaskedImage().assign(coaddPatch.getMaskedImage(), coaddPatch.getBBox())
123 if coaddFilter
is None:
124 coaddFilter = coaddPatch.getFilter()
127 if coaddPsf
is None and coaddPatch.hasPsf():
128 coaddPsf = coaddPatch.getPsf()
130 if nPatchesFound == 0:
131 raise RuntimeError(
"No patches found!")
134 raise RuntimeError(
"No coadd Psf found!")
136 coaddExposure.setPsf(coaddPsf)
137 coaddExposure.setFilter(coaddFilter)
138 return pipeBase.Struct(exposure=coaddExposure,
142 """Return coadd name for given task config 146 CoaddDatasetName : `string` 148 TODO: This nearly duplicates a method in CoaddBaseTask (DM-11985) 150 warpType = self.config.warpType
151 suffix =
"" if warpType ==
"direct" else warpType[0].upper() + warpType[1:]
152 return self.config.coaddName +
"Coadd" + suffix
156 doAddCalexpBackground = pexConfig.Field(
159 doc=
"Add background to calexp before processing it." 164 """Subtask to retrieve calexp of the same ccd number as the science image SensorRef 165 for use as an image difference template. 167 To be run as a subtask by pipe.tasks.ImageDifferenceTask. 168 Intended for use with simulations and surveys that repeatedly visit the same pointing. 169 This code was originally part of Winter2013ImageDifferenceTask. 172 ConfigClass = GetCalexpAsTemplateConfig
173 _DefaultName =
"GetCalexpAsTemplateTask" 175 def run(self, exposure, sensorRef, templateIdList):
176 """!Return a calexp exposure with based on input sensorRef. 178 Construct a dataId based on the sensorRef.dataId combined 179 with the specifications from the first dataId in templateIdList 181 @param[in] exposure -- exposure (unused) 182 @param[in] sensorRef -- a Butler data reference 183 @param[in] templateIdList -- list of data ids, which should contain a single item. 184 If there are multiple items, only the first is used. 186 @return a pipeBase.Struct 187 - exposure: a template calexp 188 - sources: source catalog measured on the template 191 if len(templateIdList) == 0:
192 raise RuntimeError(
"No template supplied! Please supply a template visit id.")
193 if len(templateIdList) > 1:
194 self.log.warn(
"Multiple template visits supplied. Getting template from first visit: %s" %
195 (templateIdList[0][
'visit']))
197 templateId = sensorRef.dataId.copy()
198 templateId.update(templateIdList[0])
200 self.log.info(
"Fetching calexp (%s) as template." % (templateId))
202 butler = sensorRef.getButler()
203 template = butler.get(datasetType=
"calexp", dataId=templateId)
204 if self.config.doAddCalexpBackground:
205 templateBg = butler.get(datasetType=
"calexpBackground", dataId=templateId)
206 mi = template.getMaskedImage()
207 mi += templateBg.getImage()
209 if not template.hasPsf():
210 raise pipeBase.TaskError(
"Template has no psf")
212 templateSources = butler.get(datasetType=
"src", dataId=templateId)
213 return pipeBase.Struct(exposure=template,
214 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.