LSSTApplications  18.1.0
LSSTDataManagementBasePackage
readers.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 "pybind11/pybind11.h"
23 
24 #include "ndarray/pybind11.h"
25 
32 #include "lsst/afw/geom/SkyWcs.h"
34 #include "lsst/afw/detection/Psf.h"
36 #include "lsst/afw/image/Filter.h"
42 
43 namespace py = pybind11;
44 using namespace pybind11::literals;
45 
46 namespace lsst { namespace afw { namespace image { namespace {
47 
48 // ImageBaseFitsReader is an implementation detail and is not exposed directly
49 // to Python, as we have better ways to share wrapper code between classes
50 // at the pybind11 level (e.g. declareCommon below).
51 using PyImageFitsReader = py::class_<ImageFitsReader, std::shared_ptr<ImageFitsReader>>;
52 using PyMaskFitsReader = py::class_<MaskFitsReader, std::shared_ptr<MaskFitsReader>>;
53 using PyMaskedImageFitsReader = py::class_<MaskedImageFitsReader, std::shared_ptr<MaskedImageFitsReader>>;
54 using PyExposureFitsReader = py::class_<ExposureFitsReader, std::shared_ptr<ExposureFitsReader>>;
55 
56 // Declare attributes common to all FitsReaders. Excludes constructors
57 // because ExposureFitsReader's don't take an HDU argument.
58 template <typename Class, typename ...Args>
59 void declareCommonMethods(py::class_<Class, Args...> & cls) {
60  cls.def("readBBox", &Class::readBBox, "origin"_a=PARENT);
61  cls.def("readXY0", &Class::readXY0, "bbox"_a=lsst::geom::Box2I(), "origin"_a=PARENT);
62  cls.def("getFileName", &Class::getFileName);
63  cls.def_property_readonly("fileName", &Class::getFileName);
64 }
65 
66 // Declare attributes common to ImageFitsReader and MaskFitsReader
67 template <typename Class, typename ...Args>
68 void declareSinglePlaneMethods(py::class_<Class, Args...> & cls) {
69  cls.def(py::init<std::string const &, int>(), "fileName"_a, "hdu"_a=fits::DEFAULT_HDU);
70  cls.def(py::init<fits::MemFileManager&, int>(), "manager"_a, "hdu"_a=fits::DEFAULT_HDU);
71  cls.def("readMetadata", &Class::readMetadata);
72  cls.def("readDType", [](Class & self) { return py::dtype(self.readDType()); });
73  cls.def("getHdu", &Class::getHdu);
74  cls.def_property_readonly("hdu", &Class::getHdu);
75  cls.def(
76  "readArray",
77  [](Class & self, lsst::geom::Box2I const & bbox, ImageOrigin origin, bool allowUnsafe,
78  py::object dtype) {
79  if (dtype.is(py::none())) {
80  dtype = py::dtype(self.readDType());
81  }
82  return utils::python::TemplateInvoker().apply(
83  [&](auto t) {
84  return self.template readArray<decltype(t)>(bbox, origin, allowUnsafe);
85  },
86  py::dtype(dtype),
87  utils::python::TemplateInvoker::Tag<std::uint16_t, int, float, double, std::uint64_t>()
88  );
89  },
90  "bbox"_a=lsst::geom::Box2I(), "origin"_a=PARENT, "allowUnsafe"_a=false, "dtype"_a=py::none()
91  );
92 }
93 
94 // Declare attributes shared by MaskedImageFitsReader and MaskedImageFitsReader.
95 template <typename Class, typename ...Args>
96 void declareMultiPlaneMethods(py::class_<Class, Args...> & cls) {
97  cls.def("readImageDType", [](Class & self) { return py::dtype(self.readImageDType()); } );
98  cls.def("readMaskDType", [](Class & self) { return py::dtype(self.readMaskDType()); });
99  cls.def("readVarianceDType", [](Class & self) { return py::dtype(self.readVarianceDType()); });
100  cls.def(
101  "readImage",
102  [](Class & self, lsst::geom::Box2I const & bbox, ImageOrigin origin, bool allowUnsafe,
103  py::object dtype) {
104  if (dtype.is(py::none())) {
105  dtype = py::dtype(self.readImageDType());
106  }
107  return utils::python::TemplateInvoker().apply(
108  [&](auto t) {
109  return self.template readImage<decltype(t)>(bbox, origin, allowUnsafe);
110  },
111  py::dtype(dtype),
112  utils::python::TemplateInvoker::Tag<std::uint16_t, int, float, double, std::uint64_t>()
113  );
114  },
115  "bbox"_a=lsst::geom::Box2I(), "origin"_a=PARENT, "allowUnsafe"_a=false, "dtype"_a=py::none()
116  );
117  cls.def(
118  "readImageArray",
119  [](Class & self, lsst::geom::Box2I const & bbox, ImageOrigin origin, bool allowUnsafe,
120  py::object dtype) {
121  if (dtype.is(py::none())) {
122  dtype = py::dtype(self.readImageDType());
123  }
124  return utils::python::TemplateInvoker().apply(
125  [&](auto t) {
126  return self.template readImageArray<decltype(t)>(bbox, origin, allowUnsafe);
127  },
128  py::dtype(dtype),
129  utils::python::TemplateInvoker::Tag<std::uint16_t, int, float, double, std::uint64_t>()
130  );
131  },
132  "bbox"_a=lsst::geom::Box2I(), "origin"_a=PARENT, "allowUnsafe"_a=false, "dtype"_a=py::none()
133  );
134  cls.def(
135  "readMask",
136  [](Class & self, lsst::geom::Box2I const & bbox, ImageOrigin origin, bool conformMasks,
137  bool allowUnsafe, py::object dtype) {
138  if (dtype.is(py::none())) {
139  dtype = py::dtype(self.readMaskDType());
140  }
141  return utils::python::TemplateInvoker().apply(
142  [&](auto t) {
143  return self.template readMask<decltype(t)>(bbox, origin, conformMasks, allowUnsafe);
144  },
145  py::dtype(dtype),
146  utils::python::TemplateInvoker::Tag<MaskPixel>()
147  );
148  },
149  "bbox"_a=lsst::geom::Box2I(), "origin"_a=PARENT, "conformMasks"_a=false, "allowUnsafe"_a=false,
150  "dtype"_a=py::none()
151  );
152  cls.def(
153  "readMaskArray",
154  [](Class & self, lsst::geom::Box2I const & bbox, ImageOrigin origin, bool allowUnsafe,
155  py::object dtype) {
156  if (dtype.is(py::none())) {
157  dtype = py::dtype(self.readMaskDType());
158  }
159  return utils::python::TemplateInvoker().apply(
160  [&](auto t) {
161  return self.template readMaskArray<decltype(t)>(bbox, origin, allowUnsafe);
162  },
163  py::dtype(dtype),
164  utils::python::TemplateInvoker::Tag<MaskPixel>()
165  );
166  },
167  "bbox"_a=lsst::geom::Box2I(), "origin"_a=PARENT, "allowUnsafe"_a=false, "dtype"_a=py::none()
168  );
169  cls.def(
170  "readVariance",
171  [](Class & self, lsst::geom::Box2I const & bbox, ImageOrigin origin, bool allowUnsafe,
172  py::object dtype) {
173  if (dtype.is(py::none())) {
174  dtype = py::dtype(self.readVarianceDType());
175  }
176  return utils::python::TemplateInvoker().apply(
177  [&](auto t) {
178  return self.template readVariance<decltype(t)>(bbox, origin, allowUnsafe);
179  },
180  py::dtype(dtype),
181  utils::python::TemplateInvoker::Tag<VariancePixel>()
182  );
183  },
184  "bbox"_a=lsst::geom::Box2I(), "origin"_a=PARENT, "allowUnsafe"_a=false, "dtype"_a=py::none()
185  );
186  cls.def(
187  "readVarianceArray",
188  [](Class & self, lsst::geom::Box2I const & bbox, ImageOrigin origin, bool allowUnsafe,
189  py::object dtype) {
190  if (dtype.is(py::none())) {
191  dtype = py::dtype(self.readVarianceDType());
192  }
193  return utils::python::TemplateInvoker().apply(
194  [&](auto t) {
195  return self.template readVarianceArray<decltype(t)>(bbox, origin, allowUnsafe);
196  },
197  py::dtype(dtype),
198  utils::python::TemplateInvoker::Tag<VariancePixel>()
199  );
200  },
201  "bbox"_a=lsst::geom::Box2I(), "origin"_a=PARENT, "allowUnsafe"_a=false, "dtype"_a=py::none()
202  );
203 }
204 
205 void declareImageFitsReader(py::module & mod) {
206  PyImageFitsReader cls(mod, "ImageFitsReader");
207  declareCommonMethods(cls);
208  declareSinglePlaneMethods(cls);
209  cls.def(
210  "read",
211  [](ImageFitsReader & self, lsst::geom::Box2I const & bbox, ImageOrigin origin, bool allowUnsafe,
212  py::object dtype) {
213  if (dtype.is(py::none())) {
214  dtype = py::dtype(self.readDType());
215  }
216  return utils::python::TemplateInvoker().apply(
217  [&](auto t) {
218  return self.read<decltype(t)>(bbox, origin, allowUnsafe);
219  },
220  py::dtype(dtype),
221  utils::python::TemplateInvoker::Tag<std::uint16_t, int, float, double, std::uint64_t>()
222  );
223  },
224  "bbox"_a=lsst::geom::Box2I(), "origin"_a=PARENT, "allowUnsafe"_a=false, "dtype"_a=py::none()
225  );
226 }
227 
228 void declareMaskFitsReader(py::module & mod) {
229  PyMaskFitsReader cls(mod, "MaskFitsReader");
230  declareCommonMethods(cls);
231  declareSinglePlaneMethods(cls);
232  cls.def(
233  "read",
234  [](MaskFitsReader & self, lsst::geom::Box2I const & bbox, ImageOrigin origin,
235  bool conformMasks, bool allowUnsafe, py::object dtype) {
236  if (dtype.is(py::none())) {
237  dtype = py::dtype(self.readDType());
238  }
239  return utils::python::TemplateInvoker().apply(
240  [&](auto t) {
241  return self.read<decltype(t)>(bbox, origin, conformMasks, allowUnsafe);
242  },
243  py::dtype(dtype),
244  utils::python::TemplateInvoker::Tag<MaskPixel>()
245  );
246  },
247  "bbox"_a=lsst::geom::Box2I(), "origin"_a=PARENT, "conformMasks"_a=false, "allowUnsafe"_a=false,
248  "dtype"_a=py::none()
249  );
250  // all other methods provided by base class wrappers
251 }
252 
253 void declareMaskedImageFitsReader(py::module & mod) {
254  PyMaskedImageFitsReader cls(mod, "MaskedImageFitsReader");
255  cls.def(py::init<std::string const &, int>(), "fileName"_a, "hdu"_a=fits::DEFAULT_HDU);
256  cls.def(py::init<fits::MemFileManager&, int>(), "manager"_a, "hdu"_a=fits::DEFAULT_HDU);
257  declareCommonMethods(cls);
258  declareMultiPlaneMethods(cls);
259  cls.def("readPrimaryMetadata", &MaskedImageFitsReader::readPrimaryMetadata);
260  cls.def("readImageMetadata", &MaskedImageFitsReader::readImageMetadata);
261  cls.def("readMaskMetadata", &MaskedImageFitsReader::readMaskMetadata);
262  cls.def("readVarianceMetadata", &MaskedImageFitsReader::readVarianceMetadata);
263  cls.def(
264  "read",
265  [](MaskedImageFitsReader & self, lsst::geom::Box2I const & bbox, ImageOrigin origin,
266  bool conformMasks, bool needAllHdus, bool allowUnsafe, py::object dtype) {
267  if (dtype.is(py::none())) {
268  dtype = py::dtype(self.readImageDType());
269  }
270  return utils::python::TemplateInvoker().apply(
271  [&](auto t) {
272  return self.read<decltype(t)>(bbox, origin, conformMasks, allowUnsafe);
273  },
274  py::dtype(dtype),
275  utils::python::TemplateInvoker::Tag<std::uint16_t, int, float, double, std::uint64_t>()
276  );
277  },
278  "bbox"_a=lsst::geom::Box2I(), "origin"_a=PARENT, "conformMasks"_a=false, "needAllHdus"_a=false,
279  "allowUnsafe"_a=false, "dtype"_a=py::none()
280  );
281 }
282 
283 void declareExposureFitsReader(py::module & mod) {
284  PyExposureFitsReader cls(mod, "ExposureFitsReader");
285  cls.def(py::init<std::string const &>(), "fileName"_a);
286  cls.def(py::init<fits::MemFileManager&>(), "manager"_a);
287  declareCommonMethods(cls);
288  declareMultiPlaneMethods(cls);
289  cls.def("readMetadata", &ExposureFitsReader::readMetadata);
290  cls.def("readWcs", &ExposureFitsReader::readWcs);
291  cls.def("readFilter", &ExposureFitsReader::readFilter);
292  cls.def("readPhotoCalib", &ExposureFitsReader::readPhotoCalib);
293  cls.def("readPsf", &ExposureFitsReader::readPsf);
294  cls.def("readValidPolygon", &ExposureFitsReader::readValidPolygon);
295  cls.def("readApCorrMap", &ExposureFitsReader::readApCorrMap);
296  cls.def("readCoaddInputs", &ExposureFitsReader::readCoaddInputs);
297  cls.def("readVisitInfo", &ExposureFitsReader::readVisitInfo);
298  cls.def("readTransmissionCurve", &ExposureFitsReader::readTransmissionCurve);
299  cls.def("readDetector", &ExposureFitsReader::readDetector);
300  cls.def("readExposureInfo", &ExposureFitsReader::readExposureInfo);
301  cls.def(
302  "readMaskedImage",
303  [](ExposureFitsReader & self, lsst::geom::Box2I const & bbox, ImageOrigin origin,
304  bool conformMasks, bool allowUnsafe, py::object dtype) {
305  if (dtype.is(py::none())) {
306  dtype = py::dtype(self.readImageDType());
307  }
308  return utils::python::TemplateInvoker().apply(
309  [&](auto t) {
310  return self.readMaskedImage<decltype(t)>(bbox, origin, conformMasks, allowUnsafe);
311  },
312  py::dtype(dtype),
313  utils::python::TemplateInvoker::Tag<std::uint16_t, int, float, double, std::uint64_t>()
314  );
315  },
316  "bbox"_a=lsst::geom::Box2I(), "origin"_a=PARENT, "conformMasks"_a=false, "allowUnsafe"_a=false,
317  "dtype"_a=py::none()
318  );
319  cls.def(
320  "read",
321  [](ExposureFitsReader & self, lsst::geom::Box2I const & bbox, ImageOrigin origin,
322  bool conformMasks, bool allowUnsafe, py::object dtype) {
323  if (dtype.is(py::none())) {
324  dtype = py::dtype(self.readImageDType());
325  }
326  return utils::python::TemplateInvoker().apply(
327  [&](auto t) {
328  return self.read<decltype(t)>(bbox, origin, conformMasks, allowUnsafe);
329  },
330  py::dtype(dtype),
331  utils::python::TemplateInvoker::Tag<std::uint16_t, int, float, double, std::uint64_t>()
332  );
333  },
334  "bbox"_a=lsst::geom::Box2I(), "origin"_a=PARENT, "conformMasks"_a=false, "allowUnsafe"_a=false,
335  "dtype"_a=py::none()
336  );
337 }
338 
339 
340 PYBIND11_MODULE(readers, mod) {
341  py::module::import("lsst.daf.base");
342  py::module::import("lsst.geom");
343  py::module::import("lsst.afw.image.image");
344  py::module::import("lsst.afw.image.maskedImage");
345  py::module::import("lsst.afw.image.exposure");
346  declareImageFitsReader(mod);
347  declareMaskFitsReader(mod);
348  declareMaskedImageFitsReader(mod);
349  declareExposureFitsReader(mod);
350 }
351 
352 }}}} // namespace lsst::afw::image::<anonymous>
PYBIND11_MODULE(camera, mod)
Definition: camera.cc:34
A base class for image defects.
table::Box2IKey bbox
Definition: Detector.cc:169
Backwards-compatibility support for depersisting the old Calib (FluxMag0/FluxMag0Err) objects...
An integer coordinate rectangle.
Definition: Box.h:54
Implementation of the Photometric Calibration class.
const int DEFAULT_HDU
Specify that the default HDU should be read.
Definition: fitsDefaults.h:18
std::shared_ptr< daf::base::PropertyList > readMetadata(std::string const &fileName, int hdu=DEFAULT_HDU, bool strip=false)
Read FITS header.
Definition: fits.cc:1616