lsst.pipe.tasks  13.0-66-gfbf2f2ce+5
warpAndPsfMatch.py
Go to the documentation of this file.
1 #
2 # LSST Data Management System
3 # Copyright 2008, 2009, 2010, 2011, 2012 LSST Corporation.
4 #
5 # This product includes software developed by the
6 # LSST Project (http://www.lsst.org/).
7 #
8 # This program is free software: you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation, either version 3 of the License, or
11 # (at your option) any later version.
12 #
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 # GNU General Public License for more details.
17 #
18 # You should have received a copy of the LSST License Statement and
19 # the GNU General Public License along with this program. If not,
20 # see <http://www.lsstcorp.org/LegalNotices/>.
21 #
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
30 
31 __all__ = ["WarpAndPsfMatchTask"]
32 
33 
34 class WarpAndPsfMatchConfig(pexConfig.Config):
35  """Config for WarpAndPsfMatchTask
36  """
37  psfMatch = pexConfig.ConfigurableField(
38  target=ModelPsfMatchTask,
39  doc="PSF matching model to model task",
40  )
41  warp = pexConfig.ConfigField(
42  dtype=afwMath.Warper.ConfigClass,
43  doc="warper configuration",
44  )
45 
46 
47 class WarpAndPsfMatchTask(pipeBase.Task):
48  """A task to warp and PSF-match an exposure
49  """
50  ConfigClass = WarpAndPsfMatchConfig
51 
52  def __init__(self, *args, **kwargs):
53  pipeBase.Task.__init__(self, *args, **kwargs)
54  self.makeSubtask("psfMatch")
55  self.warper = afwMath.Warper.fromConfig(self.config.warp)
56 
57  def run(self, exposure, wcs, modelPsf=None, maxBBox=None, destBBox=None,
58  makeDirect=True, makePsfMatched=False):
59  """Warp and optionally PSF-match exposure
60 
61  Parameters
62  ----------
63  exposure : :cpp:class: `lsst::afw::image::Exposure`
64  Exposure to preprocess.
65  wcs : :cpp:class:`lsst::afw::image::Wcs`
66  Desired WCS of temporary images.
67  modelPsf : :cpp:class: `lsst::meas::algorithms::KernelPsf` or None
68  Target PSF to which to match.
69  maxBBox : :cpp:class:`lsst::afw::geom::Box2I` or None
70  Maximum allowed parent bbox of warped exposure.
71  If None then the warped exposure will be just big enough to contain all warped pixels;
72  if provided then the warped exposure may be smaller, and so missing some warped pixels;
73  ignored if destBBox is not None.
74  destBBox: :cpp:class: `lsst::afw::geom::Box2I` or None
75  Exact parent bbox of warped exposure.
76  If None then maxBBox is used to determine the bbox, otherwise maxBBox is ignored.
77  makeDirect : bool
78  Return an exposure that has been only warped?
79  makePsfMatched : bool
80  Return an exposure that has been warped and PSF-matched?
81 
82  Returns
83  -------
84  An lsst.pipe.base.Struct with the following fields:
85 
86  direct : :cpp:class:`lsst::afw::image::Exposure`
87  warped exposure
88  psfMatched : :cpp:class: `lsst::afw::image::Exposure`
89  warped and psf-Matched temporary exposure
90  """
91  if makePsfMatched and modelPsf is None:
92  raise RuntimeError("makePsfMatched=True, but no model PSF was provided")
93 
94  if not makePsfMatched and not makeDirect:
95  self.log.warn("Neither makeDirect nor makePsfMatched requested")
96 
97  # Warp PSF before overwriting exposure
98  xyTransform = afwImage.XYTransformFromWcsPair(wcs, exposure.getWcs())
99  psfWarped = WarpedPsf(exposure.getPsf(), xyTransform)
100 
101  if makePsfMatched and maxBBox is not None:
102  # grow warped region to provide sufficient area for PSF-matching
103  pixToGrow = 2 * max(self.psfMatch.kConfig.sizeCellX,
104  self.psfMatch.kConfig.sizeCellY)
105  # replace with copy
106  maxBBox = afwGeom.Box2I(maxBBox)
107  maxBBox.grow(pixToGrow)
108 
109  with self.timer("warp"):
110  exposure = self.warper.warpExposure(wcs, exposure, maxBBox=maxBBox, destBBox=destBBox)
111  exposure.setPsf(psfWarped)
112 
113  if makePsfMatched:
114  try:
115  exposurePsfMatched = self.psfMatch.run(exposure, modelPsf).psfMatchedExposure
116  except Exception as e:
117  exposurePsfMatched = None
118  self.log.info("Cannot PSF-Match: %s" % (e))
119 
120  return pipeBase.Struct(
121  direct=exposure if makeDirect else None,
122  psfMatched=exposurePsfMatched if makePsfMatched else None
123  )
def run(self, exposure, wcs, modelPsf=None, maxBBox=None, destBBox=None, makeDirect=True, makePsfMatched=False)