Commit de01eb121bb85f19300bad41b0d41bfba80bab14

Authored by Josh Cardenzana
1 parent af442cad

Resolved issues in MC generation for GModelSpectralSmoothBrokenPlaw (#1948)

Previously neglecting the appropriate handling in the CDF computation of the different indices above and below the break energy.
Now appropriately handles the case where (Emax < Ebreak) and (Emin > Ebreak).
include/GModelSpectralSmoothBrokenPlaw.hpp
... ... @@ -40,7 +40,6 @@ class GRan;
40 40 class GTime;
41 41 class GXmlElement;
42 42  
43   -// TODO: Updated class documentation
44 43 /***********************************************************************//**
45 44 * @class GModelSpectralSmoothBrokenPlaw
46 45 *
... ... @@ -50,17 +49,18 @@ class GXmlElement;
50 49 * defined by
51 50 *
52 51 * \f[
53   - * S_{\rm E}(E | t) = k_0 \times \left \{
54   - * \left( \frac{E}{E_b} \right)^{\gamma_2} & {\rm otherwise}
55   - * \right .
  52 + * S_{\rm E}(E | t) = k_0 \left( \frac{E}{E_0} \right)^{\gamma_1}
  53 + * \left[ 1 + \left( \frac{E}{E_b} \right)^{\frac{\gamma_1 - \gamma_2}{\beta}}
  54 + * \right]^{-\beta}
56 55 * \f]
57 56 *
58 57 * where
59 58 * \f$k_0\f$ is the normalization or prefactor,
60 59 * \f$\gamma_1\f$ is the spectral index before the break,
61   - * \f$\gamma_2\f$ is the spectral index after the break, and
62   - * \f$E_b\f$ is the break energy.
63   - * \f$\beta\f$ defines the break smoothness
  60 + * \f$\gamma_2\f$ is the spectral index after the break,
  61 + * \f$E_0\f$ is the pivot energy,
  62 + * \f$E_b\f$ is the break energy, and
  63 + * \f$\beta\f$ defines the break smoothness (larger = smoother transition)
64 64 ***************************************************************************/
65 65 class GModelSpectralSmoothBrokenPlaw : public GModelSpectral {
66 66  
... ... @@ -159,12 +159,12 @@ protected:
159 159  
160 160 // Members
161 161 protected:
162   - double m_prefactor; //!< Normalization
163   - double m_index1; //!< Spectral index1
164   - double m_index2; //!< Spectral index2
165   - GEnergy m_pivot; //!< Pivot energy
166   - GEnergy m_breakenergy; //!< Break energy
167   - double m_beta; //!< Break smoothness parameter
  162 + double m_prefactor; //!< Normalization
  163 + double m_index1; //!< Spectral index1
  164 + double m_index2; //!< Spectral index2
  165 + GEnergy m_pivot; //!< Pivot energy
  166 + GEnergy m_breakenergy; //!< Break energy
  167 + double m_beta; //!< Break smoothness parameter
168 168 };
169 169  
170 170 // Class to determine the integral energy flux, derivation of flux_kern
... ... @@ -216,6 +216,9 @@ protected:
216 216 mutable double m_mc_exponentH; //!< Exponent (index+1) for harder index
217 217 mutable double m_mc_pow_ewidth_low; //!< width of energy range below break
218 218 mutable double m_mc_norm; //!< Normalization term for energy generation
  219 + mutable double m_mc_exponent_ratio; //!< Ratio of (m_mc_exponentS/m_mc_exponentH)
  220 + mutable double m_mc_ebreak; //!< Break energy (depending on the energy range,
  221 + //!< this may not actually be the break energy)
219 222 };
220 223  
221 224  
... ...
src/model/GModelSpectralSmoothBrokenPlaw.cpp
... ... @@ -318,12 +318,9 @@ GModelSpectralSmoothBrokenPlaw* GModelSpectralSmoothBrokenPlaw::clone(void) cons
318 318 * Evaluates
319 319 *
320 320 * \f[
321   - * S_{\rm E}(E | t) = k_0 \times \left \{
322   - * \begin{eqnarray}
323   - * \left( \frac{E}{E_b} \right)^{\gamma_1} & {\rm if\,\,} E < E_b \\
324   - * \left( \frac{E}{E_b} \right)^{\gamma_2} & {\rm otherwise}
325   - * \end{eqnarray}
326   - * \right .
  321 + * S_{\rm E}(E | t) = k_0 \left( \frac{E}{E_0} \right)^{\gamma_1}
  322 + * \left[ 1 + \left( \frac{E}{E_b} \right)^{\frac{\gamma_1 - \gamma_2}{\beta}}
  323 + * \right]^{-\beta}
327 324 * \f]
328 325 *
329 326 * where
... ... @@ -394,11 +391,6 @@ double GModelSpectralSmoothBrokenPlaw::eval(const GEnergy&amp; srcEng,
394 391 ? value * m_index1.scale() * (m_last_log_epivot_norm -
395 392 ((m_last_ebreak_pow * m_last_log_ebreak_norm) /
396 393 (m_last_ebreak_pow + 1.0)))
397   - /*
398   - value * m_index1.scale() / (1.0+m_last_ebreak_pow) *
399   - (m_last_log_epivot_norm+(m_last_log_epivot_norm-m_last_log_ebreak_norm)*
400   - m_last_ebreak_pow)
401   - */
402 394 : 0.0;
403 395 double g_index2 = (m_index2.is_free())
404 396 ? value * m_index2.scale() * m_last_log_ebreak_norm *
... ... @@ -622,15 +614,18 @@ GEnergy GModelSpectralSmoothBrokenPlaw::mc(const GEnergy&amp; emin,
622 614 plaw = m_mc_plaw_prefactor * std::pow(e_norm, m_mc_exponentH-1.0);
623 615  
624 616 }
  617 +
625 618 // Case 2: indices are different (things are more complicated)
626 619 else {
627 620  
  621 + double break_u = m_mc_pow_ewidth_low/m_mc_norm;
  622 +
628 623 // Case 2A: Random number suggests energy less than breakenergy
629 624 if (u <= (m_mc_pow_ewidth_low/m_mc_norm)) {
630 625  
631 626 // Case 2A-1: Hard index is not -1
632 627 if (m_mc_exponentH != 0.0) {
633   - eng = std::exp(std::log(u * m_mc_norm +
  628 + eng = std::exp(std::log(u * m_mc_norm / m_mc_exponent_ratio +
634 629 std::pow(m_mc_emin, m_mc_exponentH)) / m_mc_exponentH);
635 630 }
636 631  
... ... @@ -649,13 +644,13 @@ GEnergy GModelSpectralSmoothBrokenPlaw::mc(const GEnergy&amp; emin,
649 644 // Case 2B-1: Soft index is not -1
650 645 if (m_mc_exponentS != 0.0) {
651 646 eng = std::exp(std::log(u * m_mc_norm +
652   - std::pow(breakenergy().MeV(), m_mc_exponentS) -
  647 + std::pow(m_mc_ebreak, m_mc_exponentS) -
653 648 m_mc_pow_ewidth_low) / m_mc_exponentS) ;
654 649 }
655 650 // Case 2B-2: Soft index is -1
656 651 else {
657 652 eng = std::exp(u * m_mc_norm +
658   - std::log(breakenergy().MeV()) -
  653 + std::log(m_mc_ebreak) -
659 654 m_mc_pow_ewidth_low);
660 655 }
661 656  
... ... @@ -894,6 +889,7 @@ void GModelSpectralSmoothBrokenPlaw::init_members(void)
894 889 m_mc_exponentH = 0.0;
895 890 m_mc_pow_ewidth_low = 0.0;
896 891 m_mc_norm = 0.0;
  892 + m_mc_exponent_ratio = 1.0;
897 893  
898 894 // Return
899 895 return;
... ... @@ -947,6 +943,7 @@ void GModelSpectralSmoothBrokenPlaw::copy_members(const GModelSpectralSmoothBrok
947 943 m_mc_exponentH = model.m_mc_exponentH;
948 944 m_mc_pow_ewidth_low = model.m_mc_pow_ewidth_low;
949 945 m_mc_norm = model.m_mc_norm;
  946 + m_mc_exponent_ratio = model.m_mc_exponent_ratio;
950 947  
951 948 // Return
952 949 return;
... ... @@ -1044,14 +1041,24 @@ void GModelSpectralSmoothBrokenPlaw::update_mc_cache(const GEnergy&amp; emin,
1044 1041  
1045 1042 // CASE: index1 is harder
1046 1043 if (index1() > index2()) {
1047   - m_mc_exponentH = index1() + 1.0 ; // Hard index + 1
1048   - m_mc_exponentS = index2() + 1.0 ; // Soft index + 1
1049   -
  1044 + m_mc_exponentH = index1() + 1.0; // Hard index + 1
  1045 + m_mc_exponentS = index2() + 1.0; // Soft index + 1
1050 1046 }
1051 1047 // CASE: index2 is harder, or index1==index2
1052 1048 else {
1053   - m_mc_exponentH = index2() + 1.0 ; // Hard index + 1
1054   - m_mc_exponentS = index1() + 1.0 ; // Soft index + 1
  1049 + m_mc_exponentH = index2() + 1.0; // Hard index + 1
  1050 + m_mc_exponentS = index1() + 1.0; // Soft index + 1
  1051 + }
  1052 +
  1053 + // Store the ratio of the two exponents
  1054 + m_mc_exponent_ratio = m_mc_exponentS / m_mc_exponentH;
  1055 +
  1056 + // Create a break energy variable that select the appropriate range
  1057 + m_mc_ebreak = breakenergy().MeV();
  1058 + if (m_mc_emax <= m_mc_ebreak) {
  1059 + m_mc_ebreak = m_mc_emax;
  1060 + } else if (m_mc_emin >= m_mc_ebreak) {
  1061 + m_mc_ebreak = m_mc_emin;
1055 1062 }
1056 1063  
1057 1064 // Now handle the cases where the hard exponent is -1
... ... @@ -1064,29 +1071,31 @@ void GModelSpectralSmoothBrokenPlaw::update_mc_cache(const GEnergy&amp; emin,
1064 1071 }
1065 1072 // CASE: Only harder exponent is -1
1066 1073 else {
1067   - m_mc_pow_ewidth_low = std::log(breakenergy().MeV()/m_mc_emin);
  1074 + m_mc_pow_ewidth_low = std::log(m_mc_ebreak/m_mc_emin);
1068 1075 m_mc_norm = m_mc_pow_ewidth_low + std::pow(m_mc_emax,m_mc_exponentS) -
1069   - std::pow(breakenergy().MeV(),m_mc_exponentS);
  1076 + std::pow(m_mc_ebreak,m_mc_exponentS);
1070 1077 }
1071 1078 }
1072 1079  
1073 1080 // CASE: Only softer exponent is -1
1074 1081 else if (m_mc_exponentS == 0.0) {
1075   - m_mc_pow_ewidth_low = std::pow(breakenergy().MeV(),m_mc_exponentH) -
  1082 + m_mc_pow_ewidth_low = std::pow(m_mc_ebreak,m_mc_exponentH) -
1076 1083 std::pow(m_mc_emin, m_mc_exponentH) ;
1077 1084 m_mc_norm = m_mc_pow_ewidth_low + std::log(m_mc_emax) -
1078   - std::log(breakenergy().MeV()) ;
  1085 + std::log(m_mc_ebreak) ;
1079 1086 }
1080 1087  
1081 1088 // CASE: Neither exponent is -1.
1082 1089 else {
  1090 +
1083 1091 // Get the width of the energy range below the break energy
1084   - m_mc_pow_ewidth_low = std::pow(breakenergy().MeV(), m_mc_exponentH) -
1085   - std::pow(m_mc_emin, m_mc_exponentH);
  1092 + m_mc_pow_ewidth_low = m_mc_exponent_ratio *
  1093 + (std::pow(m_mc_ebreak, m_mc_exponentH) -
  1094 + std::pow(m_mc_emin, m_mc_exponentH));
1086 1095  
1087 1096 // Get the normalization term
1088 1097 m_mc_norm = m_mc_pow_ewidth_low + (std::pow(m_mc_emax,m_mc_exponentS) -
1089   - std::pow(breakenergy().MeV(),m_mc_exponentS));
  1098 + std::pow(m_mc_ebreak,m_mc_exponentS));
1090 1099 }
1091 1100 } // endif: Update was required
1092 1101  
... ...