LSSTApplications  18.1.0
LSSTDataManagementBasePackage
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 import lsst.pex.config as pexConfig
23 import lsst.afw.math as afwMath
24 import lsst.afw.geom as afwGeom
25 import lsst.pipe.base as pipeBase
26 from lsst.ip.diffim import ModelPsfMatchTask
27 from lsst.meas.algorithms import WarpedPsf
28 
29 __all__ = ["WarpAndPsfMatchTask"]
30 
31 
32 class WarpAndPsfMatchConfig(pexConfig.Config):
33  """Config for WarpAndPsfMatchTask
34  """
35  psfMatch = pexConfig.ConfigurableField(
36  target=ModelPsfMatchTask,
37  doc="PSF matching model to model task",
38  )
39  warp = pexConfig.ConfigField(
40  dtype=afwMath.Warper.ConfigClass,
41  doc="warper configuration",
42  )
43 
44 
45 class WarpAndPsfMatchTask(pipeBase.Task):
46  """A task to warp and PSF-match an exposure
47  """
48  ConfigClass = WarpAndPsfMatchConfig
49 
50  def __init__(self, *args, **kwargs):
51  pipeBase.Task.__init__(self, *args, **kwargs)
52  self.makeSubtask("psfMatch")
53  self.warper = afwMath.Warper.fromConfig(self.config.warp)
54 
55  def run(self, exposure, wcs, modelPsf=None, maxBBox=None, destBBox=None,
56  makeDirect=True, makePsfMatched=False):
57  """Warp and optionally PSF-match exposure
58 
59  Parameters
60  ----------
61  exposure : :cpp:class: `lsst::afw::image::Exposure`
62  Exposure to preprocess.
63  wcs : :cpp:class:`lsst::afw::image::Wcs`
64  Desired WCS of temporary images.
65  modelPsf : :cpp:class: `lsst::meas::algorithms::KernelPsf` or None
66  Target PSF to which to match.
67  maxBBox : :cpp:class:`lsst::afw::geom::Box2I` or None
68  Maximum allowed parent bbox of warped exposure.
69  If None then the warped exposure will be just big enough to contain all warped pixels;
70  if provided then the warped exposure may be smaller, and so missing some warped pixels;
71  ignored if destBBox is not None.
72  destBBox: :cpp:class: `lsst::afw::geom::Box2I` or None
73  Exact parent bbox of warped exposure.
74  If None then maxBBox is used to determine the bbox, otherwise maxBBox is ignored.
75  makeDirect : bool
76  Return an exposure that has been only warped?
77  makePsfMatched : bool
78  Return an exposure that has been warped and PSF-matched?
79 
80  Returns
81  -------
82  An lsst.pipe.base.Struct with the following fields:
83 
84  direct : :cpp:class:`lsst::afw::image::Exposure`
85  warped exposure
86  psfMatched : :cpp:class: `lsst::afw::image::Exposure`
87  warped and psf-Matched temporary exposure
88  """
89  if makePsfMatched and modelPsf is None:
90  raise RuntimeError("makePsfMatched=True, but no model PSF was provided")
91 
92  if not makePsfMatched and not makeDirect:
93  self.log.warn("Neither makeDirect nor makePsfMatched requested")
94 
95  # Warp PSF before overwriting exposure
96  xyTransform = afwGeom.makeWcsPairTransform(exposure.getWcs(), wcs)
97  psfWarped = WarpedPsf(exposure.getPsf(), xyTransform)
98 
99  if makePsfMatched and maxBBox is not None:
100  # grow warped region to provide sufficient area for PSF-matching
101  pixToGrow = 2 * max(self.psfMatch.kConfig.sizeCellX,
102  self.psfMatch.kConfig.sizeCellY)
103  # replace with copy
104  maxBBox = afwGeom.Box2I(maxBBox)
105  maxBBox.grow(pixToGrow)
106 
107  with self.timer("warp"):
108  exposure = self.warper.warpExposure(wcs, exposure, maxBBox=maxBBox, destBBox=destBBox)
109  exposure.setPsf(psfWarped)
110 
111  if makePsfMatched:
112  try:
113  exposurePsfMatched = self.psfMatch.run(exposure, modelPsf).psfMatchedExposure
114  except Exception as e:
115  exposurePsfMatched = None
116  self.log.info("Cannot PSF-Match: %s" % (e))
117 
118  return pipeBase.Struct(
119  direct=exposure if makeDirect else None,
120  psfMatched=exposurePsfMatched if makePsfMatched else None
121  )
Fit spatial kernel using approximate fluxes for candidates, and solving a linear system of equations...
def run(self, exposure, wcs, modelPsf=None, maxBBox=None, destBBox=None, makeDirect=True, makePsfMatched=False)
int max
std::shared_ptr< TransformPoint2ToPoint2 > makeWcsPairTransform(SkyWcs const &src, SkyWcs const &dst)
A Transform obtained by putting two SkyWcs objects "back to back".
Definition: SkyWcs.cc:152
An integer coordinate rectangle.
Definition: Box.h:54
A Psf class that maps an arbitrary Psf through a coordinate transformation.
Definition: WarpedPsf.h:50