GammaLib  2.1.0.dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
GCTABackgroundPerfTable.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * GCTABackgroundPerfTable.cpp - CTA performance table background class *
3  * ----------------------------------------------------------------------- *
4  * copyright (C) 2014-2021 by Juergen Knoedlseder *
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 GCTABackgroundPerfTable.cpp
23  * @brief CTA performance table background class implementation
24  * @author Juergen Knoedlseder
25  */
26 
27 /* __ Includes ___________________________________________________________ */
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 #include <cstdio> // std::fopen, std::fgets, and std::fclose
32 #include "GTools.hpp"
33 #include "GMath.hpp"
34 #include "GIntegral.hpp"
35 #include "GRan.hpp"
36 #include "GCTAInstDir.hpp"
38 
39 /* __ Method name definitions ____________________________________________ */
40 #define G_LOAD "GCTABackgroundPerfTable::load(GFilename&)"
41 #define G_MC "GCTABackgroundPerfTable::mc(GEnergy&, GTime&, GRan&)"
42 
43 /* __ Macros _____________________________________________________________ */
44 
45 /* __ Coding definitions _________________________________________________ */
46 
47 /* __ Debug definitions __________________________________________________ */
48 //#define G_DEBUG_MC //!< Debug Monte Carlo method
49 #define G_LOG_INTERPOLATION //!< Energy interpolate log(background rate)
50 
51 /* __ Constants __________________________________________________________ */
52 
53 
54 /*==========================================================================
55  = =
56  = Constructors/destructors =
57  = =
58  ==========================================================================*/
59 
60 /***********************************************************************//**
61  * @brief Void constructor
62  ***************************************************************************/
64 {
65  // Initialise class members
66  init_members();
67 
68  // Return
69  return;
70 }
71 
72 
73 /***********************************************************************//**
74  * @brief File constructor
75  *
76  * @param[in] filename Performance table file name.
77  *
78  * Construct instance by loading the background information from a
79  * performance table.
80  ***************************************************************************/
83 {
84  // Initialise class members
85  init_members();
86 
87  // Load background from file
88  load(filename);
89 
90  // Return
91  return;
92 }
93 
94 
95 /***********************************************************************//**
96  * @brief Copy constructor
97  *
98  * @param[in] bgd Background.
99  ***************************************************************************/
101  GCTABackground(bgd)
102 {
103  // Initialise class members
104  init_members();
105 
106  // Copy members
107  copy_members(bgd);
108 
109  // Return
110  return;
111 }
112 
113 
114 /***********************************************************************//**
115  * @brief Destructor
116  ***************************************************************************/
118 {
119  // Free members
120  free_members();
121 
122  // Return
123  return;
124 }
125 
126 
127 /*==========================================================================
128  = =
129  = Operators =
130  = =
131  ==========================================================================*/
132 
133 /***********************************************************************//**
134  * @brief Assignment operator
135  *
136  * @param[in] bgd Background.
137  * @return Background.
138  ***************************************************************************/
140 {
141  // Execute only if object is not identical
142  if (this != &bgd) {
143 
144  // Copy base class members
145  this->GCTABackground::operator=(bgd);
146 
147  // Free members
148  free_members();
149 
150  // Initialise private members
151  init_members();
152 
153  // Copy members
154  copy_members(bgd);
155 
156  } // endif: object was not identical
157 
158  // Return this object
159  return *this;
160 }
161 
162 
163 /***********************************************************************//**
164  * @brief Return background rate in units of events MeV\f$^{-1}\f$
165  * s\f$^{-1}\f$ sr\f$^{-1}\f$
166  *
167  * @param[in] logE Log10 of the true photon energy (TeV).
168  * @param[in] detx Tangential coordinate in nominal system (rad).
169  * @param[in] dety Tangential coordinate in nominal system (rad).
170  * @return Background rate (events MeV\f$^{-1}\f$ s\f$^{-1}\f$ sr\f$^{-1}\f$).
171  *
172  * Returns the background rate for a given energy and detector coordinates.
173  * The rate is given per ontime. The method assures that the background rate
174  * never becomes negative.
175  *
176  * If the performance table contains less than 2 nodes an empty value is
177  * returned.
178  ***************************************************************************/
179 double GCTABackgroundPerfTable::operator()(const double& logE,
180  const double& detx,
181  const double& dety) const
182 {
183  // Initialise rate
184  double rate = this->rate(logE);
185 
186  // Optionally add in Gaussian offset angle dependence
187  if (m_sigma != 0.0) {
188  double theta = std::sqrt(detx*detx + dety*dety) * gammalib::rad2deg;
189  double arg = theta * theta / m_sigma;
190  double scale = std::exp(-0.5 * arg * arg);
191  rate *= scale;
192  }
193 
194  // Return background rate
195  return rate;
196 }
197 
198 
199 /*==========================================================================
200  = =
201  = Public methods =
202  = =
203  ==========================================================================*/
204 
205 /***********************************************************************//**
206  * @brief Clear background
207  *
208  * This method properly resets the background to an initial state.
209  ***************************************************************************/
211 {
212  // Free class members (base and derived classes, derived class first)
213  free_members();
215 
216  // Initialise members
218  init_members();
219 
220  // Return
221  return;
222 }
223 
224 
225 /***********************************************************************//**
226  * @brief Clone background
227  *
228  * @return Pointer to deep copy of background.
229  ***************************************************************************/
231 {
232  return new GCTABackgroundPerfTable(*this);
233 }
234 
235 
236 /***********************************************************************//**
237  * @brief Load background from performance table
238  *
239  * @param[in] filename Performance table file name.
240  *
241  * @exception GException::file_open_error
242  * File could not be opened for read access.
243  *
244  * Loads the background information from a performance table.
245  ***************************************************************************/
247 {
248  // Clear arrays
249  m_energy.clear();
251  m_background.clear();
252  m_log_background.clear();
253 
254  // Allocate line buffer
255  const int n = 1000;
256  char line[n];
257 
258  // Open performance table readonly
259  FILE* fptr = std::fopen(filename.url().c_str(), "r");
260  if (fptr == NULL) {
261  std::string msg = "Unable to open file \""+filename.url()+"\" for "
262  "read access. Please provide the name of a readable "
263  "file.";
264  throw GException::file_error(G_LOAD, msg);
265  }
266 
267  // Read lines
268  while (std::fgets(line, n, fptr) != NULL) {
269 
270  // Split line in elements. Strip empty elements from vector.
271  std::vector<std::string> elements = gammalib::split(line, " ");
272  for (int i = elements.size()-1; i >= 0; i--) {
273  if (gammalib::strip_whitespace(elements[i]).length() == 0) {
274  elements.erase(elements.begin()+i);
275  }
276  }
277 
278  // Skip header
279  if (elements[0].find("log(E)") != std::string::npos) {
280  continue;
281  }
282 
283  // Break loop if end of data table has been reached
284  if (elements[0].find("----------") != std::string::npos) {
285  break;
286  }
287 
288  // Determine on-axis background rate (counts/s/MeV/sr)
289  double logE = gammalib::todouble(elements[0]);
290  double r80 = gammalib::todouble(elements[3]) * gammalib::deg2rad;
291  double bgrate = gammalib::todouble(elements[5]); // in Hz
292  double emin = std::pow(10.0, logE-0.1) * 1.0e6;
293  double emax = std::pow(10.0, logE+0.1) * 1.0e6;
294  double ewidth = emax - emin; // in MeV
295  double solidangle = gammalib::twopi * (1.0 - std::cos(r80)); // in sr
296  if (solidangle > 0.0) {
297  bgrate /= (solidangle * ewidth); // counts/s/MeV/sr
298  }
299  else {
300  bgrate = 0.0;
301  }
302 
303  // Set energy
304  GEnergy energy;
305  energy.log10TeV(logE);
306 
307  // Push elements in node array and vectors
308  m_energy.append(energy);
309  m_log10_energy.append(logE);
310  m_background.push_back(bgrate);
311  m_log_background.push_back(std::log(bgrate));
312 
313  } // endwhile: looped over lines
314 
315  // Close file
316  std::fclose(fptr);
317 
318  // Store filename
320 
321  // Return
322  return;
323 }
324 
325 
326 /***********************************************************************//**
327  * @brief Returns MC instrument direction
328  *
329  * @param[in] energy Photon energy.
330  * @param[in] time Photon arrival time.
331  * @param[in,out] ran Random number generator.
332  * @return CTA instrument direction.
333  ***************************************************************************/
335  const GTime& time,
336  GRan& ran) const
337 {
338  // Simulate theta angle
339  #if defined(G_DEBUG_MC)
340  int n_samples = 0;
341  #endif
342  double sigma_max = 4.0 * std::sqrt(sigma());
343  double u_max = std::sin(sigma_max * gammalib::deg2rad);
344  double value = 0.0;
345  double u = 1.0;
346  double theta = 0.0;
347  do {
348  theta = ran.uniform() * sigma_max;
349  double arg = theta * theta / sigma();
350  double arg2 = arg * arg;
351  value = std::sin(theta * gammalib::deg2rad) * exp(-0.5 * arg2);
352  u = ran.uniform() * u_max;
353  #if defined(G_DEBUG_MC)
354  n_samples++;
355  #endif
356  } while (u > value);
357  theta *= gammalib::deg2rad;
358  #if defined(G_DEBUG_MC)
359  std::cout << "#=" << n_samples << " ";
360  #endif
361 
362  // Simulate azimuth angle
363  double phi = gammalib::twopi * ran.uniform();
364 
365  // Compute detx and dety
366  double detx(0.0);
367  double dety(0.0);
368  if (theta > 0.0 ) {
369  detx = theta * std::cos(phi);
370  dety = theta * std::sin(phi);
371  }
372 
373  // Set instrument direction (in radians)
374  GCTAInstDir dir;
375  dir.detx(detx);
376  dir.dety(dety);
377 
378  // Return instrument direction
379  return dir;
380 }
381 
382 
383 /***********************************************************************//**
384  * @brief Returns background rate integrated over energy interval in units
385  * of events s\f$^{-1}\f$ sr\f$^{-1}\f$
386  *
387  * @param[in] dir Instrument direction.
388  * @param[in] emin Minimum energy of energy interval.
389  * @param[in] emax Maximum energy of energy interval.
390  * @return Integrated background count rate (events s\f$^{-1}\f$ sr\f$^{-1}\f$).
391  *
392  * Returns the background count rate for a given instrument direction that
393  * is integrated over a specified energy interval. The rate is given per
394  * ontime.
395  *
396  * If the energy interval is not positive, a zero background rate is
397  * returned.
398  ***************************************************************************/
400  const GEnergy& emin,
401  const GEnergy& emax) const
402 {
403  // Initialise rate
404  double rate = 0.0;
405 
406  // Continue only if energy interval is positive
407  if (emax > emin) {
408 
409  // Initialise first and second node
410  double x1 = emin.MeV();
411  double x2 = 0.0;
412  double f1 = this->rate(emin.log10TeV());
413  double f2 = 0.0;
414 
415  // Loop over all nodes
416  for (int i = 0; i < size(); ++i) {
417 
418  // If node energy is below x1 then skip node
419  if (m_energy[i].MeV() <= x1) {
420  continue;
421  }
422 
423  // If node energy is above emax then use emax as energy
424  if (m_energy[i] > emax) {
425  x2 = emax.MeV();
426  f2 = this->rate(emax.log10TeV());
427  }
428 
429  // ... otherwise use node energy
430  else {
431  x2 = m_energy[i].MeV();
432  f2 = m_background[i];
433  }
434 
435  // Compute integral
436  rate += gammalib::plaw_integral(x1, f1, x2, f2);
437 
438  // Set second node as first node
439  x1 = x2;
440  f1 = f2;
441 
442  // If node energy is above emax then break now
443  if (m_energy[i] > emax) {
444  break;
445  }
446 
447  } // endfor: looped over all nodes
448 
449  // If last node energy is below emax then compute last part of
450  // integral up to emax
451  if (x1 < emax.MeV()) {
452  x2 = emax.MeV();
453  f2 = this->rate(emax.log10TeV());
454  rate += gammalib::plaw_integral(x1, f1, x2, f2);
455  }
456 
457  // Optionally add in Gaussian offset angle dependence
458  if (m_sigma != 0.0) {
459  double theta = dir.theta() * gammalib::rad2deg;
460  double arg = theta * theta / m_sigma;
461  double scale = std::exp(-0.5 * arg * arg);
462  rate *= scale;
463  }
464 
465  } // endif: energy interval was positive
466 
467  // Return background rate
468  return rate;
469 }
470 
471 
472 /***********************************************************************//**
473  * @brief Print background information
474  *
475  * @param[in] chatter Chattiness.
476  * @return String containing background information.
477  ***************************************************************************/
478 std::string GCTABackgroundPerfTable::print(const GChatter& chatter) const
479 {
480  // Initialise result string
481  std::string result;
482 
483  // Continue only if chatter is not silent
484  if (chatter != SILENT) {
485 
486  // Compute energy boundaries in TeV
487  double emin = (size() > 0) ? m_energy[0].TeV() : 0.0;
488  double emax = (size() > 1) ? m_energy[size()-1].TeV() : 0.0;
489 
490  // Append header
491  result.append("=== GCTABackgroundPerfTable ===");
492 
493  // Append information
494  result.append("\n"+gammalib::parformat("Filename")+m_filename);
495  result.append("\n"+gammalib::parformat("Number of energy bins") +
496  gammalib::str(size()));
497  result.append("\n"+gammalib::parformat("Energy range"));
498  result.append(gammalib::str(emin) +
499  " - " +
500  gammalib::str(emax) +
501  " TeV");
502 
503  // Append offset angle dependence
504  if (m_sigma == 0) {
505  result.append("\n"+gammalib::parformat("Offset angle dependence") +
506  "none");
507  }
508  else {
509  std::string txt = "Fixed sigma=" + gammalib::str(m_sigma);
510  result.append("\n"+gammalib::parformat("Offset angle dependence") +
511  txt);
512  }
513 
514  } // endif: chatter was not silent
515 
516  // Return result
517  return result;
518 }
519 
520 
521 /*==========================================================================
522  = =
523  = Private methods =
524  = =
525  ==========================================================================*/
526 
527 /***********************************************************************//**
528  * @brief Initialise class members
529  ***************************************************************************/
531 {
532  // Initialise members
533  m_filename.clear();
534  m_energy.clear();
536  m_background.clear();
537  m_log_background.clear();
538  m_sigma = 3.0;
539 
540  // Initialise MC cache
542 
543  // Return
544  return;
545 }
546 
547 
548 /***********************************************************************//**
549  * @brief Copy class members
550  *
551  * @param[in] bgd Background.
552  ***************************************************************************/
554 {
555  // Copy members
556  m_filename = bgd.m_filename;
557  m_energy = bgd.m_energy;
561  m_sigma = bgd.m_sigma;
562 
563  // Copy MC cache
565 
566  // Return
567  return;
568 }
569 
570 
571 /***********************************************************************//**
572  * @brief Delete class members
573  ***************************************************************************/
575 {
576  // Return
577  return;
578 }
579 
580 
581 /***********************************************************************//**
582  * @brief Returns integral over radial model (in steradians)
583  *
584  * Computes
585  * \f[\Omega = 2 \pi \int_0^{\pi} \sin \theta f(\theta) d\theta\f]
586  * where
587  * \f[f(\theta) = \exp \left(-\frac{1}{2}
588  * \left( \frac{\theta^2}{\sigma} \right)^2 \right)\f]
589  * \f$\theta\f$ is the offset angle (in degrees), and
590  * \f$\sigma\f$ is the Gaussian width (in degrees\f$^2\f$).
591  *
592  * The integration is performed numerically, and the upper integration bound
593  * \f$\pi\f$
594  * is set to
595  * \f$\sqrt(10 \sigma)\f$
596  * to reduce inaccuracies in the numerical integration.
597  ***************************************************************************/
599 {
600  // Allocate integrand
604 
605  // Allocate intergal
606  GIntegral integral(&integrand);
607 
608  // Set upper integration boundary
609  double offset_max = std::sqrt(10.0*sigma()) * gammalib::deg2rad;
610  if (offset_max > gammalib::pi) {
611  offset_max = gammalib::pi;
612  }
613 
614  // Perform numerical integration
615  double solidangle = integral.romberg(0.0, offset_max) * gammalib::twopi;
616 
617  // Return integral
618  return solidangle;
619 }
620 
621 
622 /***********************************************************************//**
623  * @brief Initialise Monte Carlo cache
624  *
625  * @todo Verify assumption made about the solid angles of the response table
626  * elements.
627  * @todo Add optional sampling on a finer spatial grid.
628  ***************************************************************************/
630 {
631  // Initialise cache
633 
634  // Compute solid angle of model
635  double solidangle = this->solidangle();
636 
637  // Loop over nodes
638  for (int i = 0; i < size(); ++i) {
639 
640  // Compute total rate
641  double total_rate = m_background[i] * solidangle;
642 
643  // Set node
644  if (total_rate > 0.0) {
645  m_mc_spectrum.append(m_energy[i], total_rate);
646  }
647 
648  }
649 
650  // Return
651  return;
652 }
653 
654 
655 /***********************************************************************//**
656  * @brief Return background rate for a given energy (events/s/MeV/sr)
657  *
658  * @param[in] logE Log10 of the true photon energy (TeV).
659  * @return Background rate (events/s/MeV/sr)
660  ***************************************************************************/
661 double GCTABackgroundPerfTable::rate(const double& logE) const
662 {
663  // Initialise rate
664  double rate = 0.0;
665 
666  // Continue only if there are at least two nodes
667  if (size() > 1) {
668 
669  // Get background rate
670  #if defined(G_LOG_INTERPOLATION)
672  #else
674  #endif
675 
676  // Make sure that background rate is not negative
677  if (rate < 0.0) {
678  rate = 0.0;
679  }
680 
681  } // endif: there were enough rates
682 
683  // Return
684  return rate;
685 }
GCTABackgroundPerfTable(void)
Void constructor.
GCTABackgroundPerfTable & operator=(const GCTABackgroundPerfTable &bgd)
Assignment operator.
std::vector< double > m_log_background
log(background rate)
void clear(void)
Clear energy container.
Definition: GEnergies.cpp:227
void init_members(void)
Initialise class members.
double solidangle(void) const
Returns integral over radial model (in steradians)
double romberg(std::vector< double > bounds, const int &order=5)
Perform Romberg integration.
Definition: GIntegral.cpp:382
void detx(const double &x)
Set DETX coordinate (in radians)
Random number generator class definition.
const double pi
Definition: GMath.hpp:35
GVector cos(const GVector &vector)
Computes cosine of vector elements.
Definition: GVector.cpp:1190
GCTABackground & operator=(const GCTABackground &bgd)
Assignment operator.
virtual ~GCTABackgroundPerfTable(void)
Destructor.
CTA performance table background class definition.
void clear(void)
Clear node array.
Definition: GNodeArray.cpp:235
double log10TeV(void) const
Return log10 of energy in TeV.
Definition: GEnergy.cpp:457
void free_members(void)
Delete class members.
Random number generator class.
Definition: GRan.hpp:44
std::vector< std::string > split(const std::string &s, const std::string &sep)
Split string.
Definition: GTools.cpp:983
double MeV(void) const
Return energy in MeV.
Definition: GEnergy.cpp:321
void load(const GFilename &filename)
Load background from performance table.
Time class.
Definition: GTime.hpp:55
GFilename filename(void) const
Return filename.
Gammalib tools definition.
GIntegral class interface definition.
Definition: GIntegral.hpp:46
void copy_members(const GCTABackgroundPerfTable &bgd)
Copy class members.
std::string strip_whitespace(const std::string &arg)
Strip leading and trailing whitespace from string.
Definition: GTools.cpp:80
GCTABackgroundPerfTable * clone(void) const
Clone background.
void append(const GEnergy &energy, const double &intensity)
Append node.
GNodeArray m_log10_energy
log10(E) nodes for background interpolation
const double deg2rad
Definition: GMath.hpp:43
GVector sqrt(const GVector &vector)
Computes square root of vector elements.
Definition: GVector.cpp:1358
GEnergies m_energy
Vector of energies.
const double & sigma(void) const
Return sigma for offset angle dependence.
double rate(const double &logE) const
Return background rate for a given energy (events/s/MeV/sr)
double theta(void) const
Return offset angle (in radians)
Filename class.
Definition: GFilename.hpp:62
GVector log(const GVector &vector)
Computes natural logarithm of vector elements.
Definition: GVector.cpp:1274
void init_mc_cache(void) const
Initialise Monte Carlo cache.
double uniform(void)
Returns random double precision floating value in range 0 to 1.
Definition: GRan.cpp:242
double interpolate(const double &value, const std::vector< double > &vector) const
Interpolate value.
Definition: GNodeArray.cpp:536
CTA instrument direction class interface definition.
GChatter
Definition: GTypemaps.hpp:33
int size(void) const
Return number of node energies in response.
virtual double operator()(const double &logE, const double &detx, const double &dety) const
Return background rate in units of events MeV s sr .
std::string print(const GChatter &chatter=NORMAL) const
Print background information.
GModelSpectralNodes m_mc_spectrum
Background spectrum.
void init_members(void)
Initialise class members.
GCTAInstDir mc(const GEnergy &energy, const GTime &time, GRan &ran) const
Returns MC instrument direction.
double plaw_integral(const double &x1, const double &f1, const double &x2, const double &f2)
Returns the integral of a power law.
Definition: GMath.cpp:566
std::string url(void) const
Return Uniform Resource Locator (URL)
Definition: GFilename.hpp:189
void clear(void)
Clear file name.
Definition: GFilename.cpp:188
virtual void clear(void)
Clear spectral nodes model.
GVector pow(const GVector &vector, const double &power)
Computes tanh of vector elements.
Definition: GVector.cpp:1422
GVector sin(const GVector &vector)
Computes sine of vector elements.
Definition: GVector.cpp:1316
void clear(void)
Clear background.
GEnergy & append(const GEnergy &energy)
Append energy to container.
Definition: GEnergies.cpp:305
Abstract base class for the CTA background model.
CTA performance table background class.
GVector exp(const GVector &vector)
Computes exponential of vector elements.
Definition: GVector.cpp:1232
double rate_ebin(const GCTAInstDir &dir, const GEnergy &emin, const GEnergy &emax) const
Returns background rate integrated over energy interval in units of events s sr .
CTA instrument direction class.
Definition: GCTAInstDir.hpp:63
void dety(const double &y)
Set DETY coordinate (in radians)
const double twopi
Definition: GMath.hpp:36
const double rad2deg
Definition: GMath.hpp:44
std::vector< double > m_background
Background rate.
double m_sigma
Sigma for offset angle computation (0=none)
GFilename m_filename
Name of background response file.
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition: GTools.cpp:1143
void append(const double &node)
Append one node to array.
Definition: GNodeArray.cpp:351
Integration class interface definition.
Mathematical function definitions.
double todouble(const std::string &arg)
Convert string into double precision value.
Definition: GTools.cpp:926
Class that handles energies in a unit independent way.
Definition: GEnergy.hpp:48
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition: GTools.cpp:489
#define G_LOAD
void free_members(void)
Delete class members.