GammaLib 2.0.0
Loading...
Searching...
No Matches
GModelSpectralGauss.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GModelSpectralGauss.cpp - Spectral Gaussian model class *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2014-2021 by Christoph Deil & Ellis Owen *
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 GModelSpectralGauss.cpp
23 * @brief Gaussian spectral model class implementation
24 * @author Christoph Deil & Ellis Owen
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include "GException.hpp"
32#include "GTools.hpp"
33#include "GMath.hpp"
34#include "GRan.hpp"
35#include "GFunction.hpp"
36#include "GIntegral.hpp"
39
40/* __ Constants __________________________________________________________ */
41
42/* __ Globals ____________________________________________________________ */
44const GModelSpectralRegistry g_spectral_gauss_registry(&g_spectral_gauss_seed);
45
46/* __ Method name definitions ____________________________________________ */
47#define G_FLUX "GModelSpectralGauss::flux(GEnergy&, GEnergy&)"
48#define G_EFLUX "GModelSpectralGauss::eflux(GEnergy&, GEnergy&)"
49#define G_MC "GModelSpectralGauss::mc(GEnergy&, GEnergy&, GRan&)"
50#define G_READ "GModelSpectralGauss::read(GXmlElement&)"
51#define G_WRITE "GModelSpectralGauss::write(GXmlElement&)"
52
53/* __ Macros _____________________________________________________________ */
54
55/* __ Coding definitions _________________________________________________ */
56
57/* __ Debug definitions __________________________________________________ */
58
59
60/*==========================================================================
61 = =
62 = Constructors/destructors =
63 = =
64 ==========================================================================*/
65
66/***********************************************************************//**
67 * @brief Void constructor
68 ***************************************************************************/
70{
71 // Initialise members
73
74 // Return
75 return;
76}
77
78
79/***********************************************************************//**
80 * @brief XML constructor
81 *
82 * @param[in] xml XML element.
83 *
84 * Constructs constant spectral model by extracting information from an XML
85 * element. See the read() method for more information about the expected
86 * structure of the XML element.
87 ***************************************************************************/
90{
91 // Initialise members
93
94 // Read information from XML element
95 read(xml);
96
97 // Return
98 return;
99}
100
101
102/***********************************************************************//**
103 * @brief Constructor
104 *
105 * @param[in] norm Total flux under Gaussian (in ph/cm2/s).
106 * @param[in] mean Mean energy.
107 * @param[in] sigma Energy width.
108 ***************************************************************************/
110 const GEnergy& mean,
111 const GEnergy& sigma) :
113{
114 // Initialise members
115 init_members();
116
117 // Set parameters
119 m_mean.value(mean.MeV());
121
122 // Autoscale parameters
123 autoscale();
124
125 // Return
126 return;
127}
128
129
130/***********************************************************************//**
131 * @brief Copy constructor
132 *
133 * @param[in] model Spectral Gaussian model.
134 ***************************************************************************/
136 GModelSpectral(model)
137{
138 // Initialise members
139 init_members();
140
141 // Copy members
142 copy_members(model);
143
144 // Return
145 return;
146}
147
148
149/***********************************************************************//**
150 * @brief Destructor
151 ***************************************************************************/
153{
154 // Free members
155 free_members();
156
157 // Return
158 return;
159}
160
161
162/*==========================================================================
163 = =
164 = Operators =
165 = =
166 ==========================================================================*/
167
168/***********************************************************************//**
169 * @brief Assignment operator
170 *
171 * @param[in] model Gauss spectral model.
172 * @return Gauss spectral model.
173 ***************************************************************************/
175{
176 // Execute only if object is not identical
177 if (this != &model) {
178
179 // Copy base class members
180 this->GModelSpectral::operator=(model);
181
182 // Free members
183 free_members();
184
185 // Initialise members
186 init_members();
187
188 // Copy members
189 copy_members(model);
190
191 } // endif: object was not identical
192
193 // Return
194 return *this;
195}
196
197
198/*==========================================================================
199 = =
200 = Public methods =
201 = =
202 ==========================================================================*/
203
204/***********************************************************************//**
205 * @brief Clear Gaussian spectral model
206 ***************************************************************************/
208{
209 // Free class members (base and derived classes, derived class first)
210 free_members();
212
213 // Initialise members
215 init_members();
216
217 // Return
218 return;
219}
220
221
222/***********************************************************************//**
223 * @brief Clone Gaussian spectral model
224 *
225 * @return Pointer to deep copy of Gaussian spectral model.
226 ***************************************************************************/
228{
229 // Clone Gaussian spectral model
230 return new GModelSpectralGauss(*this);
231}
232
233
234/***********************************************************************//**
235 * @brief Evaluate model value
236 *
237 * @param[in] srcEng True photon energy.
238 * @param[in] srcTime True photon arrival time.
239 * @param[in] gradients Compute gradients?
240 * @return Model value (ph/cm2/s/MeV).
241 *
242 * Evaluates
243 *
244 * \f[
245 * S_{\rm E}(E | t) = \frac{m\_norm}{\sqrt{2\pi}m\_sigma}
246 * \exp(\frac{-(E-m\_mean)^2}{2 m\_sigma^2})
247 * \f]
248 *
249 * where
250 * - \f${\tt m\_norm}\f$ is the normalization,
251 * - \f${\tt m\_mean}\f$ is the mean energy, and
252 * - \f${\tt m\_sigma}\f$ is the energy width.
253 *
254 * If the @p gradients flag is true the method will also compute the
255 * partial derivatives of the model with respect to the parameters using
256 *
257 * \f[
258 * \frac{\delta S_{\rm E}(E | t)}{\delta {\tt m\_norm}} =
259 * \frac{S_{\rm E}(E | t)}{{\tt m\_norm}}
260 * \f]
261 *
262 * \f[
263 * \frac{\delta S_{\rm E}(E | t)}{\delta {\tt m\_mean}} =
264 * S_{\rm E}(E | t) \frac{E-m\_mean}{m\_sigma^2}
265 * \f]
266 *
267 * \f[
268 * \frac{\delta S_{\rm E}(E | t)}{\delta {\tt m\_sigma}} =
269 * \frac{S_{\rm E}(E | t)}{{\tt m\_sigma}}
270 * \left( \frac{(E-m\_mean)^2}{m\_sigma^2} - 1 \right)
271 * \f]
272 ***************************************************************************/
274 const GTime& srcTime,
275 const bool& gradients) const
276{
277 // Get parameter values
278 double energy = srcEng.MeV();
279 double norm = m_norm.value();
280 double mean = m_mean.value();
281 double sigma = m_sigma.value();
282
283 // Compute function terms
284 double delta = energy - mean;
285 double sigma2 = sigma * sigma;
286 double term2 = (1.0 / sigma) * gammalib::inv_sqrt2pi;
287 double term1 = norm * term2;
288 double term3 = delta * delta / (2.0 * sigma2);
289 double term4 = delta / sigma2;
290 double term5 = (norm / sigma2) * gammalib::inv_sqrt2pi;
291 double eterm3 = std::exp(-term3);
292
293 // Compute function value
294 double value = term1 * eterm3;
295
296 // Optionally compute gradients
297 if (gradients) {
298
299 // Compute partial derivatives with respect to the parameter factor
300 // values (partial differentials were determined analytically).
301 double g_norm = (m_norm.is_free())
302 ? term2 * eterm3 * m_norm.scale() : 0.0;
303 double g_mean = (m_mean.is_free())
304 ? value * term4 * m_mean.scale() : 0.0;
305 double g_sigma = (m_sigma.is_free())
306 ? -term5 * eterm3 * (1.0 - (2.0 * term3)) * m_sigma.scale()
307 : 0.0;
308
309 // Set gradients
310 m_norm.factor_gradient(g_norm);
311 m_mean.factor_gradient(g_mean);
312 m_sigma.factor_gradient(g_sigma);
313
314 } // endif: gradient computation was requested
315
316 // Compile option: Check for NaN/Inf
317 #if defined(G_NAN_CHECK)
318 if (gammalib::is_notanumber(value) || gammalib::is_infinite(value)) {
319 std::cout << "*** ERROR: GModelSpectralGauss::eval";
320 std::cout << "(srcEng=" << srcEng;
321 std::cout << ", srcTime=" << srcTime << "):";
322 std::cout << " NaN/Inf encountered";
323 std::cout << " (value=" << value;
324 std::cout << ")" << std::endl;
325 }
326 #endif
327
328 // Return
329 return value;
330}
331
332
333/***********************************************************************//**
334 * @brief Returns model photon flux between [emin, emax] (ph/cm2/s)
335 *
336 * @param[in] emin Minimum photon energy.
337 * @param[in] emax Maximum photon energy.
338 * @return Photon flux (ph/cm2/s).
339 *
340 * Computes
341 *
342 * \f[
343 * \int_{\tt emin}^{\tt emax} S_{\rm E}(E | t) dE
344 * \f]
345 *
346 * where
347 * - [@p emin, @p emax] is an energy interval, and
348 * - \f$S_{\rm E}(E | t)\f$ is the spectral model (ph/cm2/s/MeV).
349 * The integration is done analytically.
350 ***************************************************************************/
352 const GEnergy& emax) const
353{
354 // Initialise flux
355 double flux = 0.0;
356
357 // Compute only if integration range is valid
358 if (emin < emax) {
359
360 // Precomputations
361 double energy_min = emin.MeV();
362 double energy_max = emax.MeV();
363 double norm = m_norm.value();
364 double mean = m_mean.value();
365 double sigma = m_sigma.value();
366 double zmin = (energy_min - mean) / sigma;
367 double zmax = (energy_max - mean) / sigma;
368
369 // Compute flux for a constant model
370 flux = norm * gammalib::gauss_integral(zmin, zmax);
371
372 } // endif: integration range was valid
373
374 // Return
375 return flux;
376}
377
378
379/***********************************************************************//**
380 * @brief Returns model energy flux between [emin, emax] (erg/cm2/s)
381 *
382 * @param[in] emin Minimum photon energy.
383 * @param[in] emax Maximum photon energy.
384 * @return Energy flux (erg/cm2/s).
385 *
386 * Computes
387 *
388 * \f[
389 * \int_{\tt emin}^{\tt emax} S_{\rm E}(E | t) E \, dE
390 * \f]
391 *
392 * where
393 * - [@p emin, @p emax] is an energy interval, and
394 * - \f$S_{\rm E}(E | t)\f$ is the spectral model (ph/cm2/s/MeV).
395 * The integration is done analytically.
396 ***************************************************************************/
398 const GEnergy& emax) const
399{
400 // Initialise flux
401 double eflux = 0.0;
402
403 // Compute only if integration range is valid
404 if (emin < emax) {
405
406 // Setup integration kernel
407 eflux_kernel integrand(m_norm.value(), m_mean.value(),
408 m_sigma.value());
409 GIntegral integral(&integrand);
410
411 // Get integration boundaries in MeV
412 double e_min = emin.MeV();
413 double e_max = emax.MeV();
414
415 // Perform integration
416 eflux = integral.romberg(e_min, e_max);
417
418 // Convert from MeV/cm2/s to erg/cm2/s
420
421 } // endif: integration range was valid
422
423 // Return
424 return eflux;
425}
426
427
428/***********************************************************************//**
429 * @brief Returns MC energy between [emin, emax]
430 *
431 * @param[in] emin Minimum photon energy.
432 * @param[in] emax Maximum photon energy.
433 * @param[in] time True photon arrival time.
434 * @param[in,out] ran Random number generator.
435 * @return Energy.
436 *
437 * @exception GException::erange_invalid
438 * Energy range is invalid (emin < emax required).
439 *
440 * Returns Monte Carlo energy by randomly drawing from a constant between
441 * the minimum and maximum photon energy.
442 *
443 * Method Used: Box-Muller transform, outlined here:
444 * http://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform
445 *
446 * Code from: http://www.design.caltech.edu/erik/Misc/Gaussian.html
447 ***************************************************************************/
449 const GEnergy& emax,
450 const GTime& time,
451 GRan& ran) const
452{
453 // Check energy interval
455
456 // Get energy boundaries in MeV
457 double xmax = emax.MeV();
458 double xmin = emin.MeV();
459
460 // Initialize return energy
461 double energy = 0.0;
462
463 // Sample until we find a value within the requested energy range
464 do {
465
466 // Compute random value
467 double val = ran.normal();
468
469 // Scale to specified width and shift by mean value
470 energy = m_sigma.value() * val + m_mean.value();
471
472 } while (energy < xmin || energy > xmax);
473
474
475 // Return energy
476 return GEnergy(energy, "MeV");
477}
478
479
480/***********************************************************************//**
481 * @brief Read model from XML element
482 *
483 * @param[in] xml XML element containing Gaussian model information.
484 *
485 * Read the spectral Gaussian information from an XML element.
486 * The format of the XML elements is:
487 *
488 * <spectrum type="Gaussian">
489 * <parameter name="Normalization" scale=".." value=".." min=".." max=".." free=".."/>
490 * <parameter name="Mean" scale=".." value=".." min=".." max=".." free=".."/>
491 * <parameter name="Sigma" scale=".." value=".." min=".." max=".." free=".."/>
492 * </spectrum>
493 *
494 ***************************************************************************/
496{
497 // Verify number of model parameters
499
500 // Get parameters
504
505 // Read parameters
506 m_norm.read(*norm);
507 m_mean.read(*mean);
509
510 // Return
511 return;
512}
513
514
515/***********************************************************************//**
516 * @brief Write model into XML element
517 *
518 * @param[in] xml XML element into which model information is written.
519 *
520 * Writes the spectral information into an XML element. The format of the XML
521 * element is
522 *
523 * <spectrum type="Gaussian">
524 * <parameter name="Normalization" scale=".." value=".." min=".." max=".." free=".."/>
525 * <parameter name="Mean" scale=".." value=".." min=".." max=".." free=".."/>
526 * <parameter name="Sigma" scale=".." value=".." min=".." max=".." free=".."/>
527 * </spectrum>
528 ***************************************************************************/
530{
531 // Verify model type
533
534 // Get XML parameters
538
539 // Write parameters
540 m_norm.write(*norm);
541 m_mean.write(*mean);
543
544 // Return
545 return;
546}
547
548
549/***********************************************************************//**
550 * @brief Print spectral model information
551 *
552 * @param[in] chatter Chattiness (defaults to NORMAL).
553 * @return String containing spectral model information.
554 ***************************************************************************/
555std::string GModelSpectralGauss::print(const GChatter& chatter) const
556{
557 // Initialise result string
558 std::string result;
559
560 // Continue only if chatter is not silent
561 if (chatter != SILENT) {
562
563 // Append header
564 result.append("=== GModelSpectralGauss ===");
565
566 // Append model content
567 result.append("\n"+gammalib::parformat("Number of parameters"));
568 result.append(gammalib::str(size()));
569 for (int i = 0; i < size(); ++i) {
570 result.append("\n"+m_pars[i]->print(chatter));
571 }
572
573 } // endif: chatter was not silent
574
575 // Return result
576 return result;
577}
578
579
580/*==========================================================================
581 = =
582 = Private methods =
583 = =
584 ==========================================================================*/
585
586/***********************************************************************//**
587 * @brief Initialise class members
588 ***************************************************************************/
590{
591 // Initialise normalisation
592 m_norm.clear();
593 m_norm.name("Normalization");
594 m_norm.unit("ph/cm2/s");
595 m_norm.scale(1.0);
596 m_norm.value(1.0); // default: 1.0
597 m_norm.min(0.0); // min: 0.0
598 m_norm.free();
599 m_norm.gradient(0.0);
600 m_norm.has_grad(false);
601
602 // Initialise mean energy
603 m_mean.clear();
604 m_mean.name("Mean");
605 m_mean.unit("MeV");
606 m_mean.scale(1.0);
607 m_mean.value(1000.0); // default: 1000.0
608 m_mean.min(0.001); // min: 0.001 MeV
609 m_mean.free();
610 m_mean.gradient(0.0);
611 m_mean.has_grad(false);
612
613 // Initialise energy width
614 m_sigma.clear();
615 m_sigma.name("Sigma");
616 m_sigma.unit("MeV");
617 m_sigma.scale(1.0);
618 m_sigma.value(100.0); // default: 100.0 MeV
619 m_sigma.min(0.0001); // min: 0.1 keV
620 m_sigma.free();
621 m_sigma.gradient(0.0);
622 m_sigma.has_grad(false);
623
624 // Set parameter pointer(s)
625 m_pars.clear();
626 m_pars.push_back(&m_norm);
627 m_pars.push_back(&m_mean);
628 m_pars.push_back(&m_sigma);
629
630 // Return
631 return;
632}
633
634
635/***********************************************************************//**
636 * @brief Copy class members
637 *
638 * @param[in] model Spectral constant model.
639 ***************************************************************************/
641{
642 // Copy members
643 m_norm = model.m_norm;
644 m_mean = model.m_mean;
645 m_sigma = model.m_sigma;
646
647 // Set parameter pointer(s)
648 m_pars.clear();
649 m_pars.push_back(&m_norm);
650 m_pars.push_back(&m_mean);
651 m_pars.push_back(&m_sigma);
652
653 // Return
654 return;
655}
656
657
658/***********************************************************************//**
659 * @brief Delete class members
660 ***************************************************************************/
662{
663 // Return
664 return;
665}
666
667/***********************************************************************//**
668 * @brief Kernel for energy flux integration
669 *
670 * @param[in] energy Energy (MeV).
671 ***************************************************************************/
672double GModelSpectralGauss::eflux_kernel::eval(const double& energy)
673{
674 // Evaluate function value
675 double delta = energy - m_mean;
676 double term1 = (m_norm / m_sigma) * gammalib::inv_sqrt2pi;
677 double term2 = delta * delta / (2.0 * m_sigma * m_sigma);
678 double value = term1 * std::exp(- term2);
679
680 // Return value
681 return value;
682}
#define G_WRITE
#define G_READ
Exception handler interface definition.
Single parameter function abstract base class definition.
Integration class interface definition.
Mathematical function definitions.
const GModelSpectralGauss g_spectral_gauss_seed
Gaussian spectral model class interface definition.
Spectral model registry class 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
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.
double eval(const double &eng)
Kernel for energy flux integration.
Gaussian spectral model class.
GModelPar m_sigma
Gaussian energy width.
GEnergy mean(void) const
Return mean energy.
GModelPar m_norm
Normalization factor.
virtual double flux(const GEnergy &emin, const GEnergy &emax) const
Returns model photon flux between [emin, emax] (ph/cm2/s)
virtual ~GModelSpectralGauss(void)
Destructor.
virtual std::string print(const GChatter &chatter=NORMAL) const
Print spectral model information.
virtual GEnergy mc(const GEnergy &emin, const GEnergy &emax, const GTime &time, GRan &ran) const
Returns MC energy between [emin, emax].
void init_members(void)
Initialise class members.
virtual void clear(void)
Clear Gaussian spectral model.
GModelPar m_mean
Gaussian mean energy.
GModelSpectralGauss(void)
Void constructor.
void copy_members(const GModelSpectralGauss &model)
Copy class members.
virtual double eval(const GEnergy &srcEng, const GTime &srcTime=GTime(), const bool &gradients=false) const
Evaluate model value.
void free_members(void)
Delete class members.
virtual GModelSpectralGauss * clone(void) const
Clone Gaussian spectral model.
virtual void write(GXmlElement &xml) const
Write model into XML element.
virtual std::string type(void) const
Return model type.
double norm(void) const
Return normalization.
virtual GModelSpectralGauss & operator=(const GModelSpectralGauss &model)
Assignment operator.
virtual void read(const GXmlElement &xml)
Read model from XML element.
virtual double eflux(const GEnergy &emin, const GEnergy &emax) const
Returns model energy flux between [emin, emax] (erg/cm2/s)
GEnergy sigma(void) const
Return energy width.
Interface definition for the spectral model registry class.
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.
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.
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.
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 normal(void)
Returns normal deviates.
Definition GRan.cpp:257
Time class.
Definition GTime.hpp:55
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
double gauss_integral(const double &x1, const double &x2)
Returns the integral of a Gaussian function.
Definition GMath.cpp:605
const double inv_sqrt2pi
Definition GMath.hpp:41
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