LSSTApplications  20.0.0
LSSTDataManagementBasePackage
backgroundList.py
Go to the documentation of this file.
1 # This file is part of afw.
2 #
3 # Developed for the LSST Data Management System.
4 # This product includes software developed by the LSST Project
5 # (https://www.lsst.org).
6 # See the COPYRIGHT file at the top-level directory of this distribution
7 # for details of code ownership.
8 #
9 # This program is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
13 #
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
18 #
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <https://www.gnu.org/licenses/>.
21 
22 __all__ = ["BackgroundList"]
23 
24 import os
25 import lsst.daf.base as dafBase
26 import lsst.geom
27 import lsst.afw.image as afwImage
28 from lsst.afw.fits import MemFileManager, reduceToFits, Fits
29 from . import mathLib as afwMath
30 
31 
33  """A list-like class to contain a list of (`lsst.afw.math.Background`,
34  `lsst.afw.math.Interpolate.Style`, `~lsst.afw.math.UndersampleStyle`)
35  tuples.
36 
37  Parameters
38  ----------
39  *args : `tuple` or `~lsst.afw.math.Background`
40  A sequence of arguments, each of which becomes an element of the list.
41  We also accept a single `lsst.afw.math.Background` and extract the
42  ``interpStyle`` and ``undersampleStyle`` from the as-used values.
43  """
44 
45  def __init__(self, *args):
46  self._backgrounds = []
47  for a in args:
48  self.append(a)
49 
50  def __getitem__(self, *args):
51  """Return an item
52 
53  Parameters
54  ----------
55  *args
56  Any valid list index.
57  """
58  #
59  # Set any previously-unknown Styles (they are set by bkgd.getImage())
60  #
61  for i, val in enumerate(self._backgrounds):
62  bkgd, interpStyle, undersampleStyle, approxStyle, \
63  approxOrderX, approxOrderY, approxWeighting = val
64  if interpStyle is None or undersampleStyle is None:
65  interpStyle = bkgd.getAsUsedInterpStyle()
66  undersampleStyle = bkgd.getAsUsedUndersampleStyle()
67  actrl = bkgd.getBackgroundControl().getApproximateControl()
68  approxStyle = actrl.getStyle()
69  approxOrderX = actrl.getOrderX()
70  approxOrderY = actrl.getOrderY()
71  approxWeighting = actrl.getWeighting()
72  self._backgrounds[i] = (bkgd, interpStyle, undersampleStyle,
73  approxStyle, approxOrderX, approxOrderY, approxWeighting)
74  #
75  # And return what they wanted
76  #
77  return self._backgrounds.__getitem__(*args)
78 
79  def __len__(self, *args):
80  return self._backgrounds.__len__(*args)
81 
82  def append(self, val):
83  try:
84  bkgd, interpStyle, undersampleStyle, approxStyle, \
85  approxOrderX, approxOrderY, approxWeighting = val
86  except TypeError:
87  bkgd = val
88  interpStyle = None
89  undersampleStyle = None
90  approxStyle = None
91  approxOrderX = None
92  approxOrderY = None
93  approxWeighting = None
94 
95  bgInfo = (bkgd, interpStyle, undersampleStyle, approxStyle,
96  approxOrderX, approxOrderY, approxWeighting)
97  self._backgrounds.append(bgInfo)
98 
99  def clone(self):
100  """Return a shallow copy
101 
102  Shallow copies do not share backgrounds that are appended after copying,
103  but do share changes to contained background objects.
104  """
105  return BackgroundList(*self)
106 
107  def writeFits(self, fileName, flags=0):
108  """Save our list of Backgrounds to a file.
109 
110  Parameters
111  -----------
112  fileName : `str`
113  FITS file to write
114  flags : `int`
115  Flags to control details of writing; currently unused, but present
116  for consistency with `lsst.afw.table.BaseCatalog.writeFits`.
117  """
118 
119  for i, bkgd in enumerate(self):
120  (bkgd, interpStyle, undersampleStyle, approxStyle, approxOrderX, approxOrderY,
121  approxWeighting) = bkgd
122 
123  statsImage = bkgd.getStatsImage()
124 
125  md = dafBase.PropertyList()
126  md.set("INTERPSTYLE", int(interpStyle))
127  md.set("UNDERSAMPLESTYLE", int(undersampleStyle))
128  md.set("APPROXSTYLE", int(approxStyle))
129  md.set("APPROXORDERX", approxOrderX)
130  md.set("APPROXORDERY", approxOrderY)
131  md.set("APPROXWEIGHTING", approxWeighting)
132  bbox = bkgd.getImageBBox()
133  md.set("BKGD_X0", bbox.getMinX())
134  md.set("BKGD_Y0", bbox.getMinY())
135  md.set("BKGD_WIDTH", bbox.getWidth())
136  md.set("BKGD_HEIGHT", bbox.getHeight())
137 
138  statsImage.getImage().writeFits(fileName, md, "w" if i == 0 else "a")
139  statsImage.getMask().writeFits(fileName, md, "a")
140  statsImage.getVariance().writeFits(fileName, md, "a")
141 
142  @staticmethod
143  def readFits(fileName, hdu=0, flags=0):
144  """Read our list of Backgrounds from a file.
145 
146  Parameters
147  ----------
148  fileName : `str`
149  FITS file to read
150  hdu : `int`
151  First Header/Data Unit to attempt to read from
152  flags : `int`
153  Flags to control details of reading; currently unused, but present
154  for consistency with `lsst.afw.table.BaseCatalog.readFits`.
155 
156  See Also
157  --------
158  getImage()
159  """
160  if not isinstance(fileName, MemFileManager) and not os.path.exists(fileName):
161  raise RuntimeError(f"File not found: {fileName}")
162 
163  self = BackgroundList()
164 
165  f = Fits(fileName, 'r')
166  nHdus = f.countHdus()
167  f.closeFile()
168  if nHdus % 3 != 0:
169  raise RuntimeError(f"BackgroundList FITS file {fileName} has {nHdus} HDUs;"
170  f"expected a multiple of 3 (compression is not supported).")
171 
172  for hdu in range(0, nHdus, 3):
173  # It seems like we ought to be able to just use
174  # MaskedImageFitsReader here, but it warns about EXTTYPE and still
175  # doesn't work quite naturally when starting from a nonzero HDU.
176  imageReader = afwImage.ImageFitsReader(fileName, hdu=hdu)
177  maskReader = afwImage.MaskFitsReader(fileName, hdu=hdu + 1)
178  varianceReader = afwImage.ImageFitsReader(fileName, hdu=hdu + 2)
179  statsImage = afwImage.MaskedImageF(imageReader.read(), maskReader.read(), varianceReader.read())
180  md = imageReader.readMetadata()
181 
182  x0 = md["BKGD_X0"]
183  y0 = md["BKGD_Y0"]
184  width = md["BKGD_WIDTH"]
185  height = md["BKGD_HEIGHT"]
186  imageBBox = lsst.geom.BoxI(lsst.geom.PointI(x0, y0), lsst.geom.ExtentI(width, height))
187 
188  interpStyle = afwMath.Interpolate.Style(md["INTERPSTYLE"])
189  undersampleStyle = afwMath.UndersampleStyle(md["UNDERSAMPLESTYLE"])
190 
191  # Older outputs won't have APPROX* settings. Provide alternative defaults.
192  # Note: Currently X- and Y-orders must be equal due to a limitation in
193  # math::Chebyshev1Function2. Setting approxOrderY = -1 is equivalent
194  # to saying approxOrderY = approxOrderX.
195  approxStyle = md.get("APPROXSTYLE", afwMath.ApproximateControl.UNKNOWN)
196  approxStyle = afwMath.ApproximateControl.Style(approxStyle)
197  approxOrderX = md.get("APPROXORDERX", 1)
198  approxOrderY = md.get("APPROXORDERY", -1)
199  approxWeighting = md.get("APPROXWEIGHTING", True)
200 
201  bkgd = afwMath.BackgroundMI(imageBBox, statsImage)
202  bctrl = bkgd.getBackgroundControl()
203  bctrl.setInterpStyle(interpStyle)
204  bctrl.setUndersampleStyle(undersampleStyle)
205  actrl = afwMath.ApproximateControl(approxStyle, approxOrderX, approxOrderY, approxWeighting)
206  bctrl.setApproximateControl(actrl)
207  bgInfo = (bkgd, interpStyle, undersampleStyle, approxStyle,
208  approxOrderX, approxOrderY, approxWeighting)
209  self.append(bgInfo)
210 
211  return self
212 
213  def getImage(self):
214  """Compute and return a full-resolution image from our list of
215  (Background, interpStyle, undersampleStyle).
216  """
217 
218  bkgdImage = None
219  for (bkgd, interpStyle, undersampleStyle, approxStyle,
220  approxOrderX, approxOrderY, approxWeighting) in self:
221  if not bkgdImage:
222  if approxStyle != afwMath.ApproximateControl.UNKNOWN:
223  bkgdImage = bkgd.getImageF()
224  else:
225  bkgdImage = bkgd.getImageF(interpStyle, undersampleStyle)
226  else:
227  if approxStyle != afwMath.ApproximateControl.UNKNOWN:
228  bkgdImage += bkgd.getImageF()
229  else:
230  bkgdImage += bkgd.getImageF(interpStyle, undersampleStyle)
231 
232  return bkgdImage
233 
234  def __reduce__(self):
235  return reduceToFits(self)
lsst::afw::image::MaskFitsReader
A FITS reader class for Masks.
Definition: MaskFitsReader.h:39
lsst::afw::image
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
Definition: imageAlgorithm.dox:1
lsst::afw::math::UndersampleStyle
UndersampleStyle
Definition: Background.h:47
lsst::afw::math.backgroundList.BackgroundList.__getitem__
def __getitem__(self, *args)
Definition: backgroundList.py:50
lsst::afw::fits::Fits
A simple struct that combines the two arguments that must be passed to most cfitsio routines and cont...
Definition: fits.h:297
lsst::afw::math.backgroundList.BackgroundList.getImage
def getImage(self)
Definition: backgroundList.py:213
lsst::daf::base::PropertyList
Class for storing ordered metadata with comments.
Definition: PropertyList.h:68
lsst::afw::math.backgroundList.BackgroundList.readFits
def readFits(fileName, hdu=0, flags=0)
Definition: backgroundList.py:143
lsst::afw::math::BackgroundMI
A class to evaluate image background levels.
Definition: Background.h:434
lsst::afw::math.backgroundList.BackgroundList.__reduce__
def __reduce__(self)
Definition: backgroundList.py:234
lsst::afw::image::ImageFitsReader
A FITS reader class for regular Images.
Definition: ImageFitsReader.h:39
lsst::afw::math.backgroundList.BackgroundList.__init__
def __init__(self, *args)
Definition: backgroundList.py:45
lsst::afw::math.backgroundList.BackgroundList.writeFits
def writeFits(self, fileName, flags=0)
Definition: backgroundList.py:107
lsst::afw::math.backgroundList.BackgroundList
Definition: backgroundList.py:32
lsst::afw::math.backgroundList.BackgroundList._backgrounds
_backgrounds
Definition: backgroundList.py:46
lsst::afw::math.backgroundList.BackgroundList.clone
def clone(self)
Definition: backgroundList.py:99
lsst::afw::fits.pickleFits.reduceToFits
def reduceToFits(obj)
Definition: pickleFits.py:7
lsst::afw::math.backgroundList.BackgroundList.__len__
def __len__(self, *args)
Definition: backgroundList.py:79
lsst::geom
Definition: geomOperators.dox:4
lsst::daf::base
Definition: Utils.h:47
lsst::afw::fits
Definition: fits.h:31
lsst::afw::math::ApproximateControl
Control how to make an approximation.
Definition: Approximate.h:48
lsst::afw::math.backgroundList.BackgroundList.append
def append(self, val)
Definition: backgroundList.py:82
lsst::geom::Point< int, 2 >
lsst::geom::Box2I
An integer coordinate rectangle.
Definition: Box.h:55
lsst::geom::Extent< int, 2 >