GammaLib  2.1.0.dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
GModelSpectralSuperExpPlaw.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * GModelSpectralSuperExpPlaw.cpp - Super exp. cut off power law model *
3  * ----------------------------------------------------------------------- *
4  * copyright (C) 2014-2021 by Michael Mayer *
5  * ----------------------------------------------------------------------- *
6  * *
7  * This program is free software: you can redistribute it and/or modify *
8  * it under the terms of the GNU General Public License as published by *
9  * the Free Software Foundation, either version 3 of the License, or *
10  * (at your option) any later version. *
11  * *
12  * This program is distributed in the hope that it will be useful, *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15  * GNU General Public License for more details. *
16  * *
17  * You should have received a copy of the GNU General Public License *
18  * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19  * *
20  ***************************************************************************/
21 /**
22  * @file GModelSpectralSuperExpPlaw.cpp
23  * @brief Super exponential cut off power law spectral class implementation
24  * @author Michael Mayer
25  */
26 
27 /* __ Includes ___________________________________________________________ */
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 #include <cmath>
32 #include "GException.hpp"
33 #include "GTools.hpp"
34 #include "GRan.hpp"
35 #include "GIntegral.hpp"
38 
39 /* __ Constants __________________________________________________________ */
40 
41 /* __ Globals ____________________________________________________________ */
42 const GModelSpectralSuperExpPlaw g_spectral_seplaw_seed1("SuperExponentialCutoffPowerLaw",
43  "Prefactor",
44  "Index1",
45  "PivotEnergy",
46  "CutoffEnergy",
47  "Index2");
48 const GModelSpectralRegistry g_spectral_seplaw_registry1(&g_spectral_seplaw_seed1);
49 #if defined(G_LEGACY_XML_FORMAT)
50 const GModelSpectralSuperExpPlaw g_spectral_seplaw_seed2("PLSuperExpCutoff",
51  "Prefactor",
52  "Index1",
53  "Scale",
54  "Cutoff",
55  "Index2");
56 const GModelSpectralRegistry g_spectral_seplaw_registry2(&g_spectral_seplaw_seed2);
57 #endif
58 
59 /* __ Method name definitions ____________________________________________ */
60 #define G_MC "GModelSpectralSuperExpPlaw::mc(GEnergy&, GEnergy&, GTime&,"\
61  " GRan&)"
62 #define G_READ "GModelSpectralSuperExpPlaw::read(GXmlElement&)"
63 #define G_WRITE "GModelSpectralSuperExpPlaw::write(GXmlElement&)"
64 
65 /* __ Macros _____________________________________________________________ */
66 
67 /* __ Coding definitions _________________________________________________ */
68 
69 /* __ Debug definitions __________________________________________________ */
70 //#define G_DEBUG_MC //!< Debug Monte-Carlo sampling
71 
72 
73 /*==========================================================================
74  = =
75  = Constructors/destructors =
76  = =
77  ==========================================================================*/
78 
79 /***********************************************************************//**
80  * @brief Void constructor
81  ***************************************************************************/
83 {
84  // Initialise members
85  init_members();
86 
87  // Return
88  return;
89 }
90 
91 
92 /***********************************************************************//**
93  * @brief Model type and parameter name constructor
94  *
95  * @param[in] type Model type.
96  * @param[in] prefactor Name of prefactor parameter.
97  * @param[in] index1 Name of index1 parameter.
98  * @param[in] pivot Name of pivot parameter.
99  * @param[in] cutoff Name of cutoff parameter.
100  * @param[in] index2 Name of index2 parameter.
101  ***************************************************************************/
103  const std::string& prefactor,
104  const std::string& index1,
105  const std::string& pivot,
106  const std::string& cutoff,
107  const std::string& index2) :
109 {
110  // Initialise members
111  init_members();
112 
113  // Set model type
114  m_type = type;
115 
116  // Set parameter names
117  m_norm.name(prefactor);
118  m_index1.name(index1);
119  m_pivot.name(pivot);
120  m_ecut.name(cutoff);
121  m_index2.name(index2);
122 
123  // Return
124  return;
125 }
126 
127 
128 /***********************************************************************//**
129  * @brief Constructor
130  *
131  * @param[in] prefactor Pre factor normalization (ph/cm2/s/MeV).
132  * @param[in] index1 Power law index.
133  * @param[in] pivot Pivot energy.
134  * @param[in] cutoff Cut off energy.
135  * @param[in] index2 index of cut off
136  *
137  * Construct an exponentially cut off power law from
138  * - a prefactor value (in units of ph/cm2/s/MeV)
139  * - a spectral index,
140  * - a pivot energy,
141  * - a cut off energy, and
142  * - a cut off exponent
143  ***************************************************************************/
145  const double& index1,
146  const GEnergy& pivot,
147  const GEnergy& cutoff,
148  const double& index2) :
150 {
151  // Initialise members
152  init_members();
153 
154  // Set parameters
155  m_norm.value(prefactor);
156  m_index1.value(index1);
157  m_pivot.value(pivot.MeV()); // Internally stored in MeV
158  m_ecut.value(cutoff.MeV()); // Internally stored in MeV
159  m_index2.value(index2);
160 
161  // Autoscale parameters
162  autoscale();
163 
164  // Return
165  return;
166 }
167 
168 
169 /***********************************************************************//**
170  * @brief XML constructor
171  *
172  * @param[in] xml XML element.
173  *
174  * Constructs an exponentially cut off power law spectral model by extracting
175  * information from an XML element. See the read() method for more
176  * information about the expected structure of the XML element.
177  ***************************************************************************/
180 {
181  // Initialise members
182  init_members();
183 
184  // Read information from XML element
185  read(xml);
186 
187  // Return
188  return;
189 }
190 
191 
192 /***********************************************************************//**
193  * @brief Copy constructor
194  *
195  * @param[in] model Super exponentially cut off power law model.
196  ***************************************************************************/
198  GModelSpectral(model)
199 {
200  // Initialise members
201  init_members();
202 
203  // Copy members
204  copy_members(model);
205 
206  // Return
207  return;
208 }
209 
210 
211 /***********************************************************************//**
212  * @brief Destructor
213  ***************************************************************************/
215 {
216  // Free members
217  free_members();
218 
219  // Return
220  return;
221 }
222 
223 
224 /*==========================================================================
225  = =
226  = Operators =
227  = =
228  ==========================================================================*/
229 
230 /***********************************************************************//**
231  * @brief Assignment operator
232  *
233  * @param[in] model Super exponentially cut off power law model.
234  * @return Super exponentially cut off power law model.
235  ***************************************************************************/
237 {
238  // Execute only if object is not identical
239  if (this != &model) {
240 
241  // Copy base class members
242  this->GModelSpectral::operator=(model);
243 
244  // Free members
245  free_members();
246 
247  // Initialise members
248  init_members();
249 
250  // Copy members
251  copy_members(model);
252 
253  } // endif: object was not identical
254 
255  // Return
256  return *this;
257 }
258 
259 
260 /*==========================================================================
261  = =
262  = Public methods =
263  = =
264  ==========================================================================*/
265 
266 /***********************************************************************//**
267  * @brief Clear exponentially cut off power law model
268  ***************************************************************************/
270 {
271  // Free class members (base and derived classes, derived class first)
272  free_members();
274 
275  // Initialise members
277  init_members();
278 
279  // Return
280  return;
281 }
282 
283 
284 /***********************************************************************//**
285  * @brief Clone super exponentially cut off power law model
286  *
287  * @return Pointer to deep copy of super exponentially cut off power law model.
288  ***************************************************************************/
290 {
291  // Clone exponentially cut off power law model
292  return new GModelSpectralSuperExpPlaw(*this);
293 }
294 
295 
296 /***********************************************************************//**
297  * @brief Evaluate function
298  *
299  * @param[in] srcEng True photon energy.
300  * @param[in] srcTime True photon arrival time.
301  * @param[in] gradients Compute gradients?
302  * @return Model value (ph/cm2/s/MeV).
303  *
304  * Evaluates
305  *
306  * \f[
307  * S_{\rm E}(E | t) = {\tt m\_norm}
308  * \left( \frac{E}{\tt m\_pivot} \right)^{\tt m\_index1}
309  * \exp \left( - \left( \frac{E}{\tt m\_ecut} \right)^{\tt m\_index2}
310  * \right)
311  * \f]
312  *
313  * where
314  * - \f${\tt m\_norm}\f$ is the normalization or prefactor,
315  * - \f${\tt m\_pivot}\f$ is the pivot energy,
316  * - \f${\tt m\_index1}\f$ is the spectral index
317  * - \f${\tt m\_ecut}\f$ is the cut off energy, and
318  * - \f${\tt m\_index2}\f$ is the index of the cut off.
319  *
320  * If the @p gradients flag is true the method will also compute the
321  * partial derivatives of the model with respect to the parameters using
322  *
323  * \f[
324  * \frac{\delta S_{\rm E}(E | t)}{\delta {\tt m\_norm}} =
325  * \frac{S_{\rm E}(E | t)}{{\tt m\_norm}}
326  * \f]
327  *
328  * \f[
329  * \frac{\delta S_{\rm E}(E | t)}{\delta {\tt m\_index1}} =
330  * S_{\rm E}(E | t) \, \ln(E/{\tt m_pivot})
331  * \f]
332  *
333  * \f[
334  * \frac{\delta S_{\rm E}(E | t)}{\delta {\tt m\_ecut}} =
335  * S_{\rm E}(E | t) \, \left( \frac{E}{{\tt m\_ecut}^{\tt m\_index2}} \right) \,
336  * \left(\frac{\tt m\_index2}{\tt m\_ecut}\right)
337  * \f]
338  *
339  * \f[
340  * \frac{\delta S_{\rm E}(E | t)}{\delta {\tt m\_index2}} =
341  * -S_{\rm E}(E | t) \, \ln \left(\frac{E}{\tt m\_ecut}\right)\,
342  * \left(\frac{E}{{\tt m\_ecut}^{\tt m\_index2}} \right)
343  * \f]
344  *
345  * \f[
346  * \frac{\delta S_{\rm E}(E | t)}{\delta {\tt m\_pivot}} =
347  * -S_{\rm E}(E | t) \,
348  * \left( \frac{\tt m\_index}{\tt m\_pivot} \right)
349  * \f]
350  *
351  * @todo The method expects that pivot!=0 and ecut!=0. Otherwise Inf or NaN
352  * may result. We should add a test that prevents using invalid
353  * values.
354  ***************************************************************************/
356  const GTime& srcTime,
357  const bool& gradients) const
358 {
359  // Update the evaluation cache
360  update_eval_cache(srcEng);
361 
362  // Compute function value
363  double value = m_norm.value() * m_last_power;
364 
365  // Optionally compute gradients
366  if (gradients) {
367 
368  // Compute partial derivatives with respect to the parameter factor
369  // values. The partial derivatives with respect to the parameter
370  // values are obtained by multiplication with the scale factor.
371  double g_norm = (m_norm.is_free())
373  : 0.0;
374  double g_index1 = (m_index1.is_free())
375  ? value * m_index1.scale() * std::log(m_last_e_norm)
376  : 0.0;
377  double g_ecut = (m_ecut.is_free() && m_ecut.factor_value() != 0.0)
378  ? value * m_last_index2 * m_last_exponent /
380  : 0.0;
381  double g_pivot = (m_pivot.is_free() && m_pivot.factor_value() != 0.0)
382  ? -value * m_last_index1 / m_pivot.factor_value()
383  : 0.0;
384  double g_index2 = (m_index2.is_free())
385  ? -value * m_index2.scale() *
387  : 0.0;
388 
389  // Set gradients
390  m_norm.factor_gradient(g_norm);
391  m_index1.factor_gradient(g_index1);
392  m_ecut.factor_gradient(g_ecut);
393  m_pivot.factor_gradient(g_pivot);
394  m_index2.factor_gradient(g_index2);
395 
396  } // endif: gradient computation was requested
397 
398  // Compile option: Check for NaN/Inf
399  #if defined(G_NAN_CHECK)
400  if (gammalib::is_notanumber(value) || gammalib::is_infinite(value)) {
401  std::cout << "*** ERROR: GModelSpectralSuperExpPlaw::eval";
402  std::cout << "(srcEng=" << srcEng;
403  std::cout << ", srcTime=" << srcTime << "):";
404  std::cout << " NaN/Inf encountered";
405  std::cout << " (value=" << value;
406  std::cout << ", power=" << m_last_power;
407  std::cout << ")" << std::endl;
408  }
409  #endif
410 
411  // Return
412  return value;
413 }
414 
415 
416 /***********************************************************************//**
417  * @brief Returns model photon flux between [emin, emax] (units: ph/cm2/s)
418  *
419  * @param[in] emin Minimum photon energy.
420  * @param[in] emax Maximum photon energy.
421  * @return Photon flux (ph/cm2/s).
422  *
423  * Computes
424  *
425  * \f[
426  * \int_{\tt emin}^{\tt emax} S_{\rm E}(E | t) dE
427  * \f]
428  *
429  * where
430  * - [@p emin, @p emax] is an energy interval, and
431  * - \f$S_{\rm E}(E | t)\f$ is the spectral model (ph/cm2/s/MeV).
432  * The integration is done numerically.
433  ***************************************************************************/
435  const GEnergy& emax) const
436 {
437  // Initialise flux
438  double flux = 0.0;
439 
440  // Compute only if integration range is valid
441  if (emin < emax) {
442 
443  // Setup integration kernel
444  flux_kernel integrand(m_norm.value(), m_index1.value(),
446  GIntegral integral(&integrand);
447 
448  // Get integration boundaries in MeV
449  double e_min = emin.MeV();
450  double e_max = emax.MeV();
451 
452  // Perform integration
453  flux = integral.romberg(e_min, e_max);
454 
455  } // endif: integration range was valid
456 
457  // Return
458  return flux;
459 }
460 
461 
462 /***********************************************************************//**
463  * @brief Returns model energy flux between [emin, emax] (units: erg/cm2/s)
464  *
465  * @param[in] emin Minimum photon energy.
466  * @param[in] emax Maximum photon energy.
467  * @return Energy flux (erg/cm2/s).
468  *
469  * Computes
470  *
471  * \f[
472  * \int_{\tt emin}^{\tt emax} S_{\rm E}(E | t) E \, dE
473  * \f]
474  *
475  * where
476  * - [@p emin, @p emax] is an energy interval, and
477  * - \f$S_{\rm E}(E | t)\f$ is the spectral model (ph/cm2/s/MeV).
478  * The integration is done numerically.
479  ***************************************************************************/
481  const GEnergy& emax) const
482 {
483  // Initialise flux
484  double eflux = 0.0;
485 
486  // Compute only if integration range is valid
487  if (emin < emax) {
488 
489  // Setup integration kernel
490  eflux_kernel integrand(m_norm.value(), m_index1.value(),
492  GIntegral integral(&integrand);
493 
494  // Get integration boundaries in MeV
495  double e_min = emin.MeV();
496  double e_max = emax.MeV();
497 
498  // Perform integration
499  eflux = integral.romberg(e_min, e_max);
500 
501  // Convert from MeV/cm2/s to erg/cm2/s
502  eflux *= gammalib::MeV2erg;
503 
504  } // endif: integration range was valid
505 
506  // Return
507  return eflux;
508 }
509 
510 
511 /***********************************************************************//**
512  * @brief Returns MC energy between [emin, emax]
513  *
514  * @param[in] emin Minimum photon energy.
515  * @param[in] emax Maximum photon energy.
516  * @param[in] time True photon arrival time.
517  * @param[in,out] ran Random number generator.
518  * @return Energy.
519  *
520  * Simulates a random energy in the interval [emin, emax] for an
521  * exponentially cut off power law. The simulation is done using a rejection
522  * method. First, a random energy within [emin, emax] is drawn from an
523  * power law distribution. Then the energy is accepted or rejected based
524  * on an acceptance fraction that is computed from the exponential cut off.
525  ***************************************************************************/
527  const GEnergy& emax,
528  const GTime& time,
529  GRan& ran) const
530 {
531  // Check energy interval
533 
534  // Allocate energy
535  GEnergy energy;
536 
537  // Update cache
538  update_mc_cache(emin, emax);
539 
540  // Initialise energy
541  double eng;
542 
543  // Initialise acceptance fraction
544  double acceptance_fraction;
545  double inv_ecut = 1.0 / m_ecut.value();
546 
547  // Compute random number generator normalisation for speed-up of the
548  // computations. Normally it should be sufficient to always use the
549  // minimum energy for the normalisation, yet for the case that the model
550  // grows with energy we better also test the maximum energy, and we
551  // just use the larger of both normalisations
552  double norm_emin = std::exp(- std::pow(emin.MeV() * inv_ecut, m_index2.value()));
553  double norm_emax = std::exp(- std::pow(emax.MeV() * inv_ecut, m_index2.value()));
554  double norm = (norm_emin > norm_emax) ? norm_emin : norm_emax;
555 
556  // Debug option: initialise number of samples
557  #if defined(G_DEBUG_MC)
558  int samples = 0;
559  #endif
560 
561  // Use rejection method to draw a random energy. We first draw
562  // analytically from a power law, and then compare the power law
563  // at the drawn energy to the exponentially cut off function. This
564  // gives an acceptance fraction, and we accept the energy only if
565  // a uniform random number is <= the acceptance fraction.
566  do {
567 
568  // Debug option: increment number of samples
569  #if defined(G_DEBUG_MC)
570  samples++;
571  #endif
572 
573  // Get uniform random number
574  double u = ran.uniform();
575 
576  // Case A: Index is not -1
577  if (index1() != -1.0) {
578  if (u > 0.0) {
580  m_mc_exponent);
581  }
582  else {
583  eng = 0.0;
584  }
585  }
586 
587  // Case B: Index is -1
588  else {
590  }
591 
592  // Compute acceptance fraction
593  acceptance_fraction = std::exp(- std::pow(eng * inv_ecut, m_index2.value()));
594 
595  } while (ran.uniform() * norm > acceptance_fraction);
596 
597  // Set energy
598  energy.MeV(eng);
599 
600  // Debug option: write result
601  #if defined(G_DEBUG_MC)
602  std::cout << "GModelSpectralSuperExpPlaw::mc(";
603  std::cout << emin.print() << "," << emax.print() << "," << time.print() << "):";
604  std::cout << " energy=" << energy.print();
605  std::cout << " samples=" << samples << std::endl;
606  #endif
607 
608  // Return energy
609  return energy;
610 }
611 
612 
613 /***********************************************************************//**
614  * @brief Read model from XML element
615  *
616  * @param[in] xml XML element.
617  *
618  * Reads the spectral information from an XML element.
619  ***************************************************************************/
621 {
622  // Verify number of model parameters
624 
625  // Get parameter pointers
629  const GXmlElement* ecut = gammalib::xml_get_par(G_READ, xml, m_ecut.name());
631 
632  // Read parameters
633  m_norm.read(*norm);
634  m_index1.read(*index1);
635  m_index2.read(*index2);
636  m_ecut.read(*ecut);
637  m_pivot.read(*pivot);
638 
639  // Return
640  return;
641 }
642 
643 
644 /***********************************************************************//**
645  * @brief Write model into XML element
646  *
647  * @param[in] xml XML element.
648  *
649  * Writes the spectral information into an XML element.
650  ***************************************************************************/
652 {
653  // Verify model type
655 
656  // Get XML parameters
662 
663  // Write parameters
664  m_norm.write(*norm);
665  m_index1.write(*index1);
666  m_ecut.write(*ecut);
667  m_index2.write(*index2);
668  m_pivot.write(*pivot);
669 
670  // Return
671  return;
672 }
673 
674 
675 /***********************************************************************//**
676  * @brief Print model information
677  *
678  * @param[in] chatter Chattiness (defaults to NORMAL).
679  * @return String containing model information.
680  ***************************************************************************/
681 std::string GModelSpectralSuperExpPlaw::print(const GChatter& chatter) const
682 {
683  // Initialise result string
684  std::string result;
685 
686  // Continue only if chatter is not silent
687  if (chatter != SILENT) {
688 
689  // Append header
690  result.append("=== GModelSpectralSuperExpPlaw ===");
691 
692  // Append information
693  result.append("\n"+gammalib::parformat("Number of parameters"));
694  result.append(gammalib::str(size()));
695  for (int i = 0; i < size(); ++i) {
696  result.append("\n"+m_pars[i]->print(chatter));
697  }
698 
699  } // endif: chatter was not silent
700 
701  // Return result
702  return result;
703 }
704 
705 
706 /*==========================================================================
707  = =
708  = Private methods =
709  = =
710  ==========================================================================*/
711 
712 /***********************************************************************//**
713  * @brief Initialise class members
714  ***************************************************************************/
716 {
717  // Initialise model type
718  m_type = "SuperExponentialCutoffPowerLaw";
719 
720  // Initialise powerlaw normalisation
721  m_norm.clear();
722  m_norm.name("Prefactor");
723  m_norm.unit("ph/cm2/s/MeV");
724  m_norm.scale(1.0);
725  m_norm.value(1.0); // default: 1.0
726  m_norm.min(0.0); // min: 0.0
727  m_norm.free();
728  m_norm.gradient(0.0);
729  m_norm.has_grad(true);
730 
731  // Initialise powerlaw index
732  m_index1.clear();
733  m_index1.name("Index1");
734  m_index1.scale(1.0);
735  m_index1.value(-2.0); // default: -2.0
736  m_index1.range(-10.0,+10.0); // range: [-10,+10]
737  m_index1.free();
738  m_index1.gradient(0.0);
739  m_index1.has_grad(true);
740 
741  // Initialise cut off energy
742  m_ecut.clear();
743  m_ecut.name("CutoffEnergy");
744  m_ecut.unit("MeV");
745  m_ecut.scale(1.0);
746  m_ecut.value(1000.0); // default: 1000.0
747  m_ecut.min(0.1); // min: 0.1
748  m_ecut.free();
749  m_ecut.gradient(0.0);
750  m_ecut.has_grad(true);
751 
752  // Initialise pivot energy
753  m_pivot.clear();
754  m_pivot.name("PivotEnergy");
755  m_pivot.unit("MeV");
756  m_pivot.scale(1.0);
757  m_pivot.value(100.0);
758  m_pivot.fix();
759  m_pivot.gradient(0.0);
760  m_pivot.has_grad(true);
761 
762  // Initialise index2
763  m_index2.clear();
764  m_index2.name("Index2");
765  m_index2.scale(1.0);
766  m_index2.value(1.0); // default: -2.0
767  m_index2.range(0.0,5.0); // range: [0,5]
768  m_index2.free();
769  m_index2.gradient(0.0);
770  m_index2.has_grad(true);
771 
772  // Set parameter pointer(s)
773  m_pars.clear();
774  m_pars.push_back(&m_norm);
775  m_pars.push_back(&m_index1);
776  m_pars.push_back(&m_ecut);
777  m_pars.push_back(&m_pivot);
778  m_pars.push_back(&m_index2);
779 
780  // Initialise eval cache
782  m_last_index1 = 1.0e30;
783  m_last_ecut = 1.0e30;
784  m_last_pivot = 1.0e30;
785  m_last_index2 = 1.0e30;
786  m_last_e_norm = 0.0;
787  m_last_e_cut = 0.0;
788  m_last_power = 0.0;
789  m_last_exponent = 0.0;
790 
791  // Initialise MC cache
792  m_mc_emin = 0.0;
793  m_mc_emax = 0.0;
794  m_mc_exponent = 0.0;
795  m_mc_pow_emin = 0.0;
796  m_mc_pow_ewidth = 0.0;
797 
798  // Return
799  return;
800 }
801 
802 
803 /***********************************************************************//**
804  * @brief Copy class members
805  *
806  * @param[in] model Exponential cut off power law model.
807  ***************************************************************************/
809 {
810  // Copy members
811  m_type = model.m_type;
812  m_norm = model.m_norm;
813  m_index1 = model.m_index1;
814  m_ecut = model.m_ecut;
815  m_pivot = model.m_pivot;
816  m_index2 = model.m_index2;
817 
818  // Set parameter pointer(s)
819  m_pars.clear();
820  m_pars.push_back(&m_norm);
821  m_pars.push_back(&m_index1);
822  m_pars.push_back(&m_ecut);
823  m_pars.push_back(&m_pivot);
824  m_pars.push_back(&m_index2);
825 
826  // Copy eval cache
829  m_last_ecut = model.m_last_ecut;
830  m_last_pivot = model.m_last_pivot;
833  m_last_e_cut = model.m_last_e_cut;
834  m_last_power = model.m_last_power;
836 
837  // Copy MC cache
838  m_mc_emin = model.m_mc_emin;
839  m_mc_emax = model.m_mc_emax;
843 
844  // Return
845  return;
846 }
847 
848 
849 /***********************************************************************//**
850  * @brief Delete class members
851  ***************************************************************************/
853 {
854  // Return
855  return;
856 }
857 
858 
859 /***********************************************************************//**
860  * @brief Update eval precomputation cache
861  *
862  * @param[in] energy Energy.
863  *
864  * Updates the precomputation cache for eval() method.
865  ***************************************************************************/
867 {
868  // Get parameter values (takes 3 multiplications which are difficult
869  // to avoid)
870  double index1 = m_index1.value();
871  double ecut = m_ecut.value();
872  double pivot = m_pivot.value();
873  double index2 = m_index2.value();
874 
875  // If the energy or one of the parameters index1, index2, cut-off or pivot
876  // energy has changed then recompute the cache
877  if ((m_last_energy != energy) ||
878  (m_last_index1 != index1) ||
879  (m_last_ecut != ecut) ||
880  (m_last_pivot != pivot) ||
881  (m_last_index2 != index2)) {
882 
883  // Store actual energy and parameter values
884  m_last_energy = energy;
886  m_last_ecut = ecut;
889 
890  // Compute and store value
891  double eng = energy.MeV();
892  m_last_e_norm = eng / m_last_pivot;
893  m_last_e_cut = eng / m_last_ecut;
897 
898  } // endif: recomputation was required
899 
900  // Return
901  return;
902 }
903 
904 
905 /***********************************************************************//**
906  * @brief Update Monte Carlo pre computation cache
907  *
908  * @param[in] emin Minimum photon energy.
909  * @param[in] emax Maximum photon energy.
910  *
911  * Updates the precomputation cache for Monte Carlo simulations.
912  ***************************************************************************/
914  const GEnergy& emax) const
915 
916 {
917  // Case A: Index is not -1
918  if (index1() != -1.0) {
919 
920  // Change in energy boundaries?
921  if (emin.MeV() != m_mc_emin || emax.MeV() != m_mc_emax) {
922  m_mc_emin = emin.MeV();
923  m_mc_emax = emax.MeV();
924  m_mc_exponent = index1() + 1.0;
927  }
928 
929  }
930 
931  // Case B: Index is -1
932  else {
933 
934  // Change in energy boundaries?
935  if (emin.MeV() != m_mc_emin || emax.MeV() != m_mc_emax) {
936  m_mc_emin = emin.MeV();
937  m_mc_emax = emax.MeV();
938  m_mc_exponent = 0.0;
941  }
942 
943  }
944 
945  // Return
946  return;
947 }
948 
949 
950 /***********************************************************************//**
951  * @brief Kernel for photon flux integration
952  *
953  * @param[in] energy Energy (MeV).
954  ***************************************************************************/
956 {
957  // Evaluate function value
958  double e_norm = energy * m_inv_pivot;
959  double e_cut = energy * m_inv_ecut;
960  double exponent = std::pow(e_cut, m_index2);
961  double power = std::pow(e_norm, m_index1) * std::exp(-exponent);
962  double value = m_norm * power;
963 
964  // Return value
965  return value;
966 }
967 
968 
969 /***********************************************************************//**
970  * @brief Kernel for energy flux integration
971  *
972  * @param[in] energy Energy (MeV).
973  ***************************************************************************/
975 {
976  // Evaluate function value
977  double e_norm = energy * m_inv_pivot;
978  double e_cut = energy * m_inv_ecut;
979  double exponent = std::pow(e_cut, m_index2);
980  double power = std::pow(e_norm, m_index1) * std::exp(-exponent);
981  double value = m_norm * power * energy;
982 
983  // Return value
984  return value;
985 }
const GModelSpectralSuperExpPlaw g_spectral_seplaw_seed1("SuperExponentialCutoffPowerLaw","Prefactor","Index1","PivotEnergy","CutoffEnergy","Index2")
void free_members(void)
Delete class members.
GModelPar m_index2
Index of cutoff.
const double & factor_gradient(void) const
Return parameter factor gradient.
double norm(const GVector &vector)
Computes vector norm.
Definition: GVector.cpp:864
double eval(const double &eng)
Kernel for energy flux integration.
GModelPar m_ecut
Exponential cut off energy.
const std::string & name(void) const
Return parameter name.
Random number generator class definition.
virtual void clear(void)
Clear exponentially cut off power law model.
Abstract spectral model base class.
void update_mc_cache(const GEnergy &emin, const GEnergy &emax) const
Update Monte Carlo pre computation cache.
double gradient(void) const
Return parameter gradient.
double m_last_exponent
last pow(E/Ecut,index2) value
int size(void) const
Return number of parameters.
GEnergy pivot(void) const
Return pivot energy.
virtual GModelSpectral & operator=(const GModelSpectral &model)
Assignment operator.
void write(GXmlElement &xml) const
Set or update parameter attributes in XML element.
Definition: GModelPar.cpp:351
virtual double flux(const GEnergy &emin, const GEnergy &emax) const
Returns model photon flux between emin, emax
std::vector< GModelPar * > m_pars
Parameter pointers.
double m_last_index2
Last index2 parameter.
void update_eval_cache(const GEnergy &energy) const
Update eval precomputation cache.
double m_last_e_norm
Last E/Epivot value.
virtual std::string type(void) const
Return model type.
double m_mc_pow_ewidth
Power of energy width.
XML element node class.
Definition: GXmlElement.hpp:48
Spectral model registry class definition.
Random number generator class.
Definition: GRan.hpp:44
virtual double eval(const GEnergy &srcEng, const GTime &srcTime=GTime(), const bool &gradients=false) const
Evaluate function.
double MeV(void) const
Return energy in MeV.
Definition: GEnergy.cpp:321
Time class.
Definition: GTime.hpp:55
Gammalib tools definition.
GIntegral class interface definition.
Definition: GIntegral.hpp:46
void init_members(void)
Initialise class members.
double min(void) const
Return parameter minimum boundary.
bool is_free(void) const
Signal if parameter is free.
void copy_members(const GModelSpectralSuperExpPlaw &model)
Copy class members.
virtual void read(const GXmlElement &xml)
Read model from XML element.
bool is_notanumber(const double &x)
Signal if argument is not a number.
Definition: GTools.hpp:201
const double & scale(void) const
Return parameter scale.
bool is_infinite(const double &x)
Signal if argument is infinite.
Definition: GTools.hpp:184
virtual GModelSpectralSuperExpPlaw * clone(void) const
Clone super exponentially cut off power law model.
virtual ~GModelSpectralSuperExpPlaw(void)
Destructor.
GEnergy m_last_energy
Last energy value.
Super exponential cut off power law spectral class interface definition.
virtual std::string print(const GChatter &chatter=NORMAL) const
Print model information.
bool has_grad(void) const
Signal if parameter gradient is computed analytically.
virtual void write(GXmlElement &xml) const
Write model into XML element.
double m_mc_pow_emin
Power of minimum energy.
std::string print(const GChatter &chatter=NORMAL) const
Print energy.
Definition: GEnergy.cpp:748
void free(void)
Free a parameter.
#define G_WRITE
GModelPar m_norm
Normalization factor.
void fix(void)
Fix a parameter.
double m_last_pivot
Last pivot parameter.
GXmlElement * xml_need_par(const std::string &origin, GXmlElement &xml, const std::string &name)
Return pointer to parameter with given name in XML element.
Definition: GTools.cpp:1637
GVector log(const GVector &vector)
Computes natural logarithm of vector elements.
Definition: GVector.cpp:1274
double uniform(void)
Returns random double precision floating value in range 0 to 1.
Definition: GRan.cpp:242
void check_energy_interval(const std::string &origin, const GEnergy &emin, const GEnergy &emax)
Checks energy interval.
Definition: GException.cpp:364
void clear(void)
Clear parameter.
double eval(const double &eng)
Kernel for photon flux integration.
GChatter
Definition: GTypemaps.hpp:33
GModelSpectralSuperExpPlaw(void)
Void constructor.
std::string print(const GChatter &chatter=NORMAL) const
Print time.
Definition: GTime.cpp:1188
void xml_check_parnum(const std::string &origin, const GXmlElement &xml, const int &number)
Checks number of parameters.
Definition: GTools.cpp:1777
Interface definition for the spectral model registry class.
void autoscale(void)
Autoscale parameters.
#define G_READ
void init_members(void)
Initialise class members.
const double MeV2erg
Definition: GTools.hpp:45
void range(const double &min, const double &max)
Set minimum and maximum parameter boundaries.
void read(const GXmlElement &xml)
Extract parameter attributes from XML element.
Definition: GModelPar.cpp:229
double value(void) const
Return parameter value.
virtual GModelSpectralSuperExpPlaw & operator=(const GModelSpectralSuperExpPlaw &model)
Assignment operator.
virtual double eflux(const GEnergy &emin, const GEnergy &emax) const
Returns model energy flux between emin, emax
double m_last_e_cut
Last E/Ecut value.
const std::string & unit(void) const
Return parameter unit.
GVector pow(const GVector &vector, const double &power)
Computes tanh of vector elements.
Definition: GVector.cpp:1422
double m_last_ecut
Last energy cut-off parameter.
Exception handler interface definition.
Super exponential cut off power law spectral class.
GVector exp(const GVector &vector)
Computes exponential of vector elements.
Definition: GVector.cpp:1232
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition: GTools.cpp:1143
Integration class interface definition.
virtual GEnergy mc(const GEnergy &emin, const GEnergy &emax, const GTime &time, GRan &ran) const
Returns MC energy between [emin, emax].
double m_mc_exponent
Exponent (index+1)
double index2(void) const
Return cut off index.
double m_last_index1
Last index1 parameter.
const GXmlElement * xml_get_par(const std::string &origin, const GXmlElement &xml, const std::string &name)
Return pointer to parameter with given name in XML element.
Definition: GTools.cpp:1689
void free_members(void)
Delete class members.
double index1(void) const
Return power law index.
void clear(void)
Clear instance.
Definition: GEnergy.cpp:261
const double & factor_value(void) const
Return parameter factor value.
Class that handles energies in a unit independent way.
Definition: GEnergy.hpp:48
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition: GTools.cpp:489
void xml_check_type(const std::string &origin, GXmlElement &xml, const std::string &type)
Checks the model type.
Definition: GTools.cpp:1819