LSSTApplications  18.0.0+106,18.0.0+50,19.0.0,19.0.0+1,19.0.0+10,19.0.0+11,19.0.0+13,19.0.0+17,19.0.0+2,19.0.0-1-g20d9b18+6,19.0.0-1-g425ff20,19.0.0-1-g5549ca4,19.0.0-1-g580fafe+6,19.0.0-1-g6fe20d0+1,19.0.0-1-g7011481+9,19.0.0-1-g8c57eb9+6,19.0.0-1-gb5175dc+11,19.0.0-1-gdc0e4a7+9,19.0.0-1-ge272bc4+6,19.0.0-1-ge3aa853,19.0.0-10-g448f008b,19.0.0-12-g6990b2c,19.0.0-2-g0d9f9cd+11,19.0.0-2-g3d9e4fb2+11,19.0.0-2-g5037de4,19.0.0-2-gb96a1c4+3,19.0.0-2-gd955cfd+15,19.0.0-3-g2d13df8,19.0.0-3-g6f3c7dc,19.0.0-4-g725f80e+11,19.0.0-4-ga671dab3b+1,19.0.0-4-gad373c5+3,19.0.0-5-ga2acb9c+2,19.0.0-5-gfe96e6c+2,w.2020.01
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 warnings
26 import lsst.daf.base as dafBase
27 import lsst.geom
28 import lsst.afw.image as afwImage
29 from lsst.afw.fits import MemFileManager, reduceToFits, Fits
30 from . import mathLib as afwMath
31 
32 
34  """A list-like class to contain a list of (`lsst.afw.math.Background`,
35  `lsst.afw.math.Interpolate.Style`, `~lsst.afw.math.UndersampleStyle`)
36  tuples.
37 
38  Parameters
39  ----------
40  *args : `tuple` or `~lsst.afw.math.Background`
41  A sequence of arguments, each of which becomes an element of the list.
42  In deference to the deprecated-but-not-yet-removed
43  `~lsst.afw.math.Background.getImageF()` API, we also accept a single
44  `lsst.afw.math.Background` and extract the ``interpStyle`` and
45  ``undersampleStyle`` from the as-used values.
46  """
47 
48  def __init__(self, *args):
49  self._backgrounds = []
50  for a in args:
51  self.append(a)
52 
53  def __getitem__(self, *args):
54  """Return an item
55 
56  Parameters
57  ----------
58  *args
59  Any valid list index.
60  """
61  #
62  # Set any previously-unknown Styles (they are set by bkgd.getImage())
63  #
64  for i, val in enumerate(self._backgrounds):
65  bkgd, interpStyle, undersampleStyle, approxStyle, \
66  approxOrderX, approxOrderY, approxWeighting = val
67  if interpStyle is None or undersampleStyle is None:
68  interpStyle = bkgd.getAsUsedInterpStyle()
69  undersampleStyle = bkgd.getAsUsedUndersampleStyle()
70  actrl = bkgd.getBackgroundControl().getApproximateControl()
71  approxStyle = actrl.getStyle()
72  approxOrderX = actrl.getOrderX()
73  approxOrderY = actrl.getOrderY()
74  approxWeighting = actrl.getWeighting()
75  self._backgrounds[i] = (bkgd, interpStyle, undersampleStyle,
76  approxStyle, approxOrderX, approxOrderY, approxWeighting)
77  #
78  # And return what they wanted
79  #
80  return self._backgrounds.__getitem__(*args)
81 
82  def __len__(self, *args):
83  return self._backgrounds.__len__(*args)
84 
85  def append(self, val):
86  try:
87  bkgd, interpStyle, undersampleStyle, approxStyle, \
88  approxOrderX, approxOrderY, approxWeighting = val
89  except TypeError:
90  warnings.warn("Passing Background objects to BackgroundList is deprecated; "
91  "use a (Background, Interpolation.Style, UndersampleStyle, "
92  "ApproximateControl.Style, int, int, bool) tuple instead.",
93  category=FutureWarning, stacklevel=2)
94  bkgd = val
95  interpStyle = None
96  undersampleStyle = None
97  approxStyle = None
98  approxOrderX = None
99  approxOrderY = None
100  approxWeighting = None
101 
102  bgInfo = (bkgd, interpStyle, undersampleStyle, approxStyle,
103  approxOrderX, approxOrderY, approxWeighting)
104  self._backgrounds.append(bgInfo)
105 
106  def clone(self):
107  """Return a shallow copy
108 
109  Shallow copies do not share backgrounds that are appended after copying,
110  but do share changes to contained background objects.
111  """
112  return BackgroundList(*self)
113 
114  def writeFits(self, fileName, flags=0):
115  """Save our list of Backgrounds to a file.
116 
117  Parameters
118  -----------
119  fileName : `str`
120  FITS file to write
121  flags : `int`
122  Flags to control details of writing; currently unused, but present
123  for consistency with `lsst.afw.table.BaseCatalog.writeFits`.
124  """
125 
126  for i, bkgd in enumerate(self):
127  (bkgd, interpStyle, undersampleStyle, approxStyle, approxOrderX, approxOrderY,
128  approxWeighting) = bkgd
129 
130  statsImage = bkgd.getStatsImage()
131 
132  md = dafBase.PropertyList()
133  md.set("INTERPSTYLE", int(interpStyle))
134  md.set("UNDERSAMPLESTYLE", int(undersampleStyle))
135  md.set("APPROXSTYLE", int(approxStyle))
136  md.set("APPROXORDERX", approxOrderX)
137  md.set("APPROXORDERY", approxOrderY)
138  md.set("APPROXWEIGHTING", approxWeighting)
139  bbox = bkgd.getImageBBox()
140  md.set("BKGD_X0", bbox.getMinX())
141  md.set("BKGD_Y0", bbox.getMinY())
142  md.set("BKGD_WIDTH", bbox.getWidth())
143  md.set("BKGD_HEIGHT", bbox.getHeight())
144 
145  statsImage.getImage().writeFits(fileName, md, "w" if i == 0 else "a")
146  statsImage.getMask().writeFits(fileName, md, "a")
147  statsImage.getVariance().writeFits(fileName, md, "a")
148 
149  @staticmethod
150  def readFits(fileName, hdu=0, flags=0):
151  """Read our list of Backgrounds from a file.
152 
153  Parameters
154  ----------
155  fileName : `str`
156  FITS file to read
157  hdu : `int`
158  First Header/Data Unit to attempt to read from
159  flags : `int`
160  Flags to control details of reading; currently unused, but present
161  for consistency with `lsst.afw.table.BaseCatalog.readFits`.
162 
163  See Also
164  --------
165  getImage()
166  """
167  if not isinstance(fileName, MemFileManager) and not os.path.exists(fileName):
168  raise RuntimeError("File not found: %s" % fileName)
169 
170  self = BackgroundList()
171 
172  f = Fits(fileName, 'r')
173  nHdus = f.countHdus()
174  f.closeFile()
175  if nHdus % 3 != 0:
176  raise RuntimeError(f"BackgroundList FITS file {fileName} has {nHdus} HDUs;"
177  f"expected a multiple of 3 (compression is not supported).")
178 
179  for hdu in range(0, nHdus, 3):
180  # It seems like we ought to be able to just use
181  # MaskedImageFitsReader here, but it warns about EXTTYPE and still
182  # doesn't work quite naturally when starting from a nonzero HDU.
183  imageReader = afwImage.ImageFitsReader(fileName, hdu=hdu)
184  maskReader = afwImage.MaskFitsReader(fileName, hdu=hdu + 1)
185  varianceReader = afwImage.ImageFitsReader(fileName, hdu=hdu + 2)
186  statsImage = afwImage.MaskedImageF(imageReader.read(), maskReader.read(), varianceReader.read())
187  md = imageReader.readMetadata()
188 
189  x0 = md["BKGD_X0"]
190  y0 = md["BKGD_Y0"]
191  width = md["BKGD_WIDTH"]
192  height = md["BKGD_HEIGHT"]
193  imageBBox = lsst.geom.BoxI(lsst.geom.PointI(x0, y0), lsst.geom.ExtentI(width, height))
194 
195  interpStyle = afwMath.Interpolate.Style(md["INTERPSTYLE"])
196  undersampleStyle = afwMath.UndersampleStyle(md["UNDERSAMPLESTYLE"])
197 
198  # Older outputs won't have APPROX* settings. Provide alternative defaults.
199  # Note: Currently X- and Y-orders must be equal due to a limitation in
200  # math::Chebyshev1Function2. Setting approxOrderY = -1 is equivalent
201  # to saying approxOrderY = approxOrderX.
202  approxStyle = md.get("APPROXSTYLE", afwMath.ApproximateControl.UNKNOWN)
203  approxStyle = afwMath.ApproximateControl.Style(approxStyle)
204  approxOrderX = md.get("APPROXORDERX", 1)
205  approxOrderY = md.get("APPROXORDERY", -1)
206  approxWeighting = md.get("APPROXWEIGHTING", True)
207 
208  bkgd = afwMath.BackgroundMI(imageBBox, statsImage)
209  bctrl = bkgd.getBackgroundControl()
210  bctrl.setInterpStyle(interpStyle) # can't remove because other code might call old getImageF
211  bctrl.setUndersampleStyle(undersampleStyle)
212  actrl = afwMath.ApproximateControl(approxStyle, approxOrderX, approxOrderY, approxWeighting)
213  bctrl.setApproximateControl(actrl)
214  bgInfo = (bkgd, interpStyle, undersampleStyle, approxStyle,
215  approxOrderX, approxOrderY, approxWeighting)
216  self.append(bgInfo)
217 
218  return self
219 
220  def getImage(self):
221  """Compute and return a full-resolution image from our list of
222  (Background, interpStyle, undersampleStyle).
223  """
224 
225  bkgdImage = None
226  for (bkgd, interpStyle, undersampleStyle, approxStyle,
227  approxOrderX, approxOrderY, approxWeighting) in self:
228  if not bkgdImage:
229  bkgdImage = bkgd.getImageF(interpStyle, undersampleStyle)
230  else:
231  bkgdImage += bkgd.getImageF(interpStyle, undersampleStyle)
232 
233  return bkgdImage
234 
235  def __reduce__(self):
236  return reduceToFits(self)
A FITS reader class for Masks.
Class for storing ordered metadata with comments.
Definition: PropertyList.h:68
A FITS reader class for regular Images.
A simple struct that combines the two arguments that must be passed to most cfitsio routines and cont...
Definition: fits.h:297
Control how to make an approximation.
Definition: Approximate.h:48
def readFits(fileName, hdu=0, flags=0)
A class to evaluate image background levels.
Definition: Background.h:468
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects...
An integer coordinate rectangle.
Definition: Box.h:55