LSST Applications  21.0.0+c4f5df5339,21.0.0+e70536a077,21.0.0-1-ga51b5d4+7c60f8a6ea,21.0.0-10-gcf60f90+74aa0801fd,21.0.0-12-g63909ac9+643a1044a5,21.0.0-15-gedb9d5423+1041c3824f,21.0.0-2-g103fe59+a356b2badb,21.0.0-2-g1367e85+6d3f3f41db,21.0.0-2-g45278ab+e70536a077,21.0.0-2-g5242d73+6d3f3f41db,21.0.0-2-g7f82c8f+8d7c04eab9,21.0.0-2-g8f08a60+9c9a9cfcc8,21.0.0-2-ga326454+8d7c04eab9,21.0.0-2-gde069b7+bedfc5e1fb,21.0.0-2-gecfae73+6cb6558258,21.0.0-2-gfc62afb+6d3f3f41db,21.0.0-3-g21c7a62+f6e98b25aa,21.0.0-3-g357aad2+bd62456bea,21.0.0-3-g4be5c26+6d3f3f41db,21.0.0-3-g65f322c+03a4076c01,21.0.0-3-g7d9da8d+c4f5df5339,21.0.0-3-gaa929c8+c6b98066dc,21.0.0-3-gc44e71e+a26d5c1aea,21.0.0-3-ge02ed75+04b527a9d5,21.0.0-35-g64f566ff+b27e5ef93e,21.0.0-4-g591bb35+04b527a9d5,21.0.0-4-g88306b8+8773047b2e,21.0.0-4-gc004bbf+80a0b7acb7,21.0.0-4-gccdca77+a5c54364a0,21.0.0-4-ge8fba5a+ccfc328107,21.0.0-5-gdf36809+87b8d260e6,21.0.0-6-g00874e7+7eeda2b6ba,21.0.0-6-g2d4f3f3+e70536a077,21.0.0-6-g4e60332+04b527a9d5,21.0.0-6-g5ef7dad+f53629abd8,21.0.0-7-gc8ca178+b63e69433b,21.0.0-8-gfbe0b4b+c6b98066dc,w.2021.06
LSST Data Management Base Package
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 .interpolate import Interpolate
30 from .approximate import ApproximateControl
31 from .background import BackgroundMI
32 from .background import UndersampleStyle
33 
34 
36  """A list-like class to contain a list of (`lsst.afw.math.Background`,
37  `lsst.afw.math.Interpolate.Style`, `~lsst.afw.math.UndersampleStyle`)
38  tuples.
39 
40  Parameters
41  ----------
42  *args : `tuple` or `~lsst.afw.math.Background`
43  A sequence of arguments, each of which becomes an element of the list.
44  We also accept a single `lsst.afw.math.Background` and extract the
45  ``interpStyle`` and ``undersampleStyle`` from the as-used values.
46  """
47 
48  def __init__(self, *args):
49  self._backgrounds_backgrounds = []
50  for a in args:
51  self.appendappend(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_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_backgrounds[i] = (bkgd, interpStyle, undersampleStyle,
76  approxStyle, approxOrderX, approxOrderY, approxWeighting)
77  #
78  # And return what they wanted
79  #
80  return self._backgrounds_backgrounds.__getitem__(*args)
81 
82  def __len__(self, *args):
83  return self._backgrounds_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  bkgd = val
91  interpStyle = None
92  undersampleStyle = None
93  approxStyle = None
94  approxOrderX = None
95  approxOrderY = None
96  approxWeighting = None
97 
98  bgInfo = (bkgd, interpStyle, undersampleStyle, approxStyle,
99  approxOrderX, approxOrderY, approxWeighting)
100  self._backgrounds_backgrounds.append(bgInfo)
101 
102  def clone(self):
103  """Return a shallow copy
104 
105  Shallow copies do not share backgrounds that are appended after copying,
106  but do share changes to contained background objects.
107  """
108  return BackgroundList(*self)
109 
110  def writeFits(self, fileName, flags=0):
111  """Save our list of Backgrounds to a file.
112 
113  Parameters
114  -----------
115  fileName : `str`
116  FITS file to write
117  flags : `int`
118  Flags to control details of writing; currently unused, but present
119  for consistency with `lsst.afw.table.BaseCatalog.writeFits`.
120  """
121 
122  for i, bkgd in enumerate(self):
123  (bkgd, interpStyle, undersampleStyle, approxStyle, approxOrderX, approxOrderY,
124  approxWeighting) = bkgd
125 
126  statsImage = bkgd.getStatsImage()
127 
128  md = dafBase.PropertyList()
129  md.set("INTERPSTYLE", int(interpStyle))
130  md.set("UNDERSAMPLESTYLE", int(undersampleStyle))
131  md.set("APPROXSTYLE", int(approxStyle))
132  md.set("APPROXORDERX", approxOrderX)
133  md.set("APPROXORDERY", approxOrderY)
134  md.set("APPROXWEIGHTING", approxWeighting)
135  bbox = bkgd.getImageBBox()
136  md.set("BKGD_X0", bbox.getMinX())
137  md.set("BKGD_Y0", bbox.getMinY())
138  md.set("BKGD_WIDTH", bbox.getWidth())
139  md.set("BKGD_HEIGHT", bbox.getHeight())
140 
141  statsImage.getImage().writeFits(fileName, md, "w" if i == 0 else "a")
142  statsImage.getMask().writeFits(fileName, md, "a")
143  statsImage.getVariance().writeFits(fileName, md, "a")
144 
145  @staticmethod
146  def readFits(fileName, hdu=0, flags=0):
147  """Read our list of Backgrounds from a file.
148 
149  Parameters
150  ----------
151  fileName : `str`
152  FITS file to read
153  hdu : `int`
154  First Header/Data Unit to attempt to read from
155  flags : `int`
156  Flags to control details of reading; currently unused, but present
157  for consistency with `lsst.afw.table.BaseCatalog.readFits`.
158 
159  See Also
160  --------
161  getImage
162  """
163  if not isinstance(fileName, MemFileManager) and not os.path.exists(fileName):
164  raise RuntimeError(f"File not found: {fileName}")
165 
166  self = BackgroundList()
167 
168  f = Fits(fileName, 'r')
169  nHdus = f.countHdus()
170  f.closeFile()
171  if nHdus % 3 != 0:
172  raise RuntimeError(f"BackgroundList FITS file {fileName} has {nHdus} HDUs;"
173  f"expected a multiple of 3 (compression is not supported).")
174 
175  for hdu in range(0, nHdus, 3):
176  # It seems like we ought to be able to just use
177  # MaskedImageFitsReader here, but it warns about EXTTYPE and still
178  # doesn't work quite naturally when starting from a nonzero HDU.
179  imageReader = afwImage.ImageFitsReader(fileName, hdu=hdu)
180  maskReader = afwImage.MaskFitsReader(fileName, hdu=hdu + 1)
181  varianceReader = afwImage.ImageFitsReader(fileName, hdu=hdu + 2)
182  statsImage = afwImage.MaskedImageF(imageReader.read(), maskReader.read(), varianceReader.read())
183  md = imageReader.readMetadata()
184 
185  x0 = md["BKGD_X0"]
186  y0 = md["BKGD_Y0"]
187  width = md["BKGD_WIDTH"]
188  height = md["BKGD_HEIGHT"]
189  imageBBox = lsst.geom.BoxI(lsst.geom.PointI(x0, y0), lsst.geom.ExtentI(width, height))
190 
191  interpStyle = Interpolate.Style(md["INTERPSTYLE"])
192  undersampleStyle = UndersampleStyle(md["UNDERSAMPLESTYLE"])
193 
194  # Older outputs won't have APPROX* settings. Provide alternative defaults.
195  # Note: Currently X- and Y-orders must be equal due to a limitation in
196  # math::Chebyshev1Function2. Setting approxOrderY = -1 is equivalent
197  # to saying approxOrderY = approxOrderX.
198  approxStyle = md.get("APPROXSTYLE", ApproximateControl.UNKNOWN)
199  approxStyle = ApproximateControl.Style(approxStyle)
200  approxOrderX = md.get("APPROXORDERX", 1)
201  approxOrderY = md.get("APPROXORDERY", -1)
202  approxWeighting = md.get("APPROXWEIGHTING", True)
203 
204  bkgd = BackgroundMI(imageBBox, statsImage)
205  bctrl = bkgd.getBackgroundControl()
206  bctrl.setInterpStyle(interpStyle)
207  bctrl.setUndersampleStyle(undersampleStyle)
208  actrl = ApproximateControl(approxStyle, approxOrderX, approxOrderY, approxWeighting)
209  bctrl.setApproximateControl(actrl)
210  bgInfo = (bkgd, interpStyle, undersampleStyle, approxStyle,
211  approxOrderX, approxOrderY, approxWeighting)
212  self.appendappend(bgInfo)
213 
214  return self
215 
216  def getImage(self):
217  """Compute and return a full-resolution image from our list of
218  (Background, interpStyle, undersampleStyle).
219  """
220 
221  bkgdImage = None
222  for (bkgd, interpStyle, undersampleStyle, approxStyle,
223  approxOrderX, approxOrderY, approxWeighting) in self:
224  if not bkgdImage:
225  if approxStyle != ApproximateControl.UNKNOWN:
226  bkgdImage = bkgd.getImageF()
227  else:
228  bkgdImage = bkgd.getImageF(interpStyle, undersampleStyle)
229  else:
230  if approxStyle != ApproximateControl.UNKNOWN:
231  bkgdImage += bkgd.getImageF()
232  else:
233  bkgdImage += bkgd.getImageF(interpStyle, undersampleStyle)
234 
235  return bkgdImage
236 
237  def __reduce__(self):
238  return reduceToFits(self)
A simple struct that combines the two arguments that must be passed to most cfitsio routines and cont...
Definition: fits.h:297
A FITS reader class for regular Images.
A FITS reader class for Masks.
def readFits(fileName, hdu=0, flags=0)
Class for storing ordered metadata with comments.
Definition: PropertyList.h:68
An integer coordinate rectangle.
Definition: Box.h:55
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.