RTC Toolkit 4.0.1
Loading...
Searching...
No Matches
fitsIoFunctions.hpp
Go to the documentation of this file.
1
13#ifndef RTCTK_COMPONENTFRAMEWORK_FITSIOFUNCTIONS_HPP
14#define RTCTK_COMPONENTFRAMEWORK_FITSIOFUNCTIONS_HPP
15
16#include <cassert>
17#include <filesystem>
18#include <limits>
19#include <string>
20#include <type_traits>
21#include <typeinfo>
22#include <unistd.h>
23
24#include <fitsio.h>
25
26#include <fmt/format.h>
27
32
33namespace {
34
41template <typename T>
42void IdentifyCfitsioTypes(int& bitpix, int& datatype) {
43 if constexpr (std::is_integral_v<T>) {
44 if constexpr (std::is_same_v<T, bool>) {
45 bitpix = BYTE_IMG;
46 datatype = TBYTE;
47 } else if constexpr (sizeof(T) == 1) {
48 if constexpr (std::is_signed_v<T>) {
49 bitpix = SBYTE_IMG;
50 datatype = TSBYTE;
51 } else {
52 bitpix = BYTE_IMG;
53 datatype = TBYTE;
54 }
55 } else if constexpr (sizeof(T) == 2) {
56 if constexpr (std::is_signed_v<T>) {
57 bitpix = SHORT_IMG;
58 datatype = TSHORT;
59 } else {
60 bitpix = USHORT_IMG;
61 datatype = TUSHORT;
62 }
63 } else if constexpr (sizeof(T) == 4) {
64 if constexpr (std::is_signed_v<T>) {
65 bitpix = LONG_IMG;
66 if constexpr (sizeof(int) == 4) {
67 datatype = TINT;
68 } else if constexpr (sizeof(long) == 4) {
69 datatype = TLONG;
70 } else {
71 static_assert(sizeof(int) == 4 or sizeof(long) == 4,
72 "Require either int or long type to be 32 bits wide.");
73 }
74 } else {
75 bitpix = ULONG_IMG;
76 if constexpr (sizeof(unsigned int) == 4) {
77 datatype = TUINT;
78 } else if constexpr (sizeof(unsigned long) == 4) {
79 datatype = TULONG;
80 } else {
81 static_assert(
82 sizeof(unsigned int) == 4 or sizeof(unsigned long) == 4,
83 "Require either unsigned int or unsigned long type to be 32 bits wide.");
84 }
85 }
86 } else if constexpr (sizeof(T) == 8) {
87 if constexpr (std::is_signed_v<T>) {
88 bitpix = LONGLONG_IMG;
89 datatype = TLONGLONG;
90 } else {
91#ifdef ULONGLONG_IMG
92 bitpix = ULONGLONG_IMG;
93 datatype = TULONGLONG;
94#else
95 // If we are using an older Cfitsio library that does not have ULONGLONG_IMG defined
96 // then simply alias to using the signed version for the image code and data type.
97 bitpix = LONGLONG_IMG;
98 datatype = TLONGLONG;
99#endif
100 }
101 } else {
102 static_assert(
103 sizeof(T) == 1 or sizeof(T) == 2 or sizeof(T) == 4 or sizeof(T) == 8,
104 "The integer type used as the template parameter must be one of 8, 16, 32, or 64"
105 " bits wide.");
106 }
107 }
108 if constexpr (std::is_floating_point_v<T>) {
109 if constexpr (sizeof(T) == 4) {
110 bitpix = FLOAT_IMG;
111 datatype = TFLOAT;
112 } else if constexpr (sizeof(T) == 8) {
113 bitpix = DOUBLE_IMG;
114 datatype = TDOUBLE;
115 } else {
116 static_assert(
117 sizeof(T) == 4 or sizeof(T) == 8,
118 "The floating-point type used as the template parameter must be float or double.");
119 }
120 } else {
121 static_assert(std::is_arithmetic_v<T>,
122 "The template parameter used must be an integer or floating-point type.");
123 }
124}
125
126} // namespace
127
129
136std::string GetCfitsioErrorMsg(int status);
137
145std::string CfitsioImageTypeToString(int bitpix);
146
154std::string CfitsioDataTypeToString(int datatype);
155
164template <typename T>
165void WriteMatrixToFits(const std::string& filename, const T& matrix, bool boolean_items = false) {
166 static_assert(IS_MATRIX_BUFFER_TYPE<T> or IS_MATRIX_SPAN_TYPE<T>,
167 "The matrix argument must be of type MatrixBuffer or MatrixSpan.");
168 assert(int64_t(matrix.GetNrows()) <= int64_t(std::numeric_limits<long>::max()));
169 assert(int64_t(matrix.GetNcols()) <= int64_t(std::numeric_limits<long>::max()));
170
171 using U = typename T::value_type;
172 // Workout the appropriate Cfitsio image type code and data type code to use, based on the type
173 // used with MatrixBuffer or MatrixSpan, i.e. the type of U.
174 int bitpix = 0;
175 int datatype = 0;
176 IdentifyCfitsioTypes<U>(bitpix, datatype);
177
178 std::string tmpfilename = filename + ".new-" + std::to_string(getpid());
179
180 // Create the new FITS file and open it for modifications.
181 fitsfile* fptr = nullptr;
182 int status = 0; // It is important to initialise this to zero before each Cfitsio API call.
183 if (fits_create_file(&fptr, tmpfilename.c_str(), &status) != 0) {
184 std::string msg = fmt::format(
185 "Failed to create FITS file '{}'. {}", tmpfilename, GetCfitsioErrorMsg(status));
186 CII_THROW(RtctkException, msg);
187 }
188
189 try {
190 // Create the image header in the HDU.
191 long nrows = static_cast<long>(matrix.GetNrows());
192 long ncols = static_cast<long>(matrix.GetNcols());
193 long size[2] = {ncols, nrows};
194 status = 0;
195 if (fits_create_img(fptr, bitpix, 2, size, &status) != 0) {
196 std::string msg = fmt::format("Failed to create the image type from FITS file '{}'. {}",
197 tmpfilename,
198 GetCfitsioErrorMsg(status));
199 CII_THROW(RtctkException, msg);
200 }
201
202 if (boolean_items) {
203 char value[80] = "true"; // Use maximum keyword card size.
204 if (fits_write_key(fptr, TSTRING, "BOOLITEM", value, nullptr, &status) != 0) {
205 std::string msg = fmt::format("Failed to write keyword BOOLITEM to '{}'. {}",
206 filename,
207 GetCfitsioErrorMsg(status));
208 CII_THROW(RtctkException, msg);
209 }
210 }
211
212 // Write the matrix data as pixels.
213 long fpixel[2] = {1, 1}; // Pixel start location. Cfitsio counts from 1, not 0.
214 long nelements = matrix.size();
215 // We are forced to use const_cast, since the fits_write_pix function does not accept
216 // const void*.
217 void* array = const_cast<void*>(reinterpret_cast<const void*>(matrix.data()));
218 status = 0;
219 if (fits_write_pix(fptr, datatype, fpixel, nelements, array, &status) != 0) {
220 std::string msg = fmt::format("Failed to write the matrix to FITS file '{}'. {}",
221 tmpfilename,
222 GetCfitsioErrorMsg(status));
223 CII_THROW(RtctkException, msg);
224 }
225 } catch (...) {
226 // Attempt to close the FITS file if an exception was thrown. But do not throw an additional
227 // exception if closing the file failed. Just log this error and rethrow the original
228 // exception.
229 status = 0;
230 if (fits_close_file(fptr, &status) != 0) {
231 LOG4CPLUS_ERROR(GetLogger("rtctk"),
232 fmt::format("Failed to close file '{}' while handling an exception. {}",
233 tmpfilename,
234 GetCfitsioErrorMsg(status)));
235 }
236 throw;
237 }
238
239 status = 0;
240 if (fits_close_file(fptr, &status) != 0) {
241 std::string msg = fmt::format(
242 "Failed to close the FITS file '{}'. ", tmpfilename, GetCfitsioErrorMsg(status));
243 CII_THROW(RtctkException, msg);
244 }
245
246 // Rename the temporary file to its final value. Updating the file in this manner will make sure
247 // that different processes or threads will see changes to the file in an atomic manner. Either
248 // the old file will be visible, or the new file, but not a partially modified file.
249 try {
250 std::filesystem::rename(tmpfilename, filename);
251 } catch (const std::exception& error) {
252 CII_THROW_WITH_NESTED(
254 error,
255 fmt::format("Failed to rename FITS file '{}' to '{}'.", tmpfilename, filename))
256 }
257}
258
266template <typename T>
267void ReadMatrixFromFits(const std::string& filename, T& matrix) {
268 static_assert(IS_MATRIX_BUFFER_TYPE<T> or IS_MATRIX_SPAN_TYPE<T>,
269 "The matrix argument must be of type MatrixBuffer or MatrixSpan.");
270
271 using U = typename T::value_type;
272 // Identify the Cfitsio data type code to be used and the expected Cfitsio image type code,
273 // based on the type used with MatrixBuffer or MatrixSpan, i.e. type of U.
274 int expected_bitpix = 0;
275 int datatype = 0;
276 IdentifyCfitsioTypes<U>(expected_bitpix, datatype);
277
278 fitsfile* fptr = nullptr;
279 int status = 0; // It is important to initialise this to zero before every Cfitsio API call.
280 if (fits_open_image(&fptr, filename.c_str(), READONLY, &status) != 0) {
281 std::string msg =
282 fmt::format("Failed to open FITS file '{}'. {}", filename, GetCfitsioErrorMsg(status));
283 CII_THROW(RtctkException, msg);
284 }
285
286 try {
287 // Read and check that the pixel format used in the FITS file corresponds to the type used
288 // for the matrix object passed to this function.
289 int bitpix = -1;
290 status = 0;
291 if (fits_get_img_equivtype(fptr, &bitpix, &status) != 0) {
292 std::string msg = fmt::format("Failed to read the image type from FITS file '{}'. {}",
293 filename,
294 GetCfitsioErrorMsg(status));
295 CII_THROW(RtctkException, msg);
296 }
297 if (bitpix == LONGLONG_IMG) {
298 // NOTE: Correcting the bitpix for ULONGLONG_IMG. There is a bug in Cfitsio that returns
299 // LONGLONG_IMG instead of ULONGLONG_IMG.
300 char value[80]; // Use maximum possible FITS card size of 80 bytes.
301 status = 0;
302 int result = fits_read_keyword(fptr, "BZERO", value, nullptr, &status);
303 if (result != 0 and status != KEY_NO_EXIST) {
304 std::string msg = fmt::format("Failed to read keyword BZERO from '{}'. {}",
305 filename,
306 GetCfitsioErrorMsg(status));
307 CII_THROW(RtctkException, msg);
308 }
309 if (std::string(value) ==
310 std::to_string(std::numeric_limits<uint64_t>::max() / 2 + 1)) {
311#ifdef ULONGLONG_IMG
312 bitpix = ULONGLONG_IMG;
313#else
314 // If we are dealing with an older Cfitsio library that does not have ULONGLONG_IMG
315 // defined, then simply alias to using the signed version instead.
316 bitpix = LONGLONG_IMG;
317#endif
318 }
319 }
320 if (bitpix != expected_bitpix) {
321 std::string msg = fmt::format(
322 "The FITS file '{}' has the wrong image format of {}. Expected a FITS image of "
323 "type {}.",
324 filename,
326 CfitsioImageTypeToString(expected_bitpix));
327 CII_THROW(RtctkException, msg);
328 }
329
330 // Read and check that the number of image axes is 2.
331 int naxis = -1;
332 status = 0;
333 if (fits_get_img_dim(fptr, &naxis, &status) != 0) {
334 std::string msg =
335 fmt::format("Failed to read the number of image axes from FITS file '{}'. {}",
336 filename,
337 GetCfitsioErrorMsg(status));
338 CII_THROW(RtctkException, msg);
339 }
340 if (naxis != 2) {
341 std::string msg = fmt::format(
342 "The FITS file '{}' has image dimensions that we cannot handle. Expect a 2D image "
343 "when loading as a matrix.",
344 filename);
345 CII_THROW(RtctkException, msg);
346 }
347
348 long size[2] = {-1, -1};
349 status = 0;
350 if (fits_get_img_size(fptr, 2, size, &status) != 0) {
351 std::string msg = fmt::format("Failed to read the image size from FITS file '{}'. {}",
352 filename,
353 GetCfitsioErrorMsg(status));
354 CII_THROW(RtctkException, msg);
355 }
356
357 using size_type = typename T::size_type;
358 auto nrows = static_cast<size_type>(size[1]);
359 auto ncols = static_cast<size_type>(size[0]);
360 long nelements = size[0] * size[1]; // Total number of pixels, i.e. rows * columns.
361
362 long fpixel[2] = {1, 1}; // Pixel start location. Cfitsio counts from 1, not 0.
363 int anynull = 0; // Boolean flag indicating if there were any null/nil pixel values.
364 if constexpr (IS_MATRIX_BUFFER_TYPE<T>) {
365 matrix.resize(nrows, ncols);
366 } else {
367 if (matrix.size() < static_cast<size_type>(nrows * ncols)) {
368 CII_THROW(BufferTooSmall, matrix.size(), nrows * ncols);
369 }
370 }
371 void* array = matrix.data();
372 status = 0;
373 int result =
374 fits_read_pix(fptr, datatype, fpixel, nelements, nullptr, array, &anynull, &status);
375 if (result != 0) {
376 std::string msg = fmt::format("Failed to read the image from FITS file '{}'. {}",
377 filename,
378 GetCfitsioErrorMsg(status));
379 CII_THROW(RtctkException, msg);
380 }
381 } catch (...) {
382 // Attempt to close the FITS file if an exception was thrown. But do not throw an additional
383 // exception if closing the file failed. Just log this error and rethrow the original
384 // exception.
385 status = 0;
386 if (fits_close_file(fptr, &status) != 0) {
387 LOG4CPLUS_ERROR(GetLogger("rtctk"),
388 fmt::format("Failed to close file '{}' while handling an exception. {}",
389 filename,
390 GetCfitsioErrorMsg(status)));
391 }
392 throw;
393 }
394
395 status = 0;
396 if (fits_close_file(fptr, &status) != 0) {
397 std::string msg = fmt::format(
398 "Failed to close the FITS file '{}'. {}", filename, GetCfitsioErrorMsg(status));
399 CII_THROW(RtctkException, msg);
400 }
401}
402
411template <typename T>
412void WriteVectorToFits(const std::string& filename, const T& vector, bool boolean_items = false) {
413 static_assert(IS_VECTOR_TYPE<T> or IS_SPAN_TYPE<T>,
414 "The vector argument must be of type std::vector or gsl::span.");
415 assert(int64_t(vector.size()) <= int64_t(std::numeric_limits<long>::max()));
416
417 using U = typename T::value_type;
418 // Workout the appropriate Cfitsio image type code and data type code to use, based on the type
419 // used with std::vector or gsl::span, i.e. the type of U.
420 int bitpix = 0;
421 int datatype = 0;
422 IdentifyCfitsioTypes<U>(bitpix, datatype);
423
424 std::string tmpfilename = filename + ".new-" + std::to_string(getpid());
425
426 // Create the new FITS file and open it for modifications.
427 fitsfile* fptr = nullptr;
428 int status = 0; // It is important to initialise this to zero before each Cfitsio API call.
429 if (fits_create_file(&fptr, tmpfilename.c_str(), &status) != 0) {
430 std::string msg = fmt::format(
431 "Failed to create FITS file '{}'. {}", tmpfilename, GetCfitsioErrorMsg(status));
432 CII_THROW(RtctkException, msg);
433 }
434
435 try {
436 // Create the image header in the HDU.
437 long size = static_cast<long>(vector.size());
438 status = 0;
439 if (fits_create_img(fptr, bitpix, 1, &size, &status) != 0) {
440 std::string msg = fmt::format("Failed to create the image type from FITS file '{}'. {}",
441 tmpfilename,
442 GetCfitsioErrorMsg(status));
443 CII_THROW(RtctkException, msg);
444 }
445
446 if (boolean_items) {
447 char value[80] = "true"; // Use maximum keyword card size.
448 if (fits_write_key(fptr, TSTRING, "BOOLITEM", value, nullptr, &status) != 0) {
449 std::string msg = fmt::format("Failed to write keyword BOOLITEM to '{}'. {}",
450 filename,
451 GetCfitsioErrorMsg(status));
452 CII_THROW(RtctkException, msg);
453 }
454 }
455
456 // Write the vector data as pixels.
457 long fpixel = 1; // Pixel start location. Cfitsio counts from 1, not 0.
458 long nelements = vector.size();
459 // We are forced to use const_cast, since the fits_write_pix function does not accept
460 // const void*.
461 void* array = const_cast<void*>(reinterpret_cast<const void*>(vector.data()));
462 status = 0;
463 if (fits_write_pix(fptr, datatype, &fpixel, nelements, array, &status) != 0) {
464 std::string msg = fmt::format("Failed to write the vector to FITS file '{}'. {}",
465 tmpfilename,
466 GetCfitsioErrorMsg(status));
467 CII_THROW(RtctkException, msg);
468 }
469 } catch (...) {
470 // Attempt to close the FITS file if an exception was thrown. But do not throw an additional
471 // exception if closing the file failed. Just log this error and rethrow the original
472 // exception.
473 status = 0;
474 if (fits_close_file(fptr, &status) != 0) {
475 LOG4CPLUS_ERROR(GetLogger("rtctk"),
476 fmt::format("Failed to close file '{}' while handling an exception. {}",
477 tmpfilename,
478 GetCfitsioErrorMsg(status)));
479 }
480 throw;
481 }
482
483 status = 0;
484 if (fits_close_file(fptr, &status) != 0) {
485 std::string msg = fmt::format(
486 "Failed to close the FITS file '{}'. {}", tmpfilename, GetCfitsioErrorMsg(status));
487 CII_THROW(RtctkException, msg);
488 }
489
490 // Rename the temporary file to its final value. Updating the file in this manner will make sure
491 // that different processes or threads will see changes to the file in an atomic manner. Either
492 // the old file will be visible, or the new file, but not a partially modified file.
493 try {
494 std::filesystem::rename(tmpfilename, filename);
495 } catch (const std::exception& error) {
496 CII_THROW_WITH_NESTED(
498 error,
499 fmt::format("Failed to rename FITS file '{}' to '{}'.", tmpfilename, filename));
500 }
501}
502
510template <typename T>
511void ReadVectorFromFits(const std::string& filename, T& vector) {
512 static_assert(IS_VECTOR_TYPE<T> or IS_SPAN_TYPE<T>,
513 "The vector argument must be of type std::vector or gsl::span.");
514
515 using U = typename T::value_type;
516 // Identify the Cfitsio data type code to be used and the expected Cfitsio image type code,
517 // based on the type used with std::vector or gsl::span, i.e. type of U.
518 int expected_bitpix = 0;
519 int datatype = 0;
520 IdentifyCfitsioTypes<U>(expected_bitpix, datatype);
521
522 fitsfile* fptr = nullptr;
523 int status = 0; // It is important to initialise this to zero before every Cfitsio API call.
524 if (fits_open_image(&fptr, filename.c_str(), READONLY, &status) != 0) {
525 std::string msg =
526 fmt::format("Failed to open FITS file '{}'. {}", filename, GetCfitsioErrorMsg(status));
527 CII_THROW(RtctkException, msg);
528 }
529
530 try {
531 // Read and check that the pixel format used in the FITS file corresponds to the type used
532 // for the vector object passed to this function.
533 int bitpix = -1;
534 status = 0;
535 if (fits_get_img_equivtype(fptr, &bitpix, &status) != 0) {
536 std::string msg = fmt::format("Failed to read the image type from FITS file '{}'. {}",
537 filename,
538 GetCfitsioErrorMsg(status));
539 CII_THROW(RtctkException, msg);
540 }
541 if (bitpix == LONGLONG_IMG) {
542 // NOTE: Correcting the bitpix for ULONGLONG_IMG. There is a bug in Cfitsio that returns
543 // LONGLONG_IMG instead of ULONGLONG_IMG.
544 char value[80]; // Use maximum possible FITS card size of 80 bytes.
545 status = 0;
546 int result = fits_read_keyword(fptr, "BZERO", value, nullptr, &status);
547 if (result != 0 and status != KEY_NO_EXIST) {
548 std::string msg = fmt::format("Failed to read keyword BZERO from '{}'. {}",
549 filename,
550 GetCfitsioErrorMsg(status));
551 CII_THROW(RtctkException, msg);
552 }
553 if (std::string(value) ==
554 std::to_string(std::numeric_limits<uint64_t>::max() / 2 + 1)) {
555#ifdef ULONGLONG_IMG
556 bitpix = ULONGLONG_IMG;
557#else
558 // If we are dealing with an older Cfitsio library that does not have ULONGLONG_IMG
559 // defined, then simply alias to using the signed version instead.
560 bitpix = LONGLONG_IMG;
561#endif
562 }
563 }
564 if (bitpix != expected_bitpix) {
565 std::string msg = fmt::format(
566 "The FITS file '{}' has the wrong image format of {}. Expected a FITS image of "
567 "type {}.",
568 filename,
570 CfitsioImageTypeToString(expected_bitpix));
571 CII_THROW(RtctkException, msg);
572 }
573
574 // Read and check that the number of image axes is 2.
575 int naxis = -1;
576 status = 0;
577 if (fits_get_img_dim(fptr, &naxis, &status) != 0) {
578 std::string msg =
579 fmt::format("Failed to read the number of image axes from FITS file '{}'. {}",
580 filename,
581 GetCfitsioErrorMsg(status));
582 CII_THROW(RtctkException, msg);
583 }
584 if (naxis != 1) {
585 std::string msg = fmt::format(
586 "The FITS file '{}' has image dimensions that we cannot handle. Expect a 1D image "
587 "when loading as a vector.",
588 filename);
589 CII_THROW(RtctkException, msg);
590 }
591
592 long nelements = -1;
593 status = 0;
594 if (fits_get_img_size(fptr, 1, &nelements, &status) != 0) {
595 std::string msg =
596 fmt::format("Failed to read the 1D image size from FITS file '{}'. {}",
597 filename,
598 GetCfitsioErrorMsg(status));
599 CII_THROW(RtctkException, msg);
600 }
601
602 using size_type = typename T::size_type;
603 long fpixel = 1; // Pixel start location. Cfitsio counts from 1, not 0.
604 int anynull = 0; // Boolean flag indicating if there were any null/nil pixel values.
605 if constexpr (IS_VECTOR_TYPE<T>) {
606 vector.resize(static_cast<size_type>(nelements));
607 } else {
608 if (vector.size() < static_cast<size_type>(nelements)) {
609 CII_THROW(BufferTooSmall, vector.size(), nelements);
610 }
611 }
612 void* array = vector.data();
613 status = 0;
614 int result =
615 fits_read_pix(fptr, datatype, &fpixel, nelements, nullptr, array, &anynull, &status);
616 if (result != 0) {
617 std::string msg = fmt::format("Failed to read the image from FITS file '{}'. {}",
618 filename,
619 GetCfitsioErrorMsg(status));
620 CII_THROW(RtctkException, msg);
621 }
622 } catch (...) {
623 // Attempt to close the FITS file if an exception was thrown. But do not throw an additional
624 // exception if closing the file failed. Just log this error and rethrow the original
625 // exception.
626 status = 0;
627 if (fits_close_file(fptr, &status) != 0) {
628 LOG4CPLUS_ERROR(GetLogger("rtctk"),
629 fmt::format("Failed to close file '{}' while handling an exception. {}",
630 filename,
631 GetCfitsioErrorMsg(status)));
632 }
633 throw;
634 }
635
636 status = 0;
637 if (fits_close_file(fptr, &status) != 0) {
638 std::string msg = fmt::format(
639 "Failed to close the FITS file '{}'. {}", filename, GetCfitsioErrorMsg(status));
640 CII_THROW(RtctkException, msg);
641 }
642}
643
644// The following are template specialisations for vectors and matrices of boolean values.
645
649template <typename A>
650void WriteMatrixToFits(const std::string& filename, const MatrixBuffer<bool, A>& matrix) {
651 // Concert the boolean matrix to a matrix of 8 bit integers and write that to file instead.
652 MatrixBuffer<int8_t> int_matrix;
653 int_matrix.resize(matrix.GetNrows(), matrix.GetNcols());
654 for (MatrixBuffer<int8_t>::size_type n = 0; n < int_matrix.GetNrows(); ++n) {
655 for (MatrixBuffer<int8_t>::size_type m = 0; m < int_matrix.GetNcols(); ++m) {
656 int_matrix(n, m) = matrix(n, m) ? 1 : 0;
657 }
658 }
659 WriteMatrixToFits(filename, int_matrix, true);
660}
661
665template <typename A>
666void ReadMatrixFromFits(const std::string& filename, MatrixBuffer<bool, A>& matrix) {
667 // Load the matrix from file as 8 bit integers and convert it to a boolean matrix.
668 MatrixBuffer<int8_t> int_matrix;
669 ReadMatrixFromFits(filename, int_matrix);
670 matrix.resize(int_matrix.GetNrows(), int_matrix.GetNcols());
671 for (MatrixBuffer<int8_t>::size_type n = 0; n < int_matrix.GetNrows(); ++n) {
672 for (MatrixBuffer<int8_t>::size_type m = 0; m < int_matrix.GetNcols(); ++m) {
673 matrix(n, m) = int_matrix(n, m) == 0 ? false : true;
674 }
675 }
676}
677
681template <typename A>
682void WriteVectorToFits(const std::string& filename, const std::vector<bool, A>& vector) {
683 // Concert the boolean vector to a vector of 8 bit integers and write that to file instead.
684 std::vector<int8_t> int_vector;
685 int_vector.resize(vector.size());
686 for (std::vector<int8_t>::size_type n = 0; n < int_vector.size(); ++n) {
687 int_vector[n] = vector[n] ? 1 : 0;
688 }
689 WriteVectorToFits(filename, int_vector, true);
690}
691
695template <typename A>
696void ReadVectorFromFits(const std::string& filename, std::vector<bool, A>& vector) {
697 // Load the vector from file as 8 bit integers and convert it to a boolean vector.
698 std::vector<int8_t> int_vector;
699 ReadVectorFromFits(filename, int_vector);
700 vector.resize(int_vector.size());
701 for (std::vector<int8_t>::size_type n = 0; n < int_vector.size(); ++n) {
702 vector[n] = int_vector[n] == 0 ? false : true;
703 }
704}
705
718const std::type_info& GetFitsImageType(const std::string& filename);
719
731std::size_t GetFitsImageSize(const std::string& filename);
732
733} // namespace rtctk::componentFramework
734
735#endif // RTCTK_COMPONENTFRAMEWORK_FITSIOFUNCTIONS_HPP
The BufferTooSmall is thrown when an API call fails because the provided buffer is not big enough to ...
Definition: exceptions.hpp:290
A buffer class representing 2D matrix data.
Definition: matrixBuffer.hpp:28
size_type GetNcols() const
Definition: matrixBuffer.hpp:101
size_type GetNrows() const
Definition: matrixBuffer.hpp:97
constexpr void resize(size_type n, size_type m)
Definition: matrixBuffer.hpp:72
The RtctkException class is the base class for all Rtctk exceptions.
Definition: exceptions.hpp:237
Provides macros and utilities for exception handling.
std::string GetCfitsioErrorMsg(int status)
Helper function to convert a Cfitsio status code to a human readable message.
Definition: fitsIoFunctions.cpp:20
void ReadVectorFromFits(const std::string &filename, T &vector)
Reads a FITS file containing a 1D image into a buffer object representing a vector.
Definition: fitsIoFunctions.hpp:511
void WriteMatrixToFits(const std::string &filename, const T &matrix, bool boolean_items=false)
Writes data representing a matrix as an image to a FITS file.
Definition: fitsIoFunctions.hpp:165
void ReadMatrixFromFits(const std::string &filename, T &matrix)
Reads a FITS file image into a buffer object representing a matrix.
Definition: fitsIoFunctions.hpp:267
std::string CfitsioDataTypeToString(int datatype)
Returns a string representation of a Cfitsio data type code.
Definition: fitsIoFunctions.cpp:58
std::string CfitsioImageTypeToString(int bitpix)
Returns a string representation of a Cfitsio image type code.
Definition: fitsIoFunctions.cpp:29
void WriteVectorToFits(const std::string &filename, const T &vector, bool boolean_items=false)
Writes data as a 1D image to a FITS file.
Definition: fitsIoFunctions.hpp:412
const std::type_info & GetFitsImageType(const std::string &filename)
Get the C++ type corresponding to a FITS image.
Definition: fitsIoFunctions.cpp:101
std::size_t GetFitsImageSize(const std::string &filename)
Get the number of pixels in a FITS image.
Definition: fitsIoFunctions.cpp:271
log4cplus::Logger & GetLogger(const std::string &name="app")
Get handle to a specific logger.
Definition: logger.cpp:180
Logging Support Library based on log4cplus.
Declaration of the MatrixBuffer template class used in APIs.
Definition: commandReplier.cpp:22
Provides useful mechanisms to test various type traits.