LSST Applications g0f08755f38+9c285cab97,g1635faa6d4+13f3999e92,g1653933729+a8ce1bb630,g1a0ca8cf93+bf6eb00ceb,g28da252d5a+0829b12dee,g29321ee8c0+5700dc9eac,g2bbee38e9b+9634bc57db,g2bc492864f+9634bc57db,g2cdde0e794+c2c89b37c4,g3156d2b45e+41e33cbcdc,g347aa1857d+9634bc57db,g35bb328faa+a8ce1bb630,g3a166c0a6a+9634bc57db,g3e281a1b8c+9f2c4e2fc3,g414038480c+077ccc18e7,g41af890bb2+fde0dd39b6,g5fbc88fb19+17cd334064,g781aacb6e4+a8ce1bb630,g80478fca09+55a9465950,g82479be7b0+d730eedb7d,g858d7b2824+9c285cab97,g9125e01d80+a8ce1bb630,g9726552aa6+10f999ec6a,ga5288a1d22+2a84bb7594,gacf8899fa4+c69c5206e8,gae0086650b+a8ce1bb630,gb58c049af0+d64f4d3760,gc28159a63d+9634bc57db,gcf0d15dbbd+4b7d09cae4,gda3e153d99+9c285cab97,gda6a2b7d83+4b7d09cae4,gdaeeff99f8+1711a396fd,ge2409df99d+5e831397f4,ge79ae78c31+9634bc57db,gf0baf85859+147a0692ba,gf3967379c6+41c94011de,gf3fb38a9a8+8f07a9901b,gfb92a5be7c+9c285cab97,w.2024.46
LSST Data Management Base Package
Loading...
Searching...
No Matches
Classes | Functions | Variables
lsst.ip.diffim.getTemplate Namespace Reference

Classes

class  GetDcrTemplateConnections
 
class  GetTemplateConnections
 

Functions

 run (self, coaddExposures, bbox, wcs, dataIds, physical_filter)
 
 _makeExposureCatalog (self, exposures, dataIds)
 
 _merge (self, maskedImages, bbox, wcs)
 
 _makePsf (self, template, catalog, wcs)
 
 checkPatchList (self, patchList)
 
 getDcrModel (self, patchList, coaddRefs, visitInfo)
 
 _selectDataRef (coaddRef, tract, patch)
 

Variables

 detectorPolygon = geom.Box2D(inputs['bbox'])
 
int overlappingArea = 0
 
 coaddExposures = collections.defaultdict(list)
 
 dataIds = collections.defaultdict(list)
 
 skymap = inputs['skyMap']
 
 dataId = coaddRef.dataId
 
 patchWcs = skymap[dataId['tract']].getWcs()
 
 patchBBox = skymap[dataId['tract']][dataId['patch']].getOuterBBox()
 
 patchCorners = patchWcs.pixelToSky(geom.Box2D(patchBBox).getCorners())
 
 patchPolygon = afwGeom.Polygon(wcs.skyToPixel(patchCorners))
 
list coaddExposureRefList = []
 
 patchList = dict()
 

Function Documentation

◆ _makeExposureCatalog()

lsst.ip.diffim.getTemplate._makeExposureCatalog ( self,
exposures,
dataIds )
protected
Make an exposure catalog for one tract.

Parameters
----------
exposures : `list` [`lsst.afw.image.Exposuref`]
    Exposures to include in the catalog.
dataIds : `list` [`lsst.daf.butler.DataCoordinate`]
    Data ids of each of the included exposures; must have "tract" and
    "patch" entries.

Returns
-------
images : `list` [`lsst.afw.image.MaskedImage`]
    MaskedImages of each of the input exposures, for warping.
catalog : `lsst.afw.table.ExposureCatalog`
    Catalog of metadata for each exposure
totalBox : `lsst.geom.Box2I`
    The union of the bounding boxes of all the input exposures.

Definition at line 313 of file getTemplate.py.

313 def _makeExposureCatalog(self, exposures, dataIds):
314 """Make an exposure catalog for one tract.
315
316 Parameters
317 ----------
318 exposures : `list` [`lsst.afw.image.Exposuref`]
319 Exposures to include in the catalog.
320 dataIds : `list` [`lsst.daf.butler.DataCoordinate`]
321 Data ids of each of the included exposures; must have "tract" and
322 "patch" entries.
323
324 Returns
325 -------
326 images : `list` [`lsst.afw.image.MaskedImage`]
327 MaskedImages of each of the input exposures, for warping.
328 catalog : `lsst.afw.table.ExposureCatalog`
329 Catalog of metadata for each exposure
330 totalBox : `lsst.geom.Box2I`
331 The union of the bounding boxes of all the input exposures.
332 """
333 catalog = afwTable.ExposureCatalog(self.schema)
334 catalog.reserve(len(exposures))
335 images = [exposure.maskedImage for exposure in exposures]
336 totalBox = geom.Box2I()
337 for coadd, dataId in zip(exposures, dataIds):
338 totalBox = totalBox.expandedTo(coadd.getBBox())
339 record = catalog.addNew()
340 record.setPsf(coadd.psf)
341 record.setWcs(coadd.wcs)
342 record.setPhotoCalib(coadd.photoCalib)
343 record.setBBox(coadd.getBBox())
344 record.setValidPolygon(afwGeom.Polygon(geom.Box2D(coadd.getBBox()).getCorners()))
345 record.set("tract", dataId["tract"])
346 record.set("patch", dataId["patch"])
347 # Weight is used by CoaddPsf, but the PSFs from overlapping patches
348 # should be very similar, so this value mostly shouldn't matter.
349 record.set("weight", 1)
350
351 return images, catalog, totalBox
352
Cartesian polygons.
Definition Polygon.h:59
Custom catalog class for ExposureRecord/Table.
Definition Exposure.h:310
A floating-point coordinate rectangle geometry.
Definition Box.h:413
An integer coordinate rectangle.
Definition Box.h:55

◆ _makePsf()

lsst.ip.diffim.getTemplate._makePsf ( self,
template,
catalog,
wcs )
protected
Return a PSF containing the PSF at each of the input regions.

Note that although this includes all the exposures from the catalog,
the PSF knows which part of the template the inputs came from, so when
evaluated at a given position it will not include inputs that never
went in to those pixels.

Parameters
----------
template : `lsst.afw.image.Exposure`
    Generated template the PSF is for.
catalog : `lsst.afw.table.ExposureCatalog`
    Catalog of exposures that went into the template that contains all
    of the input PSFs.
wcs : `lsst.afw.geom.SkyWcs`
    WCS of the template, to warp the PSFs to.

Returns
-------
coaddPsf : `lsst.meas.algorithms.CoaddPsf`
    The meta-psf constructed from all of the input catalogs.

Definition at line 403 of file getTemplate.py.

403 def _makePsf(self, template, catalog, wcs):
404 """Return a PSF containing the PSF at each of the input regions.
405
406 Note that although this includes all the exposures from the catalog,
407 the PSF knows which part of the template the inputs came from, so when
408 evaluated at a given position it will not include inputs that never
409 went in to those pixels.
410
411 Parameters
412 ----------
413 template : `lsst.afw.image.Exposure`
414 Generated template the PSF is for.
415 catalog : `lsst.afw.table.ExposureCatalog`
416 Catalog of exposures that went into the template that contains all
417 of the input PSFs.
418 wcs : `lsst.afw.geom.SkyWcs`
419 WCS of the template, to warp the PSFs to.
420
421 Returns
422 -------
423 coaddPsf : `lsst.meas.algorithms.CoaddPsf`
424 The meta-psf constructed from all of the input catalogs.
425 """
426 # CoaddPsf centroid not only must overlap image, but must overlap the
427 # part of image with data. Use centroid of region with data.
428 boolmask = template.mask.array & template.mask.getPlaneBitMask('NO_DATA') == 0
429 maskx = afwImage.makeMaskFromArray(boolmask.astype(afwImage.MaskPixel))
430 centerCoord = afwGeom.SpanSet.fromMask(maskx, 1).computeCentroid()
431
432 ctrl = self.config.coaddPsf.makeControl()
433 coaddPsf = CoaddPsf(catalog, wcs, centerCoord, ctrl.warpingKernelName, ctrl.cacheSize)
434 return coaddPsf
435
436

◆ _merge()

lsst.ip.diffim.getTemplate._merge ( self,
maskedImages,
bbox,
wcs )
protected
Merge the images that came from one tract into one larger image,
ignoring NaN pixels and non-finite variance pixels from individual
exposures.

Parameters
----------
maskedImages : `list` [`lsst.afw.image.MaskedImage`]
    Images to be merged into one larger bounding box.
bbox : `lsst.geom.Box2I`
    Bounding box defining the image to merge into.
wcs : `lsst.afw.geom.SkyWcs`
    WCS of all of the input images to set on the output image.

Returns
-------
merged : `lsst.afw.image.MaskedImage`
    Merged image with all of the inputs at their respective bbox
    positions.

Definition at line 353 of file getTemplate.py.

353 def _merge(self, maskedImages, bbox, wcs):
354 """Merge the images that came from one tract into one larger image,
355 ignoring NaN pixels and non-finite variance pixels from individual
356 exposures.
357
358 Parameters
359 ----------
360 maskedImages : `list` [`lsst.afw.image.MaskedImage`]
361 Images to be merged into one larger bounding box.
362 bbox : `lsst.geom.Box2I`
363 Bounding box defining the image to merge into.
364 wcs : `lsst.afw.geom.SkyWcs`
365 WCS of all of the input images to set on the output image.
366
367 Returns
368 -------
369 merged : `lsst.afw.image.MaskedImage`
370 Merged image with all of the inputs at their respective bbox
371 positions.
372 """
373 merged = afwImage.ExposureF(bbox, wcs)
374 weights = afwImage.ImageF(bbox)
375 for maskedImage in maskedImages:
376 weight = afwImage.ImageF(maskedImage.variance.array**(-0.5))
377 bad = np.isnan(maskedImage.image.array) | ~np.isfinite(maskedImage.variance.array)
378 # Note that modifying the patch MaskedImage in place is fine;
379 # we're throwing it away at the end anyway.
380 maskedImage.image.array[bad] = 0.0
381 maskedImage.variance.array[bad] = 0.0
382 # Reset mask, too, since these pixels don't contribute to sum.
383 maskedImage.mask.array[bad] = 0
384 # Cannot use `merged.maskedImage *= weight` because that operator
385 # multiplies the variance by the weight twice; in this case
386 # `weight` are the exact values we want to scale by.
387 maskedImage.image *= weight
388 maskedImage.variance *= weight
389 merged.maskedImage[maskedImage.getBBox()] += maskedImage
390 # Clear the NaNs to ensure that areas missing from this input are
391 # masked with NO_DATA after the loop.
392 weight.array[np.isnan(weight.array)] = 0
393 weights[maskedImage.getBBox()] += weight
394 # Cannot use `merged.maskedImage /= weights` because that operator
395 # divides the variance by the weight twice; in this case `weights` are
396 # the exact values we want to scale by.
397 merged.image /= weights
398 merged.variance /= weights
399 merged.mask.array |= merged.mask.getPlaneBitMask("NO_DATA") * (weights.array == 0)
400
401 return merged
402

◆ _selectDataRef()

lsst.ip.diffim.getTemplate._selectDataRef ( coaddRef,
tract,
patch )
protected

Definition at line 620 of file getTemplate.py.

620def _selectDataRef(coaddRef, tract, patch):
621 condition = (coaddRef.dataId['tract'] == tract) & (coaddRef.dataId['patch'] == patch)
622 return condition

◆ checkPatchList()

lsst.ip.diffim.getTemplate.checkPatchList ( self,
patchList )
Check that all of the DcrModel subfilters are present for each
patch.

Parameters
----------
patchList : `dict`
    Dict of the patches containing valid data for each tract.

Raises
------
RuntimeError
    If the number of exposures found for a patch does not match the
    number of subfilters.

Definition at line 567 of file getTemplate.py.

567 def checkPatchList(self, patchList):
568 """Check that all of the DcrModel subfilters are present for each
569 patch.
570
571 Parameters
572 ----------
573 patchList : `dict`
574 Dict of the patches containing valid data for each tract.
575
576 Raises
577 ------
578 RuntimeError
579 If the number of exposures found for a patch does not match the
580 number of subfilters.
581 """
582 for tract in patchList:
583 for patch in set(patchList[tract]):
584 if patchList[tract].count(patch) != self.config.numSubfilters:
585 raise RuntimeError("Invalid number of DcrModel subfilters found: %d vs %d expected",
586 patchList[tract].count(patch), self.config.numSubfilters)
587

◆ getDcrModel()

lsst.ip.diffim.getTemplate.getDcrModel ( self,
patchList,
coaddRefs,
visitInfo )
Build DCR-matched coadds from a list of exposure references.

Parameters
----------
patchList : `dict`
    Dict of the patches containing valid data for each tract.
coaddRefs : `list` [`lsst.daf.butler.DeferredDatasetHandle`]
    Data references to `~lsst.afw.image.Exposure` representing
    DcrModels that overlap the detector.
visitInfo : `lsst.afw.image.VisitInfo`
    Metadata for the science image.

Returns
-------
coaddExposures : `list` [`lsst.afw.image.Exposure`]
    Coadd exposures that overlap the detector.

Definition at line 588 of file getTemplate.py.

588 def getDcrModel(self, patchList, coaddRefs, visitInfo):
589 """Build DCR-matched coadds from a list of exposure references.
590
591 Parameters
592 ----------
593 patchList : `dict`
594 Dict of the patches containing valid data for each tract.
595 coaddRefs : `list` [`lsst.daf.butler.DeferredDatasetHandle`]
596 Data references to `~lsst.afw.image.Exposure` representing
597 DcrModels that overlap the detector.
598 visitInfo : `lsst.afw.image.VisitInfo`
599 Metadata for the science image.
600
601 Returns
602 -------
603 coaddExposures : `list` [`lsst.afw.image.Exposure`]
604 Coadd exposures that overlap the detector.
605 """
606 coaddExposures = []
607 for tract in patchList:
608 for patch in set(patchList[tract]):
609 coaddRefList = [coaddRef for coaddRef in coaddRefs
610 if _selectDataRef(coaddRef, tract, patch)]
611
612 dcrModel = DcrModel.fromQuantum(coaddRefList,
613 self.config.effectiveWavelength,
614 self.config.bandwidth,
615 self.config.numSubfilters)
616 coaddExposures.append(dcrModel.buildMatchedExposure(visitInfo=visitInfo))
617 return coaddExposures
618
619

◆ run()

lsst.ip.diffim.getTemplate.run ( self,
coaddExposures,
bbox,
wcs,
dataIds,
physical_filter )
Warp coadds from multiple tracts and patches to form a template to
subtract from a science image.

Tract and patch overlap regions are combined by a variance-weighted
average, and the variance planes are combined with the same weights,
not added in quadrature; the overlap regions are not statistically
independent, because they're derived from the same original data.
The PSF on the template is created by combining the CoaddPsf on each
template image into a meta-CoaddPsf.

Parameters
----------
coaddExposures : `dict` [`int`, `list` [`lsst.afw.image.Exposure`]]
    Coadds to be mosaicked, indexed on tract id.
bbox : `lsst.geom.Box2I`
    Template Bounding box of the detector geometry onto which to
    resample the ``coaddExposures``. Modified in-place to include the
    template border.
wcs : `lsst.afw.geom.SkyWcs`
    Template WCS onto which to resample the ``coaddExposures``.
dataIds : `dict` [`int`, `list` [`lsst.daf.butler.DataCoordinate`]]
    Record of the tract and patch of each coaddExposure, indexed on
    tract id.
physical_filter : `str`
    Physical filter of the science image.

Returns
-------
result : `lsst.pipe.base.Struct`
   A struct with attributes:

   ``template``
       A template coadd exposure assembled out of patches
       (`lsst.afw.image.ExposureF`).

Raises
------
NoWorkFound
    If no coadds are found with sufficient un-masked pixels.

Definition at line 202 of file getTemplate.py.

202 def run(self, coaddExposures, bbox, wcs, dataIds, physical_filter):
203 """Warp coadds from multiple tracts and patches to form a template to
204 subtract from a science image.
205
206 Tract and patch overlap regions are combined by a variance-weighted
207 average, and the variance planes are combined with the same weights,
208 not added in quadrature; the overlap regions are not statistically
209 independent, because they're derived from the same original data.
210 The PSF on the template is created by combining the CoaddPsf on each
211 template image into a meta-CoaddPsf.
212
213 Parameters
214 ----------
215 coaddExposures : `dict` [`int`, `list` [`lsst.afw.image.Exposure`]]
216 Coadds to be mosaicked, indexed on tract id.
217 bbox : `lsst.geom.Box2I`
218 Template Bounding box of the detector geometry onto which to
219 resample the ``coaddExposures``. Modified in-place to include the
220 template border.
221 wcs : `lsst.afw.geom.SkyWcs`
222 Template WCS onto which to resample the ``coaddExposures``.
223 dataIds : `dict` [`int`, `list` [`lsst.daf.butler.DataCoordinate`]]
224 Record of the tract and patch of each coaddExposure, indexed on
225 tract id.
226 physical_filter : `str`
227 Physical filter of the science image.
228
229 Returns
230 -------
231 result : `lsst.pipe.base.Struct`
232 A struct with attributes:
233
234 ``template``
235 A template coadd exposure assembled out of patches
236 (`lsst.afw.image.ExposureF`).
237
238 Raises
239 ------
240 NoWorkFound
241 If no coadds are found with sufficient un-masked pixels.
242 """
243 band, photoCalib = self._checkInputs(dataIds, coaddExposures)
244
245 bbox.grow(self.config.templateBorderSize)
246
247 warped = {}
248 catalogs = []
249 for tract in coaddExposures:
250 maskedImages, catalog, totalBox = self._makeExposureCatalog(coaddExposures[tract],
251 dataIds[tract])
252 # Combine images from individual patches together.
253 unwarped = self._merge(maskedImages, totalBox, catalog[0].wcs)
254 potentialInput = self.warper.warpExposure(wcs, unwarped, destBBox=bbox)
255 if not np.any(np.isfinite(potentialInput.image.array)):
256 self.log.info("No overlap from coadds in tract %s; not including in output.", tract)
257 continue
258 catalogs.append(catalog)
259 warped[tract] = potentialInput
260 warped[tract].setWcs(wcs)
261
262 if len(warped) == 0:
263 raise pipeBase.NoWorkFound("No patches found to overlap science exposure.")
264 template = self._merge([x.maskedImage for x in warped.values()], bbox, wcs)
265
266 # Make a single catalog containing all the inputs that were accepted.
267 catalog = afwTable.ExposureCatalog(self.schema)
268 catalog.reserve(sum([len(c) for c in catalogs]))
269 for c in catalogs:
270 catalog.extend(c)
271
272 template.setPsf(self._makePsf(template, catalog, wcs))
273 template.setFilter(afwImage.FilterLabel(band, physical_filter))
274 template.setPhotoCalib(photoCalib)
275 return pipeBase.Struct(template=template)
276
A group of labels for a filter in an exposure or coadd.
Definition FilterLabel.h:58

Variable Documentation

◆ coaddExposureRefList

list lsst.ip.diffim.getTemplate.coaddExposureRefList = []

Definition at line 538 of file getTemplate.py.

◆ coaddExposures

lsst.ip.diffim.getTemplate.coaddExposures = collections.defaultdict(list)

Definition at line 179 of file getTemplate.py.

◆ dataId

lsst.ip.diffim.getTemplate.dataId = coaddRef.dataId

Definition at line 184 of file getTemplate.py.

◆ dataIds

list lsst.ip.diffim.getTemplate.dataIds = collections.defaultdict(list)

Definition at line 180 of file getTemplate.py.

◆ detectorPolygon

lsst.ip.diffim.getTemplate.detectorPolygon = geom.Box2D(inputs['bbox'])

Definition at line 177 of file getTemplate.py.

◆ overlappingArea

int lsst.ip.diffim.getTemplate.overlappingArea = 0

Definition at line 178 of file getTemplate.py.

◆ patchBBox

lsst.ip.diffim.getTemplate.patchBBox = skymap[dataId['tract']][dataId['patch']].getOuterBBox()

Definition at line 186 of file getTemplate.py.

◆ patchCorners

lsst.ip.diffim.getTemplate.patchCorners = patchWcs.pixelToSky(geom.Box2D(patchBBox).getCorners())

Definition at line 187 of file getTemplate.py.

◆ patchList

lsst.ip.diffim.getTemplate.patchList = dict()

Definition at line 540 of file getTemplate.py.

◆ patchPolygon

lsst.ip.diffim.getTemplate.patchPolygon = afwGeom.Polygon(wcs.skyToPixel(patchCorners))

Definition at line 188 of file getTemplate.py.

◆ patchWcs

lsst.ip.diffim.getTemplate.patchWcs = skymap[dataId['tract']].getWcs()

Definition at line 185 of file getTemplate.py.

◆ skymap

lsst.ip.diffim.getTemplate.skymap = inputs['skyMap']

Definition at line 182 of file getTemplate.py.