mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
Loading...
Searching...
No Matches
fitsFile.hpp
Go to the documentation of this file.
1/** \file fitsFile.hpp
2 * \brief Declares and defines a class to work with a FITS file
3 * \ingroup fits_processing_files
4 * \author Jared R. Males (jaredmales@gmail.com)
5 *
6 */
7
8//***********************************************************************//
9// Copyright 2015-2022 Jared R. Males (jaredmales@gmail.com)
10//
11// This file is part of mxlib.
12//
13// mxlib is free software: you can redistribute it and/or modify
14// it under the terms of the GNU General Public License as published by
15// the Free Software Foundation, either version 3 of the License, or
16// (at your option) any later version.
17//
18// mxlib is distributed in the hope that it will be useful,
19// but WITHOUT ANY WARRANTY; without even the implied warranty of
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21// GNU General Public License for more details.
22//
23// You should have received a copy of the GNU General Public License
24// along with mxlib. If not, see <http://www.gnu.org/licenses/>.
25//***********************************************************************//
26
27#ifndef ioutils_fits_fitsFile_hpp
28#define ioutils_fits_fitsFile_hpp
29
30#include "../../mxlib.hpp"
31
32#include "../../improc/eigenImage.hpp"
33
34#include "fitsUtils.hpp"
35#include "fitsHeader.hpp"
36
37namespace mx
38{
39namespace fits
40{
41
42/// Class to manage interactions with a FITS file
43/** This class wraps the functionality of cfitsio.
44 *
45 * \tparam dataT is the datatype to use for in-memory storage of the image.
46 * This does not have to match the data type
47 * stored on disk for reading, but will be the type used for writing.
48 *
49 * \ingroup fits_processing
50 */
51template <typename dataT, class verboseT = verbose::d>
53{
54
55 friend class fitsFile_test;
56
57 public:
58 typedef typename fitsHeader<verboseT>::headerIteratorT headerIteratorT;
59
60 protected:
61 /// The path to the file
62 std::string m_fileName;
63
64 /// The cfitsio data structure
65 fitsfile *m_fptr{ nullptr };
66
67 /// The dimensions of the image (1D, 2D, or 3D)
68 int m_naxis{ 0 };
69
70 /// The size of each dimension
71 long m_naxes [3];
72
73 /// Flag indicating whether the file is open or not
74 bool m_isOpen{ false };
75
76 /// The value to replace null values with
77 dataT m_nulval{ 0 };
78
79 /// Records whether any null values were replaced
80 int m_anynul{ 0 };
81
82 /// Flag to control whether the comment string is read.
83 int m_noComment{ 0 };
84
85 /// The starting x-pixel to read from
86 long m_x0{ -1 };
87
88 /// The starting y-pixel to read from
89 long m_y0{ -1 };
90
91 /// The number of x-pixels to read
92 long m_xpix{ -1 };
93
94 /// The number of y-pixels to read
95 long m_ypix{ -1 };
96
97 /// The starting frame to read from a cube
98 long m_z0{ -1 };
99
100 /// The number of frames to read from a cube
101 long m_zframes{ -1 };
102
103 /// One time initialization common to all constructors
104 void construct();
105
106 public:
107 /// Default constructor
108 fitsFile();
109
110 /// Default constructor with error code
111 fitsFile( error_t &errc /**< [out] error_t code indicating success or error */ );
112
113 /// Constructor with file name and error code
114 /** The file is not opened.
115 *
116 */
117 fitsFile( const std::string &fname, ///< [in] File name to set on construction
118 error_t &errc /**< [out] error_t code indicating success or error */
119 );
120
121 /// Constructor with file name, and option to open.
122 fitsFile( const std::string &fname, ///< [in] File name to set on construction
123 bool doopen = true ///< [in] [optional] If true, then the file is opened (the default).
124 );
125
126 /// Constructor with file name, option to open, and error code
127 fitsFile( const std::string &fname, ///< File name to set on construction
128 bool doopen, ///< If true, then the file is opened (the default).
129 error_t &errc /**< [out] error_t code indicating success or error */
130 );
131
132 /// Destructor
133 ~fitsFile();
134
135 /// Get the current value of m_fileName
136 /**
137 * \returns the current value of m_fileName.
138 */
139 std::string fileName();
140
141 /// Set the file path, and optionally open the file.
142 /**
143 * \returns mx::error_t::noerror on success
144 * \returns mx::error_t codes from \ref close or \ref open
145 */
146 error_t fileName( const std::string &fname, ///< The new file name.
147 bool doopen = true ///< If true, then the file is opened (the default).
148 );
149
150 /// Get the current value of m_naxis
151 /**
152 * \returns the current value of m_naxis
153 *
154 */
155 int naxis();
156
157 /// Get the current value of m_naxes for the specified dimension
158 /**
159 * \returns the current value of m_naxes for the specified dimension. -1 if no such dimension
160 *
161 */
162 long naxes( int dim /**< [in] the dimension */ );
163
164 /// Open the file and gets its dimensions.
165 /** File name needs to already have been set.
166 * If the file has already been opened, this returns immediately with no re-open.
167 *
168 * \returns mx::error_t::noerror on success
169 * \returns mx::invalidconfig if m_filename is empty.
170 * \returns mx::error_t::bad_alloc on an allocation error
171 * \returns mx::error_t::std_exception on other errors during allocations
172 * \returns mx::error_t::exception on unexpected errors during allocations
173 * \returns mx::error_t::allocerr if allocation fails without an exception
174 * \returns mx::error_t::fits_* codes from cfitsio functions
175 *
176 */
177 error_t open();
178
179 /// Open the file, first setting the file path.
180 /**
181 * \returns mx::error_t::noerror on success
182 * \returns mx::invalidconfig if m_filename is empty.
183 * \returns mx::error_t::bad_alloc on an allocation error
184 * \returns mx::error_t::std_exception on other errors during allocations
185 * \returns mx::error_t::exception on unexpected errors during allocations
186 * \returns mx::error_t::allocerr if allocation fails without an exception
187 * \returns mx::error_t::fits_* codes from cfitsio functions
188 */
189 error_t open( const std::string &fname /**< The name of the file to open. */ );
190
191 /// Close the file.
192 /**
193 * \returns mx::error_t::noerror on success
194 * \returns mx::error_t::fits_* codes from cfitsio functions
195 */
196 error_t close();
197
198 /// Get the number of dimensions (i.e. m_naxis)
199 int getDimensions( error_t &errc );
200
201 /// Get the total size
202 long getSize( error_t &errc );
203
204 /// Get the size of a specific dimension
205 long getSize( size_t axis, error_t &errc );
206
207 /** \name Reading Basic Arrays
208 * These methods read FITS data into basic or raw arrays specified by a pointer.
209 * @{
210 */
211
212 protected:
213 struct pixarrT
214 {
215 long *fpix{ nullptr }; ///< Populated with the lower left pixel to read.
216 long *lpix{ nullptr }; ///< Populated with the upper right pixel to read.
217 long *inc{ nullptr }; ///< The increment.
218
219 error_t allocate( int naxis )
220 {
221 if( naxis <= 0 )
222 {
223 return internal::mxlib_error_report<verboseT>( error_t::paramnotset, "naxis" );
224 }
225
226 if( fpix )
227 {
228 delete[] fpix;
229 fpix = nullptr;
230 }
231
232 if( lpix )
233 {
234 delete[] lpix;
235 lpix = nullptr;
236 }
237
238 if( inc )
239 {
240 delete[] inc;
241 inc = nullptr;
242 }
243
244 try
245 {
246 fpix = new long[naxis];
247 lpix = new long[naxis];
248 inc = new long[naxis];
249 }
250 catch( const std::bad_alloc &e )
251 {
252 internal::mxlib_error_report<verboseT>( error_t::std_bad_alloc,
253 std::string( "allocating pixel read arrays: " ) + e.what() );
254#ifdef MXLIB_TRAP_ALLOC_ERRORS
256#else
257 throw;
258#endif
259 }
260 catch( const std::exception &e )
261 {
262 internal::mxlib_error_report<verboseT>( error_t::std_exception,
263 std::string( "allocating pixel read arrays: " ) + e.what() );
264#ifdef MXLIB_TRAP_ALLOC_ERRORS
265 return error_t::exception;
266#else
267 throw;
268#endif
269 }
270 catch( ... )
271 {
272 internal::mxlib_error_report<verboseT>( error_t::exception, "allocating pixel read arrays" );
273#ifdef MXLIB_TRAP_ALLOC_ERRORS
274 return error_t::exception;
275#else
276 throw;
277#endif
278 }
279
280 // also check for null allocations (in case compiled with exceptions off)
281 if( fpix == nullptr )
282 {
283 return internal::mxlib_error_report<verboseT>( error_t::allocerr, "fpix is nullptr" );
284 }
285
286 if( lpix == nullptr )
287 {
288 return internal::mxlib_error_report<verboseT>( error_t::allocerr, "lpix is nullptr" );
289 }
290
291 if( inc == nullptr )
292 {
293 return internal::mxlib_error_report<verboseT>( error_t::allocerr, "inc is nullptr" );
294 }
295
296 return error_t::noerror;
297 }
298
299 ~pixarrT()
300 {
301 if( fpix )
302 {
303 delete[] fpix;
304 }
305
306 if( lpix )
307 {
308 delete[] lpix;
309 }
310
311 if( inc )
312 {
313 delete[] inc;
314 }
315 }
316 };
317
318 /// Fill in the read-size arrays for reading a subset (always used)
319 /**
320 */
321 error_t calcPixarrs( pixarrT &pixarr /**< [out] Populated with the allocated read-size arrays*/ );
322
323 public:
324 /// Read the contents of the FITS file into an array.
325 /** The array pointed to by data must have been allocated.
326 *
327 * \returns 0 on success
328 * \returns -1 on error
329 */
330 error_t read( dataT *data /**< [out] an allocated arrray large enough to hold the entire image */ );
331
332 /// Read the contents of the FITS file into an array.
333 /** The array pointed to by data must have been allocated.
334 *
335 * \returns 0 on success
336 * \returns -1 on error
337 */
338 error_t read( dataT *data, ///< [out] an allocated arrray large enough to hold the entire image
339 fitsHeader<verboseT> &head ///< [out] a fitsHeader object which is passed to \ref readHeader
340 );
341
342 /// Read the contents of the FITS file into an array.
343 /** The array pointed to by data must have been allocated.
344 *
345 * \returns 0 on success
346 * \returns -1 on error
347 */
348 error_t read( dataT *data, ///< [out] is an allocated arrray large enough to hold the entire image
349 const std::string &fname ///< [in] is the file path, which is passed to \ref fileName
350 );
351
352 /// Read the contents of the FITS file into an array and read the header.
353 /** The array pointed to by data must have been allocated.
354 *
355 * \returns 0 on success
356 * \returns -1 on error
357 */
358 error_t read( dataT *data, ///< [out] an allocated arrray large enough to hold the entire image
359 fitsHeader<verboseT> &head, ///< [out] a fitsHeader object which is passed to \ref readHeader
360 const std::string &fname ///< [in] the file path, which is passed to \ref fileName
361 );
362
363 /// Read data from a vector list of files into an image cube
364 error_t read( dataT *im, ///< [out] An allocated array large enough to hold all the images
365 const std::vector<std::string> &flist ///< [in] The list of files to read.
366 );
367
368 /// Read data from a vector of files into an image cube with individual headers
369 error_t read( dataT *im, /**< [out] An allocated array large enough to hold all the images */
370 std::vector<fitsHeader<verboseT>> &heads, /**< [in/out] The vector of fits headers, allocated
371 to contain one per image. */
372 const std::vector<std::string> &flist /**< [in] The list of files to read. */
373 );
374
375 ///@}
376
377 /** \name Reading Eigen Arrays
378 * These methods read FITS data into array types with an Eigen-like interface.
379 * @{
380 */
381
382 /// Read the contents of the FITS file into an Eigen array type (not a simple pointer).
383 /** The type arrT can be any type with the following members defined:
384 * - resize(int, int) (allocates memory)
385 * - data() (returns a pointer to the underlying array)
386 * - typedef arrT::Scalar (is the data type, does not have to be dataT)
387 *
388 * \tparam arrT is the type of array, see requirements above.
389 *
390 * \returns 0 on success
391 * \returns -1 on error
392 */
393 template <typename arrT>
394 error_t read( arrT &data /**< [out] is the array, which will be resized as
395 necessary using its resize(int, int) member */ );
396
397 /// Read the contents of the FITS file into an Eigen array type (not a simple pointer).
398 /** The type arrT can be any type with the following members defined:
399 * - resize(int, int) (allocates memory)
400 * - data() (returns a pointer to the underlying array)
401 * - typedef arrT::Scalar (is the data type, does not have to be dataT)
402 *
403 * \tparam arrT is the type of array, see requirements above.
404 *
405 * \returns 0 on success
406 * \returns -1 on error
407 */
408 template <typename arrT>
409 error_t read( arrT &data, /**< [out] is the array, which will be resized as necessary
410 using its resize(int, int) member*/
411 fitsHeader<verboseT> &head ///< [out] is a fitsHeader object which is passed to \ref readHeader
412 );
413
414 /// Read the contents of the FITS file into an Eigen array type (not a simple pointer).
415 /** The type arrT can be any type with the following members defined:
416 * - resize(int, int) (allocates memory)
417 * - data() (returns a pointer to the underlying array)
418 * - typedef arrT::Scalar (is the data type, does not have to be dataT)
419 *
420 * \tparam arrT is the type of array, see requirements above.
421 *
422 * \returns 0 on success
423 * \returns -1 on error
424 */
425 template <typename arrT>
426 error_t read( arrT &data, /**< [out] is the array, which will be resized as
427 necessary using its resize(int, int) member*/
428 const std::string &fname ///< [in] is the file path, which is passed to \ref fileName
429 );
430
431 /// Read the contents of the FITS file into an Eigen array type (not a simple pointer).
432 /** The type arrT can be any type with the following members defined:
433 * - resize(int, int) (allocates memory)
434 * - data() (returns a pointer to the underlying array)
435 * - typedef arrT::Scalar (is the data type, does not have to be dataT)
436 *
437 * \tparam arrT is the type of array, see requirements above.
438 *
439 * \returns 0 on success
440 * \returns -1 on error
441 */
442 template <typename arrT>
443 error_t read( arrT &data, /**< [out] the array, which will be resized as
444 necessary using its resize(int, int) member*/
445 fitsHeader<verboseT> &head, ///< [out] a fitsHeader object which is passed to \ref readHeader
446 const std::string &fname ///< [in] the file path, which is passed to \ref fileName
447 );
448
449 /// Read data from a vector list of files into an image cube
450 /** The type cubeT can be any type with the following members defined:
451 * - resize(int, int, int) (allocates memory)
452 * - data() (returns a pointer to the underlying array)
453 * - typedef cubeT::Scalar (is the data type, does not have to be dataT)
454 *
455 * \note The images must all be the same size, or all be as large or larger than the subset specified.
456 *
457 * \tparam cubeT is the type of array, see requirements above.
458 *
459 * \returns 0 on success
460 * \returns -1 on error
461 */
462 template <typename cubeT>
463 error_t read( cubeT &cube, ///< [out] A cube which will be resized using its resize(int, int, int) member.
464 const std::vector<std::string> &flist, ///< [in] The list of files to read.
465 std::vector<fitsHeader<verboseT>> *heads =
466 0 ///< [out] [optional] A vector of fits headers, allocated to contain one per image.
467 );
468
469 /// Read data from a vector of files into an image cube with individual headers
470 /** The type cubeT can be any type with the following members defined:
471 * - resize(int, int, int) (allocates memory)
472 * - data() (returns a pointer to the underlying array)
473 * - typedef cubeT::Scalar (is the data type, does not have to be dataT)
474 *
475 * \tparam cubeT is the type of array, see requirements above.
476 *
477 * \returns 0 on success
478 * \returns -1 on error
479 */
480 template <typename cubeT>
481 error_t read( cubeT &cube, /**< [out] A cube which will be resized
482 using its resize(int, int, int) member.*/
483 std::vector<fitsHeader<verboseT>> &heads, /**< [out] The vector of fits headers, allocated to
484 contain one per image.*/
485 const std::vector<std::string> &flist ///< [in] The list of files to read.
486 );
487
488 ///@}
489
490 /** \name Reading Headers
491 * @{
492 */
493
494 /// Read the header from the fits file.
495 /** If head is not empty, then only the keywords already in head are updated. Otherwise
496 * the complete header is read.
497 *
498 * \returns 0 on success
499 * \returns -1 on error
500 */
501 error_t readHeader( fitsHeader<verboseT> &head /**< [out] a fitsHeader object */ );
502
503 /// Read the header from the fits file.
504 /** If head is not empty, then only the keywords already in head are updated. Otherwise
505 * the complete header is read.
506 *
507 * \returns 0 on success
508 * \returns -1 on error
509 */
510 error_t readHeader( fitsHeader<verboseT> &head, ///< [out] a fitsHeader object
511 const std::string &fname ///< [in] the file path, which is passed to \ref fileName
512 );
513
514 /// Read the headers from a list of FITS files.
515 /** In each case, if the header is not empty then only the keywords already in head are updated. Otherwise
516 * the complete header is read.
517 *
518 * \returns 0 on success
519 * \returns -1 on error
520 */
522 std::vector<fitsHeader<verboseT>> &heads, /// A vector of fitsHeader objects to read into.
523 const std::vector<std::string> &flist ///< [in] A list of files, each of which is passed to \ref fileName
524 );
525
526 ///@}
527
528 /** \name Writing Basic Arrays
529 * These methods write basic arrays specified by a pointer to FITS.
530 * @{
531 */
532
533 /// Write the contents of a raw array to the FITS file.
534 /**
535 * \returns 0 on success
536 * \returns -1 on error
537 */
538 error_t write( const dataT *im, ///< [in] is the array
539 int d1, ///< [in] is the first dimension
540 int d2, ///< [in] is the second dimension
541 int d3, ///< [in] is the third dimenesion (minimum value is 1)
542 fitsHeader<verboseT> *head ///< [in] a pointer to the header. Set to 0 if not used.
543 );
544
545 /// Write the contents of a raw array to the FITS file.
546 /**
547 * \returns 0 on success
548 * \returns -1 on error
549 */
550 error_t write( const dataT *im, ///< [in] is the array
551 int d1, ///< [in] is the first dimension
552 int d2, ///< [in] is the second dimension
553 int d3 ///< [in] is the third dimenesion (minimum value is 1)
554 );
555
556 /// Write the contents of a raw array to the FITS file.
557 /**
558 * Note: the type of the array must match dataT
559 *
560 * \returns 0 on success
561 * \returns -1 on error
562 */
563 error_t write( const dataT *im, ///< [in] is the array
564 int d1, ///< [in] is the first dimension
565 int d2, ///< [in] is the second dimension
566 int d3, ///< [in] is the third dimenesion (minimum value is 1)
567 fitsHeader<verboseT> &head ///< [in] is the header
568 );
569
570 /// Write the contents of a raw array to the FITS file.
571 /**
572 * \returns 0 on success
573 * \returns -1 on error
574 */
575 error_t write( const std::string &fname, ///< [in] is the name of the file.
576 const dataT *im, ///< [in] is the array
577 int d1, ///< [in] is the first dimension
578 int d2, ///< [in] is the second dimension
579 int d3 ///< [in] is the third dimenesion (minimum value is 1)
580 );
581
582 /// Write the contents of a raw array to the FITS file.
583 /**
584 * \returns 0 on success
585 * \returns -1 on error
586 */
587 error_t write( const std::string &fname, ///< [in] is the name of the file.
588 const dataT *im, ///< [in] is the array
589 int d1, ///< [in] is the first dimension
590 int d2, ///< [in] is the second dimension
591 int d3, ///< [in] is the third dimenesion (minimum value is 1)
592 fitsHeader<verboseT> &head ///< [in] is the header
593 );
594
595 ///@}
596
597 /** \name Writing Eigen Arrays
598 * These methods write array types with an Eigen-like interface.
599 * @{
600 */
601
602 /// Write the contents of an Eigen-type array to a FITS file.
603 /** The type arrT can be any type with the following members defined:
604 * - data() (returns a pointer to the underlying array)
605 * - rows() (returrns the number of rows)
606 * - cols() (returns the number of columns)
607 * - may have planes() defined
608 *
609 * Note: as with all write methods, the Scalar type of the array must match dataT
610 *
611 * \tparam arrT is the type of array, see requirements above.
612 *
613 * \returns 0 on success
614 * \returns -1 on error
615 */
616 template <typename arrT>
617 error_t write( const std::string &fname, ///< [in] is the name of the file.
618 const arrT &im ///< [in] is the array
619 );
620
621 /// Write the contents of an Eigen-type array to a FITS file.
622 /** The type arrT can be any type with the following members defined:
623 * - data() (returns a pointer to the underlying array)
624 * - rows() (returrns the number of rows)
625 * - cols() (returns the number of columns)
626 * - may have planes() defined.
627 *
628 * Note: as with all write methods, the Scalar type of the array must match dataT
629 *
630 * \tparam arrT is the type of array, see requirements above.
631 *
632 * \returns 0 on success
633 * \returns -1 on error
634 */
635 template <typename arrT>
636 error_t write( const std::string &fname, ///< [in] is the file path, which is passed to \ref fileName
637 const arrT &im, ///< [in] is the array
638 fitsHeader<verboseT> &head ///< [in] is a fitsHeader object which is passed to \ref readHeader
639 );
640
641 // int writeHeader( fitsHeader<verboseT> &head );
642
643 ///@}
644
645 /** \name Reading Subsets
646 * It is often desirable to read only a subset of an image or images into memory. These methods
647 * allow you to specify this.
648 * @{
649 */
650
651 /// Set to read all the pixels in the file
652 void setReadSize();
653
654 /// Set to read only a subset of the pixels in the file
655 /**
656 */
657 void setReadSize( long x0, ///< is the starting x-pixel to read
658 long y0, ///< is the starting y-pixel to read
659 long xpix, ///< is the number of x-pixels to read
660 long ypix ///< is the number of y-pixels to read
661 );
662
663 /// Set to read all frames from a cube.
664 /**
665 */
666 void setCubeReadSize();
667
668 /// Set the number of frames to read from a cube.
669 /**
670 *
671 */
672 void setCubeReadSize( long z0, ///< is the starting frame to read
673 long zframes ///< is the number of frames to read
674 );
675
676 ///@}
677
678}; // fitsFile
679
680template <typename dataT, class verboseT>
684
685template <typename dataT, class verboseT>
690
691template <typename dataT, class verboseT>
692fitsFile<dataT, verboseT>::fitsFile( const std::string &fname, error_t &errc )
693{
694 // no errors are actually possible
695 errc = internal::mxlib_error_report<verboseT>( fileName( fname, false ) ); // nothing printed if noerror
696}
697
698template <typename dataT, class verboseT>
699fitsFile<dataT, verboseT>::fitsFile( const std::string &fname, bool doopen )
700{
701 // If an error happens on open(), then m_open will be false and this will persist
702 // so no need to throw an exception
703 internal::mxlib_error_report<verboseT>( fileName( fname, doopen ) ); // nothing printed if noerror
704}
705
706template <typename dataT, class verboseT>
707fitsFile<dataT, verboseT>::fitsFile( const std::string &fname, bool doopen, error_t &errc )
708{
709 // If an error happens on open(), then m_open will be false and this will persist
710 // so no need to throw an exception
711 errc = internal::mxlib_error_report<verboseT>( fileName( fname, doopen ) ); // nothing printed if noerror
712}
713
714template <typename dataT, class verboseT>
716{
717 if( m_isOpen )
718 {
719 internal::mxlib_error_report<verboseT>( close() );
720 }
721
722}
723
724template <typename dataT, class verboseT>
726{
727 return m_fileName;
728}
729
730template <typename dataT, class verboseT>
731error_t fitsFile<dataT, verboseT>::fileName( const std::string &fname, bool doopen )
732{
733 if( m_isOpen )
734 {
735 mxlib_error_check( close() );
736 }
737
738 m_fileName = fname;
739
740 if( doopen )
741 {
742 mxlib_error_check( open() );
743 }
744
745 return error_t::noerror;
746}
747
748template <typename dataT, class verboseT>
750{
751 return m_naxis;
752}
753
754template <typename dataT, class verboseT>
756{
757 if( dim >= m_naxis || dim > 2)
758 {
759 return -1;
760 }
761
762 return m_naxes[dim];
763}
764
765template <typename dataT, class verboseT>
767{
768 if( m_isOpen ) // no-op
769 {
770 return error_t::noerror;
771 }
772
773 if( m_fileName == "" )
774 {
775 return internal::mxlib_error_report<verboseT>( error_t::invalidconfig, "File name is not set" );
776 }
777
778 int fstatus = 0;
779
780 fits_open_file( &m_fptr, m_fileName.c_str(), READONLY, &fstatus );
781
782 if( fstatus )
783 {
784 return internal::mxlib_error_report<verboseT>( fits_status2error_t( fstatus ), "Opening file " + m_fileName );
785 }
786
787 fstatus = 0;
788 fits_get_img_dim( m_fptr, &m_naxis, &fstatus );
789 if( fstatus )
790 {
791 return internal::mxlib_error_report<verboseT>( fits_status2error_t( fstatus ),
792 "Getting number of axes in file " + m_fileName );
793 }
794
795 //Currently can't be true since it's declared [3].
796 if( m_naxes == nullptr )
797 {
798 return internal::mxlib_error_report<verboseT>( error_t::allocerr, "m_naxes is nullptr" );
799 }
800
801 fstatus = 0;
802 fits_get_img_size( m_fptr, m_naxis, m_naxes, &fstatus );
803 if( fstatus )
804 {
805 return internal::mxlib_error_report<verboseT>( fits_status2error_t( fstatus ),
806 "Getting dimensions in file " + m_fileName );
807 }
808
809 m_isOpen = true; // Only set this after opening is complete.
810
811 return error_t::noerror;
812}
813
814template <typename dataT, class verboseT>
815error_t fitsFile<dataT, verboseT>::open( const std::string &fname )
816{
817 mxlib_error_return( fileName( fname, true ) );
818}
819
820template <typename dataT, class verboseT>
822{
823 if( !m_isOpen )
824 {
825 return error_t::noerror; // No error.
826 }
827
828 int fstatus = 0;
829 fits_close_file( m_fptr, &fstatus );
830
831 if( fstatus )
832 {
833 return internal::mxlib_error_report<verboseT>( fits_status2error_t( fstatus ), "Closing file " + m_fileName );
834 }
835
836 m_isOpen = 0;
837 fstatus = 0;
838
839
840 return error_t::noerror;
841}
842
843template <typename dataT, class verboseT>
845{
846 if( !m_isOpen )
847 {
849 return -1;
850 }
851
852 return m_naxis;
853}
854
855template <typename dataT, class verboseT>
857{
858 if( !m_isOpen )
859 {
861 return -1;
862 }
863
864 long sz = 1;
865
866 errc = error_t::noerror;
867
868 if( m_x0 > -1 && m_y0 > -1 && m_xpix > -1 && m_ypix > -1 && m_naxis == 2 )
869 {
870 return m_xpix * m_ypix;
871 }
872 else
873 {
874 for( int i = 0; i < m_naxis && i < 3; ++i )
875 {
876 sz *= m_naxes[i];
877 }
878 }
879
880 return sz;
881}
882
883template <typename dataT, class verboseT>
885{
886 if( !m_isOpen )
887 {
889 return -1;
890 }
891
892 if( axis >= m_naxis || axis > 2 )
893 {
894 errc = error_t::invalidarg;
895 return -1;
896 }
897
898 errc = error_t::noerror;
899
900 if( m_x0 > -1 && m_y0 > -1 && m_xpix > -1 && m_ypix > -1 && m_naxis == 2 )
901 {
902 if( axis == 0 )
903 {
904 return m_xpix;
905 }
906 return m_ypix;
907 }
908 else
909 {
910 return m_naxes[axis];
911 }
912}
913
914template <typename dataT, class verboseT>
916{
917 error_t errc = pixarr.allocate( m_naxis );
918
919 //This currently can't be trude since it is declared as [3]
920 if( m_naxes == nullptr )
921 {
922 return internal::mxlib_error_report<verboseT>( error_t::paramnotset, "m_naxes" );
923 }
924
925 if( m_x0 > -1 && m_y0 > -1 && m_xpix > -1 && m_ypix > -1 && m_naxis == 2 )
926 {
927 pixarr.fpix[0] = m_x0 + 1;
928 pixarr.lpix[0] = pixarr.fpix[0] + m_xpix - 1;
929 pixarr.fpix[1] = m_y0 + 1;
930 pixarr.lpix[1] = pixarr.fpix[1] + m_ypix - 1;
931
932 pixarr.inc[0] = 1;
933 pixarr.inc[1] = 1;
934 }
935 else
936 {
937 if( m_x0 < 0 && m_y0 < 0 && m_xpix < 0 && m_ypix < 0 && m_z0 < 0 && m_zframes < 0 )
938 {
939 for( int i = 0; i < m_naxis && i < 3; i++ )
940 {
941 pixarr.fpix[i] = 1;
942 pixarr.lpix[i] = m_naxes[i];
943 pixarr.inc[i] = 1;
944 }
945 }
946 else
947 {
948 if( m_x0 > -1 && m_y0 > -1 && m_xpix > -1 && m_ypix > -1 )
949 {
950 pixarr.fpix[0] = m_x0 + 1;
951 pixarr.lpix[0] = pixarr.fpix[0] + m_xpix - 1;
952 pixarr.fpix[1] = m_y0 + 1;
953 pixarr.lpix[1] = pixarr.fpix[1] + m_ypix - 1;
954
955 pixarr.inc[0] = 1;
956 pixarr.inc[1] = 1;
957 }
958 else
959 {
960 pixarr.fpix[0] = 1;
961 pixarr.lpix[0] = m_naxes[0];
962 pixarr.fpix[1] = 1;
963 pixarr.lpix[1] = m_naxes[1];
964
965 pixarr.inc[0] = 1;
966 pixarr.inc[1] = 1;
967 }
968
969 if( m_z0 > -1 && m_zframes > -1 )
970 {
971 pixarr.fpix[2] = m_z0 + 1;
972 pixarr.lpix[2] = pixarr.fpix[2] + m_zframes - 1;
973 pixarr.inc[2] = 1;
974 }
975 else
976 {
977 pixarr.fpix[2] = 1;
978 pixarr.lpix[2] = m_naxes[2];
979 pixarr.inc[2] = 1;
980 }
981 }
982 }
983
984 return error_t::noerror;
985}
986
987/************************************************************/
988/*** Basic Arrays ***/
989/************************************************************/
990
991template <typename dataT, class verboseT>
993{
994 if( !m_isOpen )
995 {
996 mxlib_error_check( open() );
997 }
998
999 pixarrT pixarrs;
1000
1001 mxlib_error_check( calcPixarrs( pixarrs ) );
1002
1003 ///\todo test if there is a speed difference for full reads for fits_read_pix/subset
1004
1005 int fstatus = 0;
1006
1007 fits_read_subset( m_fptr,
1008 fitsType<dataT>(),
1009 pixarrs.fpix,
1010 pixarrs.lpix,
1011 pixarrs.inc,
1012 (void *)&m_nulval,
1013 (void *)data,
1014 &m_anynul,
1015 &fstatus );
1016
1017 if( fstatus && fstatus != END_OF_FILE )
1018 {
1019 return internal::mxlib_error_report<verboseT>( fits_status2error_t( fstatus ),
1020 "Reading data from " + m_fileName );
1021 }
1022
1023 return error_t::noerror;
1024}
1025
1026template <typename dataT, class verboseT>
1028{
1029 mxlib_error_check( read( data ) );
1030
1031 mxlib_error_return( readHeader( head ) );
1032}
1033
1034template <typename dataT, class verboseT>
1035error_t fitsFile<dataT, verboseT>::read( dataT *data, const std::string &fname )
1036{
1037 mxlib_error_check( fileName( fname ) );
1038
1039 mxlib_error_return( read( data ) );
1040}
1041
1042template <typename dataT, class verboseT>
1043error_t fitsFile<dataT, verboseT>::read( dataT *data, fitsHeader<verboseT> &head, const std::string &fname )
1044{
1045 mxlib_error_check( fileName( fname ) );
1046
1047 mxlib_error_check( read( data ) );
1048
1049 mxlib_error_return( readHeader( head ) );
1050}
1051
1052template <typename dataT, class verboseT>
1053error_t fitsFile<dataT, verboseT>::read( dataT *im, const std::vector<std::string> &flist )
1054{
1055 if( flist.size() == 0 )
1056 {
1057 return internal::mxlib_error_report<verboseT>( error_t::invalidarg, "Empty file list" );
1058 }
1059
1060 long sz0 = 0, sz1 = 0;
1061
1062 for( int i = 0; i < flist.size(); ++i )
1063 {
1064 mxlib_error_check( fileName( flist[i], 1 ) );
1065
1066 mxlib_error_check( read( im + i * sz0 * sz1 ) );
1067
1068 error_t errc;
1069 sz0 = getSize( 0, errc );
1070 mxlib_error_check( errc );
1071
1072 sz1 = getSize( 1, errc );
1073 mxlib_error_check( errc );
1074 }
1075
1076 return error_t::noerror;
1077}
1078
1079template <typename dataT, class verboseT>
1081 std::vector<fitsHeader<verboseT>> &heads,
1082 const std::vector<std::string> &flist )
1083{
1084 if( flist.size() == 0 )
1085 {
1086 return internal::mxlib_error_report<verboseT>( error_t::invalidarg, "Empty file list" );
1087 }
1088
1089 long sz0 = 0, sz1 = 0;
1090
1091 for( size_t i = 0; i < flist.size(); ++i )
1092 {
1093
1094 mxlib_error_check( fileName( flist[i], 1 ) );
1095
1096 mxlib_error_check( read( im + i * sz0 * sz1 ) );
1097
1098 mxlib_error_check( readHeader( heads[i] ) );
1099
1100 error_t errc;
1101 sz0 = getSize( 0, errc );
1102 mxlib_error_check( errc );
1103
1104 sz1 = getSize( 1, errc );
1105 mxlib_error_check( errc );
1106 }
1107
1108 return error_t::noerror;
1109}
1110
1111/************************************************************/
1112/*** Eigen Arrays ***/
1113/************************************************************/
1114
1115template <typename arrT, class verboseT, bool isCube = improc::is_eigenCube<arrT>::value>
1116struct eigenArrResize
1117{
1118 // If it's a cube, always pass zsz
1119 error_t resize( arrT &arr, int xsz, int ysz, int zsz )
1120 {
1121 try
1122 {
1123 arr.resize( xsz, ysz, zsz );
1124 }
1125 catch( const std::bad_alloc &e )
1126 {
1127 internal::mxlib_error_report<verboseT>( error_t::std_bad_alloc,
1128 std::string( "resizing array: " ) + e.what() );
1129#ifdef MXLIB_TRAP_ALLOC_ERRORS
1131#else
1132 throw;
1133#endif
1134 }
1135 catch( const std::exception &e )
1136 {
1137 internal::mxlib_error_report<verboseT>( error_t::std_exception,
1138 std::string( "resizing array: " ) + e.what() );
1139#ifdef MXLIB_TRAP_ALLOC_ERRORS
1141#else
1142 throw;
1143#endif
1144 }
1145 catch( ... )
1146 {
1147 internal::mxlib_error_report<verboseT>( error_t::exception, "resizing array" );
1148#ifdef MXLIB_TRAP_ALLOC_ERRORS
1149 return error_t::exception;
1150#else
1151 throw;
1152#endif
1153 }
1154
1155 return error_t::noerror;
1156 }
1157};
1158
1159template <typename arrT, class verboseT>
1160struct eigenArrResize<arrT, verboseT, false>
1161{
1162 // If it's not a cube, never pass zsz
1163 error_t resize( arrT &arr, int xsz, int ysz, [[maybe_unused]] int zsz )
1164 {
1165 try
1166 {
1167 arr.resize( xsz, ysz );
1168 }
1169 catch( const std::bad_alloc &e )
1170 {
1171 internal::mxlib_error_report<verboseT>( error_t::std_bad_alloc,
1172 std::string( "resizing array: " ) + e.what() );
1173#ifdef MXLIB_TRAP_ALLOC_ERRORS
1175#else
1176 throw;
1177#endif
1178 }
1179 catch( const std::exception &e )
1180 {
1181 internal::mxlib_error_report<verboseT>( error_t::std_exception,
1182 std::string( "resizing array: " ) + e.what() );
1183#ifdef MXLIB_TRAP_ALLOC_ERRORS
1185#else
1186 throw;
1187#endif
1188 }
1189 catch( ... )
1190 {
1191 internal::mxlib_error_report<verboseT>( error_t::exception, "resizing array" );
1192#ifdef MXLIB_TRAP_ALLOC_ERRORS
1193 return error_t::exception;
1194#else
1195 throw;
1196#endif
1197 }
1198
1199 return error_t::noerror;
1200 }
1201};
1202
1203template <typename dataT, class verboseT>
1204template <typename arrT>
1206{
1207 ///\todo this can probably be made part of one read function (or call read(data *)) with a call to resize with
1208 /// SFINAE
1209 int fstatus = 0;
1210
1211 if( !m_isOpen )
1212 {
1213 mxlib_error_check( open() );
1214 }
1215
1216 pixarrT pixarrs;
1217 mxlib_error_check( calcPixarrs( pixarrs ) );
1218
1219 eigenArrResize<arrT, verboseT> arrresz;
1220 if( m_naxis > 2 )
1221 {
1222 mxlib_error_check( arrresz.resize( im,
1223 pixarrs.lpix[0] - pixarrs.fpix[0] + 1,
1224 pixarrs.lpix[1] - pixarrs.fpix[1] + 1,
1225 pixarrs.lpix[2] - pixarrs.fpix[2] + 1 ) );
1226 }
1227 else if( m_naxis > 1 )
1228 {
1230 arrresz.resize( im, pixarrs.lpix[0] - pixarrs.fpix[0] + 1, pixarrs.lpix[1] - pixarrs.fpix[1] + 1, 1 ) );
1231 }
1232 else
1233 {
1234 mxlib_error_check( arrresz.resize( im, pixarrs.lpix[0] - pixarrs.fpix[0] + 1, 1, 1 ) );
1235 }
1236
1237 fits_read_subset( m_fptr,
1238 fitsType<typename arrT::Scalar>(),
1239 pixarrs.fpix,
1240 pixarrs.lpix,
1241 pixarrs.inc,
1242 (void *)&m_nulval,
1243 (void *)im.data(),
1244 &m_anynul,
1245 &fstatus );
1246
1247 if( fstatus && fstatus != END_OF_FILE )
1248 {
1249 return internal::mxlib_error_report<verboseT>( fits_status2error_t( fstatus ),
1250 "Reading data from " + m_fileName );
1251 }
1252
1253 return error_t::noerror;
1254}
1255
1256template <typename dataT, class verboseT>
1257template <typename arrT>
1259{
1260 error_t errc;
1261 errc = read( data );
1262 if( errc != error_t::noerror )
1263 {
1264 return internal::mxlib_error_report<verboseT>( errc );
1265 }
1266
1267 errc = readHeader( head );
1268 if( errc != error_t::noerror )
1269 {
1270 return internal::mxlib_error_report<verboseT>( errc );
1271 }
1272
1273 return error_t::noerror;
1274}
1275
1276template <typename dataT, class verboseT>
1277template <typename arrT>
1278error_t fitsFile<dataT, verboseT>::read( arrT &data, const std::string &fname )
1279{
1280 error_t errc;
1281 errc = fileName( fname );
1282 if( errc != error_t::noerror )
1283 {
1284 return internal::mxlib_error_report<verboseT>( errc );
1285 }
1286
1287 errc = read( data );
1288 if( errc != error_t::noerror )
1289 {
1290 return internal::mxlib_error_report<verboseT>( errc );
1291 }
1292 return error_t::noerror;
1293}
1294
1295template <typename dataT, class verboseT>
1296template <typename arrT>
1297error_t fitsFile<dataT, verboseT>::read( arrT &data, fitsHeader<verboseT> &head, const std::string &fname )
1298{
1299 error_t errc;
1300 errc = fileName( fname );
1301 if( errc != error_t::noerror )
1302 {
1303 return internal::mxlib_error_report<verboseT>( errc );
1304 }
1305
1306 errc = read( data );
1307 if( errc != error_t::noerror )
1308 {
1309 return internal::mxlib_error_report<verboseT>( errc );
1310 }
1311
1312 errc = readHeader( head );
1313 if( errc != error_t::noerror )
1314 {
1315 return internal::mxlib_error_report<verboseT>( errc );
1316 }
1317
1318 return error_t::noerror;
1319}
1320
1321template <typename dataT, class verboseT>
1322template <typename cubeT>
1324 const std::vector<std::string> &flist,
1325 std::vector<fitsHeader<verboseT>> *heads )
1326{
1327 error_t errc;
1328 int fstatus = 0;
1329
1330 if( flist.size() == 0 )
1331 {
1332 return internal::mxlib_error_report<verboseT>( error_t::invalidarg, "Empty file list" );
1333 }
1334
1335 // Open the first file to get the dimensions.
1336 errc = fileName( flist[0], 1 );
1337 if( !!errc )
1338 {
1339 return internal::mxlib_error_report<verboseT>( errc );
1340 }
1341
1342 pixarrT pixarrs;
1343 errc = calcPixarrs( pixarrs );
1344
1345 if(!!errc)
1346 {
1347 return internal::mxlib_error_report<verboseT>( errc );
1348 }
1349
1350 cube.resize( pixarrs.lpix[0] - pixarrs.fpix[0] + 1, pixarrs.lpix[1] - pixarrs.fpix[1] + 1, flist.size() );
1351
1352 // Now read first image.
1353 fits_read_subset( m_fptr,
1354 fitsType<typename cubeT::Scalar>(),
1355 pixarrs.fpix,
1356 pixarrs.lpix,
1357 pixarrs.inc,
1358 (void *)&m_nulval,
1359 (void *)cube.image( 0 ).data(),
1360 &m_anynul,
1361 &fstatus );
1362
1363 if( fstatus && fstatus != END_OF_FILE )
1364 {
1365 return internal::mxlib_error_report<verboseT>( fits_status2error_t( fstatus ),
1366 "Reading data from " + m_fileName );
1367 }
1368
1369 if( heads )
1370 {
1371 errc = readHeader( ( *heads )[0] );
1372 if( errc != error_t::noerror )
1373 {
1374 return internal::mxlib_error_report<verboseT>( errc );
1375 }
1376 }
1377
1378 // Now read in the rest.
1379 for( int i = 1; i < flist.size(); ++i )
1380 {
1381 errc = fileName( flist[i], 1 );
1382 if( errc != error_t::noerror )
1383 {
1384 return internal::mxlib_error_report<verboseT>( errc );
1385 }
1386
1387 // Now read image.
1388 fits_read_subset( m_fptr,
1389 fitsType<typename cubeT::Scalar>(),
1390 pixarrs.fpix,
1391 pixarrs.lpix,
1392 pixarrs.inc,
1393 (void *)&m_nulval,
1394 (void *)cube.image( i ).data(),
1395 &m_anynul,
1396 &fstatus );
1397
1398 if( fstatus && fstatus != END_OF_FILE )
1399 {
1400 return internal::mxlib_error_report<verboseT>( fits_status2error_t( fstatus ),
1401 "Reading data from " + m_fileName );
1402 }
1403
1404 if( heads )
1405 {
1406 errc = readHeader( ( *heads )[i] );
1407 if( errc != error_t::noerror )
1408 {
1409 return internal::mxlib_error_report<verboseT>( errc );
1410 }
1411 }
1412 }
1413
1414 return error_t::noerror;
1415}
1416
1417template <typename dataT, class verboseT>
1418template <typename cubeT>
1420 std::vector<fitsHeader<verboseT>> &heads,
1421 const std::vector<std::string> &flist )
1422{
1423 mxlib_error_return( read( cube, flist, &heads ) );
1424}
1425
1426template <typename dataT, class verboseT>
1428{
1429 int fstatus = 0;
1430
1431 char keyword[FLEN_KEYWORD];
1432 char value[FLEN_VALUE];
1433 char *comment;
1434
1435 // The keys to look for if head is already populated
1436 typename std::list<headerIteratorT> head_keys;
1437 typename std::list<headerIteratorT>::iterator head_keys_it;
1438 // int num_head_keys;
1439
1440 bool head_keys_only = false;
1441 if( head.size() > 0 )
1442 {
1443 head_keys_only = true;
1444 headerIteratorT headIt = head.begin();
1445 while( headIt != head.end() )
1446 {
1447 head_keys.push_back( headIt );
1448 ++headIt;
1449 }
1450 // num_head_keys = head.size();
1451 }
1452
1453 // If m_noComment is set, then we don't read in the comment
1454 if( m_noComment )
1455 {
1456 comment = 0;
1457 }
1458 else
1459 {
1460 comment = new char[FLEN_COMMENT];
1461 }
1462
1463 int keysexist;
1464 int morekeys;
1465
1466 if( !m_isOpen )
1467 {
1468 mxlib_error_check( open() );
1469 }
1470
1471 // This gets the number of header keys to read
1472 fits_get_hdrspace( m_fptr, &keysexist, &morekeys, &fstatus );
1473
1474 if( fstatus )
1475 {
1476 if( comment )
1477 {
1478 delete[] comment;
1479 }
1480
1481 return internal::mxlib_error_report<verboseT>( fits_status2error_t( fstatus ),
1482 "Reading header from " + m_fileName );
1483 }
1484
1485 for( int i = 0; i < keysexist; i++ )
1486 {
1487 fits_read_keyn( m_fptr, i + 1, keyword, value, comment, &fstatus );
1488
1489 if( fstatus )
1490 {
1491 if( comment )
1492 {
1493 delete[] comment;
1494 }
1495
1496 return internal::mxlib_error_report<verboseT>( fits_status2error_t( fstatus ),
1497 "Reading header from " + m_fileName );
1498 }
1499
1500 if( !head_keys_only )
1501 {
1502 if( strcmp( keyword, "COMMENT" ) == 0 )
1503 {
1504 head.template append<fitsCommentType>( keyword, fitsCommentType( value ), comment );
1505 }
1506 else if( strcmp( keyword, "HISTORY" ) == 0 )
1507 {
1508 head.template append<fitsHistoryType>( keyword, fitsHistoryType( value ), comment );
1509 }
1510 else
1511 {
1512 // Otherwise we append it as an unknown type
1513 head.append( keyword, value, comment );
1514 }
1515 }
1516 else
1517 {
1518 head_keys_it = head_keys.begin();
1519 while( head_keys_it != head_keys.end() )
1520 {
1521 if( ( *( *head_keys_it ) ).keyword() == keyword )
1522 {
1523 head[keyword].value( (const char *)value );
1524 if( comment )
1525 {
1526 head[keyword].comment( comment );
1527 }
1528
1529 head_keys.erase( head_keys_it );
1530
1531 break;
1532 }
1533 ++head_keys_it;
1534 }
1535
1536 // Quit if we're done.
1537 if( head_keys.empty() )
1538 {
1539 break;
1540 }
1541 }
1542 }
1543
1544 if( comment )
1545 {
1546 delete[] comment;
1547 }
1548
1549 return error_t::noerror;
1550}
1551
1552template <typename dataT, class verboseT>
1554{
1555 error_t errc;
1556 mxlib_error_check( fileName( fname ) );
1557 mxlib_error_check( readHeader( head ) );
1558 return error_t::noerror;
1559}
1560
1561template <typename dataT, class verboseT>
1563 const std::vector<std::string> &flist )
1564{
1565 if(heads.size() != 0 && heads.size() != flist.size())
1566 {
1567 return internal::mxlib_error_report<verboseT>(error_t::invalidarg, "head vector is not empty and not same size as file list");
1568 }
1569
1570 if(heads.size() == 0)
1571 {
1572 heads.resize(flist.size());
1573 }
1574
1575 error_t errc;
1576 for( int i = 0; i < flist.size(); ++i )
1577 {
1578 mxlib_error_check( fileName( flist[i], 1 ) );
1579
1580 mxlib_error_check( readHeader( heads[i] ) );
1581 }
1582
1583 return error_t::noerror;
1584}
1585
1586template <typename dataT, class verboseT>
1587error_t fitsFile<dataT, verboseT>::write( const dataT *im, int d1, int d2, int d3, fitsHeader<verboseT> *head )
1588{
1589 int fstatus = 0;
1590
1591 if( m_isOpen )
1592 {
1593 mxlib_error_check( close() );
1594 }
1595
1596 m_naxis = 1;
1597 if( d2 > 0 )
1598 {
1599 if( d3 > 1 )
1600 {
1601 m_naxis = 3;
1602 }
1603 else
1604 {
1605 m_naxis = 2;
1606 }
1607 }
1608
1609 //currently can't be true since declared [3]
1610 if( m_naxes == nullptr )
1611 {
1612 return internal::mxlib_error_report<verboseT>( error_t::allocerr, "m_naxes is nullptr" );
1613 }
1614
1615 m_naxes[0] = d1;
1616 if( m_naxis > 1 )
1617 {
1618 m_naxes[1] = d2;
1619 }
1620 if( m_naxis > 2 )
1621 {
1622 m_naxes[2] = d3;
1623 }
1624
1625 std::string forceFileName = "!" + m_fileName;
1626
1627 fits_create_file( &m_fptr, forceFileName.c_str(), &fstatus );
1628 if( fstatus )
1629 {
1630 return internal::mxlib_error_report<verboseT>( fits_status2error_t( fstatus ), "Creating " + m_fileName );
1631 }
1632 m_isOpen = true;
1633
1634 fstatus = 0;
1635 fits_create_img( m_fptr, fitsBITPIX<dataT>(), m_naxis, m_naxes, &fstatus );
1636 if( fstatus )
1637 {
1638 return internal::mxlib_error_report<verboseT>( fits_status2error_t( fstatus ),
1639 "Creating image in" + m_fileName );
1640 }
1641
1642 long fpixel[3];
1643 fpixel[0] = 1;
1644 fpixel[1] = 1;
1645 fpixel[2] = 1;
1646
1647 LONGLONG nelements = 1;
1648
1649 for( int i = 0; i < m_naxis && i < 3; ++i )
1650 {
1651 nelements *= m_naxes[i];
1652 }
1653
1654 fstatus = 0;
1655 fits_write_pix( m_fptr, fitsType<dataT>(), fpixel, nelements, (void *)im, &fstatus );
1656 if( fstatus )
1657 {
1658 return internal::mxlib_error_report<verboseT>( fits_status2error_t( fstatus ), "Writing data " + m_fileName );
1659 }
1660
1661 if( head != 0 )
1662 {
1663 headerIteratorT it;
1664
1665 for( it = head->begin(); it != head->end(); ++it )
1666 {
1667 error_t errc = it->write( m_fptr );
1668 if( errc != error_t::noerror )
1669 {
1670 return internal::mxlib_error_report<verboseT>( fits_status2error_t( fstatus ),
1671 "Writing keyword " + m_fileName );
1672 }
1673 }
1674 }
1675
1676 mxlib_error_return( close() )
1677}
1678
1679template <typename dataT, class verboseT>
1680error_t fitsFile<dataT, verboseT>::write( const dataT *im, int d1, int d2, int d3 )
1681{
1682 mxlib_error_return( write( im, d1, d2, d3, (fitsHeader<verboseT> *)0 ) );
1683}
1684
1685template <typename dataT, class verboseT>
1686error_t fitsFile<dataT, verboseT>::write( const dataT *im, int d1, int d2, int d3, fitsHeader<verboseT> &head )
1687{
1688 mxlib_error_return( write( im, d1, d2, d3, &head ) );
1689}
1690
1691template <typename dataT, class verboseT>
1692error_t fitsFile<dataT, verboseT>::write( const std::string &fname, const dataT *im, int d1, int d2, int d3 )
1693{
1694 mxlib_error_check( fileName( fname, false ) );
1695
1696 mxlib_error_return( write( im, d1, d2, d3, (fitsHeader<verboseT> *)0 ) );
1697}
1698
1699template <typename dataT, class verboseT>
1701 const std::string &fname, const dataT *im, int d1, int d2, int d3, fitsHeader<verboseT> &head )
1702{
1703 mxlib_error_check( fileName( fname, false ) );
1704
1705 mxlib_error_return( write( im, d1, d2, d3, &head ) );
1706}
1707
1708template <typename dataT, class verboseT>
1709template <typename arrT>
1710error_t fitsFile<dataT, verboseT>::write( const std::string &fname, const arrT &im )
1711{
1713
1714 mxlib_error_return( write( fname, im.data(), im.rows(), im.cols(), planes( im ) ) );
1715}
1716
1717template <typename dataT, class verboseT>
1718template <typename arrT>
1719error_t fitsFile<dataT, verboseT>::write( const std::string &fname, const arrT &im, fitsHeader<verboseT> &head )
1720{
1722
1723 return write( fname, im.data(), im.rows(), im.cols(), planes( im ), head );
1724}
1725
1726template <typename dataT, class verboseT>
1728{
1729 m_x0 = -1;
1730 m_y0 = -1;
1731 m_xpix = -1;
1732 m_ypix = -1;
1733}
1734
1735template <typename dataT, class verboseT>
1736void fitsFile<dataT, verboseT>::setReadSize( long x0, long y0, long xpix, long ypix )
1737{
1738 m_x0 = x0;
1739 m_y0 = y0;
1740 m_xpix = xpix;
1741 m_ypix = ypix;
1742}
1743
1744template <typename dataT, class verboseT>
1746{
1747 m_z0 = -1;
1748 m_zframes = -1;
1749}
1750
1751template <typename dataT, class verboseT>
1753{
1754 m_z0 = z0;
1755 m_zframes = zframes;
1756}
1757
1758/** \ingroup fits_processing_typedefs
1759 * @{
1760 */
1761
1762/// A \ref fitsFile to work in signed characters
1764
1765/// A \ref fitsFile to work in unsigned characters
1767
1768/// A \ref fitsFile to work in signed short integers
1770
1771/// A \ref fitsFile to work in unsigned short integers
1773
1774/// A \ref fitsFile to work in signed integers
1776
1777/// A \ref fitsFile to work in unsigned integers
1779
1780/// A \ref fitsFile to work in signed long integers
1782
1783/// A \ref fitsFile to work in single precision floats
1785
1786/// A \ref fitsFile to work in double precision
1788
1789///@}
1790
1791extern template class fitsFile<short, verbose::d>;
1792extern template class fitsFile<unsigned short, verbose::d>;
1793extern template class fitsFile<int, verbose::d>;
1794extern template class fitsFile<unsigned int, verbose::d>;
1795extern template class fitsFile<float, verbose::d>;
1796extern template class fitsFile<double, verbose::d>;
1797
1798} // namespace fits
1799} // namespace mx
1800
1801#endif // ioutils_fits_fitsFile_hpp
Class to manage interactions with a FITS file.
Definition fitsFile.hpp:53
long m_y0
The starting y-pixel to read from.
Definition fitsFile.hpp:89
long m_zframes
The number of frames to read from a cube.
Definition fitsFile.hpp:101
long m_xpix
The number of x-pixels to read.
Definition fitsFile.hpp:92
int naxis()
Get the current value of m_naxis.
Definition fitsFile.hpp:749
long getSize(error_t &errc)
Get the total size.
Definition fitsFile.hpp:856
void setCubeReadSize()
Set to read all frames from a cube.
long naxes(int dim)
Get the current value of m_naxes for the specified dimension.
Definition fitsFile.hpp:755
error_t open()
Open the file and gets its dimensions.
Definition fitsFile.hpp:766
std::string fileName()
Get the current value of m_fileName.
Definition fitsFile.hpp:725
std::string m_fileName
The path to the file.
Definition fitsFile.hpp:62
fitsfile * m_fptr
The cfitsio data structure.
Definition fitsFile.hpp:65
int getDimensions(error_t &errc)
Get the number of dimensions (i.e. m_naxis)
Definition fitsFile.hpp:844
long m_z0
The starting frame to read from a cube.
Definition fitsFile.hpp:98
void setReadSize()
Set to read all the pixels in the file.
long m_ypix
The number of y-pixels to read.
Definition fitsFile.hpp:95
int m_noComment
Flag to control whether the comment string is read.
Definition fitsFile.hpp:83
fitsFile()
Default constructor.
Definition fitsFile.hpp:681
~fitsFile()
Destructor.
Definition fitsFile.hpp:715
int m_naxis
The dimensions of the image (1D, 2D, or 3D)
Definition fitsFile.hpp:68
dataT m_nulval
The value to replace null values with.
Definition fitsFile.hpp:77
error_t close()
Close the file.
Definition fitsFile.hpp:821
error_t readHeader(fitsHeader< verboseT > &head)
Read the header from the fits file.
error_t calcPixarrs(pixarrT &pixarr)
Fill in the read-size arrays for reading a subset (always used)
Definition fitsFile.hpp:915
long m_naxes[3]
The size of each dimension.
Definition fitsFile.hpp:71
long m_x0
The starting x-pixel to read from.
Definition fitsFile.hpp:86
error_t read(dataT *data)
Read the contents of the FITS file into an array.
Definition fitsFile.hpp:992
int m_anynul
Records whether any null values were replaced.
Definition fitsFile.hpp:80
void construct()
One time initialization common to all constructors.
error_t write(const dataT *im, int d1, int d2, int d3, fitsHeader< verboseT > *head)
Write the contents of a raw array to the FITS file.
bool m_isOpen
Flag indicating whether the file is open or not.
Definition fitsFile.hpp:74
Class to manage a FITS file metadata header and provide fast access to the cards by keyword.
error_t append(const fitsHeaderCard< verboseT > &card)
Append a fitsHeaderCard to the end of the header.
cardListT::iterator headerIteratorT
The iterator type for the cards list.
error_t erase(const std::string &keyword)
Erase card by keyword.
size_t size()
Get number of cards currently stored in the header.
headerIteratorT end()
Get iterator to the end of the cards list.
headerIteratorT begin()
Get iterator to the beginning of the cards list.
Declares and defines a class to work with a FITS header.
Declares and defines utilities to work with FITS files.
error_t
The mxlib error codes.
Definition error_t.hpp:26
@ noerror
No error has occurred.
@ std_exception
An exception was thrown.
@ exception
An exception was thrown.
@ std_bad_alloc
A bad allocation exception was thrown.
@ allocerr
An error occurred during memory allocation.
@ paramnotset
A parameter was not set.
@ invalidconfig
A config setting was invalid.
@ invalidarg
An argument was invalid.
#define mxlib_error_check(fxn)
Perform an error check, if an error occurs report it and return the error. Does not return on no erro...
Definition error.hpp:405
#define mxlib_error_return(fxn)
Perform an error check, if an error occurs report it, and return the error code even if no error.
Definition error.hpp:424
fitsFile< long > fitsFilel
A fitsFile to work in signed long integers.
fitsFile< unsigned short > fitsFileus
A fitsFile to work in unsigned short integers.
fitsFile< short > fitsFiles
A fitsFile to work in signed short integers.
fitsFile< char > fitsFilec
A fitsFile to work in signed characters.
fitsFile< int > fitsFilei
A fitsFile to work in signed integers.
fitsFile< unsigned char > fitsFileuc
A fitsFile to work in unsigned characters.
fitsFile< unsigned int > fitsFileui
A fitsFile to work in unsigned integers.
fitsFile< double > fitsFiled
A fitsFile to work in double precision.
fitsFile< float > fitsFilef
A fitsFile to work in single precision floats.
static constexpr error_t fits_status2error_t(const int &err)
Convert a FITS status code to error_t.
Definition error_t.hpp:2169
The mxlib c++ namespace.
Definition mxlib.hpp:37
Function object to return the number of planes for any Eigen like object, whether 2D or a 3D cube.