Commit ed7891e8d0f6365b0a467e4949722ae6a030073a
1 parent
c2540409
Correct parameter gradient computation.
There were two bugs in the parameter gradient computation. First, the wrong index was used to compute the break value gradient. Second, the index gradients were both computed, irrespectively of the energy. However, if the energy is smaller than the break energy, only the first index gradient should be computed while the second will be 0. If the energy is larger, the first index gradient should be 0 and only the second should be computed. Both bugs have been fixed.
Showing
2 changed files
with
77 additions
and
69 deletions
include/GModelSpectralBrokenPlaw.hpp
| ... | ... | @@ -110,27 +110,27 @@ protected: |
| 110 | 110 | // Protected members |
| 111 | 111 | GModelPar m_norm; //!< Normalization factor |
| 112 | 112 | GModelPar m_index1; //!< Spectral index1 |
| 113 | + GModelPar m_index2; //!< Spectral index2 | |
| 113 | 114 | GModelPar m_breakenergy; //!< Energy of spectral break |
| 114 | - GModelPar m_index2; //!< Spectral index1 | |
| 115 | 115 | |
| 116 | 116 | // Cached members used for pre-computations |
| 117 | - mutable GEnergy m_last_energy; //!< Last energy value | |
| 118 | - mutable double m_last_index1; //!< Last index1 parameter | |
| 119 | - mutable double m_last_index2; //!< Last index1 parameter | |
| 120 | - mutable double m_last_breakenergy; //!< Last breakenergy parameter | |
| 121 | - mutable double m_last_e_norm; //!< Last E/Ebreakenergy value | |
| 122 | - mutable double m_last_log_e_norm; //!< Last ln(E/Ebreakenergy) value | |
| 123 | - mutable double m_last_power; //!< Last power value | |
| 124 | - mutable double m_mc_emin; //!< Minimum energy | |
| 125 | - mutable double m_mc_emax; //!< Maximum energy | |
| 126 | - mutable double m_mc_exponent1; //!< Exponent (index1+1) | |
| 127 | - mutable double m_mc_exponent2; //!< Exponent (index2+1) | |
| 128 | - mutable double m_mc_pow_emin; //!< Power of minimum energy | |
| 129 | - mutable double m_mc_pow_ewidth; //!< Power of energy width | |
| 130 | - mutable std::vector<double> m_mc_cum; //!< Cumulative distribution | |
| 131 | - mutable std::vector<double> m_mc_min; //!< Lower boundary for MC | |
| 132 | - mutable std::vector<double> m_mc_max; //!< Upper boundary for MC | |
| 133 | - mutable std::vector<double> m_mc_exp; //!< Exponent for MC | |
| 117 | + mutable GEnergy m_last_energy; //!< Last energy value | |
| 118 | + mutable double m_last_index1; //!< Last index1 parameter | |
| 119 | + mutable double m_last_index2; //!< Last index1 parameter | |
| 120 | + mutable double m_last_breakenergy; //!< Last breakenergy parameter | |
| 121 | + mutable double m_last_e_norm; //!< Last E/Ebreakenergy value | |
| 122 | + mutable double m_last_log_e_norm; //!< Last ln(E/Ebreakenergy) value | |
| 123 | + mutable double m_last_power; //!< Last power value | |
| 124 | + mutable double m_mc_emin; //!< Minimum energy | |
| 125 | + mutable double m_mc_emax; //!< Maximum energy | |
| 126 | + mutable double m_mc_exponent1; //!< Exponent (index1+1) | |
| 127 | + mutable double m_mc_exponent2; //!< Exponent (index2+1) | |
| 128 | + mutable double m_mc_pow_emin; //!< Power of minimum energy | |
| 129 | + mutable double m_mc_pow_ewidth; //!< Power of energy width | |
| 130 | + mutable std::vector<double> m_mc_cum; //!< Cumulative distribution | |
| 131 | + mutable std::vector<double> m_mc_min; //!< Lower boundary for MC | |
| 132 | + mutable std::vector<double> m_mc_max; //!< Upper boundary for MC | |
| 133 | + mutable std::vector<double> m_mc_exp; //!< Exponent for MC | |
| 134 | 134 | }; |
| 135 | 135 | |
| 136 | 136 | ... | ... |
src/model/GModelSpectralBrokenPlaw.cpp
| ... | ... | @@ -338,24 +338,34 @@ double GModelSpectralBrokenPlaw::eval_gradients(const GEnergy& srcEng, |
| 338 | 338 | // Compute function value |
| 339 | 339 | double value = m_norm.value() * m_last_power; |
| 340 | 340 | |
| 341 | - // Compute partial derivatives of the parameter values | |
| 341 | + // Compute normalisation gradient | |
| 342 | 342 | double g_norm = (m_norm.isfree()) |
| 343 | 343 | ? m_norm.scale() * m_last_power : 0.0; |
| 344 | - double g_index1 = (m_index1.isfree()) | |
| 345 | - ? value * m_index1.scale() * m_last_log_e_norm : 0.0; | |
| 346 | - double g_index2 = (m_index2.isfree()) | |
| 347 | - ? value * m_index2.scale() * m_last_log_e_norm : 0.0; | |
| 348 | - double index_current = (srcEng.MeV() > m_breakenergy.value()) | |
| 349 | - ? m_last_index1 : m_last_index2; | |
| 350 | - double g_breakenergy = (m_breakenergy.isfree()) | |
| 351 | - ? -value * index_current / m_breakenergy.factor_value() : 0.0; | |
| 352 | - | |
| 353 | - | |
| 354 | - // Set gradients | |
| 355 | 344 | m_norm.factor_gradient(g_norm); |
| 356 | - m_index1.factor_gradient(g_index1); | |
| 357 | - m_breakenergy.factor_gradient(g_breakenergy); | |
| 358 | - m_index2.factor_gradient(g_index2); | |
| 345 | + | |
| 346 | + // Compute index and break value gradients | |
| 347 | + if (srcEng.MeV() < m_breakenergy.value()) { | |
| 348 | + double g_index = (m_index1.isfree()) | |
| 349 | + ? value * m_index1.scale() * m_last_log_e_norm | |
| 350 | + : 0.0; | |
| 351 | + double g_break = (m_breakenergy.isfree()) | |
| 352 | + ? -value * m_last_index1 / m_breakenergy.factor_value() | |
| 353 | + : 0.0; | |
| 354 | + m_index1.factor_gradient(g_index); | |
| 355 | + m_index2.factor_gradient(0.0); | |
| 356 | + m_breakenergy.factor_gradient(g_break); | |
| 357 | + } | |
| 358 | + else { | |
| 359 | + double g_index = (m_index2.isfree()) | |
| 360 | + ? value * m_index2.scale() * m_last_log_e_norm | |
| 361 | + : 0.0; | |
| 362 | + double g_break = (m_breakenergy.isfree()) | |
| 363 | + ? -value * m_last_index2 / m_breakenergy.factor_value() | |
| 364 | + : 0.0; | |
| 365 | + m_index1.factor_gradient(0.0); | |
| 366 | + m_index2.factor_gradient(g_index); | |
| 367 | + m_breakenergy.factor_gradient(g_break); | |
| 368 | + } | |
| 359 | 369 | |
| 360 | 370 | // Compile option: Check for NaN/Inf |
| 361 | 371 | #if defined(G_NAN_CHECK) |
| ... | ... | @@ -368,9 +378,6 @@ double GModelSpectralBrokenPlaw::eval_gradients(const GEnergy& srcEng, |
| 368 | 378 | std::cout << ", e_norm=" << m_last_e_norm; |
| 369 | 379 | std::cout << ", power=" << m_last_power; |
| 370 | 380 | std::cout << ", g_norm=" << g_norm; |
| 371 | - std::cout << ", g_index1=" << g_index1; | |
| 372 | - std::cout << ", g_breakenergy=" << g_breakenergy; | |
| 373 | - std::cout << ", g_index2=" << g_index2; | |
| 374 | 381 | std::cout << ")" << std::endl; |
| 375 | 382 | } |
| 376 | 383 | #endif |
| ... | ... | @@ -806,16 +813,6 @@ void GModelSpectralBrokenPlaw::init_members(void) |
| 806 | 813 | m_index1.gradient(0.0); |
| 807 | 814 | m_index1.hasgrad(true); |
| 808 | 815 | |
| 809 | - // Initialise break energy | |
| 810 | - m_breakenergy.clear(); | |
| 811 | - m_breakenergy.name("BreakValue"); | |
| 812 | - m_breakenergy.unit("MeV"); | |
| 813 | - m_breakenergy.scale(1.0); | |
| 814 | - m_breakenergy.value(100.0); // default: 100 | |
| 815 | - m_breakenergy.fix(); | |
| 816 | - m_breakenergy.gradient(0.0); | |
| 817 | - m_breakenergy.hasgrad(true); | |
| 818 | - | |
| 819 | 816 | // Initialise powerlaw index2 |
| 820 | 817 | m_index2.clear(); |
| 821 | 818 | m_index2.name("Index2"); |
| ... | ... | @@ -826,6 +823,16 @@ void GModelSpectralBrokenPlaw::init_members(void) |
| 826 | 823 | m_index2.gradient(0.0); |
| 827 | 824 | m_index2.hasgrad(true); |
| 828 | 825 | |
| 826 | + // Initialise break energy | |
| 827 | + m_breakenergy.clear(); | |
| 828 | + m_breakenergy.name("BreakValue"); | |
| 829 | + m_breakenergy.unit("MeV"); | |
| 830 | + m_breakenergy.scale(1.0); | |
| 831 | + m_breakenergy.value(100.0); // default: 100 | |
| 832 | + m_breakenergy.fix(); | |
| 833 | + m_breakenergy.gradient(0.0); | |
| 834 | + m_breakenergy.hasgrad(true); | |
| 835 | + | |
| 829 | 836 | // Set parameter pointer(s) |
| 830 | 837 | m_pars.clear(); |
| 831 | 838 | m_pars.push_back(&m_norm); |
| ... | ... | @@ -925,8 +932,8 @@ void GModelSpectralBrokenPlaw::update_eval_cache(const GEnergy& energy) const |
| 925 | 932 | double breakenergy = m_breakenergy.value(); |
| 926 | 933 | double index2 = m_index2.value(); |
| 927 | 934 | |
| 928 | - // If the energy or one of the parameters index1, index2 or breakenergy energy has | |
| 929 | - // changed then recompute the cache | |
| 935 | + // If the energy or one of the parameters index1, index2 or breakenergy | |
| 936 | + // energy has changed then recompute the cache | |
| 930 | 937 | if ((m_last_energy != energy) || |
| 931 | 938 | (m_last_index1 != index1) || |
| 932 | 939 | (m_last_index2 != index2) || |
| ... | ... | @@ -942,7 +949,6 @@ void GModelSpectralBrokenPlaw::update_eval_cache(const GEnergy& energy) const |
| 942 | 949 | double eng = energy.MeV(); |
| 943 | 950 | m_last_e_norm = eng / m_last_breakenergy; |
| 944 | 951 | m_last_log_e_norm = std::log(m_last_e_norm); |
| 945 | - | |
| 946 | 952 | if (eng < m_last_breakenergy ) { |
| 947 | 953 | m_last_power = std::pow(m_last_e_norm, m_last_index1); |
| 948 | 954 | } |
| ... | ... | @@ -966,9 +972,9 @@ void GModelSpectralBrokenPlaw::update_eval_cache(const GEnergy& energy) const |
| 966 | 972 | * Updates the precomputation cache for Monte Carlo simulations. |
| 967 | 973 | ***************************************************************************/ |
| 968 | 974 | void GModelSpectralBrokenPlaw::update_mc_cache(const GEnergy& emin, |
| 969 | - const GEnergy& emax) const | |
| 970 | - | |
| 971 | -{ // Check if we need to update the cache | |
| 975 | + const GEnergy& emax) const | |
| 976 | +{ | |
| 977 | + // Check if we need to update the cache | |
| 972 | 978 | if (emin.MeV() != m_mc_emin || emax.MeV() != m_mc_emax) { |
| 973 | 979 | |
| 974 | 980 | // Store new energy interval |
| ... | ... | @@ -981,7 +987,6 @@ void GModelSpectralBrokenPlaw::update_mc_cache(const GEnergy& emin, |
| 981 | 987 | m_mc_max.clear(); |
| 982 | 988 | m_mc_exp.clear(); |
| 983 | 989 | |
| 984 | - | |
| 985 | 990 | // Get energy range in MeV |
| 986 | 991 | double e_min = emin.MeV(); |
| 987 | 992 | double e_max = emax.MeV(); |
| ... | ... | @@ -992,19 +997,20 @@ void GModelSpectralBrokenPlaw::update_mc_cache(const GEnergy& emin, |
| 992 | 997 | // Allocate flux |
| 993 | 998 | double flux; |
| 994 | 999 | |
| 995 | - // Determine left node index for minimum energy | |
| 1000 | + // Determine left node index for minimum and maximum energy | |
| 996 | 1001 | int inx_emin = (e_min < m_breakenergy.value() ) ? 0 : 1; |
| 997 | - // Determine left node index for maximum energy | |
| 998 | 1002 | int inx_emax = (e_max < m_breakenergy.value() ) ? 0 : 1; |
| 999 | 1003 | |
| 1000 | 1004 | // If both energies are within the same node then just |
| 1001 | 1005 | // add this one node on the stack |
| 1002 | 1006 | if (inx_emin == inx_emax) { |
| 1003 | - double exp_valid = (e_min < m_breakenergy.value()) ? m_index1.value() : m_index2.value(); | |
| 1004 | - flux = m_norm.value()*gammalib::plaw_photon_flux(e_min, | |
| 1005 | - e_max, | |
| 1006 | - m_breakenergy.value(), | |
| 1007 | - exp_valid); | |
| 1007 | + double exp_valid = (e_min < m_breakenergy.value()) | |
| 1008 | + ? m_index1.value() : m_index2.value(); | |
| 1009 | + flux = m_norm.value() * | |
| 1010 | + gammalib::plaw_photon_flux(e_min, | |
| 1011 | + e_max, | |
| 1012 | + m_breakenergy.value(), | |
| 1013 | + exp_valid); | |
| 1008 | 1014 | m_mc_cum.push_back(flux); |
| 1009 | 1015 | m_mc_min.push_back(e_min); |
| 1010 | 1016 | m_mc_max.push_back(e_max); |
| ... | ... | @@ -1014,27 +1020,28 @@ void GModelSpectralBrokenPlaw::update_mc_cache(const GEnergy& emin, |
| 1014 | 1020 | // ... otherwise integrate over both nodes |
| 1015 | 1021 | else { |
| 1016 | 1022 | // just enter the values for first pl: bin [0] |
| 1017 | - flux = m_norm.value()*gammalib::plaw_photon_flux(e_min, | |
| 1018 | - m_breakenergy.value(), | |
| 1019 | - m_breakenergy.value(), | |
| 1020 | - m_index1.value()); | |
| 1023 | + flux = m_norm.value() * | |
| 1024 | + gammalib::plaw_photon_flux(e_min, | |
| 1025 | + m_breakenergy.value(), | |
| 1026 | + m_breakenergy.value(), | |
| 1027 | + m_index1.value()); | |
| 1021 | 1028 | m_mc_cum.push_back(flux); |
| 1022 | 1029 | m_mc_exp.push_back(m_index1.value()); |
| 1023 | 1030 | m_mc_min.push_back(e_min); |
| 1024 | 1031 | m_mc_max.push_back(m_breakenergy.value()); |
| 1025 | 1032 | |
| 1026 | 1033 | // and for |
| 1027 | - flux = m_norm.value()*gammalib::plaw_photon_flux(m_breakenergy.value(), | |
| 1028 | - e_max, | |
| 1029 | - m_breakenergy.value(), | |
| 1030 | - m_index2.value()); | |
| 1034 | + flux = m_norm.value() * | |
| 1035 | + gammalib::plaw_photon_flux(m_breakenergy.value(), | |
| 1036 | + e_max, | |
| 1037 | + m_breakenergy.value(), | |
| 1038 | + m_index2.value()); | |
| 1031 | 1039 | m_mc_cum.push_back(flux); |
| 1032 | 1040 | m_mc_exp.push_back(m_index2.value()); |
| 1033 | 1041 | m_mc_max.push_back(e_max); |
| 1034 | 1042 | m_mc_min.push_back(m_breakenergy.value()); |
| 1035 | 1043 | } // endelse: emin and emax not between same nodes |
| 1036 | 1044 | |
| 1037 | - | |
| 1038 | 1045 | // Build cumulative distribution |
| 1039 | 1046 | for (int i = 1; i < m_mc_cum.size(); ++i) { |
| 1040 | 1047 | m_mc_cum[i] += m_mc_cum[i-1]; |
| ... | ... | @@ -1046,6 +1053,7 @@ void GModelSpectralBrokenPlaw::update_mc_cache(const GEnergy& emin, |
| 1046 | 1053 | |
| 1047 | 1054 | // Set MC values |
| 1048 | 1055 | for (int i = 0; i < m_mc_cum.size(); ++i) { |
| 1056 | + | |
| 1049 | 1057 | // Compute exponent |
| 1050 | 1058 | double exponent = m_mc_exp[i] + 1.0; |
| 1051 | 1059 | ... | ... |