diff --git a/inst/cta/src/GCTAAeff2D.cpp b/inst/cta/src/GCTAAeff2D.cpp index 11544f2..25e9bf9 100644 --- a/inst/cta/src/GCTAAeff2D.cpp +++ b/inst/cta/src/GCTAAeff2D.cpp @@ -395,8 +395,9 @@ void GCTAAeff2D::save(const GFilename& filename, const bool& clobber) const // Get extension name std::string extname = filename.extname("EFFECTIVE AREA"); - // Open or create FITS file (without extension) - GFits fits(filename, true); + // Open or create FITS file (without extension name since the requested + // extension may not yet exist in the file) + GFits fits(filename.url(), true); // Remove extension if it exists already if (fits.contains(extname)) { diff --git a/inst/cta/src/GCTABackground3D.cpp b/inst/cta/src/GCTABackground3D.cpp index 0626720..c376003 100644 --- a/inst/cta/src/GCTABackground3D.cpp +++ b/inst/cta/src/GCTABackground3D.cpp @@ -448,8 +448,9 @@ void GCTABackground3D::save(const GFilename& filename, const bool& clobber) cons // Get extension name std::string extname = filename.extname("BACKGROUND"); - // Open or create FITS file - GFits fits(filename, true); + // Open or create FITS file (without extension name since the requested + // extension may not yet exist in the file) + GFits fits(filename.url(), true); // Remove extension if it exists already if (fits.contains(extname)) { diff --git a/inst/cta/src/GCTAEdisp2D.cpp b/inst/cta/src/GCTAEdisp2D.cpp index 9c47b5d..7b1eeeb 100644 --- a/inst/cta/src/GCTAEdisp2D.cpp +++ b/inst/cta/src/GCTAEdisp2D.cpp @@ -461,8 +461,9 @@ void GCTAEdisp2D::save(const GFilename& filename, const bool& clobber) const // Get extension name std::string extname = filename.extname("ENERGY DISPERSION"); - // Open or create FITS file - GFits fits(filename, true); + // Open or create FITS file (without extension name since the requested + // extension may not yet exist in the file) + GFits fits(filename.url(), true); // Remove extension if it exists already if (fits.contains(extname)) { diff --git a/inst/cta/src/GCTAEventList.cpp b/inst/cta/src/GCTAEventList.cpp index 1a87748..363af53 100644 --- a/inst/cta/src/GCTAEventList.cpp +++ b/inst/cta/src/GCTAEventList.cpp @@ -303,8 +303,9 @@ void GCTAEventList::load(const GFilename& filename) void GCTAEventList::save(const GFilename& filename, const bool& clobber) const { - // Open or create FITS file - GFits fits(filename, true); + // Open or create FITS file (without extension name since the requested + // extension may not yet exist in the file) + GFits fits(filename.url(), true); // Write event list write(fits); diff --git a/inst/cta/src/GCTAPsf2D.cpp b/inst/cta/src/GCTAPsf2D.cpp index 0eaba82..6340af0 100644 --- a/inst/cta/src/GCTAPsf2D.cpp +++ b/inst/cta/src/GCTAPsf2D.cpp @@ -425,8 +425,9 @@ void GCTAPsf2D::save(const GFilename& filename, const bool& clobber) const // Get extension name std::string extname = filename.extname("POINT SPREAD FUNCTION"); - // Open or create FITS file - GFits fits(filename, true); + // Open or create FITS file (without extension name since the requested + // extension may not yet exist in the file) + GFits fits(filename.url(), true); // Remove extension if it exists already if (fits.contains(extname)) { diff --git a/inst/cta/src/GCTAPsfKing.cpp b/inst/cta/src/GCTAPsfKing.cpp index b32b1ef..9ff5872 100644 --- a/inst/cta/src/GCTAPsfKing.cpp +++ b/inst/cta/src/GCTAPsfKing.cpp @@ -423,8 +423,9 @@ void GCTAPsfKing::save(const GFilename& filename, const bool& clobber) const // Get extension name std::string extname = filename.extname("POINT SPREAD FUNCTION"); - // Open or create FITS file - GFits fits(filename, true); + // Open or create FITS file (without extension name since the requested + // extension may not yet exist in the file) + GFits fits(filename.url(), true); // Remove extension if it exists already if (fits.contains(extname)) { diff --git a/src/obs/GEbounds.cpp b/src/obs/GEbounds.cpp index 6028a36..c9601b2 100644 --- a/src/obs/GEbounds.cpp +++ b/src/obs/GEbounds.cpp @@ -599,31 +599,37 @@ void GEbounds::load(const GFilename& filename) * @brief Save energy boundaries into FITS file * * @param[in] filename FITS file name. - * @param[in] clobber Overwrite any existing file (default: false)? - * @param[in] unit Energy units (default: "keV") + * @param[in] clobber Overwrite an existing energy boundaries extension? + * @param[in] unit Energy unit * * Saves energy boundaries into a FITS file. If a file with the given * @p filename does not yet exist it will be created, otherwise the method - * opens the existing file. The method will create (or replace an existing) - * energy boundaries extension. The extension name can be specified as part - * of the @p filename, or if no extension name is given, is assumed to be - * "EBOUNDS". + * opens the existing file. Energy boundaries can only be appended to an + * existing file if the @p clobber flag is set to `true` (otherwise an + * exception is thrown). * - * An existing file will only be modified if the @p clobber flag is set to - * true. + * The method will append a binary FITS table containing the energy + * boundaries to the FITS file. The extension name can be specified as part + * of the @p filename. For example the @p filename + * + * myfile.fits[ENERGY BOUNDARIES] + * + * will save the energy boundaries in the `ENERGY BOUNDARIES` extension of + * the `myfile.fits` file. If the extension exists already in the file it + * will be replaced, otherwise a new extension will be created. If no + * extension name is provided, the method will use `EBOUNDS` as the default + * extension name for energy boundaries. ***************************************************************************/ void GEbounds::save(const GFilename& filename, const bool& clobber, const std::string& unit) const { - // Get extension name - std::string extname = filename.extname("EBOUNDS"); - - // Open or create FITS file - GFits fits(filename, true); + // Open or create FITS file (without extension name since the requested + // extension may not yet exist in the file) + GFits fits(filename.url(), true); // Write energy boundaries to FITS file - write(fits, extname, unit); + write(fits, filename.extname("EBOUNDS"), unit); // Save to file fits.save(clobber); diff --git a/src/obs/GEnergies.cpp b/src/obs/GEnergies.cpp index 8d0251d..fe6b7a4 100644 --- a/src/obs/GEnergies.cpp +++ b/src/obs/GEnergies.cpp @@ -565,30 +565,36 @@ void GEnergies::load(const GFilename& filename) /***********************************************************************//** - * @brief Save energies to FITS file + * @brief Save energies into FITS file * * @param[in] filename FITS filename. - * @param[in] clobber Overwrite any existing energies extension? + * @param[in] clobber Overwrite an existing energies extension? * - * Saves energiesinto a FITS file. If a file with the given @p filename does - * not yet exist it will be created, otherwise the method opens the existing - * file. The method will create (or replace an existing) energies extension. - * The extension name can be specified as part of the @p filename, or if no - * extension name is given, is assumed to be "ENERGIES". + * Saves energies into a FITS file. If a file with the given @p filename + * does not yet exist it will be created, otherwise the method opens the + * existing file. Energies can only be appended to an existing file if the + * @p clobber flag is set to `true` (otherwise an exception is thrown). * - * An existing file will only be modified if the @p clobber flag is set to - * true. + * The method will append a binary FITS table containing the energies to the + * FITS file. The extension name can be specified as part of the + * @p filename. For example the @p filename + * + * myfile.fits[ENERGY VALUES] + * + * will save the energies in the `ENERGY VALUES` extension of the + * `myfile.fits` file. If the extension exists already in the file it will be + * replaced, otherwise a new extension will be created. If no extension name + * is provided, the method will use `ENERGIES` as the default extension name + * for energies. ***************************************************************************/ void GEnergies::save(const GFilename& filename, const bool& clobber) const { - // Get extension name - std::string extname = filename.extname("ENERGIES"); - - // Open or create FITS file - GFits fits(filename, true); + // Open or create FITS file (without extension name since the requested + // extension may not yet exist in the file) + GFits fits(filename.url(), true); // Write energies to FITS file - write(fits, extname); + write(fits, filename.extname("ENERGIES")); // Save to file fits.save(clobber); diff --git a/src/obs/GGti.cpp b/src/obs/GGti.cpp index b4ee105..6a31c38 100644 --- a/src/obs/GGti.cpp +++ b/src/obs/GGti.cpp @@ -602,31 +602,37 @@ void GGti::load(const GFilename& filename) /***********************************************************************//** - * @brief Save Good Time Intervals intervals to FITS file + * @brief Save Good Time Intervals into FITS file * * @param[in] filename FITS filename. - * @param[in] clobber Modify any existing FITS file? (default: false) + * @param[in] clobber Overwrite an existing Good Time Interval extension? * * Saves Good Time Intervals into a FITS file. If a file with the given * @p filename does not yet exist it will be created, otherwise the method - * opens the existing file. The method will create (or replace an existing) - * Good Time Interval extension. The extension name can be specified as part - * of the @p filename, or if no extension name is given, is assumed to be - * "GTI". + * opens the existing file. Good Time Intervals can only be appended to an + * existing file if the @p clobber flag is set to `true` (otherwise an + * exception is thrown). * - * An existing file will only be modified if the @p clobber flag is set to - * true. + * The method will append a binary FITS table containing the Good Time + * Intervals to the FITS file. The extension name can be specified as part + * of the @p filename. For example the @p filename + * + * myfile.fits[GOOD TIME INTERVALS] + * + * will save the Good Time Intervals in the `GOOD TIME INTERVALS` extension + * of the `myfile.fits` file. If the extension exists already in the file it + * will be replaced, otherwise a new extension will be created. If no + * extension name is provided, the method will use `GTI` as the default + * extension name for Good Time Intervals. ***************************************************************************/ void GGti::save(const GFilename& filename, const bool& clobber) const { - // Get extension name - std::string extname = filename.extname("GTI"); - - // Open or create FITS file - GFits fits(filename, true); + // Open or create FITS file (without extension name since the requested + // extension may not yet exist in the file) + GFits fits(filename.url(), true); // Write GTI to FITS object - write(fits, extname); + write(fits, filename.extname("GTI")); // Save to file fits.save(clobber); diff --git a/src/support/GNodeArray.cpp b/src/support/GNodeArray.cpp index 0905ad0..8f9641a 100644 --- a/src/support/GNodeArray.cpp +++ b/src/support/GNodeArray.cpp @@ -721,26 +721,35 @@ void GNodeArray::load(const GFilename& filename) /***********************************************************************//** - * @brief Save nodes to FITS file + * @brief Save node array into FITS file * * @param[in] filename FITS filename. - * @param[in] clobber Overwrite any existing nodes extension? (default: false) + * @param[in] clobber Overwrite an existing node array extension? * * Saves node array into a FITS file. If a file with the given @p filename * does not yet exist it will be created, otherwise the method opens the - * existing file. The method will create (or replace an existing) node array - * extension. The extension name can be specified as part of the @p filename, - * or if no extension name is given, is assumed to be "NODES". + * existing file. Node arrays can only be appended to an existing file if the + * @p clobber flag is set to `true` (otherwise an exception is thrown). * - * An existing file will only be modified if the @p clobber flag is set to - * true. + * The method will append a binary FITS table containing the node array to + * the FITS file. The extension name can be specified as part of the + * @p filename. For example the @p filename + * + * myfile.fits[NODE ARRAY] + * + * will save the node array in the `NODE ARRAY` extension of the + * `myfile.fits` file. If the extension exists already in the file it will be + * replaced, otherwise a new extension will be created. If no extension name + * is provided, the method will use `NODES` as the default extension name + * for the node array. ***************************************************************************/ void GNodeArray::save(const GFilename& filename, const bool& clobber) const { - // Open or create FITS file - GFits fits(filename, true); + // Open or create FITS file (without extension name since the requested + // extension may not yet exist in the file) + GFits fits(filename.url(), true); - // Write GTI to FITS object + // Write node array to FITS object write(fits, filename.extname("NODES")); // Save to file diff --git a/src/xspec/GArf.cpp b/src/xspec/GArf.cpp index d63f52e..3ba40e2 100644 --- a/src/xspec/GArf.cpp +++ b/src/xspec/GArf.cpp @@ -252,11 +252,18 @@ const double& GArf::at(const int& index) const * @brief Load Auxiliary Response File * * @param[in] filename File name. + * + * Loads the Auxiliary Response File from the `SPECRESP` extension of the + * FITS file. ***************************************************************************/ void GArf::load(const GFilename& filename) { - // Open FITS file - GFits fits(filename); + // Clear response + clear(); + + // Open FITS file (without extension name as the user is not allowed + // to modify the extension names) + GFits fits(filename.url()); // Get ARF table const GFitsTable& table = *fits.table("SPECRESP"); @@ -268,7 +275,7 @@ void GArf::load(const GFilename& filename) fits.close(); // Store filename - m_filename = filename; + m_filename = filename.url(); // Return return; @@ -279,21 +286,30 @@ void GArf::load(const GFilename& filename) * @brief Save Auxiliary Response File * * @param[in] filename File name. - * @param[in] clobber Overwrite existing file? (defaults: false) + * @param[in] clobber Overwrite existing file? + * + * Saves the Auxiliary Response File into a FITS file. If a file with the + * given @p filename does not yet exist it will be created. If the file + * exists it can be overwritten if the @p clobber flag is set to `true`. + * Otherwise an exception is thrown. + * + * The method will save the `SPECRESP` binary FITS table into the FITS file + * that contains the values of the Auxiliary Response File. ***************************************************************************/ void GArf::save(const GFilename& filename, const bool& clobber) const { - // Open FITS file + // Create FITS file GFits fits; // Write ARF into file write(fits); - // Close FITS file - fits.saveto(filename, clobber); + // Save to file (without extension name since the requested extension + // may not yet exist in the file) + fits.saveto(filename.url(), clobber); // Store filename - m_filename = filename; + m_filename = filename.url(); // Return return; @@ -304,6 +320,19 @@ void GArf::save(const GFilename& filename, const bool& clobber) const * @brief Read Auxiliary Response File * * @param[in] table ARF FITS table. + * + * Reads the Auxiliary Response File from a FITS table. The true energy + * boundaries are expected in the `ENERG_LO` and `ENERG_HI` columns, the + * response information is expected in the `SPECRESP` column. + * + * The method will analyze the unit of the `SPECRESP` column, and if either + * `m^2` or `m2` are encountered, multiply the values of the column by + * \f$10^4\f$ to convert the response into units of \f$cm^2\f$. Units of the + * `ENERG_LO` and `ENERG_HI` columns are also interpreted for conversion. + * + * See + * http://heasarc.gsfc.nasa.gov/docs/heasarc/caldb/docs/memos/cal_gen_92_002/cal_gen_92_002.html#tth_sEc4 + * for details about the Auxiliary Response File format. ***************************************************************************/ void GArf::read(const GFitsTable& table) { @@ -349,6 +378,18 @@ void GArf::read(const GFitsTable& table) * @brief Write Auxiliary Response File * * @param[in] fits FITS file. + * + * Writes the Auxiliary Response File into the `SPECRESP` extension of the + * FITS file. An existing extension with the same name will be removed from + * the FITS file before writing. + * + * The method writes the boundaries of the true energy bins into the + * `ENERG_LO` and `ENERG_HI` columns, response information will be written + * into the `SPECRESP` column. + * + * See + * http://heasarc.gsfc.nasa.gov/docs/heasarc/caldb/docs/memos/cal_gen_92_002/cal_gen_92_002.html#tth_sEc4 + * for details about the Auxiliary Response File format. ***************************************************************************/ void GArf::write(GFits& fits) const { @@ -405,7 +446,7 @@ void GArf::write(GFits& fits) const /***********************************************************************//** * @brief Print Auxiliary Response File * - * @param[in] chatter Chattiness (defaults to NORMAL). + * @param[in] chatter Chattiness. * @return String containing Auxiliary Response File information. ***************************************************************************/ std::string GArf::print(const GChatter& chatter) const diff --git a/src/xspec/GPha.cpp b/src/xspec/GPha.cpp index 93d7ff1..abcf660 100644 --- a/src/xspec/GPha.cpp +++ b/src/xspec/GPha.cpp @@ -330,16 +330,18 @@ void GPha::fill(const GEnergy& energy, const double& value) * * @param[in] filename File name. * - * Loads the Pulse Height Analyzer spectrum from a FITS file. If an EBOUNDS - * extension is given, the energy boundaries information is also loaded + * Loads the Pulse Height Analyzer spectrum from the `SPECTRUM` extension + * of the FITS file. If the file contains also an `EBOUNDS` extension the + * energy boundaries of all Pulse Height Analyzer channels are also loaded. ***************************************************************************/ void GPha::load(const GFilename& filename) { - // Clear any existing models + // Clear spectrum clear(); - // Open FITS file - GFits fits(filename); + // Open FITS file (without extension name as the user is not allowed + // to modify the extension names) + GFits fits(filename.url()); // Get PHA table const GFitsTable& pha = *fits.table("SPECTRUM"); @@ -362,7 +364,7 @@ void GPha::load(const GFilename& filename) fits.close(); // Store filename - m_filename = filename; + m_filename = filename.url(); // Return return; @@ -373,30 +375,32 @@ void GPha::load(const GFilename& filename) * @brief Save Pulse Height Analyzer spectrum * * @param[in] filename File name. - * @param[in] clobber Overwrite existing file? (default: false) + * @param[in] clobber Overwrite existing file? * - * Saves Pulse Height Analyzer spectrum and energy boundaries into a FITS - * file. If a file with the given @p filename does not yet exist it will be - * created, otherwise the method opens the existing file. The method will - * create (or replace an existing) Pulse Height Analyzer spectrum and energy - * boundary extensions. + * Saves the Pulse Height Analyzer spectrum and energy boundaries into a + * FITS file. If a file with the given @p filename does not yet exist it + * will be created. If the file exists it can be overwritten if the + * @p clobber flag is set to `true`. Otherwise an exception is thrown. * - * An existing file will only be modified if the @p clobber flag is set to - * true. + * The method will save two binary FITS tables into the FITS file: a + * `SPECTRUM` extension that contains the channel values of the Pulse + * Height Analyzer spectrum and an `EBOUNDS` extension that contains the + * energy boundaries for all channels. ***************************************************************************/ void GPha::save(const GFilename& filename, const bool& clobber) const { - // Open or create FITS file - GFits fits(filename, true); + // Create FITS file + GFits fits; // Write PHA into file write(fits); - // Close FITS file - fits.save(clobber); + // Save to file (without extension name since the requested extension + // may not yet exist in the file) + fits.saveto(filename.url(), clobber); // Store filename - m_filename = filename; + m_filename = filename.url(); // Return return; @@ -406,10 +410,18 @@ void GPha::save(const GFilename& filename, const bool& clobber) const /***********************************************************************//** * @brief Read Pulse Height Analyzer spectrum * - * @param[in] table PHA FITS table. + * @param[in] table FITS table. * * @exception GException::invalid_value * Mismatch between PHA file and energy boundaries. + * + * Reads the Pulse Height Analyzer spectrum from a FITS table. The channel + * values are expected in the `COUNTS` column of the table. All other + * columns are ignored. + * + * See + * https://heasarc.gsfc.nasa.gov/docs/heasarc/ofwg/docs/spectra/ogip_92_007/node5.html + * for details about the Pulse Height Analyzer spectrum format. ***************************************************************************/ void GPha::read(const GFitsTable& table) { @@ -417,17 +429,16 @@ void GPha::read(const GFitsTable& table) const GFitsTableCol* col_data = table["COUNTS"]; // Extract number of channels in FITS file - int length = table.integer("NAXIS2"); + int length = col_data->length(); - // Check whether column length is okay + // Check whether column length is consistent with energy boundaries if (m_ebounds.size() > 0) { if (m_ebounds.size() != length) { - std::string msg = "Number of channels in PHA file (" - ""+gammalib::str(length)+") mismatches the" - " number of energy boundaries (" - ""+gammalib::str(m_ebounds.size())+") that" - " are defined in the GPha instance.\n" - "Please define the correct energy boundaries."; + std::string msg = "Mismatch between the "+gammalib::str(length)+ + " channels in the PHA file and the "+ + gammalib::str(m_ebounds.size())+" energy " + "boundaries. Please correct either the energy " + "boundaris or the PHA file."; throw GException::invalid_value(G_READ, msg); } } @@ -449,6 +460,20 @@ void GPha::read(const GFitsTable& table) * @brief Write Pulse Height Analyzer spectrum * * @param[in] fits FITS file. + * + * Writes the Pulse Height Analyzer spectrum into `SPECTRUM` and `EBOUNDS` + * extensions of the FITS file. Extensions with these names will be removed + * from the FITS file before writing. + * + * The columns `CHANNEL`, `COUNTS`, `STAT_ERR`, `SYS_ERR`, `QUALITY`, + * `GROUPING`, `AREASCAL`, and `BACKSCAL` will be written into the `SPECTRUM` + * extension, but only the `CHANNEL` and `COUNTS` columns will be filled with + * values. Note that the channels start from 1 in the Pulse Height Analyzer + * spectrum. + * + * See + * https://heasarc.gsfc.nasa.gov/docs/heasarc/ofwg/docs/spectra/ogip_92_007/node5.html + * for details about the PHA file format. ***************************************************************************/ void GPha::write(GFits& fits) const { @@ -516,7 +541,7 @@ void GPha::write(GFits& fits) const /***********************************************************************//** * @brief Print Pulse Height Analyzer spectrum * - * @param[in] chatter Chattiness (defaults to NORMAL). + * @param[in] chatter Chattiness. * @return String containing Pulse Height Analyzer spectrum information. ***************************************************************************/ std::string GPha::print(const GChatter& chatter) const diff --git a/src/xspec/GRmf.cpp b/src/xspec/GRmf.cpp index 0bcf91d..3efa0c3 100644 --- a/src/xspec/GRmf.cpp +++ b/src/xspec/GRmf.cpp @@ -369,20 +369,25 @@ GEbounds GRmf::emeasured(const GEnergy& etrue) const * @brief Load Redistribution Matrix File * * @param[in] filename File name. + * + * Loads the Redistribution Matrix File from the `MATRIX` extension of the + * FITS file. If the file contains also an `EBOUNDS` extension the energy + * boundaries of all measured energies are also loaded. ***************************************************************************/ void GRmf::load(const GFilename& filename) { - // Clear any existing models + // Clear matrix clear(); - // Open FITS file - GFits fits(filename); + // Open FITS file (without extension name as the user is not allowed + // to modify the extension names) + GFits fits(filename.url()); // Read measured energy boundaries - m_ebds_measured.load(filename); + m_ebds_measured.load(filename.url()); // Get RMF table - const GFitsTable& table = *fits.table(filename.extname("MATRIX")); + const GFitsTable& table = *fits.table("MATRIX"); // Read RMF data read(table); @@ -391,7 +396,7 @@ void GRmf::load(const GFilename& filename) fits.close(); // Store filename - m_filename = filename; + m_filename = filename.url(); // Return return; @@ -402,24 +407,36 @@ void GRmf::load(const GFilename& filename) * @brief Save Redistribution Matrix File * * @param[in] filename File name. - * @param[in] clobber Overwrite existing file? (default: false) - * @param[in] unit Energy unit (default: "keV") + * @param[in] clobber Overwrite existing file? + * @param[in] unit Energy unit. + * + * Saves the Redistribution Matrix File into a FITS file. If a file with the + * given @p filename does not yet exist it will be created. If the file + * exists it can be overwritten if the @p clobber flag is set to `true`. + * Otherwise an exception is thrown. + * + * The method will save two binary FITS tables into the FITS file: a + * `MATRIX` extension that contains the Redistribution Matrix File elements, + * and an `EBOUNDS` extension that contains the measured energy boundaries + * for all matrix. The @p unit argument specifies the unit of the true + * energies that will be saved in the `MATRIX` extension. ***************************************************************************/ void GRmf::save(const GFilename& filename, const bool& clobber, const std::string& unit) const { - // Open or create FITS file - GFits fits(filename, true); + // Create FITS file + GFits fits; // Write RMF into file write(fits, unit); - // Save to file - fits.save(clobber); + // Save to file (without extension name since the requested extension + // may not yet exist in the file) + fits.saveto(filename.url(), clobber); // Store filename - m_filename = filename; + m_filename = filename.url(); // Return return; @@ -430,6 +447,18 @@ void GRmf::save(const GFilename& filename, * @brief Read Redistribution Matrix File * * @param[in] table RMF FITS table. + * + * Reads the Redistribution Matrix File from a FITS table. The true energy + * bins are expected in the `ENERG_LO` and `ENERG_HI` columns. Information + * for matrix compression are stored in the `N_GRP`, `F_CHAN` and `N_CHAN` + * columns, and the matrix elements are stored in the `MATRIX` column. + * + * The method automatically decompresses the Redistribution Matrix File and + * stores the matrix elements in a spare matrix. + * + * See + * http://heasarc.gsfc.nasa.gov/docs/heasarc/caldb/docs/memos/cal_gen_92_002/cal_gen_92_002.html#tth_sEc3 + * for details about the Redistribution Matrix File file format. ***************************************************************************/ void GRmf::read(const GFitsTable& table) { @@ -497,7 +526,23 @@ void GRmf::read(const GFitsTable& table) * @brief Write Redistribution Matrix File * * @param[in] fits FITS file. - * @param[in] unit Energy unit (defaults to "keV") + * @param[in] unit Energy unit. + * + * Writes the Redistribution Matrix File into `MATRIX` and `EBOUNDS` + * extensions of the FITS file. Extensions with these names will be removed + * from the FITS file before writing. + * + * The true energy bins are written into the `ENERG_LO` and `ENERG_HI` + * columns. The units of the energies in these columns is specified by the + * @p unit argument. Information for matrix compression are stored in the + * `N_GRP`, `F_CHAN` and `N_CHAN` columns, and the matrix elements are + * written into the `MATRIX` column. + * + * The measured energy bins are written into the `EBOUNDS` extension. + * + * See + * http://heasarc.gsfc.nasa.gov/docs/heasarc/caldb/docs/memos/cal_gen_92_002/cal_gen_92_002.html#tth_sEc3 + * for details about the Redistribution Matrix File file format. ***************************************************************************/ void GRmf::write(GFits& fits, const std::string& unit) const { @@ -629,7 +674,7 @@ void GRmf::write(GFits& fits, const std::string& unit) const /***********************************************************************//** * @brief Print Redistribution Matrix File * - * @param[in] chatter Chattiness (defaults to NORMAL). + * @param[in] chatter Chattiness. * @return String containing Redistribution Matrix File information. ***************************************************************************/ std::string GRmf::print(const GChatter& chatter) const diff --git a/test/test_GObservation.cpp b/test/test_GObservation.cpp index 930064c..fee1db3 100644 --- a/test/test_GObservation.cpp +++ b/test/test_GObservation.cpp @@ -252,6 +252,24 @@ void TestGObservation::test_ebounds(void) test_assert(!containment.contains(GEnergy(200.0, "MeV"), GEnergy(2000.0, "MeV")), "Energy bin [200,2000] MeV should not be contained."); test_assert(!containment.contains(GEnergy(80.0, "MeV"), GEnergy(2000.0, "MeV")), "Energy bin [80,2000] MeV should not be contained."); + // Remove test file + GFilename filename("test_ebounds.fits"); + filename.remove(); + + // Check saving + containment.save("test_ebounds.fits"); + GEbounds load1("test_ebounds.fits"); + test_value(load1.size(), 1, "GEbounds should have 1 element."); + test_value(load1.emin().MeV(), 100.0, 1.0e-10, "Minimum energy should be 100."); + test_value(load1.emax().MeV(), 1000.0, 1.0e-10, "Maximum energy should be 1000."); + + // Check saving in a different extnsion + ebds.save("test_ebounds.fits[ENERGY BOUNDARIES 2]", true); + GEbounds load2("test_ebounds.fits[ENERGY BOUNDARIES 2]"); + test_value(load2.size(), 1, "GEbounds should have 1 element."); + test_value(load2.emin().MeV(), 1.0, 1.0e-10, "Minimum energy should be 1."); + test_value(load2.emax().MeV(), 10.0, 1.0e-10, "Maximum energy should be 10."); + // Return return; } @@ -379,6 +397,12 @@ void TestGObservation::test_gti(void) test_value(gti.tstart().secs(), 1.0, 1.0e-7, "Start time should be 1."); test_value(gti.tstop().secs(), 1000.0, 1.0e-7, "Stop time should be 1000."); + // Remove test file + GFilename file1("test_gti1.fits"); + GFilename file2("test_gti2.fits"); + file1.remove(); + file2.remove(); + // Check saving in and loading from FITS file gti.save("test_gti1.fits", true); GGti test1("test_gti1.fits"); @@ -480,6 +504,24 @@ void TestGObservation::test_gti(void) test_value(test5.tstart().secs(), 1.0, 1.0e-7, "Start time should be 1."); test_value(test5.tstop().secs(), 10000.0, 1.0e-7, "Stop time should be 10000."); + // Remove test file + GFilename filename("test_gti.fits"); + filename.remove(); + + // Check saving + test4.save("test_gti.fits"); + GGti load1("test_gti.fits"); + test_value(load1.size(), 4, "GGti should have 4 intervals."); + test_value(load1.tstart().secs(), 1.0, 1.0e-7, "Start time should be 1."); + test_value(load1.tstop().secs(), 10000.0, 1.0e-7, "Stop time should be 10000."); + + // Check saving in a different extnsion + test3.save("test_gti.fits[GOOD TIME INTERVALS]", true); + GGti load2("test_gti.fits[GOOD TIME INTERVALS]"); + test_value(load2.size(), 1, "GGti should have 1 interval."); + test_value(load2.tstart().convert(GTimeReference(51544.5, "s")), 0.0, 1.0e-7, "Start time should be 0."); + test_value(load2.tstop().convert(GTimeReference(51544.5, "s")), 100.0, 1.0e-7, "Stop time should be 100."); + // Return return; } @@ -984,6 +1026,10 @@ void TestGObservation::test_energies(void) test_value(energies[i].MeV(), double(i)); } + // Remove test file + GFilename filename("test_energies.fits"); + filename.remove(); + // Save and reload energies test_try("Saving and loading"); try { @@ -1012,6 +1058,21 @@ void TestGObservation::test_energies(void) test_try_failure(e); } + // Save and reload energies in another extension + test_try("Saving and loading in another extension"); + try { + energies.save("test_energies.fits[NEW ENERGIES]", true); + energies.clear(); + energies.load("test_energies.fits[NEW ENERGIES]"); + test_try_success(); + } + catch (std::exception &e) { + test_try_failure(e); + } + for (int i = 0; i < 4; ++i) { + test_value(energies[i].MeV(), double(i)); + } + // Check linear energies energies.clear(); energies.set_lin(3, GEnergy(1.0, "MeV"), GEnergy(3.0, "MeV")); diff --git a/test/test_GSupport.cpp b/test/test_GSupport.cpp index 334e032..38f11a4 100644 --- a/test/test_GSupport.cpp +++ b/test/test_GSupport.cpp @@ -381,6 +381,30 @@ void TestGSupport::test_node_array(void) test_value(nodes.wgt_left(), 0.25, 1.0e-6, "Expected weight 0.25"); test_value(nodes.wgt_right(), 0.75, 1.0e-6, "Expected weight 0.75"); + // Remove test file + GFilename filename("test_nodes.fits"); + filename.remove(); + + // Check saving + nodes.save("test_nodes.fits"); + GNodeArray load1("test_nodes.fits"); + test_value(load1.size(), 3, "GNodeArray should have 3 nodes."); + test_value(load1[0], 1.0, 1.0e-7, "First node should be 1."); + test_value(load1[1], 3.0, 1.0e-7, "First node should be 3."); + test_value(load1[2], 4.0, 1.0e-7, "First node should be 4."); + + // Check saving in a different extnsion + nodes.append(10.0); + nodes.append(11.0); + nodes.save("test_nodes.fits[NODE ARRAY]", true); + GNodeArray load2("test_nodes.fits[NODE ARRAY]"); + test_value(load2.size(), 5, "GNodeArray should have 5 nodes."); + test_value(load2[0], 1.0, 1.0e-7, "First node should be 1."); + test_value(load2[1], 3.0, 1.0e-7, "First node should be 3."); + test_value(load2[2], 4.0, 1.0e-7, "First node should be 4."); + test_value(load2[3], 10.0, 1.0e-7, "First node should be 10."); + test_value(load2[4], 11.0, 1.0e-7, "First node should be 11."); + // Return return; }