GammaLib 2.0.0
Loading...
Searching...
No Matches
GModelSpatialRadialRing.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GModelSpatialRadialRing.cpp - Radial ring source model class *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2020-2022 by Pierrick Martin *
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 GModelSpatialRadialRing.cpp
23 * @brief Radial ring model class implementation
24 * @author Pierrick Martin
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"
36
37/* __ Constants __________________________________________________________ */
38
39/* __ Globals ____________________________________________________________ */
41const GModelSpatialRegistry g_radial_ring_registry(&g_radial_ring_seed);
42
43/* __ Method name definitions ____________________________________________ */
44#define G_CONSTRUCTOR "GModelSpatialRadialRing::GModelSpatialRadialRing("\
45 "GSkyDir&, double&, double&, std::string&)"
46#define G_READ "GModelSpatialRadialRing::read(GXmlElement&)"
47#define G_WRITE "GModelSpatialRadialRing::write(GXmlElement&)"
48
49/* __ Macros _____________________________________________________________ */
50
51/* __ Coding definitions _________________________________________________ */
52
53/* __ Debug definitions __________________________________________________ */
54
55
56/*==========================================================================
57 = =
58 = Constructors/destructors =
59 = =
60 ==========================================================================*/
61
62/***********************************************************************//**
63 * @brief Void constructor
64 *
65 * Constructs empty radial ring model.
66 ***************************************************************************/
68{
69 // Initialise members
71
72 // Return
73 return;
74}
75
76
77/***********************************************************************//**
78 * @brief Ring constructor
79 *
80 * @param[in] dir Sky position of ring centre.
81 * @param[in] radius Ring inner radius (degrees).
82 * @param[in] width Ring width (degrees).
83 * @param[in] coordsys Coordinate system (either "CEL" or "GAL")
84 *
85 * @exception GException::invalid_argument
86 * Invalid @p coordsys argument specified.
87 *
88 * Constructs radial ring model from the sky position of the ring centre
89 * (@p dir) and the ring inner radius (@p radius) and width (@p width) in
90 * degrees. The @p coordsys parameter specifies whether the sky direction
91 * should be interpreted in the celestial or Galactic coordinate system.
92 ***************************************************************************/
94 const double& radius,
95 const double& width,
96 const std::string& coordsys) :
98{
99 // Throw an exception if the coordinate system is invalid
100 if ((coordsys != "CEL") && (coordsys != "GAL")) {
101 std::string msg = "Invalid coordinate system \""+coordsys+"\" "
102 "specified. Please specify either \"CEL\" or "
103 "\"GAL\".";
105 }
106
107 // Initialise members
108 init_members();
109
110 // Set parameter names
111 if (coordsys == "CEL") {
112 m_lon.name("RA");
113 m_lat.name("DEC");
114 }
115 else {
116 m_lon.name("GLON");
117 m_lat.name("GLAT");
118 }
119
120 // Assign center location, radius and width
121 this->dir(dir);
122 this->radius(radius);
123 this->width(width);
124
125 // Return
126 return;
127}
128
129
130/***********************************************************************//**
131 * @brief XML constructor
132 *
133 * @param[in] xml XML element.
134 *
135 * Creates instance of radial ring model by extracting information from an
136 * XML element. See the read() method for more information about the expected
137 * structure of the XML element.
138 ***************************************************************************/
141{
142 // Initialise members
143 init_members();
144
145 // Read information from XML element
146 read(xml);
147
148 // Return
149 return;
150}
151
152
153/***********************************************************************//**
154 * @brief Copy constructor
155 *
156 * @param[in] model Radial ring model.
157 ***************************************************************************/
160{
161 // Initialise members
162 init_members();
163
164 // Copy members
165 copy_members(model);
166
167 // Return
168 return;
169}
170
171
172/***********************************************************************//**
173 * @brief Destructor
174 ***************************************************************************/
176{
177 // Free members
178 free_members();
179
180 // Return
181 return;
182}
183
184
185/*==========================================================================
186 = =
187 = Operators =
188 = =
189 ==========================================================================*/
190
191/***********************************************************************//**
192 * @brief Assignment operator
193 *
194 * @param[in] model Radial ring model.
195 * @return Radial ring model.
196 ***************************************************************************/
198{
199 // Execute only if object is not identical
200 if (this != &model) {
201
202 // Copy base class members
204
205 // Free members
206 free_members();
207
208 // Initialise members
209 init_members();
210
211 // Copy members
212 copy_members(model);
213
214 } // endif: object was not identical
215
216 // Return
217 return *this;
218}
219
220
221/*==========================================================================
222 = =
223 = Public methods =
224 = =
225 ==========================================================================*/
226
227/***********************************************************************//**
228 * @brief Clear radial ring model
229 ***************************************************************************/
231{
232 // Free class members (base and derived classes, derived class first)
233 free_members();
236
237 // Initialise members
240 init_members();
241
242 // Return
243 return;
244}
245
246
247/***********************************************************************//**
248 * @brief Clone radial ring model
249 *
250 * @return Pointer to deep copy of radial ring model.
251 ***************************************************************************/
253{
254 // Clone radial ring model
255 return new GModelSpatialRadialRing(*this);
256}
257
258
259/***********************************************************************//**
260 * @brief Evaluate function (in units of sr^-1)
261 *
262 * @param[in] theta Angular distance from ring centre (radians).
263 * @param[in] energy Photon energy.
264 * @param[in] time Photon arrival time.
265 * @param[in] gradients Compute gradients?
266 * @return Model value.
267 *
268 * Evaluates the spatial component for a ring source model using
269 *
270 * \f[
271 * S_{\rm p}(\vec{p} | E, t) = \left \{
272 * \begin{array}{l l}
273 * \displaystyle
274 * {\tt m\_norm}
275 * & \mbox{if $\theta \le $ outer radius and $\theta \ge $ inner radius} \\
276 * \\
277 * \displaystyle
278 * 0 & \mbox{if $\theta > $ outer radius or $\theta < $ inner radius}
279 * \end{array}
280 * \right .
281 * \f]
282 *
283 * where
284 * - \f$\theta\f$ is the angular separation between ring centre and the
285 * sky direction of interest, and
286 * - \f${\tt m\_norm} = \frac{1}{2 \pi (\cos r_i - \cos r_o)} \f$ is a normalization
287 * constant (see the update() method for details).
288 *
289 * The method will not compute analytical parameter gradients, even if the
290 * @p gradients argument is set to true. Radial ring parameter gradients
291 * need to be computed numerically.
292 ***************************************************************************/
293double GModelSpatialRadialRing::eval(const double& theta,
294 const GEnergy& energy,
295 const GTime& time,
296 const bool& gradients) const
297{
298 // Update precomputation cache
299 update();
300
301 // Set value
302 double value = 0.0;
303 if ((theta >= m_inner_radius_rad) && (theta <= m_outer_radius_rad)) {
304 value = m_norm;
305 }
306
307 // Compile option: Check for NaN/Inf
308 #if defined(G_NAN_CHECK)
309 if (gammalib::is_notanumber(value) || gammalib::is_infinite(value)) {
310 std::cout << "*** ERROR: GModelSpatialRadialRing::eval";
311 std::cout << "(theta=" << theta << "): NaN/Inf encountered";
312 std::cout << " (value=" << value;
313 std::cout << ", m_inner_radius_rad=" << m_inner_radius_rad;
314 std::cout << ", m_outer_radius_rad=" << m_outer_radius_rad;
315 std::cout << ", m_norm=" << m_norm;
316 std::cout << ")" << std::endl;
317 }
318 #endif
319
320 // Return value
321 return value;
322}
323
324
325/***********************************************************************//**
326 * @brief Return MC sky direction
327 *
328 * @param[in] energy Photon energy.
329 * @param[in] time Photon arrival time.
330 * @param[in,out] ran Random number generator.
331 * @return Sky direction.
332 *
333 * Draws an arbitrary sky direction from the 2D ring distribution as function
334 * of the photon @p energy and arrival @p time.
335 ***************************************************************************/
337 const GTime& time,
338 GRan& ran) const
339{
340 // Update precomputation cache
341 update();
342
343 // Simulate offset from photon arrival direction
344 double theta = std::acos(m_cos_inner_radius_rad - ran.uniform() *
347 double phi = 360.0 * ran.uniform();
348
349 // Rotate sky direction by offset
350 GSkyDir sky_dir = dir();
351 sky_dir.rotate_deg(phi, theta);
352
353 // Return sky direction
354 return sky_dir;
355}
356
357
358/***********************************************************************//**
359 * @brief Checks whether model contains specified sky direction
360 *
361 * @param[in] dir Sky direction.
362 * @param[in] margin Margin to be added to sky direction (degrees)
363 * @return True if the model contains the sky direction.
364 *
365 * Signals whether a sky direction is contained in the radial ring model.
366 ***************************************************************************/
368 const double& margin) const
369{
370 // Compute distance to centre (radians)
371 double distance = dir.dist(this->dir());
372
373 // Compute margin in radians
374 double margin_rad = margin * gammalib::deg2rad;
375 double distance_min = theta_min() - margin_rad;
376 double distance_max = theta_max() + margin_rad;
377 if (distance_min < 0.0) {
378 distance_min = 0.0;
379 }
380
381 // Return flag
382 return ((distance >= distance_min) && (distance <= distance_max));
383}
384
385
386/***********************************************************************//**
387 * @brief Return minimum model radius (in radians)
388 *
389 * @return Minimum model radius (in radians).
390 ***************************************************************************/
392{
393 // Return value
394 return (radius() * gammalib::deg2rad);
395}
396
397
398/***********************************************************************//**
399 * @brief Return maximum model radius (in radians)
400 *
401 * @return Maximum model radius (in radians).
402 ***************************************************************************/
404{
405 // Return value
406 return ((radius()+width()) * gammalib::deg2rad);
407}
408
409
410/***********************************************************************//**
411 * @brief Read model from XML element
412 *
413 * @param[in] xml XML element.
414 *
415 * Reads the radial ring model information from an XML element. The XML
416 * element shall have either the format
417 *
418 * <spatialModel type="RadialRing">
419 * <parameter name="RA" scale="1.0" value="83.6331" min="-360" max="360" free="1"/>
420 * <parameter name="DEC" scale="1.0" value="22.0145" min="-90" max="90" free="1"/>
421 * <parameter name="Radius" scale="1.0" value="0.45" min="0.01" max="10" free="1"/>
422 * <parameter name="Width" scale="1.0" value="0.15" min="0.01" max="10" free="1"/>
423 * </spatialModel>
424 *
425 * or
426 *
427 * <spatialModel type="RadialRing">
428 * <parameter name="GLON" scale="1.0" value="83.6331" min="-360" max="360" free="1"/>
429 * <parameter name="GLAT" scale="1.0" value="22.0145" min="-90" max="90" free="1"/>
430 * <parameter name="Radius" scale="1.0" value="0.45" min="0.01" max="10" free="1"/>
431 * <parameter name="Width" scale="1.0" value="0.15" min="0.01" max="10" free="1"/>
432 * </spatialModel>
433 *
434 * @todo Implement a test of the radius and width. Both parameters should
435 * be >0.
436 ***************************************************************************/
438{
439 // Verify number of model parameters
441
442 // Read ring center location
444
445 // Get parameters
448
449 // Read parameters
452
453 // Return
454 return;
455}
456
457
458/***********************************************************************//**
459 * @brief Write model into XML element
460 *
461 * @param[in] xml XML element into which model information is written.
462 *
463 * Writes the radial ring model information into an XML element. The XML
464 * element will have the format
465 *
466 * <spatialModel type="RadialRing">
467 * <parameter name="RA" scale="1.0" value="83.6331" min="-360" max="360" free="1"/>
468 * <parameter name="DEC" scale="1.0" value="22.0145" min="-90" max="90" free="1"/>
469 * <parameter name="Radius" scale="1.0" value="0.45" min="0.01" max="10" free="1"/>
470 * <parameter name="Width" scale="1.0" value="0.15" min="0.01" max="10" free="1"/>
471 * </spatialModel>
472 *
473 ***************************************************************************/
475{
476 // Verify model type
478
479 // Write ring center location
481
482 // Get or create parameters
485
486 // Write parameters
489
490 // Return
491 return;
492}
493
494
495/***********************************************************************//**
496 * @brief Print information
497 *
498 * @param[in] chatter Chattiness.
499 * @return String containing model information.
500 ***************************************************************************/
501std::string GModelSpatialRadialRing::print(const GChatter& chatter) const
502{
503 // Initialise result string
504 std::string result;
505
506 // Continue only if chatter is not silent
507 if (chatter != SILENT) {
508
509 // Append header
510 result.append("=== GModelSpatialRadialRing ===");
511
512 // Append parameters
513 result.append("\n"+gammalib::parformat("Number of parameters"));
514 result.append(gammalib::str(size()));
515 for (int i = 0; i < size(); ++i) {
516 result.append("\n"+m_pars[i]->print(chatter));
517 }
518
519 } // endif: chatter was not silent
520
521 // Return result
522 return result;
523}
524
525
526/*==========================================================================
527 = =
528 = Private methods =
529 = =
530 ==========================================================================*/
531
532/***********************************************************************//**
533 * @brief Initialise class members
534 ***************************************************************************/
536{
537 // Initialise model type
538 m_type = "RadialRing";
539
540 // Initialise Radius
541 m_radius.clear();
542 m_radius.name("Radius");
543 m_radius.unit("deg");
544 m_radius.value(2.778e-4); // 1 arcsec
545 m_radius.min(2.778e-4); // 1 arcsec
546 m_radius.free();
547 m_radius.scale(1.0);
548 m_radius.gradient(0.0);
549 m_radius.has_grad(false); // Radial components never have gradients
550
551 // Initialise Width
552 m_width.clear();
553 m_width.name("Width");
554 m_width.unit("deg");
555 m_width.value(2.778e-4); // 1 arcsec
556 m_width.min(2.778e-4); // 1 arcsec
557 m_width.free();
558 m_width.scale(1.0);
559 m_width.gradient(0.0);
560 m_width.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_width);
565
566 // Initialise precomputation cache
567 m_last_radius = 0.0;
568 m_last_width = 0.0;
569 m_inner_radius_rad = 0.0;
570 m_outer_radius_rad = 0.0;
573 m_norm = 0.0;
574
575 // Return
576 return;
577}
578
579
580/***********************************************************************//**
581 * @brief Copy class members
582 *
583 * @param[in] model Radial ring model.
584 *
585 * We do not have to push back the members on the parameter stack as this
586 * should have been done by init_members() that was called before. Otherwise
587 * we would have the radius twice on the stack.
588 ***************************************************************************/
590{
591 // Copy members
592 m_type = model.m_type; // Needed to conserve model type
593 m_radius = model.m_radius;
594 m_width = model.m_width;
595
596 // Copy precomputation cache
603 m_norm = model.m_norm;
604
605 // Return
606 return;
607}
608
609
610/***********************************************************************//**
611 * @brief Delete class members
612 ***************************************************************************/
614{
615 // Return
616 return;
617}
618
619
620/***********************************************************************//**
621 * @brief Update precomputation cache
622 *
623 * Computes the normalization
624 * \f[
625 * {\tt m\_norm} = \frac{1}{2 \pi (\cos r_i - \cos r_o)}
626 * \f]
627 *
628 * This is the correct normalization on the sphere for any radii.
629 ***************************************************************************/
631{
632 // Update if radius or width has changed
633 if ((m_last_radius != radius()) || (m_last_width != width())) {
634
635 // Store last values
638
639 // Compute ring parameters in radians
644
645 // Perform precomputations
646 double denom = gammalib::twopi * (m_cos_inner_radius_rad -
648 m_norm = (denom > 0.0) ? 1.0 / denom : 0.0;
649
650 } // endif: update required
651
652 // Return
653 return;
654}
655
656
657/***********************************************************************//**
658 * @brief Set boundary sky region
659 ***************************************************************************/
661{
662 // Set sky region circle (maximum Gaussian sigma times a scaling
663 // factor (actually 3))
665
666 // Set region (circumvent const correctness)
667 const_cast<GModelSpatialRadialRing*>(this)->m_region = region;
668
669 // Return
670 return;
671}
#define G_WRITE
#define G_READ
Exception handler interface definition.
Mathematical function definitions.
#define G_CONSTRUCTOR
Definition GMatrix.cpp:41
const GModelSpatialRadialRing g_radial_ring_seed
Radial ring 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
void write(GXmlElement &xml) const
Set or update parameter attributes in XML element.
void read(const GXmlElement &xml)
Extract parameter attributes from XML element.
virtual ~GModelSpatialRadialRing(void)
Destructor.
virtual GModelSpatialRadialRing * clone(void) const
Clone radial ring model.
GModelSpatialRadialRing(void)
Void constructor.
virtual void clear(void)
Clear radial ring model.
virtual double theta_max(void) const
Return maximum model radius (in radians)
virtual std::string print(const GChatter &chatter=NORMAL) const
Print information.
virtual void read(const GXmlElement &xml)
Read model from XML element.
virtual GModelSpatialRadialRing & operator=(const GModelSpatialRadialRing &model)
Assignment operator.
GModelPar m_radius
Ring inner radius (degrees)
virtual void set_region(void) const
Set boundary sky region.
virtual void write(GXmlElement &xml) const
Write model into XML element.
double width(void) const
Return ring width.
double m_cos_outer_radius_rad
Cosine of outer radius in radians.
virtual bool contains(const GSkyDir &dir, const double &margin=0.0) const
Checks whether model contains specified sky direction.
double m_last_width
Last ring width.
double m_outer_radius_rad
Outer radius in radians.
virtual double theta_min(void) const
Return minimum model radius (in radians)
virtual GSkyDir mc(const GEnergy &energy, const GTime &time, GRan &ran) const
Return MC sky direction.
void free_members(void)
Delete class members.
void update(void) const
Update precomputation cache.
void copy_members(const GModelSpatialRadialRing &model)
Copy class members.
double m_cos_inner_radius_rad
Cosine of inner radius in radians.
double radius(void) const
Return ring inner radius.
virtual double eval(const double &theta, const GEnergy &energy, const GTime &time, const bool &gradients=false) const
Evaluate function (in units of sr^-1)
double m_inner_radius_rad
Inner radius in radians.
GModelPar m_width
Ring width (degrees)
double m_last_radius
Last ring radius.
void init_members(void)
Initialise class members.
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.
std::string type(void) const
Return 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
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
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
const double twopi
Definition GMath.hpp:36
const double rad2deg
Definition GMath.hpp:44
void xml_check_type(const std::string &origin, GXmlElement &xml, const std::string &type)
Checks the model type.
Definition GTools.cpp:1819