LCOV - code coverage report
Current view: top level - ioutils/fits - fitsFile.hpp (source / functions) Coverage Total Hit
Test: mxlib Lines: 60.7 % 84 51
Test Date: 2026-02-19 16:58:26 Functions: 100.0 % 5 5

            Line data    Source code
       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              : 
      37              : namespace mx
      38              : {
      39              : namespace 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              :  */
      51              : template <typename dataT, class verboseT = verbose::d>
      52              : class fitsFile
      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
     255              :                 return error_t::std_bad_alloc;
     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              :      */
     521              :     error_t readHeader(
     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              : 
     680              : template <typename dataT, class verboseT>
     681              : fitsFile<dataT, verboseT>::fitsFile()
     682              : {
     683              : }
     684              : 
     685              : template <typename dataT, class verboseT>
     686              : fitsFile<dataT, verboseT>::fitsFile( error_t &errc )
     687              : {
     688              :     errc = error_t::noerror;
     689              : }
     690              : 
     691              : template <typename dataT, class verboseT>
     692              : fitsFile<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              : 
     698              : template <typename dataT, class verboseT>
     699              : fitsFile<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              : 
     706              : template <typename dataT, class verboseT>
     707              : fitsFile<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              : 
     714              : template <typename dataT, class verboseT>
     715              : fitsFile<dataT, verboseT>::~fitsFile()
     716              : {
     717              :     if( m_isOpen )
     718              :     {
     719              :         internal::mxlib_error_report<verboseT>( close() );
     720              :     }
     721              : 
     722              : }
     723              : 
     724              : template <typename dataT, class verboseT>
     725              : std::string fitsFile<dataT, verboseT>::fileName()
     726              : {
     727              :     return m_fileName;
     728              : }
     729              : 
     730              : template <typename dataT, class verboseT>
     731              : error_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              : 
     748              : template <typename dataT, class verboseT>
     749              : int fitsFile<dataT, verboseT>::naxis()
     750              : {
     751              :     return m_naxis;
     752              : }
     753              : 
     754              : template <typename dataT, class verboseT>
     755              : long fitsFile<dataT, verboseT>::naxes( int dim )
     756              : {
     757              :     if( dim >= m_naxis || dim > 2)
     758              :     {
     759              :         return -1;
     760              :     }
     761              : 
     762              :     return m_naxes[dim];
     763              : }
     764              : 
     765              : template <typename dataT, class verboseT>
     766              : error_t fitsFile<dataT, verboseT>::open()
     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              : 
     814              : template <typename dataT, class verboseT>
     815              : error_t fitsFile<dataT, verboseT>::open( const std::string &fname )
     816              : {
     817              :     mxlib_error_return( fileName( fname, true ) );
     818              : }
     819              : 
     820              : template <typename dataT, class verboseT>
     821              : error_t fitsFile<dataT, verboseT>::close()
     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              : 
     843              : template <typename dataT, class verboseT>
     844              : int fitsFile<dataT, verboseT>::getDimensions( error_t &errc )
     845              : {
     846              :     if( !m_isOpen )
     847              :     {
     848              :         errc = error_t::invalidconfig;
     849              :         return -1;
     850              :     }
     851              : 
     852              :     return m_naxis;
     853              : }
     854              : 
     855              : template <typename dataT, class verboseT>
     856              : long fitsFile<dataT, verboseT>::getSize( error_t &errc )
     857              : {
     858              :     if( !m_isOpen )
     859              :     {
     860              :         errc = error_t::invalidconfig;
     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              : 
     883              : template <typename dataT, class verboseT>
     884              : long fitsFile<dataT, verboseT>::getSize( size_t axis, error_t &errc )
     885              : {
     886              :     if( !m_isOpen )
     887              :     {
     888              :         errc = error_t::invalidconfig;
     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              : 
     914              : template <typename dataT, class verboseT>
     915              : error_t fitsFile<dataT, verboseT>::calcPixarrs( pixarrT &pixarr )
     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              : 
     991              : template <typename dataT, class verboseT>
     992              : error_t fitsFile<dataT, verboseT>::read( dataT *data )
     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              : 
    1026              : template <typename dataT, class verboseT>
    1027              : error_t fitsFile<dataT, verboseT>::read( dataT *data, fitsHeader<verboseT> &head )
    1028              : {
    1029              :     mxlib_error_check( read( data ) );
    1030              : 
    1031              :     mxlib_error_return( readHeader( head ) );
    1032              : }
    1033              : 
    1034              : template <typename dataT, class verboseT>
    1035              : error_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              : 
    1042              : template <typename dataT, class verboseT>
    1043              : error_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              : 
    1052              : template <typename dataT, class verboseT>
    1053              : error_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              : 
    1079              : template <typename dataT, class verboseT>
    1080              : error_t fitsFile<dataT, verboseT>::read( dataT *im,
    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              : 
    1115              : template <typename arrT, class verboseT, bool isCube = improc::is_eigenCube<arrT>::value>
    1116              : struct 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
    1130              :             return error_t::std_bad_alloc;
    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
    1140              :             return error_t::std_exception;
    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              : 
    1159              : template <typename arrT, class verboseT>
    1160              : struct eigenArrResize<arrT, verboseT, false>
    1161              : {
    1162              :     // If it's not a cube, never pass zsz
    1163            1 :     error_t resize( arrT &arr, int xsz, int ysz, [[maybe_unused]] int zsz )
    1164              :     {
    1165              :         try
    1166              :         {
    1167            1 :             arr.resize( xsz, ysz );
    1168              :         }
    1169            0 :         catch( const std::bad_alloc &e )
    1170              :         {
    1171            0 :             internal::mxlib_error_report<verboseT>( error_t::std_bad_alloc,
    1172            0 :                                                     std::string( "resizing array: " ) + e.what() );
    1173              : #ifdef MXLIB_TRAP_ALLOC_ERRORS
    1174              :             return error_t::std_bad_alloc;
    1175              : #else
    1176            0 :             throw;
    1177              : #endif
    1178              :         }
    1179            0 :         catch( const std::exception &e )
    1180              :         {
    1181            0 :             internal::mxlib_error_report<verboseT>( error_t::std_exception,
    1182            0 :                                                     std::string( "resizing array: " ) + e.what() );
    1183              : #ifdef MXLIB_TRAP_ALLOC_ERRORS
    1184              :             return error_t::std_exception;
    1185              : #else
    1186            0 :             throw;
    1187              : #endif
    1188              :         }
    1189            0 :         catch( ... )
    1190              :         {
    1191            0 :             internal::mxlib_error_report<verboseT>( error_t::exception, "resizing array" );
    1192              : #ifdef MXLIB_TRAP_ALLOC_ERRORS
    1193              :             return error_t::exception;
    1194              : #else
    1195            0 :             throw;
    1196              : #endif
    1197              :         }
    1198              : 
    1199            1 :         return error_t::noerror;
    1200              :     }
    1201              : };
    1202              : 
    1203              : template <typename dataT, class verboseT>
    1204              : template <typename arrT>
    1205            1 : error_t fitsFile<dataT, verboseT>::read( arrT &im )
    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            1 :     int fstatus = 0;
    1210              : 
    1211            1 :     if( !m_isOpen )
    1212              :     {
    1213            0 :         mxlib_error_check( open() );
    1214              :     }
    1215              : 
    1216            1 :     pixarrT pixarrs;
    1217            1 :     mxlib_error_check( calcPixarrs( pixarrs ) );
    1218              : 
    1219              :     eigenArrResize<arrT, verboseT> arrresz;
    1220            1 :     if( m_naxis > 2 )
    1221              :     {
    1222            0 :         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            1 :     else if( m_naxis > 1 )
    1228              :     {
    1229            1 :         mxlib_error_check(
    1230              :             arrresz.resize( im, pixarrs.lpix[0] - pixarrs.fpix[0] + 1, pixarrs.lpix[1] - pixarrs.fpix[1] + 1, 1 ) );
    1231              :     }
    1232              :     else
    1233              :     {
    1234            0 :         mxlib_error_check( arrresz.resize( im, pixarrs.lpix[0] - pixarrs.fpix[0] + 1, 1, 1 ) );
    1235              :     }
    1236              : 
    1237            1 :     fits_read_subset( m_fptr,
    1238              :                       fitsType<typename arrT::Scalar>(),
    1239              :                       pixarrs.fpix,
    1240              :                       pixarrs.lpix,
    1241              :                       pixarrs.inc,
    1242            1 :                       (void *)&m_nulval,
    1243            1 :                       (void *)im.data(),
    1244              :                       &m_anynul,
    1245              :                       &fstatus );
    1246              : 
    1247            1 :     if( fstatus && fstatus != END_OF_FILE )
    1248              :     {
    1249            0 :         return internal::mxlib_error_report<verboseT>( fits_status2error_t( fstatus ),
    1250            0 :                                                        "Reading data from " + m_fileName );
    1251              :     }
    1252              : 
    1253            1 :     return error_t::noerror;
    1254            1 : }
    1255              : 
    1256              : template <typename dataT, class verboseT>
    1257              : template <typename arrT>
    1258              : error_t fitsFile<dataT, verboseT>::read( arrT &data, fitsHeader<verboseT> &head )
    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              : 
    1276              : template <typename dataT, class verboseT>
    1277              : template <typename arrT>
    1278              : error_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              : 
    1295              : template <typename dataT, class verboseT>
    1296              : template <typename arrT>
    1297            1 : error_t fitsFile<dataT, verboseT>::read( arrT &data, fitsHeader<verboseT> &head, const std::string &fname )
    1298              : {
    1299              :     error_t errc;
    1300            1 :     errc = fileName( fname );
    1301            1 :     if( errc != error_t::noerror )
    1302              :     {
    1303            0 :         return internal::mxlib_error_report<verboseT>( errc );
    1304              :     }
    1305              : 
    1306            1 :     errc = read( data );
    1307            1 :     if( errc != error_t::noerror )
    1308              :     {
    1309            0 :         return internal::mxlib_error_report<verboseT>( errc );
    1310              :     }
    1311              : 
    1312            1 :     errc = readHeader( head );
    1313            1 :     if( errc != error_t::noerror )
    1314              :     {
    1315            0 :         return internal::mxlib_error_report<verboseT>( errc );
    1316              :     }
    1317              : 
    1318            1 :     return error_t::noerror;
    1319              : }
    1320              : 
    1321              : template <typename dataT, class verboseT>
    1322              : template <typename cubeT>
    1323            1 : error_t fitsFile<dataT, verboseT>::read( cubeT &cube,
    1324              :                                          const std::vector<std::string> &flist,
    1325              :                                          std::vector<fitsHeader<verboseT>> *heads )
    1326              : {
    1327              :     error_t errc;
    1328            1 :     int fstatus = 0;
    1329              : 
    1330            1 :     if( flist.size() == 0 )
    1331              :     {
    1332            0 :         return internal::mxlib_error_report<verboseT>( error_t::invalidarg, "Empty file list" );
    1333              :     }
    1334              : 
    1335              :     // Open the first file to get the dimensions.
    1336            1 :     errc = fileName( flist[0], 1 );
    1337            1 :     if( !!errc )
    1338              :     {
    1339            0 :         return internal::mxlib_error_report<verboseT>( errc );
    1340              :     }
    1341              : 
    1342            1 :     pixarrT pixarrs;
    1343            1 :     errc = calcPixarrs( pixarrs );
    1344              : 
    1345            1 :     if(!!errc)
    1346              :     {
    1347            0 :         return internal::mxlib_error_report<verboseT>( errc );
    1348              :     }
    1349              : 
    1350            1 :     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            1 :     fits_read_subset( m_fptr,
    1354              :                       fitsType<typename cubeT::Scalar>(),
    1355              :                       pixarrs.fpix,
    1356              :                       pixarrs.lpix,
    1357              :                       pixarrs.inc,
    1358            1 :                       (void *)&m_nulval,
    1359            1 :                       (void *)cube.image( 0 ).data(),
    1360              :                       &m_anynul,
    1361              :                       &fstatus );
    1362              : 
    1363            1 :     if( fstatus && fstatus != END_OF_FILE )
    1364              :     {
    1365            0 :         return internal::mxlib_error_report<verboseT>( fits_status2error_t( fstatus ),
    1366            0 :                                                        "Reading data from " + m_fileName );
    1367              :     }
    1368              : 
    1369            1 :     if( heads )
    1370              :     {
    1371            0 :         errc = readHeader( ( *heads )[0] );
    1372            0 :         if( errc != error_t::noerror )
    1373              :         {
    1374            0 :             return internal::mxlib_error_report<verboseT>( errc );
    1375              :         }
    1376              :     }
    1377              : 
    1378              :     // Now read in the rest.
    1379            5 :     for( int i = 1; i < flist.size(); ++i )
    1380              :     {
    1381            4 :         errc = fileName( flist[i], 1 );
    1382            4 :         if( errc != error_t::noerror )
    1383              :         {
    1384            0 :             return internal::mxlib_error_report<verboseT>( errc );
    1385              :         }
    1386              : 
    1387              :         // Now read image.
    1388            4 :         fits_read_subset( m_fptr,
    1389              :                           fitsType<typename cubeT::Scalar>(),
    1390              :                           pixarrs.fpix,
    1391              :                           pixarrs.lpix,
    1392              :                           pixarrs.inc,
    1393            4 :                           (void *)&m_nulval,
    1394            4 :                           (void *)cube.image( i ).data(),
    1395              :                           &m_anynul,
    1396              :                           &fstatus );
    1397              : 
    1398            4 :         if( fstatus && fstatus != END_OF_FILE )
    1399              :         {
    1400            0 :             return internal::mxlib_error_report<verboseT>( fits_status2error_t( fstatus ),
    1401            0 :                                                            "Reading data from " + m_fileName );
    1402              :         }
    1403              : 
    1404            4 :         if( heads )
    1405              :         {
    1406            0 :             errc = readHeader( ( *heads )[i] );
    1407            0 :             if( errc != error_t::noerror )
    1408              :             {
    1409            0 :                 return internal::mxlib_error_report<verboseT>( errc );
    1410              :             }
    1411              :         }
    1412              :     }
    1413              : 
    1414            1 :     return error_t::noerror;
    1415            1 : }
    1416              : 
    1417              : template <typename dataT, class verboseT>
    1418              : template <typename cubeT>
    1419              : error_t fitsFile<dataT, verboseT>::read( cubeT &cube,
    1420              :                                          std::vector<fitsHeader<verboseT>> &heads,
    1421              :                                          const std::vector<std::string> &flist )
    1422              : {
    1423              :     mxlib_error_return( read( cube, flist, &heads ) );
    1424              : }
    1425              : 
    1426              : template <typename dataT, class verboseT>
    1427              : error_t fitsFile<dataT, verboseT>::readHeader( fitsHeader<verboseT> &head )
    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              : 
    1552              : template <typename dataT, class verboseT>
    1553              : error_t fitsFile<dataT, verboseT>::readHeader( fitsHeader<verboseT> &head, const std::string &fname )
    1554              : {
    1555              :     error_t errc;
    1556              :     mxlib_error_check( fileName( fname ) );
    1557              :     mxlib_error_check( readHeader( head ) );
    1558              :     return error_t::noerror;
    1559              : }
    1560              : 
    1561              : template <typename dataT, class verboseT>
    1562              : error_t fitsFile<dataT, verboseT>::readHeader( std::vector<fitsHeader<verboseT>> &heads,
    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              : 
    1586              : template <typename dataT, class verboseT>
    1587              : error_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              : 
    1679              : template <typename dataT, class verboseT>
    1680              : error_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              : 
    1685              : template <typename dataT, class verboseT>
    1686              : error_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              : 
    1691              : template <typename dataT, class verboseT>
    1692              : error_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              : 
    1699              : template <typename dataT, class verboseT>
    1700              : error_t fitsFile<dataT, verboseT>::write(
    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              : 
    1708              : template <typename dataT, class verboseT>
    1709              : template <typename arrT>
    1710              : error_t fitsFile<dataT, verboseT>::write( const std::string &fname, const arrT &im )
    1711              : {
    1712              :     improc::eigenArrPlanes<arrT> planes;
    1713              : 
    1714              :     mxlib_error_return( write( fname, im.data(), im.rows(), im.cols(), planes( im ) ) );
    1715              : }
    1716              : 
    1717              : template <typename dataT, class verboseT>
    1718              : template <typename arrT>
    1719           18 : error_t fitsFile<dataT, verboseT>::write( const std::string &fname, const arrT &im, fitsHeader<verboseT> &head )
    1720              : {
    1721              :     improc::eigenArrPlanes<arrT> planes;
    1722              : 
    1723           36 :     return write( fname, im.data(), im.rows(), im.cols(), planes( im ), head );
    1724              : }
    1725              : 
    1726              : template <typename dataT, class verboseT>
    1727              : void fitsFile<dataT, verboseT>::setReadSize()
    1728              : {
    1729              :     m_x0 = -1;
    1730              :     m_y0 = -1;
    1731              :     m_xpix = -1;
    1732              :     m_ypix = -1;
    1733              : }
    1734              : 
    1735              : template <typename dataT, class verboseT>
    1736              : void 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              : 
    1744              : template <typename dataT, class verboseT>
    1745              : void fitsFile<dataT, verboseT>::setCubeReadSize()
    1746              : {
    1747              :     m_z0 = -1;
    1748              :     m_zframes = -1;
    1749              : }
    1750              : 
    1751              : template <typename dataT, class verboseT>
    1752              : void fitsFile<dataT, verboseT>::setCubeReadSize( long z0, long zframes )
    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
    1763              : typedef fitsFile<char> fitsFilec;
    1764              : 
    1765              : /// A \ref fitsFile to work in unsigned characters
    1766              : typedef fitsFile<unsigned char> fitsFileuc;
    1767              : 
    1768              : /// A \ref fitsFile to work in signed short integers
    1769              : typedef fitsFile<short> fitsFiles;
    1770              : 
    1771              : /// A \ref fitsFile to work in unsigned short integers
    1772              : typedef fitsFile<unsigned short> fitsFileus;
    1773              : 
    1774              : /// A \ref fitsFile to work in signed integers
    1775              : typedef fitsFile<int> fitsFilei;
    1776              : 
    1777              : /// A \ref fitsFile to work in unsigned integers
    1778              : typedef fitsFile<unsigned int> fitsFileui;
    1779              : 
    1780              : /// A \ref fitsFile to work in signed long integers
    1781              : typedef fitsFile<long> fitsFilel;
    1782              : 
    1783              : /// A \ref fitsFile to work in single precision floats
    1784              : typedef fitsFile<float> fitsFilef;
    1785              : 
    1786              : /// A \ref fitsFile to work in double precision
    1787              : typedef fitsFile<double> fitsFiled;
    1788              : 
    1789              : ///@}
    1790              : 
    1791              : extern template class fitsFile<short, verbose::d>;
    1792              : extern template class fitsFile<unsigned short, verbose::d>;
    1793              : extern template class fitsFile<int, verbose::d>;
    1794              : extern template class fitsFile<unsigned int, verbose::d>;
    1795              : extern template class fitsFile<float, verbose::d>;
    1796              : extern template class fitsFile<double, verbose::d>;
    1797              : 
    1798              : } // namespace fits
    1799              : } // namespace mx
    1800              : 
    1801              : #endif // ioutils_fits_fitsFile_hpp
        

Generated by: LCOV version 2.0-1