LSST Applications g00d0e8bbd7+edbf708997,g03191d30f7+9ce8016dbd,g1955dfad08+0bd186d245,g199a45376c+5137f08352,g1fd858c14a+a888a50aa2,g262e1987ae+45f9aba685,g29ae962dfc+1c7d47a24f,g2cef7863aa+73c82f25e4,g35bb328faa+edbf708997,g3fd5ace14f+eed17d2c67,g47891489e3+6dc8069a4c,g53246c7159+edbf708997,g64539dfbff+c4107e45b5,g67b6fd64d1+6dc8069a4c,g74acd417e5+f452e9c21a,g786e29fd12+af89c03590,g7ae74a0b1c+a25e60b391,g7aefaa3e3d+2025e9ce17,g7cc15d900a+2d158402f9,g87389fa792+a4172ec7da,g89139ef638+6dc8069a4c,g8d4809ba88+c4107e45b5,g8d7436a09f+e96c132b44,g8ea07a8fe4+db21c37724,g98df359435+aae6d409c1,ga2180abaac+edbf708997,gac66b60396+966efe6077,gb632fb1845+88945a90f8,gbaa8f7a6c5+38b34f4976,gbf99507273+edbf708997,gca7fc764a6+6dc8069a4c,gd7ef33dd92+6dc8069a4c,gda68eeecaf+7d1e613a8d,gdab6d2f7ff+f452e9c21a,gdbb4c4dda9+c4107e45b5,ge410e46f29+6dc8069a4c,ge41e95a9f2+c4107e45b5,geaed405ab2+e194be0d2b,w.2025.47
LSST Data Management Base Package
Loading...
Searching...
No Matches
_fits.cc
Go to the documentation of this file.
1/*
2 * This file is part of afw.
3 *
4 * Developed for the LSST Data Management System.
5 * This product includes software developed by the LSST Project
6 * (https://www.lsst.org).
7 * See the COPYRIGHT file at the top-level directory of this distribution
8 * for details of code ownership.
9 *
10 * This program is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 */
23
24#include <pybind11/pybind11.h>
25#include <pybind11/stl.h>
26#include <pybind11/native_enum.h>
27
29
30#include "ndarray/pybind11.h"
31
35#include "lsst/daf/base.h"
37
38#include "lsst/afw/fits.h"
39
40namespace py = pybind11;
41
42using namespace pybind11::literals;
43namespace lsst {
44namespace afw {
45namespace fits {
46namespace {
47void declareCompression(lsst::cpputils::python::WrapperCollection &wrappers) {
48 py::native_enum<CompressionAlgorithm>(wrappers.module, "CompressionAlgorithm", "enum.Enum")
49 .value("GZIP_1", CompressionAlgorithm::GZIP_1_)
50 .value("GZIP_2", CompressionAlgorithm::GZIP_2_)
51 .value("RICE_1", CompressionAlgorithm::RICE_1_)
52 .finalize();
53 py::native_enum<DitherAlgorithm>(wrappers.module, "DitherAlgorithm", "enum.Enum")
54 .value("NO_DITHER", DitherAlgorithm::NO_DITHER_)
55 .value("SUBTRACTIVE_DITHER_1", DitherAlgorithm::SUBTRACTIVE_DITHER_1_)
56 .value("SUBTRACTIVE_DITHER_2", DitherAlgorithm::SUBTRACTIVE_DITHER_2_)
57 .finalize();
58 py::native_enum<ScalingAlgorithm>(wrappers.module, "ScalingAlgorithm", "enum.Enum")
59 .value("RANGE", ScalingAlgorithm::RANGE)
60 .value("STDEV_MASKED", ScalingAlgorithm::STDEV_MASKED)
61 .value("STDEV_CFITSIO", ScalingAlgorithm::STDEV_CFITSIO)
62 .value("MANUAL", ScalingAlgorithm::MANUAL)
63 .finalize();
64 wrappers.wrapType(
65 py::class_<QuantizationOptions>(wrappers.module, "QuantizationOptions"),
66 [](auto &mod, auto &cls) {
67 cls.def(
68 py::init<DitherAlgorithm, ScalingAlgorithm, std::vector<std::string>, float, int>(),
69 py::kw_only(),
70 "dither"_a = DitherAlgorithm::NO_DITHER_,
71 "scaling"_a = ScalingAlgorithm::STDEV_MASKED,
72 "mask_planes"_a = py::list(),
73 "level"_a = 0.0,
74 "seed"_a = 0
75 );
76 cls.def_readwrite("dither", &QuantizationOptions::dither);
77 cls.def_readwrite("scaling", &QuantizationOptions::scaling);
78 cls.def_readwrite("mask_planes", &QuantizationOptions::mask_planes);
79 cls.def_readwrite("level", &QuantizationOptions::level);
80 cls.def_readwrite("seed", &QuantizationOptions::seed);
81 });
82 wrappers.wrapType(
83 py::class_<CompressionOptions>(wrappers.module, "CompressionOptions"),
84 [](auto &mod, auto &cls) {
85 cls.def(
86 py::init<
87 CompressionAlgorithm,
88 std::size_t,
89 std::size_t,
90 std::optional<QuantizationOptions>
91 >(),
92 py::kw_only(),
93 "algorithm"_a = CompressionAlgorithm::GZIP_2_,
94 "tile_width"_a = 0,
95 "tile_height"_a = 1,
96 "quantization"_a = py::none()
97 );
98 cls.def_readwrite("algorithm", &CompressionOptions::algorithm);
99 cls.def_readwrite("tile_width", &CompressionOptions::tile_width);
100 cls.def_readwrite("tile_height", &CompressionOptions::tile_height);
101 cls.def_readwrite("quantization", &CompressionOptions::quantization);
102 });
103}
104
105// Wrapping for lsst::afw::fits::Fits
106//
107// Not every feature is wrapped, only those that we guess might be useful.
108// In particular, the header keyword read/write and table read/write are not wrapped.
109void declareFits(lsst::cpputils::python::WrapperCollection &wrappers) {
110 wrappers.wrapType(py::class_<Fits>(wrappers.module, "Fits"), [](auto &mod, auto &cls) {
111 cls.def(py::init<std::string const &, std::string const &, int>(), "filename"_a, "mode"_a,
112 "behavior"_a = Fits::AUTO_CLOSE | Fits::AUTO_CHECK);
113 cls.def(py::init<MemFileManager &, std::string const &, int>(), "manager"_a, "mode"_a,
114 "behavior"_a = Fits::AUTO_CLOSE | Fits::AUTO_CHECK);
115
116 cls.def("closeFile", &Fits::closeFile);
117 cls.def("getFileName", &Fits::getFileName);
118 cls.def("getHdu", &Fits::getHdu);
119 cls.def("setHdu", py::overload_cast<int, bool>(&Fits::setHdu), "hdu"_a, "relative"_a = false);
120 cls.def(
121 "setHdu", [](Fits &self, std::string const &name) { self.setHdu(name); }, "name"_a);
122 cls.def("countHdus", &Fits::countHdus);
123
124 cls.def("writeMetadata", &Fits::writeMetadata);
125 cls.def(
126 "readMetadata", [](Fits &self, bool strip = false) { return readMetadata(self, strip); },
127 "strip"_a = false);
128 cls.def("createEmpty", &Fits::createEmpty);
129
130 cls.def("readImageI", [](Fits &self) {
131 ndarray::Vector<int, 2> const offset; // initialized to zero by default
132 ndarray::Vector<ndarray::Size, 2> shape = self.getImageShape<2>();
133 ndarray::Array<int, 2, 2> result = ndarray::allocate(shape[0], shape[1]);
134 self.readImage(result, offset);
135 return result;
136 });
137
138 cls.def("gotoFirstHdu", [](Fits &self) { self.setHdu(DEFAULT_HDU); });
139
140 cls.def("checkCompressedImagePhu", &Fits::checkCompressedImagePhu);
141
142 cls.def_readonly("status", &Fits::status);
143 });
144}
145
146void declareFitsModule(lsst::cpputils::python::WrapperCollection &wrappers) {
147 wrappers.wrap([](auto &mod) {
148 py::class_<MemFileManager> clsMemFileManager(mod, "MemFileManager");
149
150 clsMemFileManager.def(py::init<>());
151 clsMemFileManager.def(py::init<size_t>());
152
153 /* TODO: We should really revisit persistence and pickling as this is quite ugly.
154 * But it is what Swig did (sort of, it used the cdata.i extension), so I reckon this
155 * is cleaner because it does not expose casting to the Python side. */
156 clsMemFileManager.def("getLength", &MemFileManager::getLength);
157 clsMemFileManager.def("getData", [](MemFileManager &m) {
158 return py::bytes(static_cast<char *>(m.getData()), m.getLength());
159 });
160 clsMemFileManager.def("setData", [](MemFileManager &m, py::bytes const &d, size_t size) {
161 memcpy(m.getData(), PyBytes_AsString(d.ptr()), size);
162 });
163 clsMemFileManager.def(
164 "readMetadata",
165 [](MemFileManager &self, int hdu = DEFAULT_HDU, bool strip = false) {
166 return readMetadata(self, hdu, strip);
167 },
168 "hdu"_a = DEFAULT_HDU, "strip"_a = false);
169 mod.attr("DEFAULT_HDU") = DEFAULT_HDU;
170 mod.def(
171 "combineMetadata",
172 py::overload_cast<daf::base::PropertyList const&, daf::base::PropertyList const &>(
174 ),
175 "first"_a, "second"_a
176 );
177 mod.def("makeLimitedFitsHeader", &makeLimitedFitsHeader, "metadata"_a,
178 "excludeNames"_a = std::set<std::string>());
179 mod.def(
180 "readMetadata",
181 [](std::string const &filename, int hdu = DEFAULT_HDU, bool strip = false) {
182 return readMetadata(filename, hdu, strip);
183 },
184 "fileName"_a, "hdu"_a = DEFAULT_HDU, "strip"_a = false);
185
186 mod.def(
187 "readMetadata",
188 [](std::string const &filename, std::string const &hduname, bool strip = false) {
189 return readMetadata(filename, hduname, HduType::ANY, 0, strip);
190 },
191 "fileName"_a, "hduName"_a, "strip"_a = false);
192 });
193}
194} // namespace
195PYBIND11_MODULE(_fits, mod) {
196 lsst::cpputils::python::WrapperCollection wrappers(mod, "lsst.afw.fits");
197 wrappers.addInheritanceDependency("lsst.pex.exceptions");
198 wrappers.addSignatureDependency("lsst.daf.base");
199 // FIXME: after afw.image pybind wrappers are converted
200 //wrappers.addSignatureDependency("lsst.afw.image");
201 auto cls = wrappers.wrapException<FitsError, lsst::pex::exceptions::IoError>("FitsError", "IoError");
202 cls.def(py::init<std::string const &>());
203 declareCompression(wrappers);
204 declareFits(wrappers);
205 declareFitsModule(wrappers);
206 wrappers.finish();
207}
208} // namespace fits
209} // namespace afw
210} // namespace lsst
An exception thrown when problems are found when reading or writing FITS files.
Definition fits.h:37
A simple struct that combines the two arguments that must be passed to most cfitsio routines and cont...
Definition fits.h:242
void createEmpty()
Create an empty image HDU with NAXIS=0 at the end of the file.
Definition fits.cc:1534
bool checkCompressedImagePhu()
Go to the first image header in the FITS file.
Definition fits.cc:1902
int countHdus()
Return the number of HDUs in the file.
Definition fits.cc:518
void writeMetadata(daf::base::PropertySet const &metadata)
Read a FITS header into a PropertySet or PropertyList.
Definition fits.cc:1086
Lifetime-management for memory that goes into FITS memory files.
Definition fits.h:126
std::size_t getLength() const
Return the buffer length.
Definition fits.h:199
A helper class for subdividing pybind11 module across multiple translation units (i....
Definition python.h:242
void addSignatureDependency(std::string const &name)
Indicate an external module that provides a type used in function/method signatures.
Definition python.h:357
void wrap(WrapperCallback function)
Add a set of wrappers without defining a class.
Definition python.h:369
void addInheritanceDependency(std::string const &name)
Indicate an external module that provides a base class for a subsequent addType call.
Definition python.h:343
PyType wrapType(PyType cls, ClassWrapperCallback function, bool setModuleName=true)
Add a type (class or enum) wrapper, deferring method and other attribute definitions until finish() i...
Definition python.h:391
pybind11::module module
The module object passed to the PYBIND11_MODULE block that contains this WrapperCollection.
Definition python.h:448
void finish()
Invoke all deferred wrapper-declaring callables.
Definition python.h:435
auto wrapException(std::string const &pyName, std::string const &pyBase, bool setModuleName=true)
Wrap a C++ exception as a Python exception.
Definition python.h:421
Reports errors in external input/output operations.
Definition Runtime.h:160
PYBIND11_MODULE(_gauss2d, m)
Definition pybind11.cc:31
T memcpy(T... args)
std::shared_ptr< daf::base::PropertyList > combineMetadata(daf::base::PropertyList const &first, daf::base::PropertyList const &second)
Combine two sets of metadata in a FITS-appropriate fashion.
Definition fits.cc:1783
const int DEFAULT_HDU
Specify that the default HDU should be read.
std::shared_ptr< daf::base::PropertyList > readMetadata(std::string const &fileName, int hdu=DEFAULT_HDU, bool strip=false)
Read FITS header.
Definition fits.cc:1824
@ RANGE
Scale to preserve dynamic range with bad pixels msasked out.
@ STDEV_MASKED
Scale based on the standard deviation with bad pixels masked out.
@ STDEV_CFITSIO
Let CFITSIO work out the scaling (per-tile; does not respect mask planes)
std::string makeLimitedFitsHeader(lsst::daf::base::PropertySet const &metadata, std::set< std::string > const &excludeNames={})
Format a PropertySet into an FITS header string in a simplistic fashion.
Definition fits.cc:433