12 #ifndef RTCTK_COMPONENTFRAMEWORK_FITSIOFUNCTIONS_HPP
13 #define RTCTK_COMPONENTFRAMEWORK_FITSIOFUNCTIONS_HPP
15 #include <boost/filesystem.hpp>
23 #include <type_traits>
36 void IdentifyCfitsioTypes(
int& bitpix,
int& datatype) {
37 if constexpr (std::is_integral_v<T>) {
38 if constexpr (std::is_same_v<T, bool>) {
41 }
else if constexpr (
sizeof(T) == 1) {
42 if constexpr (std::is_signed_v<T>) {
49 }
else if constexpr (
sizeof(T) == 2) {
50 if constexpr (std::is_signed_v<T>) {
57 }
else if constexpr (
sizeof(T) == 4) {
58 if constexpr (std::is_signed_v<T>) {
60 if constexpr (
sizeof(
int) == 4) {
62 }
else if constexpr (
sizeof(
long) == 4) {
65 static_assert(
sizeof(
int) == 4 or
sizeof(
long) == 4,
66 "Require either int or long type to be 32 bits wide.");
70 if constexpr (
sizeof(
unsigned int) == 4) {
72 }
else if constexpr (
sizeof(
unsigned long) == 4) {
76 sizeof(
unsigned int) == 4 or
sizeof(
unsigned long) == 4,
77 "Require either unsigned int or unsigned long type to be 32 bits wide.");
80 }
else if constexpr (
sizeof(T) == 8) {
81 if constexpr (std::is_signed_v<T>) {
82 bitpix = LONGLONG_IMG;
86 bitpix = ULONGLONG_IMG;
87 datatype = TULONGLONG;
91 bitpix = LONGLONG_IMG;
97 sizeof(T) == 1 or
sizeof(T) == 2 or
sizeof(T) == 4 or
sizeof(T) == 8,
98 "The integer type used as the template parameter must be one of 8, 16, 32, or 64"
102 if constexpr (std::is_floating_point_v<T>) {
103 if constexpr (
sizeof(T) == 4) {
106 }
else if constexpr (
sizeof(T) == 8) {
111 sizeof(T) == 4 or
sizeof(T) == 8,
112 "The floating-point type used as the template parameter must be float or double.");
115 static_assert(std::is_arithmetic_v<T>,
116 "The template parameter used must be an integer or floating-point type.");
152 template <
typename T,
typename A>
154 assert(int64_t(matrix.
GetNrows()) <= int64_t(std::numeric_limits<long>::max()));
155 assert(int64_t(matrix.
GetNcols()) <= int64_t(std::numeric_limits<long>::max()));
161 IdentifyCfitsioTypes<T>(bitpix, datatype);
163 std::string tmpfilename =
filename +
".new-" + std::to_string(getpid());
166 fitsfile* fptr =
nullptr;
168 if (fits_create_file(&fptr, tmpfilename.c_str(), &status) != 0) {
176 long nrows = long(matrix.
GetNrows());
177 long ncols = long(matrix.
GetNcols());
178 long size[2] = {ncols, nrows};
180 if (fits_create_img(fptr, bitpix, 2, size, &status) != 0) {
181 std::string msg =
"Failed to create the image type from FITS file '" + tmpfilename +
187 long fpixel[2] = {1, 1};
188 long nelements = matrix.size();
191 void* array =
const_cast<void*
>(
reinterpret_cast<const void*
>(matrix.data()));
193 if (fits_write_pix(fptr, datatype, fpixel, nelements, array, &status) != 0) {
194 std::string msg =
"Failed to write the matrix to FITS file '" + tmpfilename +
"'. " +
203 if (fits_close_file(fptr, &status) != 0) {
205 "Failed to close file '" + tmpfilename +
212 if (fits_close_file(fptr, &status) != 0) {
222 boost::filesystem::rename(tmpfilename,
filename);
223 }
catch (
const std::exception& error) {
224 CII_THROW_WITH_NESTED(
227 "Failed to rename FITS file '" + tmpfilename +
"' to '" +
filename +
"'.")
236 template <
typename T,
typename A>
240 int expected_bitpix = 0;
242 IdentifyCfitsioTypes<T>(expected_bitpix, datatype);
244 fitsfile* fptr =
nullptr;
246 if (fits_open_image(&fptr,
filename.c_str(), READONLY, &status) != 0) {
257 if (fits_get_img_equivtype(fptr, &bitpix, &status) != 0) {
258 std::string msg =
"Failed to read the image type from FITS file '" +
filename +
"'. " +
262 if (bitpix == LONGLONG_IMG) {
267 int result = fits_read_keyword(fptr,
"BZERO", value,
nullptr, &status);
268 if (result != 0 and status != KEY_NO_EXIST) {
269 std::string msg =
"Failed to read keyword BZERO from '" +
filename +
"'. " +
273 if (std::string(value) ==
274 std::to_string(std::numeric_limits<uint64_t>::max() / 2 + 1)) {
276 bitpix = ULONGLONG_IMG;
280 bitpix = LONGLONG_IMG;
284 if (bitpix != expected_bitpix) {
285 std::string msg =
"The FITS file '" +
filename +
"' has the wrong image format of " +
287 ". Expected a FITS image of type " +
295 if (fits_get_img_dim(fptr, &naxis, &status) != 0) {
296 std::string msg =
"Failed to read the number of image axes from FITS file '" +
301 std::string msg =
"The FITS file '" +
filename +
302 "' has image dimensions that we cannot handle. Expect a 2D image "
303 "when loading as a matrix.";
307 long size[2] = {-1, -1};
309 if (fits_get_img_size(fptr, 2, size, &status) != 0) {
310 std::string msg =
"Failed to read the image size from FITS file '" +
filename +
"'. " +
316 auto nrows = size_type(size[1]);
317 auto ncols = size_type(size[0]);
318 long nelements = size[0] * size[1];
320 long fpixel[2] = {1, 1};
322 matrix.
resize(nrows, ncols);
323 void* array = matrix.data();
326 fits_read_pix(fptr, datatype, fpixel, nelements,
nullptr, array, &anynull, &status);
328 std::string msg =
"Failed to read the image from FITS file '" +
filename +
"'. " +
337 if (fits_close_file(fptr, &status) != 0) {
339 "Failed to close file '" +
filename +
346 if (fits_close_file(fptr, &status) != 0) {
358 template <
typename T,
typename A>
360 assert(int64_t(vector.size()) <= int64_t(std::numeric_limits<long>::max()));
366 IdentifyCfitsioTypes<T>(bitpix, datatype);
368 std::string tmpfilename =
filename +
".new-" + std::to_string(getpid());
371 fitsfile* fptr =
nullptr;
373 if (fits_create_file(&fptr, tmpfilename.c_str(), &status) != 0) {
381 long size = long(vector.size());
383 if (fits_create_img(fptr, bitpix, 1, &size, &status) != 0) {
384 std::string msg =
"Failed to create the image type from FITS file '" + tmpfilename +
391 long nelements = vector.size();
394 void* array =
const_cast<void*
>(
reinterpret_cast<const void*
>(vector.data()));
396 if (fits_write_pix(fptr, datatype, &fpixel, nelements, array, &status) != 0) {
397 std::string msg =
"Failed to write the vector to FITS file '" + tmpfilename +
"'. " +
406 if (fits_close_file(fptr, &status) != 0) {
408 "Failed to close file '" + tmpfilename +
415 if (fits_close_file(fptr, &status) != 0) {
425 boost::filesystem::rename(tmpfilename,
filename);
426 }
catch (
const std::exception& error) {
427 CII_THROW_WITH_NESTED(
430 "Failed to rename FITS file '" + tmpfilename +
"' to '" +
filename +
"'.")
439 template <
typename T,
typename A>
443 int expected_bitpix = 0;
445 IdentifyCfitsioTypes<T>(expected_bitpix, datatype);
447 fitsfile* fptr =
nullptr;
449 if (fits_open_image(&fptr,
filename.c_str(), READONLY, &status) != 0) {
460 if (fits_get_img_equivtype(fptr, &bitpix, &status) != 0) {
461 std::string msg =
"Failed to read the image type from FITS file '" +
filename +
"'. " +
465 if (bitpix == LONGLONG_IMG) {
470 int result = fits_read_keyword(fptr,
"BZERO", value,
nullptr, &status);
471 if (result != 0 and status != KEY_NO_EXIST) {
472 std::string msg =
"Failed to read keyword BZERO from '" +
filename +
"'. " +
476 if (std::string(value) ==
477 std::to_string(std::numeric_limits<uint64_t>::max() / 2 + 1)) {
479 bitpix = ULONGLONG_IMG;
483 bitpix = LONGLONG_IMG;
487 if (bitpix != expected_bitpix) {
488 std::string msg =
"The FITS file '" +
filename +
"' has the wrong image format of " +
490 ". Expected a FITS image of type " +
498 if (fits_get_img_dim(fptr, &naxis, &status) != 0) {
499 std::string msg =
"Failed to read the number of image axes from FITS file '" +
504 std::string msg =
"The FITS file '" +
filename +
505 "' has image dimensions that we cannot handle. Expect a 1D image "
506 "when loading as a vector.";
512 if (fits_get_img_size(fptr, 1, &nelements, &status) != 0) {
513 std::string msg =
"Failed to read the 1D image size from FITS file '" +
filename +
518 using size_type =
typename std::vector<T, A>::size_type;
521 vector.resize(size_type(nelements));
522 void* array = vector.data();
525 fits_read_pix(fptr, datatype, &fpixel, nelements,
nullptr, array, &anynull, &status);
527 std::string msg =
"Failed to read the image from FITS file '" +
filename +
"'. " +
536 if (fits_close_file(fptr, &status) != 0) {
538 "Failed to close file '" +
filename +
545 if (fits_close_file(fptr, &status) != 0) {
557 template <
typename A>
564 int_matrix(n, m) = matrix(n, m) ? 1 : 0;
573 template <
typename A>
581 matrix(n, m) = int_matrix(n, m) == 1 ? true :
false;
589 template <
typename A>
592 std::vector<int8_t> int_vector;
593 int_vector.resize(vector.size());
594 for (std::vector<int8_t>::size_type n = 0; n < int_vector.size(); ++n) {
595 int_vector[n] = vector[n] ? 1 : 0;
603 template <
typename A>
606 std::vector<int8_t> int_vector;
608 vector.resize(int_vector.size());
609 for (std::vector<int8_t>::size_type n = 0; n < int_vector.size(); ++n) {
610 vector[n] = int_vector[n] == 1 ? true :
false;
641 #endif // RTCTK_COMPONENTFRAMEWORK_FITSIOFUNCTIONS_HPP