GammaLib 2.0.0
Loading...
Searching...
No Matches
GCTAModelSpatial.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GCTAModelSpatial.cpp - Spatial model abstract base class *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2018-2020 by Jurgen Knodlseder *
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 GCTAModelSpatial.cpp
23 * @brief Abstract spatial model class implementation
24 * @author Juergen Knoedlseder
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 "GIntegral.hpp"
34#include "GObservation.hpp"
35#include "GCTASupport.hpp"
36#include "GCTAEventList.hpp"
37#include "GCTAInstDir.hpp"
38#include "GCTAModelSpatial.hpp"
40
41/* __ Method name definitions ____________________________________________ */
42#define G_ACCESS1 "GCTAModelSpatial::operator[](int&)"
43#define G_ACCESS2 "GCTAModelSpatial::operator[](std::string&)"
44#define G_MC "GCTAModelSpatial::mc(GEnergy&, GTime&, GCTAObservation&, "\
45 "GRan&)"
46#define G_NPRED "GCTAModelSpatial::npred(GEnergy&, GTime&, GObservation&)"
47
48/* __ Macros _____________________________________________________________ */
49
50/* __ Coding definitions _________________________________________________ */
51
52/* __ Debug definitions __________________________________________________ */
53
54/* __ Constants __________________________________________________________ */
55const double g_npred_resolution = 0.1*gammalib::deg2rad; //!< Scale of bkg.
56 // variation
57
58
59/*==========================================================================
60 = =
61 = Constructors/destructors =
62 = =
63 ==========================================================================*/
64
65/***********************************************************************//**
66 * @brief Void constructor
67 ***************************************************************************/
69{
70 // Initialise members
72
73 // Return
74 return;
75}
76
77
78/***********************************************************************//**
79 * @brief Copy constructor
80 *
81 * @param[in] model Spatial model.
82 ***************************************************************************/
84{
85 // Initialise members
87
88 // Copy members
89 copy_members(model);
90
91 // Return
92 return;
93}
94
95
96/***********************************************************************//**
97 * @brief Destructor
98 ***************************************************************************/
100{
101 // Free members
102 free_members();
103
104 // Return
105 return;
106}
107
108
109/*==========================================================================
110 = =
111 = Operators =
112 = =
113 ==========================================================================*/
114
115/***********************************************************************//**
116 * @brief Assignment operator
117 *
118 * @param[in] model Spatial model.
119 ***************************************************************************/
121{
122 // Execute only if object is not identical
123 if (this != &model) {
124
125 // Free members
126 free_members();
127
128 // Initialise members
129 init_members();
130
131 // Copy members
132 copy_members(model);
133
134 } // endif: object was not identical
135
136 // Return
137 return *this;
138}
139
140
141/***********************************************************************//**
142 * @brief Returns model parameter
143 *
144 * @param[in] index Parameter index [0,...,size()-1].
145 *
146 * @exception GException::out_of_range
147 * Parameter index is out of range.
148 ***************************************************************************/
150{
151 // Compile option: raise exception if index is out of range
152 #if defined(G_RANGE_CHECK)
153 if (index < 0 || index >= size()) {
154 throw GException::out_of_range(G_ACCESS1, "Spatial parameter index",
155 index, size());
156 }
157 #endif
158
159 // Return reference
160 return *(m_pars[index]);
161}
162
163
164/***********************************************************************//**
165 * @brief Returns model parameter (const version)
166 *
167 * @param[in] index Parameter index [0,...,size()-1].
168 *
169 * @exception GException::out_of_range
170 * Parameter index is out of range.
171 ***************************************************************************/
172const GModelPar& GCTAModelSpatial::operator[](const int& index) const
173{
174 // Compile option: raise exception if index is out of range
175 #if defined(G_RANGE_CHECK)
176 if (index < 0 || index >= size()) {
177 throw GException::out_of_range(G_ACCESS1, "Spatial parameter index",
178 index, size());
179 }
180 #endif
181
182 // Return reference
183 return *(m_pars[index]);
184}
185
186
187/***********************************************************************//**
188 * @brief Returns reference to model parameter
189 *
190 * @param[in] name Parameter name.
191 *
192 * @exception GException::invalid_argument
193 * Parameter with specified name not found in container.
194 ***************************************************************************/
196{
197 // Get parameter index
198 int index = 0;
199 for (; index < size(); ++index) {
200 if (m_pars[index]->name() == name)
201 break;
202 }
203
204 // Throw exception if parameter name was not found
205 if (index >= size()) {
206 std::string msg = "Parameter \""+name+"\" not found in spatial "
207 "component of background model.";
209 }
210
211 // Return reference
212 return *(m_pars[index]);
213}
214
215
216/***********************************************************************//**
217 * @brief Returns reference to model parameter (const version)
218 *
219 * @param[in] name Parameter name.
220 *
221 * @exception GException::invalid_argument
222 * Parameter with specified name not found in container.
223 ***************************************************************************/
224const GModelPar& GCTAModelSpatial::operator[](const std::string& name) const
225{
226 // Get parameter index
227 int index = 0;
228 for (; index < size(); ++index) {
229 if (m_pars[index]->name() == name)
230 break;
231 }
232
233 // Throw exception if parameter name was not found
234 if (index >= size()) {
235 std::string msg = "Parameter \""+name+"\" not found in spatial "
236 "component of background model.";
238 }
239
240 // Return reference
241 return *(m_pars[index]);
242}
243
244
245/*==========================================================================
246 = =
247 = Public methods =
248 = =
249 ==========================================================================*/
250
251/***********************************************************************//**
252 * @brief Returns MC instrument direction
253 *
254 * @param[in] energy Event energy.
255 * @param[in] time Event time.
256 * @param[in] obs CTA Observation.
257 * @param[in,out] ran Random number generator.
258 * @return Instrument direction
259 *
260 * @exception GException::invalid_return_value
261 * Spatial background model is empty, or method repeatedly
262 * encounters zero model values.
263 *
264 * Return random instrument direction.
265 ***************************************************************************/
267 const GTime& time,
268 const GCTAObservation& obs,
269 GRan& ran) const
270{
271 // Initialise instrument direction
272 GCTAInstDir dir;
273
274 // Get maximum value for Monte Carlo simulations (include some margin)
275 double mc_max_value = 1.5 * this->mc_max_value(obs);
276
277 // Throw an exception if maximum value is zero
278 if (mc_max_value <= 0.0) {
279 std::string msg = "Spatial background model is empty. Please provide "
280 "a valid spatial background model.";
282 }
283
284 // Get DETX and DETY value of RoI centre in radians
285 GCTARoi roi = obs.roi();
286 GCTAInstDir roi_centre = roi.centre();
287 double detx_centre = roi_centre.detx();
288 double dety_centre = roi_centre.dety();
289
290 // Get DETX and DETY minima and maximum in radians
291 double radius = obs.roi().radius() * gammalib::deg2rad;
292 double detx_min = detx_centre - radius;
293 double detx_max = detx_centre + radius;
294 double dety_min = dety_centre - radius;
295 double dety_max = dety_centre + radius;
296 double detx_width = detx_max - detx_min;
297 double dety_width = dety_max - dety_min;
298
299 // Initialise rejection method
300 double f = 0.0;
301 double ftest = 1.0;
302 const int max_subsequent_zeros = 10;
303
304 // Find instrument direction by rejection method
305 while (ftest > f) {
306
307 // Draw random DETX/DETY until a non-zero function value is found.
308 // Subsequent zero values may indicate that there is an issue with
309 // the model. After a limited number of subsequent zeros the loop
310 // is terminated with an exception
311 int zeros = 0;
312 do {
313
314 // Draw random DETX and DETY coordinates
315 double detx = detx_min + detx_width * ran.uniform();
316 double dety = dety_min + dety_width * ran.uniform();
317
318 // Set instrument direction
319 dir.detx(detx);
320 dir.dety(dety);
321
322 // Derive sky direction from instrument coordinates
323 GSkyDir skydir = obs.pointing().skydir(dir);
324
325 // Set sky direction in GCTAInstDir object
326 dir.dir(skydir);
327
328 // Compute function value if the coordinate is comprised in
329 // the RoI
330 if (roi.contains(dir)) {
331 f = eval(dir, energy, time, false);
332 }
333 else {
334 f = 0.0;
335 }
336
337 // Handle zero function value
338 if (f == 0.0) {
339 zeros++;
340 if (zeros > max_subsequent_zeros) {
341 std::string msg = "Method repeatedly encounters zero values "
342 "of spatial background model. Make sure "
343 "that the background model is correct.";
345 }
346 }
347
348 } while (f == 0);
349
350 // Get uniform random value between zero and the maximum model value.
351 // The loop is quit if the random number is smaller than the function
352 // value.
353 ftest = ran.uniform() * mc_max_value;
354
355 } // endwhile
356
357 // Return instrument direction
358 return dir;
359}
360
361
362/***********************************************************************//**
363 * @brief Return integral of spatial model component
364 *
365 * @param[in] energy Measured event energy.
366 * @param[in] time Measured event time.
367 * @param[in] obs Observation.
368 * @return Integral of spatial model component.
369 *
370 * Spatially integrates the spatial background model component for a given
371 * measured event energy and event time over the region of interest (RoI)
372 * of a given observation.
373 *
374 * The method uses a 2D Romberg integration to numerically integrate the
375 * spatial background model component.
376 ***************************************************************************/
377double GCTAModelSpatial::npred(const GEnergy& energy,
378 const GTime& time,
379 const GObservation& obs) const
380{
381 // Set number of iterations for Romberg integration.
382 static const int min_iter_theta = 5;
383 static const int min_iter_phi = 5;
384 static const int max_iter_theta = 8;
385 static const int max_iter_phi = 8;
386
387 // Get reference on CTA pointing and event list from observation
388 const GCTAPointing& pnt = gammalib::cta_pnt(G_NPRED, obs);
389 const GCTAEventList& events = gammalib::cta_event_list(G_NPRED, obs);
390
391 // Get instrument direction of RoI centre
392 GCTAInstDir roi_centre = pnt.instdir(events.roi().centre().dir());
393
394 // Get RoI radius in radians
395 double roi_radius = events.roi().radius() * gammalib::deg2rad;
396
397 // Set number of radial integration iterations
398 int iter_theta = gammalib::iter_rho(roi_radius, g_npred_resolution,
399 min_iter_theta, max_iter_theta);
400
401 // Setup integration function
403 energy,
404 time,
405 roi_centre,
406 min_iter_phi,
407 max_iter_phi);
408
409 // Setup integration
410 GIntegral integral(&integrand);
411
412 // Set fixed number of iterations
413 integral.fixed_iter(iter_theta);
414
415 // Spatially integrate radial component (assumes that RoI centre is
416 // at DETX=DETY=0)
417 double npred = integral.romberg(0.0, roi_radius);
418
419 // Debug: Check for NaN
420 #if defined(G_NAN_CHECK)
422 std::string origin = "GCTAModelSpatial::npred";
423 std::string message = " NaN/Inf encountered (npred=" +
424 gammalib::str(npred) + ", roi_radius=" +
425 gammalib::str(roi_radius) + ")";
426 gammalib::warning(origin, message);
427 }
428 #endif
429
430 // Return Npred
431 return npred;
432}
433
434
435/*==========================================================================
436 = =
437 = Private methods =
438 = =
439 ==========================================================================*/
440
441/***********************************************************************//**
442 * @brief Initialise class members
443 ***************************************************************************/
445{
446 // Initialise members
447 m_pars.clear();
448
449 // Return
450 return;
451}
452
453
454/***********************************************************************//**
455 * @brief Copy class members
456 *
457 * @param[in] model Spatial background model component.
458 ***************************************************************************/
460{
461 // Copy members
462 m_pars = model.m_pars;
463
464 // Return
465 return;
466}
467
468
469/***********************************************************************//**
470 * @brief Delete class members
471 ***************************************************************************/
473{
474 // Return
475 return;
476}
477
478
479/***********************************************************************//**
480 * @brief Kernel for offset angle integration of spatial component
481 *
482 * @param[in] theta Offset angle from RoI centre (radians).
483 *
484 * Computes
485 *
486 * \f[
487 * K(\rho | E, t) = \sin \theta \times
488 * \int_{0}^{2\pi}
489 * B(\theta,\phi | E, t) d\phi
490 * \f]
491 *
492 * where \f$B(\theta,\phi | E, t)\f$ is the spatial component of the
493 * background model for a specific observed energy \f$E\f$ and time \f$t\f$.
494 ***************************************************************************/
496{
497 // Initialise value
498 double value = 0.0;
499
500 // Continue only if offset angle is positive
501 if (theta > 0.0) {
502
503 // Setup phi integration kernel
505 m_energy,
506 m_time,
508 theta);
509
510 // Setup integration
511 GIntegral integral(&integrand);
512
513 // Set number of azimuthal integration iterations
514 int iter = gammalib::iter_phi(theta, g_npred_resolution,
516
517 // Set fixed number of iterations
518 integral.fixed_iter(iter);
519
520 // Integrate over phi
521 value = integral.romberg(0.0, gammalib::twopi) * std::sin(theta);
522
523 // Debug: Check for NaN
524 #if defined(G_NAN_CHECK)
525 if (gammalib::is_notanumber(value) || gammalib::is_infinite(value)) {
526 std::string origin = "GCTAModelSpatial::npred_roi_kern_theta::eval"
527 "(" + gammalib::str(theta) + ")";
528 std::string message = " NaN/Inf encountered (value=" +
529 gammalib::str(value) + ")";
530 gammalib::warning(origin, message);
531 }
532 #endif
533
534 } // endif: offset angle was positive
535
536 // Return value
537 return value;
538}
539
540
541/***********************************************************************//**
542 * @brief Kernel for azimuth angle integration of spatial component
543 *
544 * @param[in] phi Azimuth angle around RoI centre (radians).
545 *
546 * Computes
547 *
548 * \f[
549 * B(\theta, \phi | E, t)
550 * \f]
551 *
552 * using
553 *
554 * \f[ {\rm detx} = \theta \cos \phi \f]
555 * \f[ {\rm dety} = \theta \sin \phi \f]
556 *
557 * @todo Verify correct orientation of detx and dety with respect to phi
558 ***************************************************************************/
560{
561 // Compute detx and dety in radians
562 double detx = m_roi_centre.detx();
563 double dety = m_roi_centre.dety();
564 if (m_theta > 0.0 ) {
565 detx += m_theta * std::cos(phi);
566 dety += m_theta * std::sin(phi);
567 }
568
569 // Setup CTA instrument direction
570 GCTAInstDir dir(detx, dety);
571
572 // Get background value
573 double value = m_spatial->eval(dir, m_energy, m_time);
574
575 // Debug: Check for NaN
576 #if defined(G_NAN_CHECK)
577 if (gammalib::is_notanumber(value) || gammalib::is_infinite(value)) {
578 std::string origin = "GCTAModelSpatial::npred_roi_kern_phi::eval"
579 "(" + gammalib::str(phi) + ")";
580 std::string message = " NaN/Inf encountered (value=" +
581 gammalib::str(value) + ", detx=" +
582 gammalib::str(detx) + ", dety=" +
583 gammalib::str(dety) + ")";
584 gammalib::warning(origin, message);
585 }
586 #endif
587
588 // Return Npred
589 return value;
590}
CTA event list class interface definition.
CTA instrument direction class interface definition.
const double g_npred_resolution
Scale of bkg.
Abstract spatial model class interface definition.
CTA response helper classes definition.
Definition of support function used by CTA classes.
Exception handler interface definition.
#define G_ACCESS2
#define G_ACCESS1
Integration class interface definition.
#define G_NPRED
Definition GModelSky.cpp:60
Abstract observation base class interface definition.
Gammalib tools definition.
CTA event list class.
virtual void roi(const GRoi &roi)
Set ROI.
CTA instrument direction class.
void dir(const GSkyDir &dir)
Set sky direction.
void dety(const double &y)
Set DETY coordinate (in radians)
void detx(const double &x)
Set DETX coordinate (in radians)
double eval(const double &phi)
Kernel for azimuth angle integration of spatial component.
const GCTAModelSpatial * m_spatial
Pointer to spatial component.
int m_min_iter
Minimum number of Romberg iterations.
double eval(const double &theta)
Kernel for offset angle integration of spatial component.
int m_max_iter
Maximum number of Romberg iterations.
Abstract spatial model class.
void init_members(void)
Initialise class members.
GCTAModelSpatial(void)
Void constructor.
virtual double mc_max_value(const GCTAObservation &obs) const =0
virtual ~GCTAModelSpatial(void)
Destructor.
std::vector< GModelPar * > m_pars
Parameter pointers.
virtual GModelPar & operator[](const int &index)
Returns model parameter.
int size(void) const
Return number of model parameters.
virtual double eval(const GCTAInstDir &dir, const GEnergy &energy, const GTime &time, const bool &gradients=false) const =0
virtual double npred(const GEnergy &energy, const GTime &time, const GObservation &obs) const
Return integral of spatial model component.
virtual GCTAModelSpatial & operator=(const GCTAModelSpatial &model)
Assignment operator.
virtual GCTAInstDir mc(const GEnergy &energy, const GTime &time, const GCTAObservation &obs, GRan &ran) const
Returns MC instrument direction.
void copy_members(const GCTAModelSpatial &model)
Copy class members.
void free_members(void)
Delete class members.
CTA observation class.
void pointing(const GCTAPointing &pointing)
Set CTA pointing.
GCTARoi roi(void) const
Get Region of Interest.
CTA pointing class.
GCTAInstDir instdir(const GSkyDir &skydir) const
Get instrument direction from sky direction.
Interface for the CTA region of interest class.
Definition GCTARoi.hpp:49
const double & radius(void) const
Returns radius of region of interest in degrees.
Definition GCTARoi.hpp:125
virtual bool contains(const GEvent &event) const
Check if region of interest contains an event.
Definition GCTARoi.cpp:215
const GCTAInstDir & centre(void) const
Returns region of interest centre.
Definition GCTARoi.hpp:111
Class that handles energies in a unit independent way.
Definition GEnergy.hpp:48
GIntegral class interface definition.
Definition GIntegral.hpp:46
double romberg(std::vector< double > bounds, const int &order=5)
Perform Romberg integration.
void fixed_iter(const int &iter)
Set fixed number of iterations.
Model parameter class.
Definition GModelPar.hpp:87
Abstract observation base class.
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
Time class.
Definition GTime.hpp:55
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
const GCTAPointing & cta_pnt(const std::string &origin, const GObservation &obs)
Retrieve CTA pointing from generic observation.
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition GTools.cpp:489
const GCTAEventList & cta_event_list(const std::string &origin, const GObservation &obs)
Retrieve CTA event list from generic observation.
const double deg2rad
Definition GMath.hpp:43
int iter_phi(const double &rho, const double &resolution, const int &iter_min, const int &iter_max)
Determine number of azimuthal Romberg iterations.
void warning(const std::string &origin, const std::string &message)
Emits warning.
Definition GTools.cpp:1386
const double twopi
Definition GMath.hpp:36
int iter_rho(const double &rho_max, const double &resolution, const int &iter_min, const int &iter_max)
Determine number of radial Romberg iterations.