Commit c93d18a699e0ced3c1e9cf6f0d43f88bf9d7b731
1 parent
9faf87f1
Correct handling of FITS extension names.
Showing
15 changed files
with
347 additions
and
118 deletions
inst/cta/src/GCTAAeff2D.cpp
| ... | ... | @@ -395,8 +395,9 @@ void GCTAAeff2D::save(const GFilename& filename, const bool& clobber) const |
| 395 | 395 | // Get extension name |
| 396 | 396 | std::string extname = filename.extname("EFFECTIVE AREA"); |
| 397 | 397 | |
| 398 | - // Open or create FITS file (without extension) | |
| 399 | - GFits fits(filename, true); | |
| 398 | + // Open or create FITS file (without extension name since the requested | |
| 399 | + // extension may not yet exist in the file) | |
| 400 | + GFits fits(filename.url(), true); | |
| 400 | 401 | |
| 401 | 402 | // Remove extension if it exists already |
| 402 | 403 | if (fits.contains(extname)) { | ... | ... |
inst/cta/src/GCTABackground3D.cpp
| ... | ... | @@ -448,8 +448,9 @@ void GCTABackground3D::save(const GFilename& filename, const bool& clobber) cons |
| 448 | 448 | // Get extension name |
| 449 | 449 | std::string extname = filename.extname("BACKGROUND"); |
| 450 | 450 | |
| 451 | - // Open or create FITS file | |
| 452 | - GFits fits(filename, true); | |
| 451 | + // Open or create FITS file (without extension name since the requested | |
| 452 | + // extension may not yet exist in the file) | |
| 453 | + GFits fits(filename.url(), true); | |
| 453 | 454 | |
| 454 | 455 | // Remove extension if it exists already |
| 455 | 456 | if (fits.contains(extname)) { | ... | ... |
inst/cta/src/GCTAEdisp2D.cpp
| ... | ... | @@ -461,8 +461,9 @@ void GCTAEdisp2D::save(const GFilename& filename, const bool& clobber) const |
| 461 | 461 | // Get extension name |
| 462 | 462 | std::string extname = filename.extname("ENERGY DISPERSION"); |
| 463 | 463 | |
| 464 | - // Open or create FITS file | |
| 465 | - GFits fits(filename, true); | |
| 464 | + // Open or create FITS file (without extension name since the requested | |
| 465 | + // extension may not yet exist in the file) | |
| 466 | + GFits fits(filename.url(), true); | |
| 466 | 467 | |
| 467 | 468 | // Remove extension if it exists already |
| 468 | 469 | if (fits.contains(extname)) { | ... | ... |
inst/cta/src/GCTAEventList.cpp
| ... | ... | @@ -303,8 +303,9 @@ void GCTAEventList::load(const GFilename& filename) |
| 303 | 303 | void GCTAEventList::save(const GFilename& filename, |
| 304 | 304 | const bool& clobber) const |
| 305 | 305 | { |
| 306 | - // Open or create FITS file | |
| 307 | - GFits fits(filename, true); | |
| 306 | + // Open or create FITS file (without extension name since the requested | |
| 307 | + // extension may not yet exist in the file) | |
| 308 | + GFits fits(filename.url(), true); | |
| 308 | 309 | |
| 309 | 310 | // Write event list |
| 310 | 311 | write(fits); | ... | ... |
inst/cta/src/GCTAPsf2D.cpp
| ... | ... | @@ -425,8 +425,9 @@ void GCTAPsf2D::save(const GFilename& filename, const bool& clobber) const |
| 425 | 425 | // Get extension name |
| 426 | 426 | std::string extname = filename.extname("POINT SPREAD FUNCTION"); |
| 427 | 427 | |
| 428 | - // Open or create FITS file | |
| 429 | - GFits fits(filename, true); | |
| 428 | + // Open or create FITS file (without extension name since the requested | |
| 429 | + // extension may not yet exist in the file) | |
| 430 | + GFits fits(filename.url(), true); | |
| 430 | 431 | |
| 431 | 432 | // Remove extension if it exists already |
| 432 | 433 | if (fits.contains(extname)) { | ... | ... |
inst/cta/src/GCTAPsfKing.cpp
| ... | ... | @@ -423,8 +423,9 @@ void GCTAPsfKing::save(const GFilename& filename, const bool& clobber) const |
| 423 | 423 | // Get extension name |
| 424 | 424 | std::string extname = filename.extname("POINT SPREAD FUNCTION"); |
| 425 | 425 | |
| 426 | - // Open or create FITS file | |
| 427 | - GFits fits(filename, true); | |
| 426 | + // Open or create FITS file (without extension name since the requested | |
| 427 | + // extension may not yet exist in the file) | |
| 428 | + GFits fits(filename.url(), true); | |
| 428 | 429 | |
| 429 | 430 | // Remove extension if it exists already |
| 430 | 431 | if (fits.contains(extname)) { | ... | ... |
src/obs/GEbounds.cpp
| ... | ... | @@ -599,31 +599,37 @@ void GEbounds::load(const GFilename& filename) |
| 599 | 599 | * @brief Save energy boundaries into FITS file |
| 600 | 600 | * |
| 601 | 601 | * @param[in] filename FITS file name. |
| 602 | - * @param[in] clobber Overwrite any existing file (default: false)? | |
| 603 | - * @param[in] unit Energy units (default: "keV") | |
| 602 | + * @param[in] clobber Overwrite an existing energy boundaries extension? | |
| 603 | + * @param[in] unit Energy unit | |
| 604 | 604 | * |
| 605 | 605 | * Saves energy boundaries into a FITS file. If a file with the given |
| 606 | 606 | * @p filename does not yet exist it will be created, otherwise the method |
| 607 | - * opens the existing file. The method will create (or replace an existing) | |
| 608 | - * energy boundaries extension. The extension name can be specified as part | |
| 609 | - * of the @p filename, or if no extension name is given, is assumed to be | |
| 610 | - * "EBOUNDS". | |
| 607 | + * opens the existing file. Energy boundaries can only be appended to an | |
| 608 | + * existing file if the @p clobber flag is set to `true` (otherwise an | |
| 609 | + * exception is thrown). | |
| 611 | 610 | * |
| 612 | - * An existing file will only be modified if the @p clobber flag is set to | |
| 613 | - * true. | |
| 611 | + * The method will append a binary FITS table containing the energy | |
| 612 | + * boundaries to the FITS file. The extension name can be specified as part | |
| 613 | + * of the @p filename. For example the @p filename | |
| 614 | + * | |
| 615 | + * myfile.fits[ENERGY BOUNDARIES] | |
| 616 | + * | |
| 617 | + * will save the energy boundaries in the `ENERGY BOUNDARIES` extension of | |
| 618 | + * the `myfile.fits` file. If the extension exists already in the file it | |
| 619 | + * will be replaced, otherwise a new extension will be created. If no | |
| 620 | + * extension name is provided, the method will use `EBOUNDS` as the default | |
| 621 | + * extension name for energy boundaries. | |
| 614 | 622 | ***************************************************************************/ |
| 615 | 623 | void GEbounds::save(const GFilename& filename, |
| 616 | 624 | const bool& clobber, |
| 617 | 625 | const std::string& unit) const |
| 618 | 626 | { |
| 619 | - // Get extension name | |
| 620 | - std::string extname = filename.extname("EBOUNDS"); | |
| 621 | - | |
| 622 | - // Open or create FITS file | |
| 623 | - GFits fits(filename, true); | |
| 627 | + // Open or create FITS file (without extension name since the requested | |
| 628 | + // extension may not yet exist in the file) | |
| 629 | + GFits fits(filename.url(), true); | |
| 624 | 630 | |
| 625 | 631 | // Write energy boundaries to FITS file |
| 626 | - write(fits, extname, unit); | |
| 632 | + write(fits, filename.extname("EBOUNDS"), unit); | |
| 627 | 633 | |
| 628 | 634 | // Save to file |
| 629 | 635 | fits.save(clobber); | ... | ... |
src/obs/GEnergies.cpp
| ... | ... | @@ -565,30 +565,36 @@ void GEnergies::load(const GFilename& filename) |
| 565 | 565 | |
| 566 | 566 | |
| 567 | 567 | /***********************************************************************//** |
| 568 | - * @brief Save energies to FITS file | |
| 568 | + * @brief Save energies into FITS file | |
| 569 | 569 | * |
| 570 | 570 | * @param[in] filename FITS filename. |
| 571 | - * @param[in] clobber Overwrite any existing energies extension? | |
| 571 | + * @param[in] clobber Overwrite an existing energies extension? | |
| 572 | 572 | * |
| 573 | - * Saves energiesinto a FITS file. If a file with the given @p filename does | |
| 574 | - * not yet exist it will be created, otherwise the method opens the existing | |
| 575 | - * file. The method will create (or replace an existing) energies extension. | |
| 576 | - * The extension name can be specified as part of the @p filename, or if no | |
| 577 | - * extension name is given, is assumed to be "ENERGIES". | |
| 573 | + * Saves energies into a FITS file. If a file with the given @p filename | |
| 574 | + * does not yet exist it will be created, otherwise the method opens the | |
| 575 | + * existing file. Energies can only be appended to an existing file if the | |
| 576 | + * @p clobber flag is set to `true` (otherwise an exception is thrown). | |
| 578 | 577 | * |
| 579 | - * An existing file will only be modified if the @p clobber flag is set to | |
| 580 | - * true. | |
| 578 | + * The method will append a binary FITS table containing the energies to the | |
| 579 | + * FITS file. The extension name can be specified as part of the | |
| 580 | + * @p filename. For example the @p filename | |
| 581 | + * | |
| 582 | + * myfile.fits[ENERGY VALUES] | |
| 583 | + * | |
| 584 | + * will save the energies in the `ENERGY VALUES` extension of the | |
| 585 | + * `myfile.fits` file. If the extension exists already in the file it will be | |
| 586 | + * replaced, otherwise a new extension will be created. If no extension name | |
| 587 | + * is provided, the method will use `ENERGIES` as the default extension name | |
| 588 | + * for energies. | |
| 581 | 589 | ***************************************************************************/ |
| 582 | 590 | void GEnergies::save(const GFilename& filename, const bool& clobber) const |
| 583 | 591 | { |
| 584 | - // Get extension name | |
| 585 | - std::string extname = filename.extname("ENERGIES"); | |
| 586 | - | |
| 587 | - // Open or create FITS file | |
| 588 | - GFits fits(filename, true); | |
| 592 | + // Open or create FITS file (without extension name since the requested | |
| 593 | + // extension may not yet exist in the file) | |
| 594 | + GFits fits(filename.url(), true); | |
| 589 | 595 | |
| 590 | 596 | // Write energies to FITS file |
| 591 | - write(fits, extname); | |
| 597 | + write(fits, filename.extname("ENERGIES")); | |
| 592 | 598 | |
| 593 | 599 | // Save to file |
| 594 | 600 | fits.save(clobber); | ... | ... |
src/obs/GGti.cpp
| ... | ... | @@ -602,31 +602,37 @@ void GGti::load(const GFilename& filename) |
| 602 | 602 | |
| 603 | 603 | |
| 604 | 604 | /***********************************************************************//** |
| 605 | - * @brief Save Good Time Intervals intervals to FITS file | |
| 605 | + * @brief Save Good Time Intervals into FITS file | |
| 606 | 606 | * |
| 607 | 607 | * @param[in] filename FITS filename. |
| 608 | - * @param[in] clobber Modify any existing FITS file? (default: false) | |
| 608 | + * @param[in] clobber Overwrite an existing Good Time Interval extension? | |
| 609 | 609 | * |
| 610 | 610 | * Saves Good Time Intervals into a FITS file. If a file with the given |
| 611 | 611 | * @p filename does not yet exist it will be created, otherwise the method |
| 612 | - * opens the existing file. The method will create (or replace an existing) | |
| 613 | - * Good Time Interval extension. The extension name can be specified as part | |
| 614 | - * of the @p filename, or if no extension name is given, is assumed to be | |
| 615 | - * "GTI". | |
| 612 | + * opens the existing file. Good Time Intervals can only be appended to an | |
| 613 | + * existing file if the @p clobber flag is set to `true` (otherwise an | |
| 614 | + * exception is thrown). | |
| 616 | 615 | * |
| 617 | - * An existing file will only be modified if the @p clobber flag is set to | |
| 618 | - * true. | |
| 616 | + * The method will append a binary FITS table containing the Good Time | |
| 617 | + * Intervals to the FITS file. The extension name can be specified as part | |
| 618 | + * of the @p filename. For example the @p filename | |
| 619 | + * | |
| 620 | + * myfile.fits[GOOD TIME INTERVALS] | |
| 621 | + * | |
| 622 | + * will save the Good Time Intervals in the `GOOD TIME INTERVALS` extension | |
| 623 | + * of the `myfile.fits` file. If the extension exists already in the file it | |
| 624 | + * will be replaced, otherwise a new extension will be created. If no | |
| 625 | + * extension name is provided, the method will use `GTI` as the default | |
| 626 | + * extension name for Good Time Intervals. | |
| 619 | 627 | ***************************************************************************/ |
| 620 | 628 | void GGti::save(const GFilename& filename, const bool& clobber) const |
| 621 | 629 | { |
| 622 | - // Get extension name | |
| 623 | - std::string extname = filename.extname("GTI"); | |
| 624 | - | |
| 625 | - // Open or create FITS file | |
| 626 | - GFits fits(filename, true); | |
| 630 | + // Open or create FITS file (without extension name since the requested | |
| 631 | + // extension may not yet exist in the file) | |
| 632 | + GFits fits(filename.url(), true); | |
| 627 | 633 | |
| 628 | 634 | // Write GTI to FITS object |
| 629 | - write(fits, extname); | |
| 635 | + write(fits, filename.extname("GTI")); | |
| 630 | 636 | |
| 631 | 637 | // Save to file |
| 632 | 638 | fits.save(clobber); | ... | ... |
src/support/GNodeArray.cpp
| ... | ... | @@ -721,26 +721,35 @@ void GNodeArray::load(const GFilename& filename) |
| 721 | 721 | |
| 722 | 722 | |
| 723 | 723 | /***********************************************************************//** |
| 724 | - * @brief Save nodes to FITS file | |
| 724 | + * @brief Save node array into FITS file | |
| 725 | 725 | * |
| 726 | 726 | * @param[in] filename FITS filename. |
| 727 | - * @param[in] clobber Overwrite any existing nodes extension? (default: false) | |
| 727 | + * @param[in] clobber Overwrite an existing node array extension? | |
| 728 | 728 | * |
| 729 | 729 | * Saves node array into a FITS file. If a file with the given @p filename |
| 730 | 730 | * does not yet exist it will be created, otherwise the method opens the |
| 731 | - * existing file. The method will create (or replace an existing) node array | |
| 732 | - * extension. The extension name can be specified as part of the @p filename, | |
| 733 | - * or if no extension name is given, is assumed to be "NODES". | |
| 731 | + * existing file. Node arrays can only be appended to an existing file if the | |
| 732 | + * @p clobber flag is set to `true` (otherwise an exception is thrown). | |
| 734 | 733 | * |
| 735 | - * An existing file will only be modified if the @p clobber flag is set to | |
| 736 | - * true. | |
| 734 | + * The method will append a binary FITS table containing the node array to | |
| 735 | + * the FITS file. The extension name can be specified as part of the | |
| 736 | + * @p filename. For example the @p filename | |
| 737 | + * | |
| 738 | + * myfile.fits[NODE ARRAY] | |
| 739 | + * | |
| 740 | + * will save the node array in the `NODE ARRAY` extension of the | |
| 741 | + * `myfile.fits` file. If the extension exists already in the file it will be | |
| 742 | + * replaced, otherwise a new extension will be created. If no extension name | |
| 743 | + * is provided, the method will use `NODES` as the default extension name | |
| 744 | + * for the node array. | |
| 737 | 745 | ***************************************************************************/ |
| 738 | 746 | void GNodeArray::save(const GFilename& filename, const bool& clobber) const |
| 739 | 747 | { |
| 740 | - // Open or create FITS file | |
| 741 | - GFits fits(filename, true); | |
| 748 | + // Open or create FITS file (without extension name since the requested | |
| 749 | + // extension may not yet exist in the file) | |
| 750 | + GFits fits(filename.url(), true); | |
| 742 | 751 | |
| 743 | - // Write GTI to FITS object | |
| 752 | + // Write node array to FITS object | |
| 744 | 753 | write(fits, filename.extname("NODES")); |
| 745 | 754 | |
| 746 | 755 | // Save to file | ... | ... |
src/xspec/GArf.cpp
| ... | ... | @@ -252,11 +252,18 @@ const double& GArf::at(const int& index) const |
| 252 | 252 | * @brief Load Auxiliary Response File |
| 253 | 253 | * |
| 254 | 254 | * @param[in] filename File name. |
| 255 | + * | |
| 256 | + * Loads the Auxiliary Response File from the `SPECRESP` extension of the | |
| 257 | + * FITS file. | |
| 255 | 258 | ***************************************************************************/ |
| 256 | 259 | void GArf::load(const GFilename& filename) |
| 257 | 260 | { |
| 258 | - // Open FITS file | |
| 259 | - GFits fits(filename); | |
| 261 | + // Clear response | |
| 262 | + clear(); | |
| 263 | + | |
| 264 | + // Open FITS file (without extension name as the user is not allowed | |
| 265 | + // to modify the extension names) | |
| 266 | + GFits fits(filename.url()); | |
| 260 | 267 | |
| 261 | 268 | // Get ARF table |
| 262 | 269 | const GFitsTable& table = *fits.table("SPECRESP"); |
| ... | ... | @@ -268,7 +275,7 @@ void GArf::load(const GFilename& filename) |
| 268 | 275 | fits.close(); |
| 269 | 276 | |
| 270 | 277 | // Store filename |
| 271 | - m_filename = filename; | |
| 278 | + m_filename = filename.url(); | |
| 272 | 279 | |
| 273 | 280 | // Return |
| 274 | 281 | return; |
| ... | ... | @@ -279,21 +286,30 @@ void GArf::load(const GFilename& filename) |
| 279 | 286 | * @brief Save Auxiliary Response File |
| 280 | 287 | * |
| 281 | 288 | * @param[in] filename File name. |
| 282 | - * @param[in] clobber Overwrite existing file? (defaults: false) | |
| 289 | + * @param[in] clobber Overwrite existing file? | |
| 290 | + * | |
| 291 | + * Saves the Auxiliary Response File into a FITS file. If a file with the | |
| 292 | + * given @p filename does not yet exist it will be created. If the file | |
| 293 | + * exists it can be overwritten if the @p clobber flag is set to `true`. | |
| 294 | + * Otherwise an exception is thrown. | |
| 295 | + * | |
| 296 | + * The method will save the `SPECRESP` binary FITS table into the FITS file | |
| 297 | + * that contains the values of the Auxiliary Response File. | |
| 283 | 298 | ***************************************************************************/ |
| 284 | 299 | void GArf::save(const GFilename& filename, const bool& clobber) const |
| 285 | 300 | { |
| 286 | - // Open FITS file | |
| 301 | + // Create FITS file | |
| 287 | 302 | GFits fits; |
| 288 | 303 | |
| 289 | 304 | // Write ARF into file |
| 290 | 305 | write(fits); |
| 291 | 306 | |
| 292 | - // Close FITS file | |
| 293 | - fits.saveto(filename, clobber); | |
| 307 | + // Save to file (without extension name since the requested extension | |
| 308 | + // may not yet exist in the file) | |
| 309 | + fits.saveto(filename.url(), clobber); | |
| 294 | 310 | |
| 295 | 311 | // Store filename |
| 296 | - m_filename = filename; | |
| 312 | + m_filename = filename.url(); | |
| 297 | 313 | |
| 298 | 314 | // Return |
| 299 | 315 | return; |
| ... | ... | @@ -304,6 +320,19 @@ void GArf::save(const GFilename& filename, const bool& clobber) const |
| 304 | 320 | * @brief Read Auxiliary Response File |
| 305 | 321 | * |
| 306 | 322 | * @param[in] table ARF FITS table. |
| 323 | + * | |
| 324 | + * Reads the Auxiliary Response File from a FITS table. The true energy | |
| 325 | + * boundaries are expected in the `ENERG_LO` and `ENERG_HI` columns, the | |
| 326 | + * response information is expected in the `SPECRESP` column. | |
| 327 | + * | |
| 328 | + * The method will analyze the unit of the `SPECRESP` column, and if either | |
| 329 | + * `m^2` or `m2` are encountered, multiply the values of the column by | |
| 330 | + * \f$10^4\f$ to convert the response into units of \f$cm^2\f$. Units of the | |
| 331 | + * `ENERG_LO` and `ENERG_HI` columns are also interpreted for conversion. | |
| 332 | + * | |
| 333 | + * See | |
| 334 | + * http://heasarc.gsfc.nasa.gov/docs/heasarc/caldb/docs/memos/cal_gen_92_002/cal_gen_92_002.html#tth_sEc4 | |
| 335 | + * for details about the Auxiliary Response File format. | |
| 307 | 336 | ***************************************************************************/ |
| 308 | 337 | void GArf::read(const GFitsTable& table) |
| 309 | 338 | { |
| ... | ... | @@ -349,6 +378,18 @@ void GArf::read(const GFitsTable& table) |
| 349 | 378 | * @brief Write Auxiliary Response File |
| 350 | 379 | * |
| 351 | 380 | * @param[in] fits FITS file. |
| 381 | + * | |
| 382 | + * Writes the Auxiliary Response File into the `SPECRESP` extension of the | |
| 383 | + * FITS file. An existing extension with the same name will be removed from | |
| 384 | + * the FITS file before writing. | |
| 385 | + * | |
| 386 | + * The method writes the boundaries of the true energy bins into the | |
| 387 | + * `ENERG_LO` and `ENERG_HI` columns, response information will be written | |
| 388 | + * into the `SPECRESP` column. | |
| 389 | + * | |
| 390 | + * See | |
| 391 | + * http://heasarc.gsfc.nasa.gov/docs/heasarc/caldb/docs/memos/cal_gen_92_002/cal_gen_92_002.html#tth_sEc4 | |
| 392 | + * for details about the Auxiliary Response File format. | |
| 352 | 393 | ***************************************************************************/ |
| 353 | 394 | void GArf::write(GFits& fits) const |
| 354 | 395 | { |
| ... | ... | @@ -405,7 +446,7 @@ void GArf::write(GFits& fits) const |
| 405 | 446 | /***********************************************************************//** |
| 406 | 447 | * @brief Print Auxiliary Response File |
| 407 | 448 | * |
| 408 | - * @param[in] chatter Chattiness (defaults to NORMAL). | |
| 449 | + * @param[in] chatter Chattiness. | |
| 409 | 450 | * @return String containing Auxiliary Response File information. |
| 410 | 451 | ***************************************************************************/ |
| 411 | 452 | std::string GArf::print(const GChatter& chatter) const | ... | ... |
src/xspec/GPha.cpp
| ... | ... | @@ -330,16 +330,18 @@ void GPha::fill(const GEnergy& energy, const double& value) |
| 330 | 330 | * |
| 331 | 331 | * @param[in] filename File name. |
| 332 | 332 | * |
| 333 | - * Loads the Pulse Height Analyzer spectrum from a FITS file. If an EBOUNDS | |
| 334 | - * extension is given, the energy boundaries information is also loaded | |
| 333 | + * Loads the Pulse Height Analyzer spectrum from the `SPECTRUM` extension | |
| 334 | + * of the FITS file. If the file contains also an `EBOUNDS` extension the | |
| 335 | + * energy boundaries of all Pulse Height Analyzer channels are also loaded. | |
| 335 | 336 | ***************************************************************************/ |
| 336 | 337 | void GPha::load(const GFilename& filename) |
| 337 | 338 | { |
| 338 | - // Clear any existing models | |
| 339 | + // Clear spectrum | |
| 339 | 340 | clear(); |
| 340 | 341 | |
| 341 | - // Open FITS file | |
| 342 | - GFits fits(filename); | |
| 342 | + // Open FITS file (without extension name as the user is not allowed | |
| 343 | + // to modify the extension names) | |
| 344 | + GFits fits(filename.url()); | |
| 343 | 345 | |
| 344 | 346 | // Get PHA table |
| 345 | 347 | const GFitsTable& pha = *fits.table("SPECTRUM"); |
| ... | ... | @@ -362,7 +364,7 @@ void GPha::load(const GFilename& filename) |
| 362 | 364 | fits.close(); |
| 363 | 365 | |
| 364 | 366 | // Store filename |
| 365 | - m_filename = filename; | |
| 367 | + m_filename = filename.url(); | |
| 366 | 368 | |
| 367 | 369 | // Return |
| 368 | 370 | return; |
| ... | ... | @@ -373,30 +375,32 @@ void GPha::load(const GFilename& filename) |
| 373 | 375 | * @brief Save Pulse Height Analyzer spectrum |
| 374 | 376 | * |
| 375 | 377 | * @param[in] filename File name. |
| 376 | - * @param[in] clobber Overwrite existing file? (default: false) | |
| 378 | + * @param[in] clobber Overwrite existing file? | |
| 377 | 379 | * |
| 378 | - * Saves Pulse Height Analyzer spectrum and energy boundaries into a FITS | |
| 379 | - * file. If a file with the given @p filename does not yet exist it will be | |
| 380 | - * created, otherwise the method opens the existing file. The method will | |
| 381 | - * create (or replace an existing) Pulse Height Analyzer spectrum and energy | |
| 382 | - * boundary extensions. | |
| 380 | + * Saves the Pulse Height Analyzer spectrum and energy boundaries into a | |
| 381 | + * FITS file. If a file with the given @p filename does not yet exist it | |
| 382 | + * will be created. If the file exists it can be overwritten if the | |
| 383 | + * @p clobber flag is set to `true`. Otherwise an exception is thrown. | |
| 383 | 384 | * |
| 384 | - * An existing file will only be modified if the @p clobber flag is set to | |
| 385 | - * true. | |
| 385 | + * The method will save two binary FITS tables into the FITS file: a | |
| 386 | + * `SPECTRUM` extension that contains the channel values of the Pulse | |
| 387 | + * Height Analyzer spectrum and an `EBOUNDS` extension that contains the | |
| 388 | + * energy boundaries for all channels. | |
| 386 | 389 | ***************************************************************************/ |
| 387 | 390 | void GPha::save(const GFilename& filename, const bool& clobber) const |
| 388 | 391 | { |
| 389 | - // Open or create FITS file | |
| 390 | - GFits fits(filename, true); | |
| 392 | + // Create FITS file | |
| 393 | + GFits fits; | |
| 391 | 394 | |
| 392 | 395 | // Write PHA into file |
| 393 | 396 | write(fits); |
| 394 | 397 | |
| 395 | - // Close FITS file | |
| 396 | - fits.save(clobber); | |
| 398 | + // Save to file (without extension name since the requested extension | |
| 399 | + // may not yet exist in the file) | |
| 400 | + fits.saveto(filename.url(), clobber); | |
| 397 | 401 | |
| 398 | 402 | // Store filename |
| 399 | - m_filename = filename; | |
| 403 | + m_filename = filename.url(); | |
| 400 | 404 | |
| 401 | 405 | // Return |
| 402 | 406 | return; |
| ... | ... | @@ -406,10 +410,18 @@ void GPha::save(const GFilename& filename, const bool& clobber) const |
| 406 | 410 | /***********************************************************************//** |
| 407 | 411 | * @brief Read Pulse Height Analyzer spectrum |
| 408 | 412 | * |
| 409 | - * @param[in] table PHA FITS table. | |
| 413 | + * @param[in] table FITS table. | |
| 410 | 414 | * |
| 411 | 415 | * @exception GException::invalid_value |
| 412 | 416 | * Mismatch between PHA file and energy boundaries. |
| 417 | + * | |
| 418 | + * Reads the Pulse Height Analyzer spectrum from a FITS table. The channel | |
| 419 | + * values are expected in the `COUNTS` column of the table. All other | |
| 420 | + * columns are ignored. | |
| 421 | + * | |
| 422 | + * See | |
| 423 | + * https://heasarc.gsfc.nasa.gov/docs/heasarc/ofwg/docs/spectra/ogip_92_007/node5.html | |
| 424 | + * for details about the Pulse Height Analyzer spectrum format. | |
| 413 | 425 | ***************************************************************************/ |
| 414 | 426 | void GPha::read(const GFitsTable& table) |
| 415 | 427 | { |
| ... | ... | @@ -417,17 +429,16 @@ void GPha::read(const GFitsTable& table) |
| 417 | 429 | const GFitsTableCol* col_data = table["COUNTS"]; |
| 418 | 430 | |
| 419 | 431 | // Extract number of channels in FITS file |
| 420 | - int length = table.integer("NAXIS2"); | |
| 432 | + int length = col_data->length(); | |
| 421 | 433 | |
| 422 | - // Check whether column length is okay | |
| 434 | + // Check whether column length is consistent with energy boundaries | |
| 423 | 435 | if (m_ebounds.size() > 0) { |
| 424 | 436 | if (m_ebounds.size() != length) { |
| 425 | - std::string msg = "Number of channels in PHA file (" | |
| 426 | - ""+gammalib::str(length)+") mismatches the" | |
| 427 | - " number of energy boundaries (" | |
| 428 | - ""+gammalib::str(m_ebounds.size())+") that" | |
| 429 | - " are defined in the GPha instance.\n" | |
| 430 | - "Please define the correct energy boundaries."; | |
| 437 | + std::string msg = "Mismatch between the "+gammalib::str(length)+ | |
| 438 | + " channels in the PHA file and the "+ | |
| 439 | + gammalib::str(m_ebounds.size())+" energy " | |
| 440 | + "boundaries. Please correct either the energy " | |
| 441 | + "boundaris or the PHA file."; | |
| 431 | 442 | throw GException::invalid_value(G_READ, msg); |
| 432 | 443 | } |
| 433 | 444 | } |
| ... | ... | @@ -449,6 +460,20 @@ void GPha::read(const GFitsTable& table) |
| 449 | 460 | * @brief Write Pulse Height Analyzer spectrum |
| 450 | 461 | * |
| 451 | 462 | * @param[in] fits FITS file. |
| 463 | + * | |
| 464 | + * Writes the Pulse Height Analyzer spectrum into `SPECTRUM` and `EBOUNDS` | |
| 465 | + * extensions of the FITS file. Extensions with these names will be removed | |
| 466 | + * from the FITS file before writing. | |
| 467 | + * | |
| 468 | + * The columns `CHANNEL`, `COUNTS`, `STAT_ERR`, `SYS_ERR`, `QUALITY`, | |
| 469 | + * `GROUPING`, `AREASCAL`, and `BACKSCAL` will be written into the `SPECTRUM` | |
| 470 | + * extension, but only the `CHANNEL` and `COUNTS` columns will be filled with | |
| 471 | + * values. Note that the channels start from 1 in the Pulse Height Analyzer | |
| 472 | + * spectrum. | |
| 473 | + * | |
| 474 | + * See | |
| 475 | + * https://heasarc.gsfc.nasa.gov/docs/heasarc/ofwg/docs/spectra/ogip_92_007/node5.html | |
| 476 | + * for details about the PHA file format. | |
| 452 | 477 | ***************************************************************************/ |
| 453 | 478 | void GPha::write(GFits& fits) const |
| 454 | 479 | { |
| ... | ... | @@ -516,7 +541,7 @@ void GPha::write(GFits& fits) const |
| 516 | 541 | /***********************************************************************//** |
| 517 | 542 | * @brief Print Pulse Height Analyzer spectrum |
| 518 | 543 | * |
| 519 | - * @param[in] chatter Chattiness (defaults to NORMAL). | |
| 544 | + * @param[in] chatter Chattiness. | |
| 520 | 545 | * @return String containing Pulse Height Analyzer spectrum information. |
| 521 | 546 | ***************************************************************************/ |
| 522 | 547 | std::string GPha::print(const GChatter& chatter) const | ... | ... |
src/xspec/GRmf.cpp
| ... | ... | @@ -369,20 +369,25 @@ GEbounds GRmf::emeasured(const GEnergy& etrue) const |
| 369 | 369 | * @brief Load Redistribution Matrix File |
| 370 | 370 | * |
| 371 | 371 | * @param[in] filename File name. |
| 372 | + * | |
| 373 | + * Loads the Redistribution Matrix File from the `MATRIX` extension of the | |
| 374 | + * FITS file. If the file contains also an `EBOUNDS` extension the energy | |
| 375 | + * boundaries of all measured energies are also loaded. | |
| 372 | 376 | ***************************************************************************/ |
| 373 | 377 | void GRmf::load(const GFilename& filename) |
| 374 | 378 | { |
| 375 | - // Clear any existing models | |
| 379 | + // Clear matrix | |
| 376 | 380 | clear(); |
| 377 | 381 | |
| 378 | - // Open FITS file | |
| 379 | - GFits fits(filename); | |
| 382 | + // Open FITS file (without extension name as the user is not allowed | |
| 383 | + // to modify the extension names) | |
| 384 | + GFits fits(filename.url()); | |
| 380 | 385 | |
| 381 | 386 | // Read measured energy boundaries |
| 382 | - m_ebds_measured.load(filename); | |
| 387 | + m_ebds_measured.load(filename.url()); | |
| 383 | 388 | |
| 384 | 389 | // Get RMF table |
| 385 | - const GFitsTable& table = *fits.table(filename.extname("MATRIX")); | |
| 390 | + const GFitsTable& table = *fits.table("MATRIX"); | |
| 386 | 391 | |
| 387 | 392 | // Read RMF data |
| 388 | 393 | read(table); |
| ... | ... | @@ -391,7 +396,7 @@ void GRmf::load(const GFilename& filename) |
| 391 | 396 | fits.close(); |
| 392 | 397 | |
| 393 | 398 | // Store filename |
| 394 | - m_filename = filename; | |
| 399 | + m_filename = filename.url(); | |
| 395 | 400 | |
| 396 | 401 | // Return |
| 397 | 402 | return; |
| ... | ... | @@ -402,24 +407,36 @@ void GRmf::load(const GFilename& filename) |
| 402 | 407 | * @brief Save Redistribution Matrix File |
| 403 | 408 | * |
| 404 | 409 | * @param[in] filename File name. |
| 405 | - * @param[in] clobber Overwrite existing file? (default: false) | |
| 406 | - * @param[in] unit Energy unit (default: "keV") | |
| 410 | + * @param[in] clobber Overwrite existing file? | |
| 411 | + * @param[in] unit Energy unit. | |
| 412 | + * | |
| 413 | + * Saves the Redistribution Matrix File into a FITS file. If a file with the | |
| 414 | + * given @p filename does not yet exist it will be created. If the file | |
| 415 | + * exists it can be overwritten if the @p clobber flag is set to `true`. | |
| 416 | + * Otherwise an exception is thrown. | |
| 417 | + * | |
| 418 | + * The method will save two binary FITS tables into the FITS file: a | |
| 419 | + * `MATRIX` extension that contains the Redistribution Matrix File elements, | |
| 420 | + * and an `EBOUNDS` extension that contains the measured energy boundaries | |
| 421 | + * for all matrix. The @p unit argument specifies the unit of the true | |
| 422 | + * energies that will be saved in the `MATRIX` extension. | |
| 407 | 423 | ***************************************************************************/ |
| 408 | 424 | void GRmf::save(const GFilename& filename, |
| 409 | 425 | const bool& clobber, |
| 410 | 426 | const std::string& unit) const |
| 411 | 427 | { |
| 412 | - // Open or create FITS file | |
| 413 | - GFits fits(filename, true); | |
| 428 | + // Create FITS file | |
| 429 | + GFits fits; | |
| 414 | 430 | |
| 415 | 431 | // Write RMF into file |
| 416 | 432 | write(fits, unit); |
| 417 | 433 | |
| 418 | - // Save to file | |
| 419 | - fits.save(clobber); | |
| 434 | + // Save to file (without extension name since the requested extension | |
| 435 | + // may not yet exist in the file) | |
| 436 | + fits.saveto(filename.url(), clobber); | |
| 420 | 437 | |
| 421 | 438 | // Store filename |
| 422 | - m_filename = filename; | |
| 439 | + m_filename = filename.url(); | |
| 423 | 440 | |
| 424 | 441 | // Return |
| 425 | 442 | return; |
| ... | ... | @@ -430,6 +447,18 @@ void GRmf::save(const GFilename& filename, |
| 430 | 447 | * @brief Read Redistribution Matrix File |
| 431 | 448 | * |
| 432 | 449 | * @param[in] table RMF FITS table. |
| 450 | + * | |
| 451 | + * Reads the Redistribution Matrix File from a FITS table. The true energy | |
| 452 | + * bins are expected in the `ENERG_LO` and `ENERG_HI` columns. Information | |
| 453 | + * for matrix compression are stored in the `N_GRP`, `F_CHAN` and `N_CHAN` | |
| 454 | + * columns, and the matrix elements are stored in the `MATRIX` column. | |
| 455 | + * | |
| 456 | + * The method automatically decompresses the Redistribution Matrix File and | |
| 457 | + * stores the matrix elements in a spare matrix. | |
| 458 | + * | |
| 459 | + * See | |
| 460 | + * http://heasarc.gsfc.nasa.gov/docs/heasarc/caldb/docs/memos/cal_gen_92_002/cal_gen_92_002.html#tth_sEc3 | |
| 461 | + * for details about the Redistribution Matrix File file format. | |
| 433 | 462 | ***************************************************************************/ |
| 434 | 463 | void GRmf::read(const GFitsTable& table) |
| 435 | 464 | { |
| ... | ... | @@ -497,7 +526,23 @@ void GRmf::read(const GFitsTable& table) |
| 497 | 526 | * @brief Write Redistribution Matrix File |
| 498 | 527 | * |
| 499 | 528 | * @param[in] fits FITS file. |
| 500 | - * @param[in] unit Energy unit (defaults to "keV") | |
| 529 | + * @param[in] unit Energy unit. | |
| 530 | + * | |
| 531 | + * Writes the Redistribution Matrix File into `MATRIX` and `EBOUNDS` | |
| 532 | + * extensions of the FITS file. Extensions with these names will be removed | |
| 533 | + * from the FITS file before writing. | |
| 534 | + * | |
| 535 | + * The true energy bins are written into the `ENERG_LO` and `ENERG_HI` | |
| 536 | + * columns. The units of the energies in these columns is specified by the | |
| 537 | + * @p unit argument. Information for matrix compression are stored in the | |
| 538 | + * `N_GRP`, `F_CHAN` and `N_CHAN` columns, and the matrix elements are | |
| 539 | + * written into the `MATRIX` column. | |
| 540 | + * | |
| 541 | + * The measured energy bins are written into the `EBOUNDS` extension. | |
| 542 | + * | |
| 543 | + * See | |
| 544 | + * http://heasarc.gsfc.nasa.gov/docs/heasarc/caldb/docs/memos/cal_gen_92_002/cal_gen_92_002.html#tth_sEc3 | |
| 545 | + * for details about the Redistribution Matrix File file format. | |
| 501 | 546 | ***************************************************************************/ |
| 502 | 547 | void GRmf::write(GFits& fits, const std::string& unit) const |
| 503 | 548 | { |
| ... | ... | @@ -629,7 +674,7 @@ void GRmf::write(GFits& fits, const std::string& unit) const |
| 629 | 674 | /***********************************************************************//** |
| 630 | 675 | * @brief Print Redistribution Matrix File |
| 631 | 676 | * |
| 632 | - * @param[in] chatter Chattiness (defaults to NORMAL). | |
| 677 | + * @param[in] chatter Chattiness. | |
| 633 | 678 | * @return String containing Redistribution Matrix File information. |
| 634 | 679 | ***************************************************************************/ |
| 635 | 680 | std::string GRmf::print(const GChatter& chatter) const | ... | ... |
test/test_GObservation.cpp
| ... | ... | @@ -252,6 +252,24 @@ void TestGObservation::test_ebounds(void) |
| 252 | 252 | test_assert(!containment.contains(GEnergy(200.0, "MeV"), GEnergy(2000.0, "MeV")), "Energy bin [200,2000] MeV should not be contained."); |
| 253 | 253 | test_assert(!containment.contains(GEnergy(80.0, "MeV"), GEnergy(2000.0, "MeV")), "Energy bin [80,2000] MeV should not be contained."); |
| 254 | 254 | |
| 255 | + // Remove test file | |
| 256 | + GFilename filename("test_ebounds.fits"); | |
| 257 | + filename.remove(); | |
| 258 | + | |
| 259 | + // Check saving | |
| 260 | + containment.save("test_ebounds.fits"); | |
| 261 | + GEbounds load1("test_ebounds.fits"); | |
| 262 | + test_value(load1.size(), 1, "GEbounds should have 1 element."); | |
| 263 | + test_value(load1.emin().MeV(), 100.0, 1.0e-10, "Minimum energy should be 100."); | |
| 264 | + test_value(load1.emax().MeV(), 1000.0, 1.0e-10, "Maximum energy should be 1000."); | |
| 265 | + | |
| 266 | + // Check saving in a different extnsion | |
| 267 | + ebds.save("test_ebounds.fits[ENERGY BOUNDARIES 2]", true); | |
| 268 | + GEbounds load2("test_ebounds.fits[ENERGY BOUNDARIES 2]"); | |
| 269 | + test_value(load2.size(), 1, "GEbounds should have 1 element."); | |
| 270 | + test_value(load2.emin().MeV(), 1.0, 1.0e-10, "Minimum energy should be 1."); | |
| 271 | + test_value(load2.emax().MeV(), 10.0, 1.0e-10, "Maximum energy should be 10."); | |
| 272 | + | |
| 255 | 273 | // Return |
| 256 | 274 | return; |
| 257 | 275 | } |
| ... | ... | @@ -379,6 +397,12 @@ void TestGObservation::test_gti(void) |
| 379 | 397 | test_value(gti.tstart().secs(), 1.0, 1.0e-7, "Start time should be 1."); |
| 380 | 398 | test_value(gti.tstop().secs(), 1000.0, 1.0e-7, "Stop time should be 1000."); |
| 381 | 399 | |
| 400 | + // Remove test file | |
| 401 | + GFilename file1("test_gti1.fits"); | |
| 402 | + GFilename file2("test_gti2.fits"); | |
| 403 | + file1.remove(); | |
| 404 | + file2.remove(); | |
| 405 | + | |
| 382 | 406 | // Check saving in and loading from FITS file |
| 383 | 407 | gti.save("test_gti1.fits", true); |
| 384 | 408 | GGti test1("test_gti1.fits"); |
| ... | ... | @@ -480,6 +504,24 @@ void TestGObservation::test_gti(void) |
| 480 | 504 | test_value(test5.tstart().secs(), 1.0, 1.0e-7, "Start time should be 1."); |
| 481 | 505 | test_value(test5.tstop().secs(), 10000.0, 1.0e-7, "Stop time should be 10000."); |
| 482 | 506 | |
| 507 | + // Remove test file | |
| 508 | + GFilename filename("test_gti.fits"); | |
| 509 | + filename.remove(); | |
| 510 | + | |
| 511 | + // Check saving | |
| 512 | + test4.save("test_gti.fits"); | |
| 513 | + GGti load1("test_gti.fits"); | |
| 514 | + test_value(load1.size(), 4, "GGti should have 4 intervals."); | |
| 515 | + test_value(load1.tstart().secs(), 1.0, 1.0e-7, "Start time should be 1."); | |
| 516 | + test_value(load1.tstop().secs(), 10000.0, 1.0e-7, "Stop time should be 10000."); | |
| 517 | + | |
| 518 | + // Check saving in a different extnsion | |
| 519 | + test3.save("test_gti.fits[GOOD TIME INTERVALS]", true); | |
| 520 | + GGti load2("test_gti.fits[GOOD TIME INTERVALS]"); | |
| 521 | + test_value(load2.size(), 1, "GGti should have 1 interval."); | |
| 522 | + test_value(load2.tstart().convert(GTimeReference(51544.5, "s")), 0.0, 1.0e-7, "Start time should be 0."); | |
| 523 | + test_value(load2.tstop().convert(GTimeReference(51544.5, "s")), 100.0, 1.0e-7, "Stop time should be 100."); | |
| 524 | + | |
| 483 | 525 | // Return |
| 484 | 526 | return; |
| 485 | 527 | } |
| ... | ... | @@ -984,6 +1026,10 @@ void TestGObservation::test_energies(void) |
| 984 | 1026 | test_value(energies[i].MeV(), double(i)); |
| 985 | 1027 | } |
| 986 | 1028 | |
| 1029 | + // Remove test file | |
| 1030 | + GFilename filename("test_energies.fits"); | |
| 1031 | + filename.remove(); | |
| 1032 | + | |
| 987 | 1033 | // Save and reload energies |
| 988 | 1034 | test_try("Saving and loading"); |
| 989 | 1035 | try { |
| ... | ... | @@ -1012,6 +1058,21 @@ void TestGObservation::test_energies(void) |
| 1012 | 1058 | test_try_failure(e); |
| 1013 | 1059 | } |
| 1014 | 1060 | |
| 1061 | + // Save and reload energies in another extension | |
| 1062 | + test_try("Saving and loading in another extension"); | |
| 1063 | + try { | |
| 1064 | + energies.save("test_energies.fits[NEW ENERGIES]", true); | |
| 1065 | + energies.clear(); | |
| 1066 | + energies.load("test_energies.fits[NEW ENERGIES]"); | |
| 1067 | + test_try_success(); | |
| 1068 | + } | |
| 1069 | + catch (std::exception &e) { | |
| 1070 | + test_try_failure(e); | |
| 1071 | + } | |
| 1072 | + for (int i = 0; i < 4; ++i) { | |
| 1073 | + test_value(energies[i].MeV(), double(i)); | |
| 1074 | + } | |
| 1075 | + | |
| 1015 | 1076 | // Check linear energies |
| 1016 | 1077 | energies.clear(); |
| 1017 | 1078 | energies.set_lin(3, GEnergy(1.0, "MeV"), GEnergy(3.0, "MeV")); | ... | ... |
test/test_GSupport.cpp
| ... | ... | @@ -381,6 +381,30 @@ void TestGSupport::test_node_array(void) |
| 381 | 381 | test_value(nodes.wgt_left(), 0.25, 1.0e-6, "Expected weight 0.25"); |
| 382 | 382 | test_value(nodes.wgt_right(), 0.75, 1.0e-6, "Expected weight 0.75"); |
| 383 | 383 | |
| 384 | + // Remove test file | |
| 385 | + GFilename filename("test_nodes.fits"); | |
| 386 | + filename.remove(); | |
| 387 | + | |
| 388 | + // Check saving | |
| 389 | + nodes.save("test_nodes.fits"); | |
| 390 | + GNodeArray load1("test_nodes.fits"); | |
| 391 | + test_value(load1.size(), 3, "GNodeArray should have 3 nodes."); | |
| 392 | + test_value(load1[0], 1.0, 1.0e-7, "First node should be 1."); | |
| 393 | + test_value(load1[1], 3.0, 1.0e-7, "First node should be 3."); | |
| 394 | + test_value(load1[2], 4.0, 1.0e-7, "First node should be 4."); | |
| 395 | + | |
| 396 | + // Check saving in a different extnsion | |
| 397 | + nodes.append(10.0); | |
| 398 | + nodes.append(11.0); | |
| 399 | + nodes.save("test_nodes.fits[NODE ARRAY]", true); | |
| 400 | + GNodeArray load2("test_nodes.fits[NODE ARRAY]"); | |
| 401 | + test_value(load2.size(), 5, "GNodeArray should have 5 nodes."); | |
| 402 | + test_value(load2[0], 1.0, 1.0e-7, "First node should be 1."); | |
| 403 | + test_value(load2[1], 3.0, 1.0e-7, "First node should be 3."); | |
| 404 | + test_value(load2[2], 4.0, 1.0e-7, "First node should be 4."); | |
| 405 | + test_value(load2[3], 10.0, 1.0e-7, "First node should be 10."); | |
| 406 | + test_value(load2[4], 11.0, 1.0e-7, "First node should be 11."); | |
| 407 | + | |
| 384 | 408 | // Return |
| 385 | 409 | return; |
| 386 | 410 | } | ... | ... |