GammaLib 2.0.0
Loading...
Searching...
No Matches
GCTAPsfPerfTable.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GCTAPsfPerfTable.cpp - CTA performance table PSF class *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2012-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 GCTAPsfPerfTable.hpp
23 * @brief CTA performance table point spread function 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 <cmath>
33#include "GException.hpp"
34#include "GTools.hpp"
35#include "GMath.hpp"
36#include "GRan.hpp"
37#include "GCTAPsfPerfTable.hpp"
38
39/* __ Method name definitions ____________________________________________ */
40#define G_LOAD "GCTAPsfPerfTable::load(GFilename&)"
41#define G_CONTAINMENT_RADIUS "GCTAPsfPerfTable::containment_radius(double&,"\
42 " double&, double&, double&, double&, double&, bool&)"
43
44/* __ Macros _____________________________________________________________ */
45
46/* __ Coding definitions _________________________________________________ */
47#define G_SMOOTH_PSF
48
49/* __ Debug definitions __________________________________________________ */
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 point spread function information from
79 * an ASCII performance table.
80 ***************************************************************************/
82{
83 // Initialise class members
85
86 // Load point spread function from file
88
89 // Return
90 return;
91}
92
93
94/***********************************************************************//**
95 * @brief Copy constructor
96 *
97 * @param[in] psf Point spread function.
98 ***************************************************************************/
100{
101 // Initialise class members
102 init_members();
103
104 // Copy members
105 copy_members(psf);
106
107 // Return
108 return;
109}
110
111
112/***********************************************************************//**
113 * @brief Destructor
114 ***************************************************************************/
116{
117 // Free members
118 free_members();
119
120 // Return
121 return;
122}
123
124
125/*==========================================================================
126 = =
127 = Operators =
128 = =
129 ==========================================================================*/
130
131/***********************************************************************//**
132 * @brief Assignment operator
133 *
134 * @param[in] psf Point spread function.
135 * @return Point spread function.
136 ***************************************************************************/
138{
139 // Execute only if object is not identical
140 if (this != &psf) {
141
142 // Copy base class members
143 this->GCTAPsf::operator=(psf);
144
145 // Free members
146 free_members();
147
148 // Initialise private members
149 init_members();
150
151 // Copy members
152 copy_members(psf);
153
154 } // endif: object was not identical
155
156 // Return this object
157 return *this;
158}
159
160
161/***********************************************************************//**
162 * @brief Return point spread function (in units of sr^-1)
163 *
164 * @param[in] delta Angular separation between true and measured photon
165 * directions (rad).
166 * @param[in] logE Log10 of the true photon energy (TeV).
167 * @param[in] theta Offset angle in camera system (rad). Not used.
168 * @param[in] phi Azimuth angle in camera system (rad). Not used.
169 * @param[in] zenith Zenith angle in Earth system (rad). Not used.
170 * @param[in] azimuth Azimuth angle in Earth system (rad). Not used.
171 * @param[in] etrue Use true energy (true/false). Not used.
172 *
173 * Returns the point spread function for a given angular separation in units
174 * of sr^-1 for a given energy.
175 ***************************************************************************/
176double GCTAPsfPerfTable::operator()(const double& delta,
177 const double& logE,
178 const double& theta,
179 const double& phi,
180 const double& zenith,
181 const double& azimuth,
182 const bool& etrue) const
183{
184 #if defined(G_SMOOTH_PSF)
185 // Compute offset so that PSF goes to 0 at 5 times the sigma value. This
186 // is a kluge to get a PSF that smoothly goes to zero at the edge, which
187 // prevents steps or kinks in the log-likelihood function.
188 static const double offset = std::exp(-0.5*5.0*5.0);
189 #endif
190
191 // Update the parameter cache
192 update(logE);
193
194 // Compute PSF value
195 #if defined(G_SMOOTH_PSF)
196 double psf = m_par_scale * (std::exp(m_par_width * delta * delta) - offset);
197 #else
198 double psf = m_par_scale * (std::exp(m_par_width * delta * delta));
199 #endif
200
201 #if defined(G_SMOOTH_PSF)
202 // Make sure that PSF is non-negative
203 if (psf < 0.0) {
204 psf = 0.0;
205 }
206 #endif
207
208 // Return PSF
209 return psf;
210}
211
212
213/*==========================================================================
214 = =
215 = Public methods =
216 = =
217 ==========================================================================*/
218
219/***********************************************************************//**
220 * @brief Clear instance
221 *
222 * This method properly resets the object to an initial state.
223 ***************************************************************************/
225{
226 // Free class members (base and derived classes, derived class first)
227 free_members();
228 this->GCTAPsf::free_members();
229
230 // Initialise members
231 this->GCTAPsf::init_members();
232 init_members();
233
234 // Return
235 return;
236}
237
238
239/***********************************************************************//**
240 * @brief Clone instance
241 *
242 * @return Deep copy of point spread function instance.
243 ***************************************************************************/
245{
246 return new GCTAPsfPerfTable(*this);
247}
248
249
250/***********************************************************************//**
251 * @brief Load point spread function from performance table
252 *
253 * @param[in] filename Performance table file name.
254 *
255 * @exception GException::file_error
256 * File could not be opened for read access.
257 *
258 * This method loads the point spread function information from an ASCII
259 * performance table.
260 ***************************************************************************/
262{
263 // Set conversion factor from 68% containment radius to 1 sigma
264 const double conv = 0.6624305 * gammalib::deg2rad;
265
266 // Clear arrays
267 m_logE.clear();
268 m_r68.clear();
269 m_r80.clear();
270 m_sigma.clear();
271
272 // Allocate line buffer
273 const int n = 1000;
274 char line[n];
275
276 // Open performance table readonly
277 FILE* fptr = std::fopen(filename.url().c_str(), "r");
278 if (fptr == NULL) {
279 std::string msg = "Point spread function file \""+filename.url()+
280 "\" not found or readable. Please specify a valid "
281 "and readable point spread function file.";
282 throw GException::file_error(G_LOAD, msg);
283 }
284
285 // Read lines
286 while (std::fgets(line, n, fptr) != NULL) {
287
288 // Split line in elements. Strip empty elements from vector.
289 std::vector<std::string> elements = gammalib::split(line, " ");
290 for (int i = elements.size()-1; i >= 0; i--) {
291 if (gammalib::strip_whitespace(elements[i]).length() == 0) {
292 elements.erase(elements.begin()+i);
293 }
294 }
295
296 // Skip header
297 if (elements[0].find("log(E)") != std::string::npos) {
298 continue;
299 }
300
301 // Break loop if end of data table has been reached
302 if (elements[0].find("----------") != std::string::npos) {
303 break;
304 }
305
306 // Push elements in node array and vector
307 m_logE.append(gammalib::todouble(elements[0]));
308 m_r68.push_back(gammalib::todouble(elements[2]));
309 m_r80.push_back(gammalib::todouble(elements[3]));
310 m_sigma.push_back(gammalib::todouble(elements[2])*conv);
311
312 } // endwhile: looped over lines
313
314 // Close file
315 std::fclose(fptr);
316
317 // Store filename
319
320 // Return
321 return;
322}
323
324
325/***********************************************************************//**
326 * @brief Simulate PSF offset (radians)
327 *
328 * @param[in] ran Random number generator.
329 * @param[in] logE Log10 of the true photon energy (TeV).
330 * @param[in] theta Offset angle in camera system (rad). Not used.
331 * @param[in] phi Azimuth angle in camera system (rad). Not used.
332 * @param[in] zenith Zenith angle in Earth system (rad). Not used.
333 * @param[in] azimuth Azimuth angle in Earth system (rad). Not used.
334 * @param[in] etrue Use true energy (true/false). Not used.
335 ***************************************************************************/
337 const double& logE,
338 const double& theta,
339 const double& phi,
340 const double& zenith,
341 const double& azimuth,
342 const bool& etrue) const
343{
344 // Update the parameter cache
345 update(logE);
346
347 // Draw offset
348 double delta = m_par_sigma * ran.chisq2();
349
350 // Return PSF offset
351 return delta;
352}
353
354
355/***********************************************************************//**
356 * @brief Return maximum size of PSF (radians)
357 *
358 * @param[in] logE Log10 of the true photon energy (TeV).
359 * @param[in] theta Offset angle in camera system (rad). Not used.
360 * @param[in] phi Azimuth angle in camera system (rad). Not used.
361 * @param[in] zenith Zenith angle in Earth system (rad). Not used.
362 * @param[in] azimuth Azimuth angle in Earth system (rad). Not used.
363 * @param[in] etrue Use true energy (true/false). Not used.
364 *
365 * Determine the radius beyond which the PSF becomes negligible. This radius
366 * is set by this method to \f$5 \times \sigma\f$, where \f$\sigma\f$ is the
367 * Gaussian width of the largest PSF component.
368 ***************************************************************************/
369double GCTAPsfPerfTable::delta_max(const double& logE,
370 const double& theta,
371 const double& phi,
372 const double& zenith,
373 const double& azimuth,
374 const bool& etrue) const
375{
376 // Update the parameter cache
377 update(logE);
378
379 // Compute maximum PSF radius
380 double radius = 5.0 * m_par_sigma;
381
382 // Return maximum PSF radius
383 return radius;
384}
385
386
387/***********************************************************************//**
388 * @brief Return the radius that contains a fraction of the events (radians)
389 *
390 * @param[in] fraction of events (0.0-1.0)
391 * @param[in] logE Log10 of the true photon energy (TeV).
392 * @param[in] theta Offset angle in camera system (rad). Not used.
393 * @param[in] phi Azimuth angle in camera system (rad). Not used.
394 * @param[in] zenith Zenith angle in Earth system (rad). Not used.
395 * @param[in] azimuth Azimuth angle in Earth system (rad). Not used.
396 * @param[in] etrue Use true energy (true/false). Not used.
397 * @return Containment radius (radians).
398 *
399 * @exception GException::invalid_argument
400 * Invalid fraction specified.
401 *
402 * Evaluates:
403 *
404 * \f[
405 *
406 * radius = \sqrt{ \frac{\ln{\left( \frac{ fraction * m\_par\_width}
407 * {\pi*m\_par\_scale} +1\right)}}{m\_par\_width} }
408 *
409 * \f]
410 *
411 * which is derived by integrating
412 *
413 * \f[
414 *
415 * fraction = \int_{0}^{2\pi}\int_{0}^{radius}r *
416 * e^{ m\_par\_width * r^{2}}dr d\phi
417 *
418 * \f]
419 *
420 * and solving for radius.
421 *
422 * Calculate the radius from the center that contains 'fraction' percent
423 * of the events. fraction * 100. = Containment % .
424 ***************************************************************************/
425double GCTAPsfPerfTable::containment_radius(const double& fraction,
426 const double& logE,
427 const double& theta,
428 const double& phi,
429 const double& zenith,
430 const double& azimuth,
431 const bool& etrue) const
432{
433 // Check input argument
434 if (fraction <= 0.0 || fraction >= 1.0) {
435 std::string message = "Containment fraction "+
436 gammalib::str(fraction)+" must be between " +
437 "0.0 and 1.0, not inclusive.";
439 }
440
441 // Update the parameter cache
442 update(logE);
443
444 // Compute radius
445 double arg = fraction * m_par_width / ( gammalib::pi * m_par_scale);
446 double radius = std::sqrt(std::log(arg + 1.0) / m_par_width);
447
448 // Return containement radius
449 return radius;
450}
451
452
453/***********************************************************************//**
454 * @brief Print point spread function information
455 *
456 * @param[in] chatter Chattiness.
457 * @return String containing point spread function information.
458 ***************************************************************************/
459std::string GCTAPsfPerfTable::print(const GChatter& chatter) const
460{
461 // Initialise result string
462 std::string result;
463
464 // Continue only if chatter is not silent
465 if (chatter != SILENT) {
466
467 // Compute energy boundaries in TeV
468 int num = m_logE.size();
469 double emin = std::pow(10.0, m_logE[0]);
470 double emax = std::pow(10.0, m_logE[num-1]);
471
472 // Append header
473 result.append("=== GCTAPsfPerfTable ===");
474
475 // Append information
476 result.append("\n"+gammalib::parformat("Filename")+m_filename);
477 result.append("\n"+gammalib::parformat("Number of energy bins") +
478 gammalib::str(num));
479 result.append("\n"+gammalib::parformat("Energy range"));
480 result.append(gammalib::str(emin)+" - "+gammalib::str(emax)+" TeV");
481
482 } // endif: chatter was not silent
483
484 // Return result
485 return result;
486}
487
488
489/*==========================================================================
490 = =
491 = Private methods =
492 = =
493 ==========================================================================*/
494
495/***********************************************************************//**
496 * @brief Initialise class members
497 ***************************************************************************/
499{
500 // Initialise members
502 m_logE.clear();
503 m_r68.clear();
504 m_r80.clear();
505 m_sigma.clear();
506 m_par_logE = -1.0e30;
507 m_par_scale = 1.0;
508 m_par_sigma = 0.0;
509 m_par_width = 0.0;
510
511 // Return
512 return;
513}
514
515
516/***********************************************************************//**
517 * @brief Copy class members
518 *
519 * @param[in] psf Point spread function.
520 ***************************************************************************/
522{
523 // Copy members
525 m_logE = psf.m_logE;
526 m_r68 = psf.m_r68;
527 m_r80 = psf.m_r80;
528 m_sigma = psf.m_sigma;
533
534 // Return
535 return;
536}
537
538
539/***********************************************************************//**
540 * @brief Delete class members
541 ***************************************************************************/
543{
544 // Return
545 return;
546}
547
548
549/***********************************************************************//**
550 * @brief Update PSF parameter cache
551 *
552 * @param[in] logE Log10 of the true photon energy (TeV).
553 *
554 * This method updates the PSF parameter cache. As the performance table PSF
555 * only depends on energy, the only parameter on which the cache values
556 * depend is the energy.
557 ***************************************************************************/
558void GCTAPsfPerfTable::update(const double& logE) const
559{
560 // Only compute PSF parameters if arguments have changed
561 if (logE != m_par_logE) {
562
563 // Save energy
564 m_par_logE = logE;
565
566 // Determine Gaussian sigma in radians
568
569 // Derive width=-0.5/(sigma*sigma) and scale=1/(twopi*sigma*sigma)
570 double sigma2 = m_par_sigma * m_par_sigma;
571 m_par_scale = 1.0 / (gammalib::twopi * sigma2);
572 m_par_width = -0.5 / sigma2;
573
574 }
575
576 // Return
577 return;
578}
#define G_CONTAINMENT_RADIUS
Definition GCTAPsf2D.cpp:44
CTA performance table point spread function class definition.
Exception handler 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
CTA performance table point spread function class.
double operator()(const double &delta, const double &logE, const double &theta=0.0, const double &phi=0.0, const double &zenith=0.0, const double &azimuth=0.0, const bool &etrue=true) const
Return point spread function (in units of sr^-1)
void init_members(void)
Initialise class members.
std::vector< double > m_r68
68% containment radius of PSF in degrees
double delta_max(const double &logE, const double &theta=0.0, const double &phi=0.0, const double &zenith=0.0, const double &azimuth=0.0, const bool &etrue=true) const
Return maximum size of PSF (radians)
double m_par_width
Gaussian width parameter.
std::string print(const GChatter &chatter=NORMAL) const
Print point spread function information.
double containment_radius(const double &fraction, const double &logE, const double &theta=0.0, const double &phi=0.0, const double &zenith=0.0, const double &azimuth=0.0, const bool &etrue=true) const
Return the radius that contains a fraction of the events (radians)
GFilename filename(void) const
Return filename.
double m_par_logE
Energy for which precomputation is done.
virtual ~GCTAPsfPerfTable(void)
Destructor.
double mc(GRan &ran, const double &logE, const double &theta=0.0, const double &phi=0.0, const double &zenith=0.0, const double &azimuth=0.0, const bool &etrue=true) const
Simulate PSF offset (radians)
std::vector< double > m_sigma
Sigma value of PSF in radians.
void copy_members(const GCTAPsfPerfTable &psf)
Copy class members.
void update(const double &logE) const
Update PSF parameter cache.
GCTAPsfPerfTable(void)
Void constructor.
std::vector< double > m_r80
80% containment radius of PSF in degrees
GCTAPsfPerfTable * clone(void) const
Clone instance.
void clear(void)
Clear instance.
void load(const GFilename &filename)
Load point spread function from performance table.
GCTAPsfPerfTable & operator=(const GCTAPsfPerfTable &psf)
Assignment operator.
double m_par_scale
Gaussian normalization.
GFilename m_filename
Name of Aeff response file.
void free_members(void)
Delete class members.
GNodeArray m_logE
log(E) nodes for Aeff interpolation
double m_par_sigma
Gaussian sigma (radians)
Abstract base class for the CTA point spread function.
Definition GCTAPsf.hpp:47
void free_members(void)
Delete class members.
Definition GCTAPsf.cpp:164
void init_members(void)
Initialise class members.
Definition GCTAPsf.cpp:142
GCTAPsf & operator=(const GCTAPsf &psf)
Assignment operator.
Definition GCTAPsf.cpp:106
Filename class.
Definition GFilename.hpp:62
std::string url(void) const
Return Uniform Resource Locator (URL)
void clear(void)
Clear file name.
double interpolate(const double &value, const std::vector< double > &vector) const
Interpolate value.
void clear(void)
Clear node array.
int size(void) const
Return number of nodes in node array.
void append(const double &node)
Append one node to array.
Random number generator class.
Definition GRan.hpp:44
double chisq2(void)
Returns Chi2 deviates for 2 degrees of freedom.
Definition GRan.cpp:370
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition GTools.cpp:1143
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