LSST Applications  21.0.0-172-gfb10e10a+18fedfabac,22.0.0+297cba6710,22.0.0+80564b0ff1,22.0.0+8d77f4f51a,22.0.0+a28f4c53b1,22.0.0+dcf3732eb2,22.0.1-1-g7d6de66+2a20fdde0d,22.0.1-1-g8e32f31+297cba6710,22.0.1-1-geca5380+7fa3b7d9b6,22.0.1-12-g44dc1dc+2a20fdde0d,22.0.1-15-g6a90155+515f58c32b,22.0.1-16-g9282f48+790f5f2caa,22.0.1-2-g92698f7+dcf3732eb2,22.0.1-2-ga9b0f51+7fa3b7d9b6,22.0.1-2-gd1925c9+bf4f0e694f,22.0.1-24-g1ad7a390+a9625a72a8,22.0.1-25-g5bf6245+3ad8ecd50b,22.0.1-25-gb120d7b+8b5510f75f,22.0.1-27-g97737f7+2a20fdde0d,22.0.1-32-gf62ce7b1+aa4237961e,22.0.1-4-g0b3f228+2a20fdde0d,22.0.1-4-g243d05b+871c1b8305,22.0.1-4-g3a563be+32dcf1063f,22.0.1-4-g44f2e3d+9e4ab0f4fa,22.0.1-42-gca6935d93+ba5e5ca3eb,22.0.1-5-g15c806e+85460ae5f3,22.0.1-5-g58711c4+611d128589,22.0.1-5-g75bb458+99c117b92f,22.0.1-6-g1c63a23+7fa3b7d9b6,22.0.1-6-g50866e6+84ff5a128b,22.0.1-6-g8d3140d+720564cf76,22.0.1-6-gd805d02+cc5644f571,22.0.1-8-ge5750ce+85460ae5f3,master-g6e05de7fdc+babf819c66,master-g99da0e417a+8d77f4f51a,w.2021.48
LSST Data Management Base Package
MaskedImageFitsReader.cc
Go to the documentation of this file.
1 /*
2  * Developed for the LSST Data Management System.
3  * This product includes software developed by the LSST Project
4  * (https://www.lsst.org).
5  * See the COPYRIGHT file at the top-level directory of this distribution
6  * for details of code ownership.
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 GNU General Public License
19  * along with this program. If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #include "lsst/log/Log.h"
23 #include "boost/algorithm/string/trim.hpp"
24 
26 
27 namespace lsst { namespace afw { namespace image {
28 
29 namespace {
30 
31 fits::Fits * nextHdu(fits::Fits * fitsFile) {
32  if (fitsFile == nullptr) {
33  return nullptr;
34  }
35  try {
36  fitsFile->setHdu(1, true);
37  } catch (fits::FitsError &) {
38  fitsFile->status = 0;
39  return nullptr;
40  }
41  return fitsFile;
42 }
43 
44 } // anonymous
45 
47  _imageReader(fileName, hdu),
48  _maskReader(nextHdu(_imageReader._fitsFile)),
49  _varianceReader(nextHdu(_maskReader._fitsFile))
50 {}
51 
53  _imageReader(manager, hdu),
54  _maskReader(nextHdu(_imageReader._fitsFile)),
55  _varianceReader(nextHdu(_maskReader._fitsFile))
56 {}
57 
59  _imageReader(fitsFile),
60  _maskReader(nextHdu(_imageReader._fitsFile)),
61  _varianceReader(nextHdu(_maskReader._fitsFile))
62 {}
63 
65 
66 std::string MaskedImageFitsReader::readImageDType() const { return _imageReader.readDType(); }
67 
69 
70 std::string MaskedImageFitsReader::readVarianceDType() const { return _varianceReader.readDType(); }
71 
73  return _imageReader.readBBox(origin);
74 }
75 
77  return _imageReader.readXY0(bbox, origin);
78 }
79 
80 namespace {
81 
82 void checkExtType(ImageBaseFitsReader const & reader, std::shared_ptr<daf::base::PropertyList> metadata,
83  std::string const& expected) {
84  try {
85  std::string exttype = boost::algorithm::trim_right_copy(metadata->getAsString("EXTTYPE"));
86  if (exttype != "" && exttype != expected) {
88  str(boost::format("Reading %s (hdu %d) Expected EXTTYPE==\"%s\", saw \"%s\"") %
89  reader.getFileName() % reader.getHdu() % expected % exttype));
90  }
91  metadata->remove("EXTTYPE");
92  } catch (pex::exceptions::NotFoundError const&) {
93  LOGL_WARN("lsst.afw.image.MaskedImageFitsReader", "Expected extension type not found: %s",
94  expected.c_str());
95  }
96 }
97 
98 } // anonymous
99 
101  auto fitsFile = _imageReader._fitsFile;
102  fits::HduMoveGuard guard(*fitsFile, 0);
103  return fits::readMetadata(*fitsFile, /*strip=*/true);
104 }
105 
107  if (!_imageMetadata) {
108  _imageMetadata = _imageReader.readMetadata();
109  checkExtType(_imageReader, _imageMetadata, "IMAGE");
110  }
111  return _imageMetadata;
112 }
113 
115  if (!_maskMetadata) {
116  _maskReader.readMetadata();
117  checkExtType(_maskReader, _maskMetadata, "MASK");
118  }
119  return _maskMetadata;
120 }
121 
123  if (!_varianceMetadata) {
124  _varianceReader.readMetadata();
125  checkExtType(_varianceReader, _varianceMetadata, "VARIANCE");
126  }
127  return _varianceMetadata;
128 }
129 
130 template <typename ImagePixelT>
132  bool allowUnsafe) {
133  return _imageReader.read<ImagePixelT>(bbox, origin, allowUnsafe);
134 }
135 
136 template <typename ImagePixelT>
137 ndarray::Array<ImagePixelT, 2, 2> MaskedImageFitsReader::readImageArray(lsst::geom::Box2I const & bbox,
138  ImageOrigin origin,
139  bool allowUnsafe) {
140  return _imageReader.readArray<ImagePixelT>(bbox, origin, allowUnsafe);
141 }
142 
143 template <typename MaskPixelT>
145  bool conformMasks, bool allowUnsafe) {
146  return _maskReader.read<MaskPixelT>(bbox, origin, conformMasks, allowUnsafe);
147 }
148 
149 template <typename MaskPixelT>
150 ndarray::Array<MaskPixelT, 2, 2> MaskedImageFitsReader::readMaskArray(lsst::geom::Box2I const & bbox,
151  ImageOrigin origin,
152  bool allowUnsafe) {
153  return _maskReader.readArray<MaskPixelT>(bbox, origin, allowUnsafe);
154 }
155 
156 template <typename VariancePixelT>
158  ImageOrigin origin, bool allowUnsafe) {
159  return _varianceReader.read<VariancePixelT>(bbox, origin, allowUnsafe);
160 }
161 
162 template <typename VariancePixelT>
163 ndarray::Array<VariancePixelT, 2, 2> MaskedImageFitsReader::readVarianceArray(lsst::geom::Box2I const & bbox,
164  ImageOrigin origin,
165  bool allowUnsafe) {
166  return _varianceReader.readArray<VariancePixelT>(bbox, origin, allowUnsafe);
167 }
168 
169 template <typename ImagePixelT, typename MaskPixelT, typename VariancePixelT>
171  lsst::geom::Box2I const & bbox, ImageOrigin origin,
172  bool conformMasks, bool needAllHdus, bool allowUnsafe
173 ) {
174  // When reading a standard Masked Image, we expect four HDUs:
175  // * The primary (HDU 0) is empty;
176  // * The first extension (HDU 1) contains the image data;
177  // * The second extension (HDU 2) contains mask data;
178  // * The third extension (HDU 3) contains the variance.
179  //
180  // If the image HDU is unreadable, we will throw.
181  //
182  // If the user has specified a non-default HDU, we load image data from
183  // that HDU, but do not attempt to load mask/variance data; rather, log a
184  // warning and return (blank) defaults.
185  //
186  // If the mask and/or variance is unreadable, we log a warning and return
187  // (blank) defaults.
188 
189  LOG_LOGGER _log = LOG_GET("lsst.afw.image.MaskedImageFitsReader");
190 
191  enum class Hdu { Primary = 0, Image, Mask, Variance };
192 
193  // If the user has requested a non-default HDU and we require all HDUs, we fail.
194  if (needAllHdus && _imageReader.getHdu() > static_cast<int>(Hdu::Image)) {
195  throw LSST_EXCEPT(fits::FitsError, "Cannot read all HDUs starting from non-default");
196  }
197 
198  auto image = std::make_shared<Image<ImagePixelT>>(_imageReader.read<ImagePixelT>(bbox, origin,
199  allowUnsafe));
202 
203  // only read other planes if they're in their normal HDUs
204  if (_imageReader.getHdu() == static_cast<int>(Hdu::Image)) {
205  // Do not even try if we are missing the HDU
206  if (_maskReader._fitsFile) {
207  try {
208  mask = std::make_shared<Mask<MaskPixelT>>(
209  _maskReader.read<MaskPixelT>(bbox, origin, conformMasks, allowUnsafe)
210  );
211  } catch (fits::FitsError& e) {
212  if (needAllHdus) {
213  LSST_EXCEPT_ADD(e, "Reading Mask");
214  throw e;
215  }
216  LOGL_WARN(_log, "Mask unreadable (%s); using default", e.what());
217  // By resetting the status we are able to read the next HDU (the variance).
218  _maskReader._fitsFile->status = 0;
219  }
220  } else if (needAllHdus) {
221  throw LSST_EXCEPT(pex::exceptions::NotFoundError, "No mask extensions found");
222  }
223  if (_varianceReader._fitsFile) {
224  try {
225  variance = std::make_shared<Image<VariancePixelT>>(
226  _varianceReader.read<VariancePixelT>(bbox, origin, allowUnsafe)
227  );
228  } catch (fits::FitsError& e) {
229  if (needAllHdus) {
230  LSST_EXCEPT_ADD(e, "Reading Variance");
231  throw e;
232  }
233  LOGL_WARN(_log, "Variance unreadable (%s); using default", e.what());
234  // By resetting the status we are able to read the next HDU (the variance).
235  _varianceReader._fitsFile->status = 0;
236  }
237  } else if (needAllHdus) {
238  throw LSST_EXCEPT(pex::exceptions::NotFoundError, "No variance extensions found");
239  }
240  }
242 }
243 
244 #define INSTANTIATE(ImagePixelT) \
245  template MaskedImage<ImagePixelT, MaskPixel, VariancePixel> MaskedImageFitsReader::read( \
246  lsst::geom::Box2I const &, \
247  ImageOrigin, \
248  bool, bool, bool \
249  ); \
250  template Image<ImagePixelT> MaskedImageFitsReader::readImage(\
251  lsst::geom::Box2I const &, \
252  ImageOrigin, \
253  bool \
254  ); \
255  template ndarray::Array<ImagePixelT, 2, 2> MaskedImageFitsReader::readImageArray(\
256  lsst::geom::Box2I const &, \
257  ImageOrigin, \
258  bool \
259  )
260 
262 INSTANTIATE(int);
263 INSTANTIATE(float);
264 INSTANTIATE(double);
266 
267 template Mask<MaskPixel> MaskedImageFitsReader::readMask(
268  lsst::geom::Box2I const &,
269  ImageOrigin,
270  bool,
271  bool
272 );
273 template ndarray::Array<MaskPixel, 2, 2> MaskedImageFitsReader::readMaskArray(
274  lsst::geom::Box2I const &,
275  ImageOrigin,
276  bool
277 );
278 
279 template Image<VariancePixel> MaskedImageFitsReader::readVariance(
280  lsst::geom::Box2I const &,
281  ImageOrigin,
282  bool
283 );
284 template ndarray::Array<VariancePixel, 2, 2> MaskedImageFitsReader::readVarianceArray(
285  lsst::geom::Box2I const &,
286  ImageOrigin,
287  bool
288 );
289 
290 }}} // lsst::afw::image
AmpInfoBoxKey bbox
Definition: Amplifier.cc:117
#define LSST_EXCEPT_ADD(e, m)
Add the current location and a message to an existing exception before rethrowing it.
Definition: Exception.h:54
#define LSST_EXCEPT(type,...)
Create an exception with a given type.
Definition: Exception.h:48
afw::table::Key< afw::table::Array< MaskPixelT > > mask
afw::table::Key< afw::table::Array< VariancePixelT > > variance
LSST DM logging module built on log4cxx.
#define LOGL_WARN(logger, message...)
Log a warn-level message using a varargs/printf style interface.
Definition: Log.h:547
#define LOG_GET(logger)
Returns a Log object associated with logger.
Definition: Log.h:75
#define LOG_LOGGER
Definition: Log.h:714
#define INSTANTIATE(ImagePixelT)
T c_str(T... args)
An exception thrown when problems are found when reading or writing FITS files.
Definition: fits.h:36
A simple struct that combines the two arguments that must be passed to most cfitsio routines and cont...
Definition: fits.h:297
RAII scoped guard for moving the HDU in a Fits object.
Definition: fits.h:724
Lifetime-management for memory that goes into FITS memory files.
Definition: fits.h:121
Base class for image FITS readers.
lsst::geom::Point2I readXY0(lsst::geom::Box2I const &bbox=lsst::geom::Box2I(), ImageOrigin origin=PARENT)
Read the image origin from the on-disk image or a subimage thereof.
std::shared_ptr< daf::base::PropertyList > readMetadata()
Read the image's FITS header.
ndarray::Array< T, 2, 2 > readArray(lsst::geom::Box2I const &bbox, ImageOrigin origin=PARENT, bool allowUnsafe=false)
Read the image's data array.
std::string getFileName() const
Return the name of the file this reader targets.
int getHdu() const noexcept
Return the HDU this reader targets.
lsst::geom::Box2I readBBox(ImageOrigin origin=PARENT)
Read the bounding box of the on-disk image.
std::string readDType() const
Read a string describing the pixel type of the on-disk image.
Image< PixelT > read(lsst::geom::Box2I const &bbox=lsst::geom::Box2I(), ImageOrigin origin=PARENT, bool allowUnsafe=false)
Read the Image.
A class to represent a 2-dimensional array of pixels.
Definition: Image.h:51
Mask< PixelT > read(lsst::geom::Box2I const &bbox=lsst::geom::Box2I(), ImageOrigin origin=PARENT, bool conformMasks=false, bool allowUnsafe=false)
Read the Mask.
Represent a 2-dimensional array of bitmask pixels.
Definition: Mask.h:77
A FITS reader class for MaskedImages and their components.
std::string readMaskDType() const
Read a string describing the pixel type of the on-disk image plane.
std::shared_ptr< daf::base::PropertyList > readImageMetadata()
Read the FITS header of one of the HDUs.
std::shared_ptr< daf::base::PropertyList > readPrimaryMetadata()
Read the FITS header of one of the HDUs.
std::string readVarianceDType() const
Read a string describing the pixel type of the on-disk image plane.
ndarray::Array< MaskPixelT, 2, 2 > readMaskArray(lsst::geom::Box2I const &bbox=lsst::geom::Box2I(), ImageOrigin origin=PARENT, bool allowUnsafe=false)
Read the mask plane.
MaskedImageFitsReader(std::string const &fileName, int hdu=fits::DEFAULT_HDU)
Construct a FITS reader object.
std::shared_ptr< daf::base::PropertyList > readMaskMetadata()
Read the FITS header of one of the HDUs.
ndarray::Array< ImagePixelT, 2, 2 > readImageArray(lsst::geom::Box2I const &bbox=lsst::geom::Box2I(), ImageOrigin origin=PARENT, bool allowUnsafe=false)
Read the image plane.
std::shared_ptr< daf::base::PropertyList > readVarianceMetadata()
Read the FITS header of one of the HDUs.
ndarray::Array< VariancePixelT, 2, 2 > readVarianceArray(lsst::geom::Box2I const &bbox=lsst::geom::Box2I(), ImageOrigin origin=PARENT, bool allowUnsafe=false)
Read the variance plane.
Mask< MaskPixelT > readMask(lsst::geom::Box2I const &bbox=lsst::geom::Box2I(), ImageOrigin origin=PARENT, bool conformMasks=false, bool allowUnsafe=false)
Read the mask plane.
lsst::geom::Box2I readBBox(ImageOrigin origin=PARENT)
Read the bounding box of the on-disk image.
MaskedImage< ImagePixelT, MaskPixelT, VariancePixelT > read(lsst::geom::Box2I const &bbox=lsst::geom::Box2I(), ImageOrigin origin=PARENT, bool conformMasks=false, bool needAllHdus=false, bool allowUnsafe=false)
Read the full MaskedImage.
Image< ImagePixelT > readImage(lsst::geom::Box2I const &bbox=lsst::geom::Box2I(), ImageOrigin origin=PARENT, bool allowUnsafe=false)
Read the image plane.
Image< VariancePixelT > readVariance(lsst::geom::Box2I const &bbox=lsst::geom::Box2I(), ImageOrigin origin=PARENT, bool allowUnsafe=false)
Read the variance plane.
lsst::geom::Point2I readXY0(lsst::geom::Box2I const &bbox=lsst::geom::Box2I(), ImageOrigin origin=PARENT)
Read the image origin from the on-disk image or a subimage thereof.
A class to manipulate images, masks, and variance as a single object.
Definition: MaskedImage.h:73
An integer coordinate rectangle.
Definition: Box.h:55
virtual char const * what(void) const noexcept
Return a character string summarizing this exception.
Definition: Exception.cc:99
Reports invalid arguments.
Definition: Runtime.h:66
Reports attempts to access elements using an invalid key.
Definition: Runtime.h:151
std::shared_ptr< daf::base::PropertyList > readMetadata(std::string const &fileName, int hdu=DEFAULT_HDU, bool strip=false)
Read FITS header.
Definition: fits.cc:1657
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects.
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:174
A base class for image defects.
STL namespace.