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