GammaLib 2.0.0
Loading...
Searching...
No Matches
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 ____________________________________________________________ */
42const GModelSpectralSuperExpPlaw g_spectral_seplaw_seed1("SuperExponentialCutoffPowerLaw",
43 "Prefactor",
44 "Index1",
45 "PivotEnergy",
46 "CutoffEnergy",
47 "Index2");
48const GModelSpectralRegistry g_spectral_seplaw_registry1(&g_spectral_seplaw_seed1);
49#if defined(G_LEGACY_XML_FORMAT)
50const GModelSpectralSuperExpPlaw g_spectral_seplaw_seed2("PLSuperExpCutoff",
51 "Prefactor",
52 "Index1",
53 "Scale",
54 "Cutoff",
55 "Index2");
56const 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
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
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
157 m_pivot.value(pivot.MeV()); // Internally stored in MeV
158 m_ecut.value(cutoff.MeV()); // Internally stored in MeV
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() *
386 std::log(m_last_e_cut) * m_last_exponent
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
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) {
579 eng = std::exp(std::log(u * m_mc_pow_ewidth + m_mc_pow_emin) /
581 }
582 else {
583 eng = 0.0;
584 }
585 }
586
587 // Case B: Index is -1
588 else {
589 eng = std::exp(u * m_mc_pow_ewidth + m_mc_pow_emin);
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);
636 m_ecut.read(*ecut);
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);
666 m_ecut.write(*ecut);
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 ***************************************************************************/
681std::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;
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();
896 std::exp(-m_last_exponent);
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;
939 m_mc_pow_emin = std::log(m_mc_emin);
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}
#define G_WRITE
#define G_READ
Exception handler interface definition.
Integration class interface definition.
Spectral model registry class definition.
const GModelSpectralSuperExpPlaw g_spectral_seplaw_seed1("SuperExponentialCutoffPowerLaw", "Prefactor", "Index1", "PivotEnergy", "CutoffEnergy", "Index2")
Super exponential cut off power law spectral class interface definition.
Random number generator class definition.
Gammalib tools definition.
GChatter
Definition GTypemaps.hpp:33
@ SILENT
Definition GTypemaps.hpp:34
double norm(const GVector &vector)
Computes vector norm.
Definition GVector.cpp:864
Class that handles energies in a unit independent way.
Definition GEnergy.hpp:48
double MeV(void) const
Return energy in MeV.
Definition GEnergy.cpp:321
std::string print(const GChatter &chatter=NORMAL) const
Print energy.
Definition GEnergy.cpp:748
void clear(void)
Clear instance.
Definition GEnergy.cpp:261
GIntegral class interface definition.
Definition GIntegral.hpp:46
double romberg(std::vector< double > bounds, const int &order=5)
Perform Romberg integration.
void write(GXmlElement &xml) const
Set or update parameter attributes in XML element.
void read(const GXmlElement &xml)
Extract parameter attributes from XML element.
Interface definition for the spectral model registry class.
double eval(const double &eng)
Kernel for energy flux integration.
double eval(const double &eng)
Kernel for photon flux integration.
Super exponential cut off power law spectral class.
virtual GModelSpectralSuperExpPlaw * clone(void) const
Clone super exponentially cut off power law model.
double prefactor(void) const
Return pre factor.
void update_eval_cache(const GEnergy &energy) const
Update eval precomputation cache.
double m_last_ecut
Last energy cut-off parameter.
virtual GModelSpectralSuperExpPlaw & operator=(const GModelSpectralSuperExpPlaw &model)
Assignment operator.
virtual void write(GXmlElement &xml) const
Write model into XML element.
void init_members(void)
Initialise class members.
virtual void read(const GXmlElement &xml)
Read model from XML element.
virtual ~GModelSpectralSuperExpPlaw(void)
Destructor.
GEnergy cutoff(void) const
Return exponential cut-off energy.
GModelSpectralSuperExpPlaw(void)
Void constructor.
double m_mc_pow_ewidth
Power of energy width.
double m_mc_pow_emin
Power of minimum energy.
void copy_members(const GModelSpectralSuperExpPlaw &model)
Copy class members.
virtual void clear(void)
Clear exponentially cut off power law model.
GEnergy m_last_energy
Last energy value.
virtual double flux(const GEnergy &emin, const GEnergy &emax) const
Returns model photon flux between [emin, emax] (units: ph/cm2/s)
void free_members(void)
Delete class members.
double m_last_pivot
Last pivot parameter.
virtual GEnergy mc(const GEnergy &emin, const GEnergy &emax, const GTime &time, GRan &ran) const
Returns MC energy between [emin, emax].
virtual double eval(const GEnergy &srcEng, const GTime &srcTime=GTime(), const bool &gradients=false) const
Evaluate function.
double index1(void) const
Return power law index.
double m_last_exponent
last pow(E/Ecut,index2) value
double m_last_index1
Last index1 parameter.
double index2(void) const
Return cut off index.
GEnergy pivot(void) const
Return pivot energy.
GModelPar m_ecut
Exponential cut off energy.
double m_last_e_norm
Last E/Epivot value.
void update_mc_cache(const GEnergy &emin, const GEnergy &emax) const
Update Monte Carlo pre computation cache.
virtual double eflux(const GEnergy &emin, const GEnergy &emax) const
Returns model energy flux between [emin, emax] (units: erg/cm2/s)
virtual std::string print(const GChatter &chatter=NORMAL) const
Print model information.
GModelPar m_norm
Normalization factor.
virtual std::string type(void) const
Return model type.
double m_last_index2
Last index2 parameter.
Abstract spectral model base class.
void free_members(void)
Delete class members.
virtual GModelSpectral & operator=(const GModelSpectral &model)
Assignment operator.
std::vector< GModelPar * > m_pars
Parameter pointers.
void autoscale(void)
Autoscale parameters.
int size(void) const
Return number of parameters.
void init_members(void)
Initialise class members.
const double & factor_value(void) const
Return parameter factor value.
bool is_free(void) const
Signal if parameter is free.
void free(void)
Free a parameter.
const double & scale(void) const
Return parameter scale.
bool has_grad(void) const
Signal if parameter gradient is computed analytically.
void range(const double &min, const double &max)
Set minimum and maximum parameter boundaries.
const std::string & unit(void) const
Return parameter unit.
double min(void) const
Return parameter minimum boundary.
const double & factor_gradient(void) const
Return parameter factor gradient.
void fix(void)
Fix a parameter.
double gradient(void) const
Return parameter gradient.
void clear(void)
Clear parameter.
double value(void) const
Return parameter value.
const std::string & name(void) const
Return parameter name.
Random number generator class.
Definition GRan.hpp:44
double uniform(void)
Returns random double precision floating value in range 0 to 1.
Definition GRan.cpp:242
Time class.
Definition GTime.hpp:55
std::string print(const GChatter &chatter=NORMAL) const
Print time.
Definition GTime.cpp:1188
XML element node class.
void check_energy_interval(const std::string &origin, const GEnergy &emin, const GEnergy &emax)
Checks energy interval.
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition GTools.cpp:1143
bool is_infinite(const double &x)
Signal if argument is infinite.
Definition GTools.hpp:184
bool is_notanumber(const double &x)
Signal if argument is not a number.
Definition GTools.hpp:201
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition GTools.cpp:489
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
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
void xml_check_parnum(const std::string &origin, const GXmlElement &xml, const int &number)
Checks number of parameters.
Definition GTools.cpp:1777
const double MeV2erg
Definition GTools.hpp:45
void xml_check_type(const std::string &origin, GXmlElement &xml, const std::string &type)
Checks the model type.
Definition GTools.cpp:1819