Commit 4c6f4ae35ad0949e4e2119d7bc448367c1f028eb
1 parent
86c0af65
Normalise phase curves by default (#2154)
Showing
7 changed files
with
159 additions
and
32 deletions
ChangeLog
NEWS
| 1 | 1 | New Features and Important Changes in GammaLib 1.4.0 |
| 2 | 2 | |
| 3 | -6 July 2017 | |
| 3 | +18 July 2017 | |
| 4 | 4 | |
| 5 | 5 | |
| 6 | 6 | 1. Introduction |
| ... | ... | @@ -23,6 +23,7 @@ The following classes have been renamed: |
| 23 | 23 | The following methods have been added: |
| 24 | 24 | - GSkyRegion::overlaps(GSkyRegions&) |
| 25 | 25 | - GSkyMap::overlaps(GSkyRegion&) |
| 26 | +- GModelTemporalPhaseCurve::normalise() | |
| 26 | 27 | |
| 27 | 28 | The following methods have been removed: |
| 28 | 29 | - n.a. |
| ... | ... | @@ -64,7 +65,10 @@ None |
| 64 | 65 | |
| 65 | 66 | 8. Model module |
| 66 | 67 | --------------- |
| 67 | -None | |
| 68 | +The GModelTemporalPhaseCurve models are now normalised by default unless a | |
| 69 | +normalize="0" attribute is explicitly added into the XML file. Thus the spectral | |
| 70 | +component of a sky model with a GModelTemporalPhaseCurve temporal component now | |
| 71 | +gives the phase-averaged flux (#2154). | |
| 68 | 72 | |
| 69 | 73 | |
| 70 | 74 | 9. Numerics module | ... | ... |
doc/source/users/user_manual/modules/model.rst
| ... | ... | @@ -1084,6 +1084,18 @@ between 0 and 1. |
| 1084 | 1084 | |
| 1085 | 1085 | *Structure of phase curve FITS file* |
| 1086 | 1086 | |
| 1087 | +By default, the ``NORM`` values are recomputed internally so that the phase | |
| 1088 | +averaged normalisation is one. In that case, the spectral component corresponds | |
| 1089 | +to the phase-averaged spectrum. If the internal normalisation should be disabled | |
| 1090 | +the ``normalize="0"`` attribute needs to be added to the temporal tag, i.e. | |
| 1091 | + | |
| 1092 | +.. code-block:: xml | |
| 1093 | + | |
| 1094 | + <temporal type="PhaseCurve" file="model_temporal_phasecurve.fits" normalize="0"> | |
| 1095 | + | |
| 1096 | +In that case the ``NORM`` values are directly multiplied with the spectral | |
| 1097 | +component. | |
| 1098 | + | |
| 1087 | 1099 | |
| 1088 | 1100 | Background models |
| 1089 | 1101 | ~~~~~~~~~~~~~~~~~ | ... | ... |
include/GModelTemporalPhaseCurve.hpp
| ... | ... | @@ -85,7 +85,8 @@ public: |
| 85 | 85 | const double& f0, |
| 86 | 86 | const double& f1, |
| 87 | 87 | const double& f2, |
| 88 | - const double& norm = 1.0); | |
| 88 | + const double& norm = 1.0, | |
| 89 | + const bool& normalize = true); | |
| 89 | 90 | GModelTemporalPhaseCurve(const GModelTemporalPhaseCurve& model); |
| 90 | 91 | virtual ~GModelTemporalPhaseCurve(void); |
| 91 | 92 | |
| ... | ... | @@ -121,6 +122,7 @@ public: |
| 121 | 122 | void f1(const double& f1); |
| 122 | 123 | double f2(void) const; |
| 123 | 124 | void f2(const double& f2); |
| 125 | + bool normalize(void) const; | |
| 124 | 126 | |
| 125 | 127 | protected: |
| 126 | 128 | // Protected methods |
| ... | ... | @@ -128,14 +130,17 @@ protected: |
| 128 | 130 | void copy_members(const GModelTemporalPhaseCurve& model); |
| 129 | 131 | void free_members(void); |
| 130 | 132 | void load_nodes(const GFilename& filename); |
| 133 | + void normalise_nodes(void); | |
| 131 | 134 | |
| 132 | 135 | // Protected parameter members |
| 133 | - GModelPar m_norm; //!< Normalization factor | |
| 134 | - GModelPar m_mjd; //!< Reference MJD | |
| 135 | - GModelPar m_phase; //!< Phase at reference MJD | |
| 136 | - GModelPar m_f0; //!< Frequency at reference MJD | |
| 137 | - GModelPar m_f1; //!< First freq. derivative at reference MJD | |
| 138 | - GModelPar m_f2; //!< Second freq. derivative at reference MJD | |
| 136 | + GModelPar m_norm; //!< Normalization factor | |
| 137 | + GModelPar m_mjd; //!< Reference MJD | |
| 138 | + GModelPar m_phase; //!< Phase at reference MJD | |
| 139 | + GModelPar m_f0; //!< Frequency at reference MJD | |
| 140 | + GModelPar m_f1; //!< First freq. derivative at reference MJD | |
| 141 | + GModelPar m_f2; //!< Second freq. derivative at reference MJD | |
| 142 | + bool m_normalize; //!< Normalize phase curve (default: true) | |
| 143 | + bool m_has_normalize; //!< XML has normalize attribute | |
| 139 | 144 | |
| 140 | 145 | // Protected members |
| 141 | 146 | mutable GNodeArray m_nodes; //!< Phase values of nodes |
| ... | ... | @@ -166,7 +171,7 @@ std::string GModelTemporalPhaseCurve::classname(void) const |
| 166 | 171 | inline |
| 167 | 172 | std::string GModelTemporalPhaseCurve::type(void) const |
| 168 | 173 | { |
| 169 | - return "PhaseCurve"; | |
| 174 | + return ("PhaseCurve"); | |
| 170 | 175 | } |
| 171 | 176 | |
| 172 | 177 | |
| ... | ... | @@ -374,4 +379,18 @@ void GModelTemporalPhaseCurve::f2(const double& f2) |
| 374 | 379 | return; |
| 375 | 380 | } |
| 376 | 381 | |
| 382 | + | |
| 383 | +/***********************************************************************//** | |
| 384 | + * @brief Return normalization flag | |
| 385 | + * | |
| 386 | + * @return True if the phase curve has been normalized, false otherwise. | |
| 387 | + * | |
| 388 | + * Signals whether a phase curve has been normalized or not. | |
| 389 | + ***************************************************************************/ | |
| 390 | +inline | |
| 391 | +bool GModelTemporalPhaseCurve::normalize(void) const | |
| 392 | +{ | |
| 393 | + return (m_normalize); | |
| 394 | +} | |
| 395 | + | |
| 377 | 396 | #endif /* GMODELTEMPORALPHASECURVE_HPP */ | ... | ... |
pyext/GModelTemporalPhaseCurve.i
| ... | ... | @@ -46,7 +46,8 @@ public: |
| 46 | 46 | const double& f0, |
| 47 | 47 | const double& f1, |
| 48 | 48 | const double& f2, |
| 49 | - const double& norm = 1.0); | |
| 49 | + const double& norm = 1.0, | |
| 50 | + const bool& normalize = true); | |
| 50 | 51 | GModelTemporalPhaseCurve(const GModelTemporalPhaseCurve& model); |
| 51 | 52 | virtual ~GModelTemporalPhaseCurve(void); |
| 52 | 53 | |
| ... | ... | @@ -78,6 +79,7 @@ public: |
| 78 | 79 | void f1(const double& f1); |
| 79 | 80 | double f2(void) const; |
| 80 | 81 | void f2(const double& f2); |
| 82 | + bool normalize(void) const; | |
| 81 | 83 | }; |
| 82 | 84 | |
| 83 | 85 | ... | ... |
src/model/GModelTemporalPhaseCurve.cpp
| ... | ... | @@ -47,6 +47,7 @@ const GModelTemporalRegistry g_temporal_phase_registry(&g_temporal_phase_seed) |
| 47 | 47 | #define G_READ "GModelTemporalPhaseCurve::read(GXmlElement&)" |
| 48 | 48 | #define G_WRITE "GModelTemporalPhaseCurve::write(GXmlElement&)" |
| 49 | 49 | #define G_LOAD_NODES "GModelTemporalPhaseCurve::load_nodes(GFilename&)" |
| 50 | +#define G_NORMALISE_NODES "GModelTemporalPhaseCurve::normalise_nodes()" | |
| 50 | 51 | |
| 51 | 52 | /* __ Macros _____________________________________________________________ */ |
| 52 | 53 | |
| ... | ... | @@ -84,6 +85,7 @@ GModelTemporalPhaseCurve::GModelTemporalPhaseCurve(void) : GModelTemporal() |
| 84 | 85 | * @param[in] f1 First frequency derivative at reference time. |
| 85 | 86 | * @param[in] f2 Second frequency derivative at reference time. |
| 86 | 87 | * @param[in] norm Normalization factor. |
| 88 | + * @param[in] normalize Normalize phase curve? | |
| 87 | 89 | * |
| 88 | 90 | * Constructs phase curve from a list of nodes that is found in the specified |
| 89 | 91 | * FITS file, a reference time and phase information at the reference time. |
| ... | ... | @@ -96,7 +98,8 @@ GModelTemporalPhaseCurve::GModelTemporalPhaseCurve(const GFilename& filename, |
| 96 | 98 | const double& f0, |
| 97 | 99 | const double& f1, |
| 98 | 100 | const double& f2, |
| 99 | - const double& norm) : | |
| 101 | + const double& norm, | |
| 102 | + const bool& normalize) : | |
| 100 | 103 | GModelTemporal() |
| 101 | 104 | { |
| 102 | 105 | // Initialise members |
| ... | ... | @@ -110,6 +113,9 @@ GModelTemporalPhaseCurve::GModelTemporalPhaseCurve(const GFilename& filename, |
| 110 | 113 | this->f2(f2); |
| 111 | 114 | this->norm(norm); |
| 112 | 115 | |
| 116 | + // Set normalization flag | |
| 117 | + m_normalize = normalize; | |
| 118 | + | |
| 113 | 119 | // Load nodes |
| 114 | 120 | load_nodes(filename); |
| 115 | 121 | |
| ... | ... | @@ -385,6 +391,17 @@ void GModelTemporalPhaseCurve::read(const GXmlElement& xml) |
| 385 | 391 | m_f1.read(*f1); |
| 386 | 392 | m_f2.read(*f2); |
| 387 | 393 | |
| 394 | + // Get optional normalization attribute | |
| 395 | + m_normalize = true; | |
| 396 | + m_has_normalize = false; | |
| 397 | + if (xml.has_attribute("normalize")) { | |
| 398 | + m_has_normalize = true; | |
| 399 | + std::string arg = xml.attribute("normalize"); | |
| 400 | + if (arg == "0" || gammalib::tolower(arg) == "false") { | |
| 401 | + m_normalize = false; | |
| 402 | + } | |
| 403 | + } | |
| 404 | + | |
| 388 | 405 | // Load nodes from file |
| 389 | 406 | load_nodes(gammalib::xml_file_expand(xml, xml.attribute("file"))); |
| 390 | 407 | |
| ... | ... | @@ -446,6 +463,16 @@ void GModelTemporalPhaseCurve::write(GXmlElement& xml) const |
| 446 | 463 | // Set file attribute |
| 447 | 464 | xml.attribute("file", gammalib::xml_file_reduce(xml, m_filename)); |
| 448 | 465 | |
| 466 | + // Set optional normalization attribute | |
| 467 | + if (m_has_normalize || !m_normalize) { | |
| 468 | + if (m_normalize) { | |
| 469 | + xml.attribute("normalize", "1"); | |
| 470 | + } | |
| 471 | + else { | |
| 472 | + xml.attribute("normalize", "0"); | |
| 473 | + } | |
| 474 | + } | |
| 475 | + | |
| 449 | 476 | // Return |
| 450 | 477 | return; |
| 451 | 478 | } |
| ... | ... | @@ -514,19 +541,24 @@ std::string GModelTemporalPhaseCurve::print(const GChatter& chatter) const |
| 514 | 541 | // Append information |
| 515 | 542 | result.append("\n"+gammalib::parformat("Function file")); |
| 516 | 543 | result.append(m_filename.url()); |
| 544 | + if (normalize()) { | |
| 545 | + result.append(" [normalized]"); | |
| 546 | + } | |
| 517 | 547 | result.append("\n"+gammalib::parformat("Number of parameters")); |
| 518 | 548 | result.append(gammalib::str(size())); |
| 519 | 549 | for (int i = 0; i < size(); ++i) { |
| 520 | 550 | result.append("\n"+m_pars[i]->print(chatter)); |
| 521 | 551 | } |
| 522 | - | |
| 523 | - // Append node information | |
| 524 | 552 | result.append("\n"+gammalib::parformat("Number of phase nodes")); |
| 525 | 553 | result.append(gammalib::str(m_nodes.size())); |
| 526 | - for (int i = 0; i < m_nodes.size(); ++i) { | |
| 527 | - result.append("\n"); | |
| 528 | - result.append(gammalib::parformat(" Phase "+gammalib::str(m_nodes[i]))); | |
| 529 | - result.append(gammalib::str(m_values[i])); | |
| 554 | + | |
| 555 | + // EXPLICIT: Append node values | |
| 556 | + if (chatter >= EXPLICIT) { | |
| 557 | + for (int i = 0; i < m_nodes.size(); ++i) { | |
| 558 | + result.append("\n"); | |
| 559 | + result.append(gammalib::parformat(" Phase "+gammalib::str(m_nodes[i]))); | |
| 560 | + result.append(gammalib::str(m_values[i])); | |
| 561 | + } | |
| 530 | 562 | } |
| 531 | 563 | |
| 532 | 564 | } // endif: chatter was not silent |
| ... | ... | @@ -626,7 +658,9 @@ void GModelTemporalPhaseCurve::init_members(void) |
| 626 | 658 | m_nodes.clear(); |
| 627 | 659 | m_values.clear(); |
| 628 | 660 | m_filename.clear(); |
| 629 | - | |
| 661 | + m_normalize = true; | |
| 662 | + m_has_normalize = false; | |
| 663 | + | |
| 630 | 664 | // Return |
| 631 | 665 | return; |
| 632 | 666 | } |
| ... | ... | @@ -640,15 +674,17 @@ void GModelTemporalPhaseCurve::init_members(void) |
| 640 | 674 | void GModelTemporalPhaseCurve::copy_members(const GModelTemporalPhaseCurve& model) |
| 641 | 675 | { |
| 642 | 676 | // Copy members |
| 643 | - m_norm = model.m_norm; | |
| 644 | - m_mjd = model.m_mjd; | |
| 645 | - m_phase = model.m_phase; | |
| 646 | - m_f0 = model.m_f0; | |
| 647 | - m_f1 = model.m_f1; | |
| 648 | - m_f2 = model.m_f2; | |
| 649 | - m_nodes = model.m_nodes; | |
| 650 | - m_values = model.m_values; | |
| 651 | - m_filename = model.m_filename; | |
| 677 | + m_norm = model.m_norm; | |
| 678 | + m_mjd = model.m_mjd; | |
| 679 | + m_phase = model.m_phase; | |
| 680 | + m_f0 = model.m_f0; | |
| 681 | + m_f1 = model.m_f1; | |
| 682 | + m_f2 = model.m_f2; | |
| 683 | + m_nodes = model.m_nodes; | |
| 684 | + m_values = model.m_values; | |
| 685 | + m_filename = model.m_filename; | |
| 686 | + m_normalize = model.m_normalize; | |
| 687 | + m_has_normalize = model.m_has_normalize; | |
| 652 | 688 | |
| 653 | 689 | // Set parameter pointer(s) |
| 654 | 690 | m_pars.clear(); |
| ... | ... | @@ -797,6 +833,59 @@ void GModelTemporalPhaseCurve::load_nodes(const GFilename& filename) |
| 797 | 833 | // Close FITS file |
| 798 | 834 | fits.close(); |
| 799 | 835 | |
| 836 | + // Optionally normalise nodes | |
| 837 | + if (m_normalize) { | |
| 838 | + normalise_nodes(); | |
| 839 | + } | |
| 840 | + | |
| 841 | + // Return | |
| 842 | + return; | |
| 843 | +} | |
| 844 | + | |
| 845 | + | |
| 846 | +/***********************************************************************//** | |
| 847 | + * @brief Normalise nodes | |
| 848 | + * | |
| 849 | + * @exception GException::invalid_value | |
| 850 | + * Phase curve FITS file is invalid | |
| 851 | + * | |
| 852 | + * Normalise the node values so that the integral over the phase interval | |
| 853 | + * [0,1] gives an average normalisation of 1. | |
| 854 | + ***************************************************************************/ | |
| 855 | +void GModelTemporalPhaseCurve::normalise_nodes(void) | |
| 856 | +{ | |
| 857 | + // Initialise node integral | |
| 858 | + double sum = 0.0; | |
| 859 | + | |
| 860 | + // Loop over all nodes-1 | |
| 861 | + for (int i = 0; i < m_nodes.size()-1; ++i) { | |
| 862 | + | |
| 863 | + // Compute phase values | |
| 864 | + double a = (m_nodes[i] < 0.0) ? 0.0 : m_nodes[i]; | |
| 865 | + double b = (m_nodes[i+1] > 1.0) ? 1.0 : m_nodes[i+1]; | |
| 866 | + | |
| 867 | + // Compute normalisation at phase values | |
| 868 | + double fa = m_nodes.interpolate(a, m_values); | |
| 869 | + double fb = m_nodes.interpolate(b, m_values); | |
| 870 | + | |
| 871 | + // Compute intergal for this interval using the Trapezoid rule | |
| 872 | + sum += 0.5 * (b - a) * (fa + fb); | |
| 873 | + | |
| 874 | + } | |
| 875 | + | |
| 876 | + // Throw an exception if the integral is not positive | |
| 877 | + if (sum <= 0.0) { | |
| 878 | + std::string msg = "Integral over phase curve is not positive ("+ | |
| 879 | + gammalib::str(sum)+"). Please provide a valid phase " | |
| 880 | + "curve file."; | |
| 881 | + throw GException::invalid_value(G_NORMALISE_NODES, msg); | |
| 882 | + } | |
| 883 | + | |
| 884 | + // Normalise the node values | |
| 885 | + for (int i = 0; i < m_values.size(); ++i) { | |
| 886 | + m_values[i] /= sum; | |
| 887 | + } | |
| 888 | + | |
| 800 | 889 | // Return |
| 801 | 890 | return; |
| 802 | 891 | } | ... | ... |
src/obs/GObservations.cpp
| ... | ... | @@ -880,7 +880,7 @@ int GObservations::nobserved(void) const |
| 880 | 880 | /***********************************************************************//** |
| 881 | 881 | * @brief Print observation list information |
| 882 | 882 | * |
| 883 | - * @param[in] chatter Chattiness (defaults to NORMAL). | |
| 883 | + * @param[in] chatter Chattiness. | |
| 884 | 884 | * @return String containing observation list information |
| 885 | 885 | ***************************************************************************/ |
| 886 | 886 | std::string GObservations::print(const GChatter& chatter) const |
| ... | ... | @@ -910,12 +910,12 @@ std::string GObservations::print(const GChatter& chatter) const |
| 910 | 910 | result.append("\n"); |
| 911 | 911 | result.append((*this)[i]->print()); |
| 912 | 912 | } |
| 913 | - } // endif: chatter was explicit | |
| 913 | + } | |
| 914 | 914 | |
| 915 | 915 | // VERBOSE: Append models |
| 916 | 916 | if (chatter == VERBOSE) { |
| 917 | 917 | result.append("\n"+m_models.print()); |
| 918 | - } // endif: chatter was verbose | |
| 918 | + } | |
| 919 | 919 | |
| 920 | 920 | } // endif: chatter was not silent |
| 921 | 921 | ... | ... |