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', 'goodSeeing', or 'dcr'",
46 numSubfilters = pexConfig.Field(
47 doc=
"Number of subfilters in the DcrCoadd, used only if ``coaddName``='dcr'",
51 warpType = pexConfig.Field(
52 doc=
"Warp type of the coadd template: one of 'direct' or 'psfMatched'",
59 """Subtask to retrieve coadd for use as an image difference template. 61 This is the default getTemplate Task to be run as a subtask by 62 ``pipe.tasks.ImageDifferenceTask``. The main method is ``run()``. 63 It assumes that coadds reside in the repository given by sensorRef. 66 ConfigClass = GetCoaddAsTemplateConfig
67 _DefaultName =
"GetCoaddAsTemplateTask" 69 def run(self, exposure, sensorRef, templateIdList=None):
70 """Retrieve and mosaic a template coadd exposure that overlaps the exposure 74 exposure: `lsst.afw.image.Exposure` 75 an exposure for which to generate an overlapping template 77 a Butler data reference that can be used to obtain coadd data 78 templateIdList : TYPE, optional 79 list of data ids (unused) 84 return a pipeBase.Struct: 86 - ``exposure`` : a template coadd exposure assembled out of patches 87 - ``sources`` : None for this subtask 89 skyMap = sensorRef.get(datasetType=self.config.coaddName +
"Coadd_skyMap")
90 expWcs = exposure.getWcs()
92 expBoxD.grow(self.config.templateBorderSize)
93 ctrSkyPos = expWcs.pixelToSky(expBoxD.getCenter())
94 tractInfo = skyMap.findTract(ctrSkyPos)
95 self.log.
info(
"Using skyMap tract %s" % (tractInfo.getId(),))
96 skyCorners = [expWcs.pixelToSky(pixPos)
for pixPos
in expBoxD.getCorners()]
97 patchList = tractInfo.findPatchList(skyCorners)
100 raise RuntimeError(
"No suitable tract found")
101 self.log.
info(
"Assembling %s coadd patches" % (len(patchList),))
104 coaddWcs = tractInfo.getWcs()
106 for skyPos
in skyCorners:
107 coaddBBox.include(coaddWcs.skyToPixel(skyPos))
109 self.log.
info(
"exposure dimensions=%s; coadd dimensions=%s" %
110 (exposure.getDimensions(), coaddBBox.getDimensions()))
113 coaddExposure = afwImage.ExposureF(coaddBBox, coaddWcs)
114 coaddExposure.maskedImage.set(np.nan, afwImage.Mask.getPlaneBitMask(
"NO_DATA"), np.nan)
118 for patchInfo
in patchList:
119 patchSubBBox = patchInfo.getOuterBBox()
120 patchSubBBox.clip(coaddBBox)
124 tract=tractInfo.getId(),
125 patch=
"%s,%s" % (patchInfo.getIndex()[0], patchInfo.getIndex()[1]),
126 numSubfilters=self.config.numSubfilters,
128 if patchSubBBox.isEmpty():
129 self.log.
info(
"skip tract=%(tract)s, patch=%(patch)s; no overlapping pixels" % patchArgDict)
132 if self.config.coaddName ==
'dcr':
133 if not sensorRef.datasetExists(subfilter=0, **patchArgDict):
134 self.log.
warn(
"%(datasetType)s, tract=%(tract)s, patch=%(patch)s," 135 " numSubfilters=%(numSubfilters)s, subfilter=0 does not exist" 138 self.log.
info(
"Constructing DCR-matched template for patch %s" % patchArgDict)
139 dcrModel = DcrModel.fromDataRef(sensorRef, **patchArgDict)
140 coaddPatch = dcrModel.buildMatchedExposure(bbox=patchSubBBox,
142 visitInfo=exposure.getInfo().getVisitInfo())
144 if not sensorRef.datasetExists(**patchArgDict):
145 self.log.
warn(
"%(datasetType)s, tract=%(tract)s, patch=%(patch)s does not exist" 148 self.log.
info(
"Reading patch %s" % patchArgDict)
149 coaddPatch = sensorRef.get(**patchArgDict)
151 coaddExposure.maskedImage.assign(coaddPatch.maskedImage, coaddPatch.getBBox())
152 if coaddFilter
is None:
153 coaddFilter = coaddPatch.getFilter()
156 if coaddPsf
is None and coaddPatch.hasPsf():
157 coaddPsf = coaddPatch.getPsf()
159 if nPatchesFound == 0:
160 raise RuntimeError(
"No patches found!")
163 raise RuntimeError(
"No coadd Psf found!")
165 coaddExposure.setPsf(coaddPsf)
166 coaddExposure.setFilter(coaddFilter)
167 return pipeBase.Struct(exposure=coaddExposure,
171 """Return coadd name for given task config 175 CoaddDatasetName : `string` 177 TODO: This nearly duplicates a method in CoaddBaseTask (DM-11985) 179 warpType = self.config.warpType
180 suffix =
"" if warpType ==
"direct" else warpType[0].upper() + warpType[1:]
181 return self.config.coaddName +
"Coadd" + suffix
185 doAddCalexpBackground = pexConfig.Field(
188 doc=
"Add background to calexp before processing it." 193 """Subtask to retrieve calexp of the same ccd number as the science image SensorRef 194 for use as an image difference template. 196 To be run as a subtask by pipe.tasks.ImageDifferenceTask. 197 Intended for use with simulations and surveys that repeatedly visit the same pointing. 198 This code was originally part of Winter2013ImageDifferenceTask. 201 ConfigClass = GetCalexpAsTemplateConfig
202 _DefaultName =
"GetCalexpAsTemplateTask" 204 def run(self, exposure, sensorRef, templateIdList):
205 """Return a calexp exposure with based on input sensorRef. 207 Construct a dataId based on the sensorRef.dataId combined 208 with the specifications from the first dataId in templateIdList 212 exposure : `lsst.afw.image.Exposure` 215 a Butler data reference 216 templateIdList : TYPE 217 list of data ids, which should contain a single item. 218 If there are multiple items, only the first is used. 224 return a pipeBase.Struct: 226 - ``exposure`` : a template calexp 227 - ``sources`` : source catalog measured on the template 230 if len(templateIdList) == 0:
231 raise RuntimeError(
"No template supplied! Please supply a template visit id.")
232 if len(templateIdList) > 1:
233 self.log.
warn(
"Multiple template visits supplied. Getting template from first visit: %s" %
234 (templateIdList[0][
'visit']))
236 templateId = sensorRef.dataId.copy()
237 templateId.update(templateIdList[0])
239 self.log.
info(
"Fetching calexp (%s) as template." % (templateId))
241 butler = sensorRef.getButler()
242 template = butler.get(datasetType=
"calexp", dataId=templateId)
243 if self.config.doAddCalexpBackground:
244 templateBg = butler.get(datasetType=
"calexpBackground", dataId=templateId)
245 mi = template.getMaskedImage()
246 mi += templateBg.getImage()
248 if not template.hasPsf():
249 raise pipeBase.TaskError(
"Template has no psf")
251 templateSources = butler.get(datasetType=
"src", dataId=templateId)
252 return pipeBase.Struct(exposure=template,
253 sources=templateSources)
def getCoaddDatasetName(self)
A floating-point coordinate rectangle geometry.
def run(self, exposure, sensorRef, templateIdList)
def run(self, exposure, sensorRef, templateIdList=None)
An integer coordinate rectangle.