Commit 4c6f4ae35ad0949e4e2119d7bc448367c1f028eb

Authored by Jürgen Knödlseder
1 parent 86c0af65

Normalise phase curves by default (#2154)

ChangeLog
1   -2017-07-06
  1 +2017-07-18
2 2  
3 3 * Version 1.4.0 released
4 4 =========================
5 5  
  6 + Normalise phase curves by default (#2154)
6 7 Add GSkyRegions::overlaps() and GSkyMap::overlaps() classes (#1980)
7 8  
8 9  
... ...
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&amp; 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(&amp;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&amp; 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&amp; 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&amp; 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&amp; 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&amp; 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&amp; 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&amp; 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  
... ...