12 #ifndef RTCTK_COMPONENTFRAMEWORK_FITSIOFUNCTIONS_HPP
13 #define RTCTK_COMPONENTFRAMEWORK_FITSIOFUNCTIONS_HPP
15 #include <boost/filesystem.hpp>
23 #include <type_traits>
35 void IdentifyCfitsioTypes(
int& bitpix,
int& datatype) {
36 if constexpr (std::is_integral_v<T>) {
37 if constexpr (std::is_same_v<T, bool>) {
40 }
else if constexpr (
sizeof(T) == 1) {
41 if constexpr (std::is_signed_v<T>) {
48 }
else if constexpr (
sizeof(T) == 2) {
49 if constexpr (std::is_signed_v<T>) {
56 }
else if constexpr (
sizeof(T) == 4) {
57 if constexpr (std::is_signed_v<T>) {
59 if constexpr (
sizeof(
int) == 4) {
61 }
else if constexpr (
sizeof(
long) == 4) {
64 static_assert(
sizeof(
int) == 4 or
sizeof(
long) == 4,
65 "Require either int or long type to be 32 bits wide.");
69 if constexpr (
sizeof(
unsigned int) == 4) {
71 }
else if constexpr (
sizeof(
unsigned long) == 4) {
75 sizeof(
unsigned int) == 4 or
sizeof(
unsigned long) == 4,
76 "Require either unsigned int or unsigned long type to be 32 bits wide.");
79 }
else if constexpr (
sizeof(T) == 8) {
80 if constexpr (std::is_signed_v<T>) {
81 bitpix = LONGLONG_IMG;
85 bitpix = ULONGLONG_IMG;
86 datatype = TULONGLONG;
90 bitpix = LONGLONG_IMG;
96 sizeof(T) == 1 or
sizeof(T) == 2 or
sizeof(T) == 4 or
sizeof(T) == 8,
97 "The integer type used as the template parameter must be one of 8, 16, 32, or 64"
101 if constexpr (std::is_floating_point_v<T>) {
102 if constexpr (
sizeof(T) == 4) {
105 }
else if constexpr (
sizeof(T) == 8) {
110 sizeof(T) == 4 or
sizeof(T) == 8,
111 "The floating-point type used as the template parameter must be float or double.");
114 static_assert(std::is_arithmetic_v<T>,
115 "The template parameter used must be an integer or floating-point type.");
151 template <
typename T,
typename A>
153 assert(int64_t(matrix.
GetNrows()) <= int64_t(std::numeric_limits<long>::max()));
154 assert(int64_t(matrix.
GetNcols()) <= int64_t(std::numeric_limits<long>::max()));
160 IdentifyCfitsioTypes<T>(bitpix, datatype);
162 std::string tmpfilename =
filename +
".new-" + std::to_string(getpid());
165 fitsfile* fptr =
nullptr;
167 if (fits_create_file(&fptr, tmpfilename.c_str(), &status) != 0) {
175 long nrows = long(matrix.
GetNrows());
176 long ncols = long(matrix.
GetNcols());
177 long size[2] = {ncols, nrows};
179 if (fits_create_img(fptr, bitpix, 2, size, &status) != 0) {
180 std::string msg =
"Failed to create the image type from FITS file '" + tmpfilename +
186 long fpixel[2] = {1, 1};
187 long nelements = matrix.size();
190 void* array =
const_cast<void*
>(
reinterpret_cast<const void*
>(matrix.data()));
192 if (fits_write_pix(fptr, datatype, fpixel, nelements, array, &status) != 0) {
193 std::string msg =
"Failed to write the matrix to FITS file '" + tmpfilename +
"'. " +
202 if (fits_close_file(fptr, &status) != 0) {
204 "Failed to close file '" + tmpfilename +
211 if (fits_close_file(fptr, &status) != 0) {
221 boost::filesystem::rename(tmpfilename,
filename);
222 }
catch (
const std::exception&
error) {
223 CII_THROW_WITH_NESTED(
226 "Failed to rename FITS file '" + tmpfilename +
"' to '" +
filename +
"'.")
235 template <
typename T,
typename A>
239 int expected_bitpix = 0;
241 IdentifyCfitsioTypes<T>(expected_bitpix, datatype);
243 fitsfile* fptr =
nullptr;
245 if (fits_open_image(&fptr,
filename.c_str(), READONLY, &status) != 0) {
256 if (fits_get_img_equivtype(fptr, &bitpix, &status) != 0) {
257 std::string msg =
"Failed to read the image type from FITS file '" +
filename +
"'. " +
261 if (bitpix == LONGLONG_IMG) {
266 int result = fits_read_keyword(fptr,
"BZERO", value,
nullptr, &status);
267 if (result != 0 and status != KEY_NO_EXIST) {
268 std::string msg =
"Failed to read keyword BZERO from '" +
filename +
"'. " +
272 if (std::string(value) ==
273 std::to_string(std::numeric_limits<uint64_t>::max() / 2 + 1)) {
275 bitpix = ULONGLONG_IMG;
279 bitpix = LONGLONG_IMG;
283 if (bitpix != expected_bitpix) {
284 std::string msg =
"The FITS file '" +
filename +
"' has the wrong image format of " +
286 ". Expected a FITS image of type " +
294 if (fits_get_img_dim(fptr, &naxis, &status) != 0) {
295 std::string msg =
"Failed to read the number of image axes from FITS file '" +
300 std::string msg =
"The FITS file '" +
filename +
301 "' has image dimensions that we cannot handle. Expect a 2D image "
302 "when loading as a matrix.";
306 long size[2] = {-1, -1};
308 if (fits_get_img_size(fptr, 2, size, &status) != 0) {
309 std::string msg =
"Failed to read the image size from FITS file '" +
filename +
"'. " +
315 auto nrows = size_type(size[1]);
316 auto ncols = size_type(size[0]);
317 long nelements = size[0] * size[1];
319 long fpixel[2] = {1, 1};
321 matrix.
resize(nrows, ncols);
322 void* array = matrix.data();
325 fits_read_pix(fptr, datatype, fpixel, nelements,
nullptr, array, &anynull, &status);
327 std::string msg =
"Failed to read the image from FITS file '" +
filename +
"'. " +
336 if (fits_close_file(fptr, &status) != 0) {
338 "Failed to close file '" +
filename +
345 if (fits_close_file(fptr, &status) != 0) {
357 template <
typename T,
typename A>
359 assert(int64_t(vector.size()) <= int64_t(std::numeric_limits<long>::max()));
365 IdentifyCfitsioTypes<T>(bitpix, datatype);
367 std::string tmpfilename =
filename +
".new-" + std::to_string(getpid());
370 fitsfile* fptr =
nullptr;
372 if (fits_create_file(&fptr, tmpfilename.c_str(), &status) != 0) {
380 long size = long(vector.size());
382 if (fits_create_img(fptr, bitpix, 1, &size, &status) != 0) {
383 std::string msg =
"Failed to create the image type from FITS file '" + tmpfilename +
390 long nelements = vector.size();
393 void* array =
const_cast<void*
>(
reinterpret_cast<const void*
>(vector.data()));
395 if (fits_write_pix(fptr, datatype, &fpixel, nelements, array, &status) != 0) {
396 std::string msg =
"Failed to write the vector to FITS file '" + tmpfilename +
"'. " +
405 if (fits_close_file(fptr, &status) != 0) {
407 "Failed to close file '" + tmpfilename +
414 if (fits_close_file(fptr, &status) != 0) {
424 boost::filesystem::rename(tmpfilename,
filename);
425 }
catch (
const std::exception&
error) {
426 CII_THROW_WITH_NESTED(
429 "Failed to rename FITS file '" + tmpfilename +
"' to '" +
filename +
"'.")
438 template <
typename T,
typename A>
442 int expected_bitpix = 0;
444 IdentifyCfitsioTypes<T>(expected_bitpix, datatype);
446 fitsfile* fptr =
nullptr;
448 if (fits_open_image(&fptr,
filename.c_str(), READONLY, &status) != 0) {
459 if (fits_get_img_equivtype(fptr, &bitpix, &status) != 0) {
460 std::string msg =
"Failed to read the image type from FITS file '" +
filename +
"'. " +
464 if (bitpix == LONGLONG_IMG) {
469 int result = fits_read_keyword(fptr,
"BZERO", value,
nullptr, &status);
470 if (result != 0 and status != KEY_NO_EXIST) {
471 std::string msg =
"Failed to read keyword BZERO from '" +
filename +
"'. " +
475 if (std::string(value) ==
476 std::to_string(std::numeric_limits<uint64_t>::max() / 2 + 1)) {
478 bitpix = ULONGLONG_IMG;
482 bitpix = LONGLONG_IMG;
486 if (bitpix != expected_bitpix) {
487 std::string msg =
"The FITS file '" +
filename +
"' has the wrong image format of " +
489 ". Expected a FITS image of type " +
497 if (fits_get_img_dim(fptr, &naxis, &status) != 0) {
498 std::string msg =
"Failed to read the number of image axes from FITS file '" +
503 std::string msg =
"The FITS file '" +
filename +
504 "' has image dimensions that we cannot handle. Expect a 1D image "
505 "when loading as a vector.";
511 if (fits_get_img_size(fptr, 1, &nelements, &status) != 0) {
512 std::string msg =
"Failed to read the 1D image size from FITS file '" +
filename +
517 using size_type =
typename std::vector<T, A>::size_type;
520 vector.resize(size_type(nelements));
521 void* array = vector.data();
524 fits_read_pix(fptr, datatype, &fpixel, nelements,
nullptr, array, &anynull, &status);
526 std::string msg =
"Failed to read the image from FITS file '" +
filename +
"'. " +
535 if (fits_close_file(fptr, &status) != 0) {
537 "Failed to close file '" +
filename +
544 if (fits_close_file(fptr, &status) != 0) {
556 template <
typename A>
563 int_matrix(n, m) = matrix(n, m) ? 1 : 0;
572 template <
typename A>
580 matrix(n, m) = int_matrix(n, m) == 1 ? true :
false;
588 template <
typename A>
591 std::vector<int8_t> int_vector;
592 int_vector.resize(vector.size());
593 for (std::vector<int8_t>::size_type n = 0; n < int_vector.size(); ++n) {
594 int_vector[n] = vector[n] ? 1 : 0;
602 template <
typename A>
605 std::vector<int8_t> int_vector;
607 vector.resize(int_vector.size());
608 for (std::vector<int8_t>::size_type n = 0; n < int_vector.size(); ++n) {
609 vector[n] = int_vector[n] == 1 ? true :
false;
615 #endif // RTCTK_COMPONENTFRAMEWORK_FITSIOFUNCTIONS_HPP