GammaLib 2.0.0
Loading...
Searching...
No Matches
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
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
86
87 // Load background from file
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 ***************************************************************************/
179double 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 ***************************************************************************/
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);
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 ***************************************************************************/
478std::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") +
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
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
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 ***************************************************************************/
661double 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}
CTA performance table background class definition.
CTA instrument direction class interface definition.
Integration class interface definition.
Mathematical function definitions.
#define G_LOAD
Random number generator class definition.
Gammalib tools definition.
GChatter
Definition GTypemaps.hpp:33
@ SILENT
Definition GTypemaps.hpp:34
GVector exp(const GVector &vector)
Computes exponential of vector elements.
Definition GVector.cpp:1232
CTA performance table background class.
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 .
double rate(const double &logE) const
Return background rate for a given energy (events/s/MeV/sr)
void copy_members(const GCTABackgroundPerfTable &bgd)
Copy class members.
GModelSpectralNodes m_mc_spectrum
Background spectrum.
void load(const GFilename &filename)
Load background from performance table.
std::vector< double > m_log_background
log(background rate)
GFilename filename(void) const
Return filename.
std::string print(const GChatter &chatter=NORMAL) const
Print background information.
void init_members(void)
Initialise class members.
virtual double operator()(const double &logE, const double &detx, const double &dety) const
Return background rate in units of events MeV s sr .
GCTABackgroundPerfTable & operator=(const GCTABackgroundPerfTable &bgd)
Assignment operator.
virtual ~GCTABackgroundPerfTable(void)
Destructor.
double m_sigma
Sigma for offset angle computation (0=none)
std::vector< double > m_background
Background rate.
GEnergies m_energy
Vector of energies.
void init_mc_cache(void) const
Initialise Monte Carlo cache.
GCTABackgroundPerfTable * clone(void) const
Clone background.
GCTABackgroundPerfTable(void)
Void constructor.
void clear(void)
Clear background.
GNodeArray m_log10_energy
log10(E) nodes for background interpolation
int size(void) const
Return number of node energies in response.
void free_members(void)
Delete class members.
GCTAInstDir mc(const GEnergy &energy, const GTime &time, GRan &ran) const
Returns MC instrument direction.
double solidangle(void) const
Returns integral over radial model (in steradians)
const double & sigma(void) const
Return sigma for offset angle dependence.
GFilename m_filename
Name of background response file.
Abstract base class for the CTA background model.
void init_members(void)
Initialise class members.
GCTABackground & operator=(const GCTABackground &bgd)
Assignment operator.
void free_members(void)
Delete class members.
CTA instrument direction class.
double theta(void) const
Return offset angle (in radians)
void dety(const double &y)
Set DETY coordinate (in radians)
void detx(const double &x)
Set DETX coordinate (in radians)
void clear(void)
Clear energy container.
GEnergy & append(const GEnergy &energy)
Append energy to container.
Class that handles energies in a unit independent way.
Definition GEnergy.hpp:48
double log10TeV(void) const
Return log10 of energy in TeV.
Definition GEnergy.cpp:457
double MeV(void) const
Return energy in MeV.
Definition GEnergy.cpp:321
Filename class.
Definition GFilename.hpp:62
std::string url(void) const
Return Uniform Resource Locator (URL)
void clear(void)
Clear file name.
GIntegral class interface definition.
Definition GIntegral.hpp:46
double romberg(std::vector< double > bounds, const int &order=5)
Perform Romberg integration.
virtual void clear(void)
Clear spectral nodes model.
void append(const GEnergy &energy, const double &intensity)
Append node.
double interpolate(const double &value, const std::vector< double > &vector) const
Interpolate value.
void clear(void)
Clear node array.
void append(const double &node)
Append one node to array.
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
Time class.
Definition GTime.hpp:55
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition GTools.cpp:1143
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 str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition GTools.cpp:489
const double pi
Definition GMath.hpp:35
double todouble(const std::string &arg)
Convert string into double precision value.
Definition GTools.cpp:926
std::string strip_whitespace(const std::string &arg)
Strip leading and trailing whitespace from string.
Definition GTools.cpp:80
const double deg2rad
Definition GMath.hpp:43
const double twopi
Definition GMath.hpp:36
std::vector< std::string > split(const std::string &s, const std::string &sep)
Split string.
Definition GTools.cpp:983
const double rad2deg
Definition GMath.hpp:44