22 from __future__
import absolute_import, division, print_function
23 import lsst.pex.config
as pexConfig
24 import lsst.afw.math
as afwMath
25 import lsst.afw.image
as afwImage
26 import lsst.afw.geom
as afwGeom
27 import lsst.pipe.base
as pipeBase
28 from lsst.ip.diffim
import ModelPsfMatchTask
29 from lsst.meas.algorithms
import WarpedPsf
31 __all__ = [
"WarpAndPsfMatchTask"]
35 """Config for WarpAndPsfMatchTask
37 psfMatch = pexConfig.ConfigurableField(
38 target=ModelPsfMatchTask,
39 doc=
"PSF matching model to model task",
41 warp = pexConfig.ConfigField(
42 dtype=afwMath.Warper.ConfigClass,
43 doc=
"warper configuration",
45 matchThenWarp = pexConfig.Field(
47 doc=
"Reverse order of warp and match operations to replicate legacy coadd temporary exposures",
53 """A task to warp and PSF-match an exposure
55 ConfigClass = WarpAndPsfMatchConfig
58 pipeBase.Task.__init__(self, *args, **kwargs)
59 self.makeSubtask(
"psfMatch")
60 self.
warper = afwMath.Warper.fromConfig(self.config.warp)
62 def run(self, exposure, wcs, modelPsf=None, maxBBox=None, destBBox=None):
63 """Warp and PSF-match exposure (if modelPsf is not None)
67 exposure : :cpp:class: `lsst::afw::image::Exposure`
68 Exposure to preprocess. PSF matching is done in place.
69 wcs : :cpp:class:`lsst::afw::image::Wcs`
70 Desired WCS of temporary images.
71 modelPsf : :cpp:class: `lsst::meas::algorithms::KernelPsf` or None
72 Target PSF to which to match.
73 If None then exposures are not PSF matched.
74 maxBBox : :cpp:class:`lsst::afw::geom::Box2I` or None
75 Maximum allowed parent bbox of warped exposure.
76 If None then the warped exposure will be just big enough to contain all warped pixels;
77 if provided then the warped exposure may be smaller, and so missing some warped pixels;
78 ignored if destBBox is not None.
79 destBBox: :cpp:class: `lsst::afw::geom::Box2I` or None
80 Exact parent bbox of warped exposure.
81 If None then maxBBox is used to determine the bbox, otherwise maxBBox is ignored.
86 An lsst.pipe.base.Struct with the following fields:
88 exposure : :cpp:class:`lsst::afw::image::Exposure`
91 if self.config.matchThenWarp:
96 if modelPsf
is not None:
97 exposure = self.psfMatch.run(exposure, modelPsf).psfMatchedExposure
98 with self.timer(
"warp"):
99 exposure = self.warper.warpExposure(wcs, exposure, maxBBox=maxBBox, destBBox=destBBox)
101 if modelPsf
is not None:
103 xyTransform = afwImage.XYTransformFromWcsPair(wcs, exposure.getWcs())
104 psfWarped = WarpedPsf(exposure.getPsf(), xyTransform)
106 if maxBBox
is not None:
108 pixToGrow = 2 * max(self.config.psfMatch.kernel.active.sizeCellX,
109 self.config.psfMatch.kernel.active.sizeCellY)
111 maxBBox = afwGeom.Box2I(maxBBox)
112 maxBBox.grow(pixToGrow)
114 with self.timer(
"warp"):
115 exposure = self.warper.warpExposure(wcs, exposure, maxBBox=maxBBox, destBBox=destBBox)
117 if modelPsf
is not None:
118 exposure.setPsf(psfWarped)
119 exposure = self.psfMatch.run(exposure, modelPsf).psfMatchedExposure
121 return pipeBase.Struct(