GammaLib 2.0.0
Loading...
Searching...
No Matches
GModelSpatialRadialGeneralGauss.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GModelSpatialRadialGeneralGauss.cpp - Generalised radial Gaussian *
3 * source model class *
4 * ----------------------------------------------------------------------- *
5 * copyright (C) 2021-2022 by Luigi Tibaldo *
6 * ----------------------------------------------------------------------- *
7 * *
8 * This program is free software: you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation, either version 3 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This program is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
20 * *
21 ***************************************************************************/
22/**
23 * @file GModelSpatialRadialGeneralGauss.cpp
24 * @brief Radial Generallized Gaussian model class implementation
25 * @author Luigi Tibaldo
26 */
27
28/* __ Includes ___________________________________________________________ */
29#ifdef HAVE_CONFIG_H
30#include <config.h>
31#endif
32#include "GException.hpp"
33#include "GTools.hpp"
34#include "GMath.hpp"
37
38/* __ Constants __________________________________________________________ */
39
40/* __ Globals ____________________________________________________________ */
42const GModelSpatialRegistry g_radial_general_gauss_registry(&g_radial_general_gauss_seed);
43
44/* __ Method name definitions ____________________________________________ */
45#define G_CONSTRUCTOR "GModelSpatialRadialGeneralGauss::"\
46 "GModelSpatialRadialGeneralGauss(GSkyDir&, double&, double&, std::string&)"
47#define G_EVAL "GModelSpatialRadialGeneralGauss::eval(double&, GEnergy&, "\
48 "GTime&, bool&)"
49#define G_READ "GModelSpatialRadialGeneralGauss::read(GXmlElement&)"
50#define G_WRITE "GModelSpatialRadialGeneralGauss::write(GXmlElement&)"
51#define G_MC "GModelSpatialRadialGeneralGauss::mc(GEnergy&, GTime&, GRan&)"
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 *
69 * Constructs empty radial Gaussian model.
70 ***************************************************************************/
73{
74 // Initialise members
76
77 // Return
78 return;
79}
80
81
82/***********************************************************************//**
83 * @brief Constructor
84 *
85 * @param[in] dir Sky position of Gaussian.
86 * @param[in] radius Width of generalised Gaussian (deg).
87 * @param[in] ridx Reciprocal of exponential index of radial profile.
88 * @param[in] coordsys Coordinate system (either "CEL" or "GAL")
89 *
90 * @exception GException::invalid_argument
91 * Invalid @p coordsys argument specified.
92 *
93 * Constructs a generalised Gaussian spatial model using a sky direction
94 * (@p dir), a Gaussian width parameter @p radius in degrees and a reciprocal
95 * of the exponential index @p ridx. The @p coordsys parameter specifies
96 * whether the sky direction should be interpreted in the celestial or
97 * Galactic coordinate system.
98 ***************************************************************************/
100 const double& radius,
101 const double& ridx,
102 const std::string& coordsys) :
104{
105 // Initialise members
106 init_members();
107
108 // Set parameter names
109 if (coordsys == "CEL") {
110 m_lon.name("RA");
111 m_lat.name("DEC");
112 }
113 else {
114 m_lon.name("GLON");
115 m_lat.name("GLAT");
116 }
117
118 // Assign direction and radius
119 this->dir(dir);
120 this->radius(radius);
121 this->ridx(ridx);
122
123 // Return
124 return;
125}
126
127
128/***********************************************************************//**
129 * @brief XML constructor
130 *
131 * @param[in] xml XML element.
132 *
133 * Constructs a generalised Gaussian spatial model by extracting information
134 * from an XML element. See the method read() for more information about the
135 * expected structure of the XML element.
136 ***************************************************************************/
139{
140 // Initialise members
141 init_members();
142
143 // Read information from XML element
144 read(xml);
145
146 // Return
147 return;
148}
149
150
151/***********************************************************************//**
152 * @brief Copy constructor
153 *
154 * @param[in] model Generalised radial Gaussian model.
155 ***************************************************************************/
158{
159 // Initialise members
160 init_members();
161
162 // Copy members
163 copy_members(model);
164
165 // Return
166 return;
167}
168
169
170/***********************************************************************//**
171 * @brief Destructor
172 ***************************************************************************/
174{
175 // Free members
176 free_members();
177
178 // Return
179 return;
180}
181
182
183/*==========================================================================
184 = =
185 = Operators =
186 = =
187 ==========================================================================*/
188
189/***********************************************************************//**
190 * @brief Assignment operator
191 *
192 * @param[in] model Generalised radial Gaussian model.
193 * @return Radial Generalised radial Gaussian model.
194 ***************************************************************************/
196{
197 // Execute only if object is not identical
198 if (this != &model) {
199
200 // Copy base class members
202
203 // Free members
204 free_members();
205
206 // Initialise members
207 init_members();
208
209 // Copy members
210 copy_members(model);
211
212 } // endif: object was not identical
213
214 // Return
215 return *this;
216}
217
218
219/*==========================================================================
220 = =
221 = Public methods =
222 = =
223 ==========================================================================*/
224
225/***********************************************************************//**
226 * @brief Clear radial Gauss model
227 ***************************************************************************/
229{
230 // Free class members (base and derived classes, derived class first)
231 free_members();
234
235 // Initialise members
238 init_members();
239
240 // Return
241 return;
242}
243
244
245/***********************************************************************//**
246 * @brief Clone radial Gauss model
247 ***************************************************************************/
249{
250 // Clone radial Gauss model
251 return new GModelSpatialRadialGeneralGauss(*this);
252}
253
254
255/***********************************************************************//**
256 * @brief Evaluate Generalised Gaussian source model
257 *
258 * @param[in] theta Angular distance from source centre (radians).
259 * @param[in] energy Photon energy (not used).
260 * @param[in] time Photon arrival time (not used).
261 * @param[in] gradients Compute gradients?
262 * @return Model value (\f${\rm sr}^{-1}\f$).
263 *
264 * Evaluates the spatial component for a Generalised Gaussian source model using
265 *
266 * \f[
267 * M_{\rm S}({\bf p} | E, t) = M_{\rm S}(\theta) =
268 * \frac{1}{2 \pi r^2 \eta \Gamma(\eta)} \exp
269 * \left(-(\frac{\theta}{r})^1/\eta \right)
270 * \f]
271 *
272 * where
273 * - \f$\theta\f$ is the angular separation from the centre of the model, and
274 * - \f$r\f$ is the Generalised Gaussian radius.
275 * - \f$\eta\f$ is the reciprocal of the radial profile exponent.
276 *
277 * If @p gradients is `true` the method will also compute parameter
278 * gradients
279 *
280 *
281 * Note that the model normalisation is only correct in the small angle
282 * approximation and for \f$\eta\f$ order unity or smaller.
283 ***************************************************************************/
284double GModelSpatialRadialGeneralGauss::eval(const double& theta,
285 const GEnergy& energy,
286 const GTime& time,
287 const bool& gradients) const
288{
289 // Update
290 update();
291
292 // Compute value
293 double arg = -1.0 * std::pow(m_inv_radius_rad * theta,m_inv_ridx);
294 double value = m_value_norm * std::exp(arg);
295
296 // Compile option: Check for NaN/Inf
297 #if defined(G_NAN_CHECK)
298 if (gammalib::is_notanumber(value) || gammalib::is_infinite(value)) {
299 std::string msg = "Model value not a number:";
300 for (int i = 0; i < m_pars.size(); ++i) {
301 msg += " " + m_pars[i]->name() + "=";
302 msg += gammalib::str(m_pars[i]->value());
303 }
304 msg += " energy=" + energy.print();
305 msg += " time=" + time.print();
307 }
308 #endif
309
310 // Return value
311 return value;
312}
313
314
315/***********************************************************************//**
316 * @brief Returns MC sky direction
317 *
318 * @param[in] energy Photon energy.
319 * @param[in] time Photon arrival time.
320 * @param[in,out] ran Random number generator.
321 * @return Sky direction.
322 *
323 * Draws an arbitrary sky direction from the 2D Generalised Gaussian
324 * distribution as function of the photon @p energy and arrival @p time.
325 *
326 * @todo This method is only valid in the small angle approximation.
327 ***************************************************************************/
329 const GTime& time,
330 GRan& ran) const
331{
332
333 // Update precomputation cache
334 update();
335
336 // Initialise simulation
337 #if defined(G_DEBUG_MC)
338 int n_samples = 0;
339 #endif
340 double u_max = m_value_norm * std::sin(theta_max());
341 double value = 0.0;
342 double u = 1.0;
343 double theta = 0.0;
344
345 // Throw an exception if the maximum value is zero
346 if (u_max <= 0.0) {
347 std::string msg = "Non positive maximum radial genral Gauss model value.";
349 }
350
351 // Simulate offset from photon arrival direction using a rejection method
352 do {
353 theta = ran.uniform() * theta_max();
354 value = eval(theta, energy, time) * std::sin(theta);
355 u = ran.uniform() * u_max;
356 #if defined(G_DEBUG_MC)
357 n_samples++;
358 #endif
359 } while (u > value);
360 #if defined(G_DEBUG_MC)
361 std::cout << "#=" << n_samples << " ";
362 #endif
363
364 // Simulate azimuth angle
365 double phi = 360.0 * ran.uniform();
366
367 // Rotate pointing direction by offset and azimuth angle
368 GSkyDir sky_dir = dir();
369 sky_dir.rotate_deg(phi, theta * gammalib::rad2deg);
370
371 // Return sky direction
372 return sky_dir;
373
374}
375
376
377/***********************************************************************//**
378 * @brief Checks where model contains specified sky direction
379 *
380 * @param[in] dir Sky direction.
381 * @param[in] margin Margin to be added to sky direction (deg)
382 * @return True if the model contains the sky direction.
383 *
384 * Signals whether a sky direction is contained in the radial gauss model.
385 ***************************************************************************/
387 const double& margin) const
388{
389 // Compute distance to centre (radians)
390 double distance = dir.dist(this->dir());
391
392 // Return flag
393 return (distance <= theta_max() + margin*gammalib::deg2rad);
394}
395
396
397/***********************************************************************//**
398 * @brief Return maximum model radius (in radians)
399 *
400 * Returns \f$5 \sigma\f$ as approximate edge of the Gaussian. This limit
401 * is of course arbitrary, but allows to limit the integration region for
402 * response computation.
403 ***************************************************************************/
405{
406 // Return value
407 return (radius() * gammalib::deg2rad * 5.0);
408}
409
410
411/***********************************************************************//**
412 * @brief Read model from XML element
413 *
414 * @param[in] xml XML element.
415 *
416 * Reads the generalised radial Gaussian model information from an XML
417 * element. The XML element shall have either the format
418 *
419 * <spatialModel type="RadialGeneralGaussian">
420 * <parameter name="RA" scale="1.0" value="83.6331" min="-360" max="360" free="1"/>
421 * <parameter name="DEC" scale="1.0" value="22.0145" min="-90" max="90" free="1"/>
422 * <parameter name="Radius" scale="1.0" value="0.45" min="0.01" max="10" free="1"/>
423 * <parameter name="R_Index" scale="1.0" value="0.5" min="0.01" max="10" free="1"/>
424 * </spatialModel>
425 *
426 * or
427 *
428 * <spatialModel type="RadialGeneralGaussian">
429 * <parameter name="GLON" scale="1.0" value="83.6331" min="-360" max="360" free="1"/>
430 * <parameter name="GLAT" scale="1.0" value="22.0145" min="-90" max="90" free="1"/>
431 * <parameter name="Radius" scale="1.0" value="0.45" min="0.01" max="10" free="1"/>
432 * <parameter name="R_Index" scale="1.0" value="0.5" min="0.01" max="10" free="1"/>
433 * </spatialModel>
434 *
435 * @todo Implement a test of the radius and radius boundary. The sigma
436 * and sigma minimum should be >0.
437 ***************************************************************************/
439{
440 // Verify number of model parameters
442
443 // Read location
445
446 // Get parameters
449
450 // Read parameters
452 m_ridx.read(*ridx);
453
454 // Return
455 return;
456}
457
458
459/***********************************************************************//**
460 * @brief Write model into XML element
461 *
462 * @param[in] xml XML element into which model information is written.
463 *
464 * Writes the radial disk model information into an XML element. The XML
465 * element will have the format
466 *
467 * <spatialModel type="RadialGeneralGaussian">
468 * <parameter name="RA" scale="1.0" value="83.6331" min="-360" max="360" free="1"/>
469 * <parameter name="DEC" scale="1.0" value="22.0145" min="-90" max="90" free="1"/>
470 * <parameter name="Sigma" scale="1.0" value="0.45" min="0.01" max="10" free="1"/>
471 * <parameter name="R_Index" scale="1.0" value="0.5" min="0.01" max="10" free="1"/>
472 * </spatialModel>
473 *
474 ***************************************************************************/
476{
477 // Write Gaussian location
479
480 // Get or create parameters
483
484 // Write parameters
486 m_ridx.write(*ridx);
487
488 // Return
489 return;
490}
491
492
493/***********************************************************************//**
494 * @brief Print generalised radial Gaussian source information
495 *
496 * @param[in] chatter Chattiness.
497 * @return String containing model information.
498 ***************************************************************************/
499std::string GModelSpatialRadialGeneralGauss::print(const GChatter& chatter) const
500{
501 // Initialise result string
502 std::string result;
503
504 // Continue only if chatter is not silent
505 if (chatter != SILENT) {
506
507 // Append header
508 result.append("=== GModelSpatialRadialGeneralGauss ===");
509
510 // Append parameters
511 result.append("\n"+gammalib::parformat("Number of parameters"));
512 result.append(gammalib::str(size()));
513 for (int i = 0; i < size(); ++i) {
514 result.append("\n"+m_pars[i]->print(chatter));
515 }
516
517 } // endif: chatter was not silent
518
519 // Return result
520 return result;
521}
522
523
524/*==========================================================================
525 = =
526 = Private methods =
527 = =
528 ==========================================================================*/
529
530/***********************************************************************//**
531 * @brief Initialise class members
532 *
533 * Note that the minimum Gaussian width is set to 1 arcsec
534 * and w set the minimum reciprocal index to 1.e-15
535 ***************************************************************************/
537{
538 // Initialise model type
539 m_type = "RadialGeneralGaussian";
540
541 // Initialise Radius
542 m_radius.clear();
543 m_radius.name("Radius");
544 m_radius.unit("deg");
545 m_radius.value(2.778e-4); // 1 arcsec
546 m_radius.min(2.778e-4); // 1 arcsec
547 m_radius.free();
548 m_radius.scale(1.0);
549 m_radius.gradient(0.0);
550 m_radius.has_grad(false);
551
552 // Initialise Reciprocal index
553 m_ridx.clear();
554 m_ridx.name("R_Index");
555 m_ridx.value(0.5); // Gaussian
556 m_ridx.min(1.e-15); // need to be > 0
557 m_ridx.free();
558 m_ridx.scale(1.0);
559 m_ridx.gradient(0.0);
560 m_ridx.has_grad(false); // Radial components never have gradients
561
562 // Set parameter pointer(s)
563 m_pars.push_back(&m_radius);
564 m_pars.push_back(&m_ridx);
565
566 // Initialise precomputation cache. Note that zero values flag
567 // uninitialised as a zero radius and width shell is not meaningful
568 m_last_radius = 0.0;
569 m_inv_radius_rad = 0.0;
570 m_last_ridx = 0.0;
571 m_inv_ridx = 0.0;
572 m_value_norm = 0.0;
573
574 // Return
575 return;
576}
577
578
579/***********************************************************************//**
580 * @brief Copy class members
581 *
582 * @param[in] model Generalised radial Gaussian spatial model.
583 *
584 * We do not have to push back the members on the parameter stack as this
585 * should have been done by init_members() that was called before. Otherwise
586 * we would have sigma twice on the stack.
587 ***************************************************************************/
589{
590 // Copy members
591 m_type = model.m_type; // Needed to conserve model type
592 m_radius = model.m_radius;
593 m_ridx = model.m_ridx;
594
595 // Copy pre-computation cache
598 m_last_ridx = model.m_last_ridx;
599 m_inv_ridx = model.m_inv_ridx;
601
602 // Return
603 return;
604}
605
606
607/***********************************************************************//**
608 * @brief Delete class members
609 ***************************************************************************/
611{
612 // Return
613 return;
614}
615
616
617/***********************************************************************//**
618 * @brief Update precomputation cache
619 ***************************************************************************/
621{
622 // Update if radius has changed
623 if (m_last_radius != radius() || m_last_ridx != ridx()) {
624
625 // Store last values
627 m_last_ridx = ridx();
628
629 // Compute radius in radians
630 double radius_rad = radius() * gammalib::deg2rad;
631 if (radius_rad > 0.0 && ridx() > 0.0) {
632 m_inv_radius_rad = 1.0 / radius_rad;
633 m_inv_ridx = 1.0 / ridx() ;
634 m_value_norm = 1.0 / (gammalib::twopi * radius_rad * radius_rad * ridx() *
635 std::exp(gammalib::gammln(2.0 * ridx())));
636 }
637 else {
638 m_inv_radius_rad = 0.0;
639 m_inv_ridx = 1.0;
640 m_value_norm = 0.0;
641 }
642
643 } // endif: update required
644
645 // Return
646 return;
647}
648
649
650/***********************************************************************//**
651 * @brief Set boundary sky region
652 ***************************************************************************/
654{
655 // Set sky region circle (5 times radius)
657
658 // Set region (circumvent const correctness)
659 const_cast<GModelSpatialRadialGeneralGauss*>(this)->m_region = region;
660
661 // Return
662 return;
663}
#define G_WRITE
#define G_READ
Exception handler interface definition.
Mathematical function definitions.
#define G_EVAL
const GModelSpatialRadialGeneralGauss g_radial_general_gauss_seed
Generalized radial Gaussian model class interface definition.
Spatial model registry class definition.
Gammalib tools definition.
GChatter
Definition GTypemaps.hpp:33
@ SILENT
Definition GTypemaps.hpp:34
Class that handles energies in a unit independent way.
Definition GEnergy.hpp:48
std::string print(const GChatter &chatter=NORMAL) const
Print energy.
Definition GEnergy.cpp:748
void write(GXmlElement &xml) const
Set or update parameter attributes in XML element.
void read(const GXmlElement &xml)
Extract parameter attributes from XML element.
Generalized radial Gaussian model class.
GModelPar m_ridx
Reciprocal of exponent of the radial profile.
virtual GModelSpatialRadialGeneralGauss & operator=(const GModelSpatialRadialGeneralGauss &model)
Assignment operator.
virtual void write(GXmlElement &xml) const
Write model into XML element.
virtual GSkyDir mc(const GEnergy &energy, const GTime &time, GRan &ran) const
Returns MC sky direction.
virtual std::string print(const GChatter &chatter=NORMAL) const
Print generalised radial Gaussian source information.
virtual double eval(const double &theta, const GEnergy &energy, const GTime &time, const bool &gradients=false) const
Evaluate Generalised Gaussian source model.
void update(void) const
Update precomputation cache.
double m_value_norm
1/(2pi radius(rad)^2 ridx Gamma(ridx))
double m_last_ridx
Last reciprocal radial index.
void init_members(void)
Initialise class members.
virtual void set_region(void) const
Set boundary sky region.
virtual GModelSpatialRadialGeneralGauss * clone(void) const
Clone radial Gauss model.
virtual void read(const GXmlElement &xml)
Read model from XML element.
virtual void clear(void)
Clear radial Gauss model.
virtual bool contains(const GSkyDir &dir, const double &margin=0.0) const
Checks where model contains specified sky direction.
void copy_members(const GModelSpatialRadialGeneralGauss &model)
Copy class members.
virtual double theta_max(void) const
Return maximum model radius (in radians)
Abstract radial spatial model base class.
void free_members(void)
Delete class members.
GModelPar m_lon
Right Ascension or Galactic longitude (deg)
virtual void write(GXmlElement &xml) const
Write model into XML element.
virtual void read(const GXmlElement &xml)
Read model from XML element.
std::string coordsys(void) const
Return coordinate system.
void init_members(void)
Initialise class members.
virtual GModelSpatialRadial & operator=(const GModelSpatialRadial &model)
Assignment operator.
const GSkyDir & dir(void) const
Return position of radial spatial model.
GModelPar m_lat
Declination or Galactic latitude (deg)
Interface definition for the spatial model registry class.
std::string m_type
Spatial model type.
const GSkyRegion * region(void) const
Return boundary sky region.
std::vector< GModelPar * > m_pars
Parameter pointers.
void init_members(void)
Initialise class members.
int size(void) const
Return number of parameters.
void free_members(void)
Delete class members.
GSkyRegionCircle m_region
Bounding circle.
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.
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
Sky direction class.
Definition GSkyDir.hpp:62
void rotate_deg(const double &phi, const double &theta)
Rotate sky direction by zenith and azimuth angle.
Definition GSkyDir.cpp:424
double dist(const GSkyDir &dir) const
Compute angular distance between sky directions in radians.
Definition GSkyDir.hpp:271
Interface for the circular sky region class.
Time class.
Definition GTime.hpp:55
std::string print(const GChatter &chatter=NORMAL) const
Print time.
Definition GTime.cpp:1188
XML element node class.
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
double gammln(const double &arg)
Computes logarithm of gamma function.
Definition GMath.cpp:383
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
const double deg2rad
Definition GMath.hpp:43
void xml_check_parnum(const std::string &origin, const GXmlElement &xml, const int &number)
Checks number of parameters.
Definition GTools.cpp:1777
void warning(const std::string &origin, const std::string &message)
Emits warning.
Definition GTools.cpp:1386
const double twopi
Definition GMath.hpp:36
const double rad2deg
Definition GMath.hpp:44