9 #ifndef RTCTK_COMPONENTFRAMEWORK_FITSIOFUNCTIONS_HPP
10 #define RTCTK_COMPONENTFRAMEWORK_FITSIOFUNCTIONS_HPP
13 #include <type_traits>
16 #include <boost/filesystem.hpp>
32 void IdentifyCfitsioTypes(
int& bitpix,
int& datatype) {
33 if constexpr (std::is_integral_v<T>) {
34 if constexpr (std::is_same_v<T, bool>) {
37 }
else if constexpr (
sizeof(T) == 1) {
38 if constexpr (std::is_signed_v<T>) {
45 }
else if constexpr (
sizeof(T) == 2) {
46 if constexpr (std::is_signed_v<T>) {
53 }
else if constexpr (
sizeof(T) == 4) {
54 if constexpr (std::is_signed_v<T>) {
56 if constexpr (
sizeof(
int) == 4) {
58 }
else if constexpr (
sizeof(
long) == 4) {
61 static_assert(
sizeof(
int) == 4 or
sizeof(
long) == 4,
62 "Require either int or long type to be 32 bits wide.");
66 if constexpr (
sizeof(
unsigned int) == 4) {
68 }
else if constexpr (
sizeof(
unsigned long) == 4) {
71 static_assert(
sizeof(
unsigned int) == 4 or
sizeof(
unsigned long) == 4,
72 "Require either unsigned int or unsigned long type to be 32 bits wide.");
75 }
else if constexpr (
sizeof(T) == 8) {
76 if constexpr (std::is_signed_v<T>) {
77 bitpix = LONGLONG_IMG;
81 bitpix = ULONGLONG_IMG;
82 datatype = TULONGLONG;
86 bitpix = LONGLONG_IMG;
91 static_assert(
sizeof(T) == 1 or
sizeof(T) == 2 or
sizeof(T) == 4 or
sizeof(T) == 8,
92 "The integer type used as the template parameter must be one of 8, 16, 32, or 64"
95 }
if constexpr (std::is_floating_point_v<T>) {
96 if constexpr (
sizeof(T) == 4) {
99 }
else if constexpr (
sizeof(T) == 8) {
103 static_assert(
sizeof(T) == 4 or
sizeof(T) == 8,
104 "The floating-point type used as the template parameter must be float or double.");
107 static_assert(std::is_arithmetic_v<T>,
108 "The template parameter used must be an integer or floating-point type.");
125 template <
typename T,
typename A>
127 assert(int64_t(matrix.
get_nrows()) <= int64_t(std::numeric_limits<long>::max()));
128 assert(int64_t(matrix.
get_ncols()) <= int64_t(std::numeric_limits<long>::max()));
134 IdentifyCfitsioTypes<T>(bitpix, datatype);
136 std::string tmpfilename =
filename +
".new-" + std::to_string(getpid());
139 fitsfile* fptr =
nullptr;
141 if (fits_create_file(&fptr, tmpfilename.c_str(), &status) != 0) {
142 std::string msg =
"Failed to create FITS file '" + tmpfilename +
"'. "
151 long size[2] = {ncols, nrows};
153 if (fits_create_img(fptr, bitpix, 2, size, &status) != 0) {
154 std::string msg =
"Failed to create the image type from FITS file '" + tmpfilename
160 long fpixel[2] = {1, 1};
161 long nelements = matrix.size();
164 void* array =
const_cast<void*
>(
reinterpret_cast<const void*
>(matrix.data()));
166 if (fits_write_pix(fptr, datatype, fpixel, nelements, array, &status) != 0) {
167 std::string msg =
"Failed to write the matrix to FITS file '" + tmpfilename +
"'. "
176 if (fits_close_file(fptr, &status) != 0) {
177 LOG4CPLUS_ERROR(
GetLogger(),
"Failed to close file '" + tmpfilename
184 if (fits_close_file(fptr, &status) != 0) {
185 std::string msg =
"Failed to close the FITS file '" + tmpfilename +
"'. "
194 boost::filesystem::rename(tmpfilename,
filename);
195 }
catch (
const std::exception&
error) {
197 "Failed to rename FITS file '" + tmpfilename +
"' to '" +
filename +
"'.")
206 template <
typename T,
typename A>
210 int expected_bitpix = 0;
212 IdentifyCfitsioTypes<T>(expected_bitpix, datatype);
214 fitsfile* fptr =
nullptr;
216 if (fits_open_image(&fptr,
filename.c_str(), READONLY, &status) != 0) {
217 std::string msg =
"Failed to open FITS file '" +
filename +
"'. "
227 if (fits_get_img_equivtype(fptr, &bitpix, &status) != 0) {
228 std::string msg =
"Failed to read the image type from FITS file '" +
filename +
"'. "
232 if (bitpix == LONGLONG_IMG) {
237 int result = fits_read_keyword(fptr,
"BZERO", value,
nullptr, &status);
238 if (result != 0 and status != KEY_NO_EXIST) {
239 std::string msg =
"Failed to read keyword BZERO from '" +
filename +
"'. "
243 if (std::string(value) == std::to_string(std::numeric_limits<uint64_t>::max()/2+1)) {
245 bitpix = ULONGLONG_IMG;
249 bitpix = LONGLONG_IMG;
253 if (bitpix != expected_bitpix) {
254 std::string msg =
"The FITS file '" +
filename +
"' has the wrong image format of " +
263 if (fits_get_img_dim(fptr, &naxis, &status) != 0) {
264 std::string msg =
"Failed to read the number of image axes from FITS file '"
269 std::string msg =
"The FITS file '" +
filename +
"' has image dimensions that we cannot"
270 " handle. Expect a 2D image when loading as a matrix.";
274 long size[2] = {-1, -1};
276 if (fits_get_img_size(fptr, 2, size, &status) != 0) {
277 std::string msg =
"Failed to read the image size from FITS file '" +
filename +
"'. "
283 auto nrows = size_type(size[1]);
284 auto ncols = size_type(size[0]);
285 long nelements = size[0] * size[1];
287 long fpixel[2] = {1, 1};
289 matrix.
resize(nrows, ncols);
290 void* array = matrix.data();
292 if (fits_read_pix(fptr, datatype, fpixel, nelements,
nullptr, array, &anynull,
294 std::string msg =
"Failed to read the image from FITS file '" +
filename +
"'. "
303 if (fits_close_file(fptr, &status) != 0) {
311 if (fits_close_file(fptr, &status) != 0) {
312 std::string msg =
"Failed to close the FITS file '" +
filename +
"'. "
323 template <
typename T,
typename A>
325 assert(int64_t(vector.size()) <= int64_t(std::numeric_limits<long>::max()));
331 IdentifyCfitsioTypes<T>(bitpix, datatype);
333 std::string tmpfilename =
filename +
".new-" + std::to_string(getpid());
336 fitsfile* fptr =
nullptr;
338 if (fits_create_file(&fptr, tmpfilename.c_str(), &status) != 0) {
339 std::string msg =
"Failed to create FITS file '" + tmpfilename +
"'. "
346 long size = long(vector.size());
348 if (fits_create_img(fptr, bitpix, 1, &size, &status) != 0) {
349 std::string msg =
"Failed to create the image type from FITS file '" + tmpfilename
356 long nelements = vector.size();
359 void* array =
const_cast<void*
>(
reinterpret_cast<const void*
>(vector.data()));
361 if (fits_write_pix(fptr, datatype, &fpixel, nelements, array, &status) != 0) {
362 std::string msg =
"Failed to write the vector to FITS file '" + tmpfilename +
"'. "
371 if (fits_close_file(fptr, &status) != 0) {
372 LOG4CPLUS_ERROR(
GetLogger(),
"Failed to close file '" + tmpfilename
379 if (fits_close_file(fptr, &status) != 0) {
380 std::string msg =
"Failed to close the FITS file '" + tmpfilename +
"'. "
389 boost::filesystem::rename(tmpfilename,
filename);
390 }
catch (
const std::exception&
error) {
392 "Failed to rename FITS file '" + tmpfilename +
"' to '" +
filename +
"'.")
401 template <
typename T,
typename A>
405 int expected_bitpix = 0;
407 IdentifyCfitsioTypes<T>(expected_bitpix, datatype);
409 fitsfile* fptr =
nullptr;
411 if (fits_open_image(&fptr,
filename.c_str(), READONLY, &status) != 0) {
412 std::string msg =
"Failed to open FITS file '" +
filename +
"'. "
422 if (fits_get_img_equivtype(fptr, &bitpix, &status) != 0) {
423 std::string msg =
"Failed to read the image type from FITS file '" +
filename +
"'. "
427 if (bitpix == LONGLONG_IMG) {
432 int result = fits_read_keyword(fptr,
"BZERO", value,
nullptr, &status);
433 if (result != 0 and status != KEY_NO_EXIST) {
434 std::string msg =
"Failed to read keyword BZERO from '" +
filename +
"'. "
438 if (std::string(value) == std::to_string(std::numeric_limits<uint64_t>::max()/2+1)) {
440 bitpix = ULONGLONG_IMG;
444 bitpix = LONGLONG_IMG;
448 if (bitpix != expected_bitpix) {
449 std::string msg =
"The FITS file '" +
filename +
"' has the wrong image format of " +
458 if (fits_get_img_dim(fptr, &naxis, &status) != 0) {
459 std::string msg =
"Failed to read the number of image axes from FITS file '"
464 std::string msg =
"The FITS file '" +
filename +
"' has image dimensions that we cannot"
465 " handle. Expect a 1D image when loading as a vector.";
471 if (fits_get_img_size(fptr, 1, &nelements, &status) != 0) {
472 std::string msg =
"Failed to read the 1D image size from FITS file '" +
filename +
"'. "
477 using size_type =
typename std::vector<T, A>::size_type;
480 vector.resize(size_type(nelements));
481 void* array = vector.data();
483 if (fits_read_pix(fptr, datatype, &fpixel, nelements,
nullptr, array, &anynull,
485 std::string msg =
"Failed to read the image from FITS file '" +
filename +
"'. "
494 if (fits_close_file(fptr, &status) != 0) {
502 if (fits_close_file(fptr, &status) != 0) {
503 std::string msg =
"Failed to close the FITS file '" +
filename +
"'. "
514 template <
typename A>
521 int_matrix(n, m) = matrix(n, m) ? 1 : 0;
530 template <
typename A>
538 matrix(n, m) = int_matrix(n, m) == 1 ? true :
false;
546 template <
typename A>
549 std::vector<int8_t> int_vector;
550 int_vector.resize(vector.size());
551 for (std::vector<int8_t>::size_type n = 0; n < int_vector.size(); ++n) {
552 int_vector[n] = vector[n] ? 1 : 0;
560 template <
typename A>
563 std::vector<int8_t> int_vector;
565 vector.resize(int_vector.size());
566 for (std::vector<int8_t>::size_type n = 0; n < int_vector.size(); ++n) {
567 vector[n] = int_vector[n] == 1 ? true :
false;
573 #endif // RTCTK_COMPONENTFRAMEWORK_FITSIOFUNCTIONS_HPP