Commit f9cdd63373dca6b76c40b73c2a5f460d6b049e82

Authored by Jürgen Knödlseder
1 parent eda368fe

Add King profile PSF unit test, correctly normalize fixed delta_max PSF, and aut…

…omatically detected King profile PSF upon IRF loading.

A unit test was added to verify that the King profile PSF is normalized correctly. For this purpose a King profile PSF calibration was inserted in slot 2 (bcf/000002) of the calibration database.

As the delta_max has been fixed to 0.7 degrees, the King profile PSF now returns 0 for delta angles larger than 0.7 deg. Furthermore, the PSF is normalized so that the integral from 0 to 0.7 deg gives 1. In that way we assure that the PSF integral is always 1.

The GCTAResponse::load_psf method now automatically detected the King profile PSF. Also, the load method now allow specification of a FITS file as the IRF name.
inst/cta/caldb/data/cta/e/bcf/000002/irf_test.fits
No preview for this file type
inst/cta/include/GCTAPsfKing.hpp
1 1 /***************************************************************************
2   - * GCTAPsfKing.hpp - CTA point spread function vector class *
  2 + * GCTAPsfKing.hpp - King profile CTA point spread function class *
3 3 * ----------------------------------------------------------------------- *
4   - * copyright (C) 2012 by Juergen Knoedlseder *
  4 + * copyright (C) 2013 by Michael Mayer *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -20,7 +20,7 @@
20 20 ***************************************************************************/
21 21 /**
22 22 * @file GCTAPsfKing.hpp
23   - * @brief CTA point spread function class definition with a King profile
  23 + * @brief King profile CTA point spread function class definition
24 24 * @author Michael Mayer
25 25 */
26 26  
... ... @@ -48,7 +48,7 @@ class GCTAPsfKing : public GCTAPsf {
48 48 public:
49 49 // Constructors and destructors
50 50 GCTAPsfKing(void);
51   - GCTAPsfKing(const std::string& filename);
  51 + explicit GCTAPsfKing(const std::string& filename);
52 52 GCTAPsfKing(const GCTAPsfKing& psf);
53 53 virtual ~GCTAPsfKing(void);
54 54  
... ... @@ -63,24 +63,24 @@ public:
63 63 const bool& etrue = true) const;
64 64  
65 65 // Implemented pure virtual methods
66   - void clear(void);
  66 + void clear(void);
67 67 GCTAPsfKing* clone(void) const;
68   - void load(const std::string& filename);
69   - std::string filename(void) const;
70   - double mc(GRan& ran,
71   - const double& logE,
72   - const double& theta = 0.0,
73   - const double& phi = 0.0,
74   - const double& zenith = 0.0,
75   - const double& azimuth = 0.0,
76   - const bool& etrue = true) const;
77   - double delta_max(const double& logE,
78   - const double& theta = 0.0,
79   - const double& phi = 0.0,
80   - const double& zenith = 0.0,
81   - const double& azimuth = 0.0,
82   - const bool& etrue = true) const;
83   - std::string print(const GChatter& chatter = NORMAL) const;
  68 + void load(const std::string& filename);
  69 + std::string filename(void) const;
  70 + double mc(GRan& ran,
  71 + const double& logE,
  72 + const double& theta = 0.0,
  73 + const double& phi = 0.0,
  74 + const double& zenith = 0.0,
  75 + const double& azimuth = 0.0,
  76 + const bool& etrue = true) const;
  77 + double delta_max(const double& logE,
  78 + const double& theta = 0.0,
  79 + const double& phi = 0.0,
  80 + const double& zenith = 0.0,
  81 + const double& azimuth = 0.0,
  82 + const bool& etrue = true) const;
  83 + std::string print(const GChatter& chatter = NORMAL) const;
84 84  
85 85  
86 86 private:
... ... @@ -91,15 +91,30 @@ private:
91 91 void update(const double& logE, const double& theta) const;
92 92  
93 93 // Members
94   - std::string m_filename; //!< Name of Aeff response file
95   - GCTAResponseTable m_psf; //!< PSF response table
96   -
97   - mutable double m_par_logE; //!< Cache energy
98   - mutable double m_par_theta; //!< Cache offset angle
99   - mutable double m_par_norm; //!< King profile normalization
100   - mutable double m_par_sigma; //!< King profile sigma (radians)
101   - mutable double m_par_gamma; //!< King profile gamma parameter
  94 + std::string m_filename; //!< Name of Aeff response file
  95 + GCTAResponseTable m_psf; //!< PSF response table
102 96  
  97 + // Evaluation cache
  98 + mutable double m_par_logE; //!< Cache energy
  99 + mutable double m_par_theta; //!< Cache offset angle
  100 + mutable double m_par_norm; //!< King profile normalization
  101 + mutable double m_par_sigma; //!< King profile sigma (radians)
  102 + mutable double m_par_sigma2; //!< King profile sigma squared
  103 + mutable double m_par_gamma; //!< King profile gamma parameter
103 104 };
104 105  
  106 +
  107 +/***********************************************************************//**
  108 + * @brief Return filename
  109 + *
  110 + * @return Filename from which point spread function was loaded.
  111 + *
  112 + * Returns filename from which point spread function was loaded.
  113 + ***************************************************************************/
  114 +inline
  115 +std::string GCTAPsfKing::filename(void) const
  116 +{
  117 + return m_filename;
  118 +}
  119 +
105 120 #endif /* GCTAPsfKing_HPP */
... ...
inst/cta/pyext/GCTAPsfKing.i
1 1 /***************************************************************************
2   - * GCTAPsfKing.i - CTA point spread function class *
  2 + * GCTAPsfKing.i - King profile CTA point spread function class *
3 3 * ----------------------------------------------------------------------- *
4   - * copyright (C) 2012 by Michael Mayer *
  4 + * copyright (C) 2013 by Michael Mayer *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -20,7 +20,7 @@
20 20 ***************************************************************************/
21 21 /**
22 22 * @file GCTAPsfKing.i
23   - * @brief CTA point spread function with a King Profile
  23 + * @brief King profile CTA point spread function class definition
24 24 * @author Michael Mayer
25 25 */
26 26 %{
... ... @@ -39,11 +39,10 @@
39 39 * of energy as determined from a FITS table.
40 40 ***************************************************************************/
41 41 class GCTAPsfKing : public GCTAPsf {
42   -
43 42 public:
44 43 // Constructors and destructors
45 44 GCTAPsfKing(void);
46   - GCTAPsfKing(const std::string& filename);
  45 + explicit GCTAPsfKing(const std::string& filename);
47 46 GCTAPsfKing(const GCTAPsfKing& psf);
48 47 virtual ~GCTAPsfKing(void);
49 48  
... ... @@ -57,24 +56,23 @@ public:
57 56 const bool& etrue = true) const;
58 57  
59 58 // Implemented pure virtual methods
60   - void clear(void);
  59 + void clear(void);
61 60 GCTAPsfKing* clone(void) const;
62   - void load(const std::string& filename);
63   - std::string filename(void) const;
64   - double mc(GRan& ran,
65   - const double& logE,
66   - const double& theta = 0.0,
67   - const double& phi = 0.0,
68   - const double& zenith = 0.0,
69   - const double& azimuth = 0.0,
70   - const bool& etrue = true) const;
71   - double delta_max(const double& logE,
72   - const double& theta = 0.0,
73   - const double& phi = 0.0,
74   - const double& zenith = 0.0,
75   - const double& azimuth = 0.0,
76   - const bool& etrue = true) const;
77   -
  61 + void load(const std::string& filename);
  62 + std::string filename(void) const;
  63 + double mc(GRan& ran,
  64 + const double& logE,
  65 + const double& theta = 0.0,
  66 + const double& phi = 0.0,
  67 + const double& zenith = 0.0,
  68 + const double& azimuth = 0.0,
  69 + const bool& etrue = true) const;
  70 + double delta_max(const double& logE,
  71 + const double& theta = 0.0,
  72 + const double& phi = 0.0,
  73 + const double& zenith = 0.0,
  74 + const double& azimuth = 0.0,
  75 + const bool& etrue = true) const;
78 76 };
79 77  
80 78  
... ... @@ -82,4 +80,7 @@ public:
82 80 * @brief GCTAPsfKing class extension
83 81 ***************************************************************************/
84 82 %extend GCTAPsfKing {
  83 + GCTAPsfKing copy() {
  84 + return (*self);
  85 + }
85 86 };
... ...
inst/cta/src/GCTAPsfKing.cpp
1 1 /***************************************************************************
2   - * GCTAPsfKing.cpp - CTA point spread function vector class *
  2 + * GCTAPsfKing.cpp - King profile CTA point spread function class *
3 3 * ----------------------------------------------------------------------- *
4   - * copyright (C) 2012 by Juergen Knoedlseder *
  4 + * copyright (C) 2013 by Michael Mayer *
5 5 * ----------------------------------------------------------------------- *
6 6 * *
7 7 * This program is free software: you can redistribute it and/or modify *
... ... @@ -19,8 +19,8 @@
19 19 * *
20 20 ***************************************************************************/
21 21 /**
22   - * @file GCTAPsfKing.cpp
23   - * @brief CTA point spread function using a King profile
  22 + * @file GCTAPsfKing.hpp
  23 + * @brief King profile CTA point spread function class definition
24 24 * @author Michael Mayer
25 25 */
26 26  
... ... @@ -35,15 +35,18 @@
35 35 #include "GCTAException.hpp"
36 36  
37 37 /* __ Method name definitions ____________________________________________ */
38   -#define G_LOAD "GCTAPsfKing::load(std::string&)"
  38 +#define G_UPDATE "GCTAPsfKing::update(double&, double&)"
39 39  
40 40 /* __ Macros _____________________________________________________________ */
41 41  
42 42 /* __ Coding definitions _________________________________________________ */
  43 +#define G_FIX_DELTA_MAX
43 44  
44 45 /* __ Debug definitions __________________________________________________ */
45 46  
46 47 /* __ Constants __________________________________________________________ */
  48 +const double r_max = 0.7 * gammalib::deg2rad; // Maximum delta for fixed
  49 + // delta_max computation
47 50  
48 51  
49 52 /*==========================================================================
... ... @@ -169,16 +172,21 @@ GCTAPsfKing&amp; GCTAPsfKing::operator=(const GCTAPsfKing&amp; psf)
169 172 * of sr^-1 for a given energy.
170 173 ***************************************************************************/
171 174 double GCTAPsfKing::operator()(const double& delta,
172   - const double& logE,
173   - const double& theta,
174   - const double& phi,
175   - const double& zenith,
176   - const double& azimuth,
177   - const bool& etrue) const
  175 + const double& logE,
  176 + const double& theta,
  177 + const double& phi,
  178 + const double& zenith,
  179 + const double& azimuth,
  180 + const bool& etrue) const
178 181 {
179 182 // Initialise PSF value
180 183 double psf = 0.0;
181 184  
  185 + // Compile option: set PSF to zero outside delta_max
  186 + #if defined(G_FIX_DELTA_MAX)
  187 + if (delta <= r_max) {
  188 + #endif
  189 +
182 190 // Update the parameter cache
183 191 update(logE, theta);
184 192  
... ... @@ -186,10 +194,18 @@ double GCTAPsfKing::operator()(const double&amp; delta,
186 194 if (m_par_norm > 0.0) {
187 195  
188 196 // Compute PSF value
189   - psf = m_par_norm*pow((1 + 1 / (2 * m_par_gamma) * pow(delta / m_par_sigma, 2)), -m_par_gamma);
  197 + double arg = delta / m_par_sigma;
  198 + double arg2 = arg * arg;
  199 + psf = m_par_norm *
  200 + std::pow((1.0 + 1.0 / (2.0 * m_par_gamma) * arg2), -m_par_gamma);
190 201  
191 202 } // endif: normalization was positive
192 203  
  204 + // Compile option: set PSF to zero outside delta_max
  205 + #if defined(G_FIX_DELTA_MAX)
  206 + }
  207 + #endif
  208 +
193 209 // Return PSF
194 210 return psf;
195 211 }
... ... @@ -249,10 +265,10 @@ void GCTAPsfKing::load(const std::string&amp; filename)
249 265 GFits file(filename);
250 266  
251 267 // Get PSF table
252   - const GFitsTable* table = file.table("POINT SPREAD FUNCTION");
  268 + const GFitsTable& table = *file.table("POINT SPREAD FUNCTION");
253 269  
254 270 // Read PSF table
255   - m_psf.read(*table);
  271 + m_psf.read(table);
256 272  
257 273 // Set energy axis to logarithmic scale
258 274 m_psf.axis_log10(0);
... ... @@ -260,7 +276,7 @@ void GCTAPsfKing::load(const std::string&amp; filename)
260 276 // Set offset angle axis to radians
261 277 m_psf.axis_radians(1);
262 278  
263   - // Convert sigma parameters to radians
  279 + // Convert sigma parameter to radians
264 280 m_psf.scale(1, gammalib::deg2rad);
265 281  
266 282 // Close PSF FITS file
... ... @@ -275,18 +291,6 @@ void GCTAPsfKing::load(const std::string&amp; filename)
275 291  
276 292  
277 293 /***********************************************************************//**
278   - * @brief Return filename
279   - *
280   - * @return Returns filename from which point spread function was loaded
281   - ***************************************************************************/
282   -std::string GCTAPsfKing::filename(void) const
283   -{
284   - // Return filename
285   - return m_filename;
286   -}
287   -
288   -
289   -/***********************************************************************//**
290 294 * @brief Simulate PSF offset (radians)
291 295 *
292 296 * @param[in] ran Random number generator.
... ... @@ -300,12 +304,12 @@ std::string GCTAPsfKing::filename(void) const
300 304 * Draws a random offset for the King Profile
301 305 ***************************************************************************/
302 306 double GCTAPsfKing::mc(GRan& ran,
303   - const double& logE,
304   - const double& theta,
305   - const double& phi,
306   - const double& zenith,
307   - const double& azimuth,
308   - const bool& etrue) const
  307 + const double& logE,
  308 + const double& theta,
  309 + const double& phi,
  310 + const double& zenith,
  311 + const double& azimuth,
  312 + const bool& etrue) const
309 313 {
310 314 // Initialise random offset
311 315 double delta = 0.0;
... ... @@ -317,7 +321,9 @@ double GCTAPsfKing::mc(GRan&amp; ran,
317 321 double u = ran.uniform();
318 322  
319 323 // Draw random offset using inversion sampling
320   - delta = std::sqrt( ( pow(1.0 - u, 1.0 / (1.0 - m_par_gamma) ) - 1.0 ) * 2.0 * pow(m_par_sigma, 2.0) * m_par_gamma);
  324 + //delta = std::sqrt( ( pow(1.0 - u, 1.0 / (1.0 - m_par_gamma) ) - 1.0 ) * 2.0 * pow(m_par_sigma, 2.0) * m_par_gamma);
  325 + delta = std::sqrt( ( std::pow(1.0 - u, 1.0 / (1.0 - m_par_gamma) ) - 1.0 ) *
  326 + 2.0 * m_par_sigma2 * m_par_gamma);
321 327  
322 328 // Return PSF offset
323 329 return delta;
... ... @@ -335,26 +341,30 @@ double GCTAPsfKing::mc(GRan&amp; ran,
335 341 * @param[in] etrue Use true energy (true/false). Not used.
336 342 *
337 343 * Determine the radius beyond which the PSF becomes negligible. This radius
338   - * is set by this method to where the containment fraction become 99.995% which equal
339   - * \f$5 \times \sigma\f$ of a Gaussian width.
  344 + * is set by this method to where the containment fraction become 99.995%
  345 + * which equals \f$5 \times \sigma\f$ of a Gaussian width.
340 346 ***************************************************************************/
341 347 double GCTAPsfKing::delta_max(const double& logE,
342   - const double& theta,
343   - const double& phi,
344   - const double& zenith,
345   - const double& azimuth,
346   - const bool& etrue) const
  348 + const double& theta,
  349 + const double& phi,
  350 + const double& zenith,
  351 + const double& azimuth,
  352 + const bool& etrue) const
347 353 {
  354 + // Compile option: use fixed maximum delta
  355 + #if defined(G_FIX_DELTA_MAX)
  356 + double radius = r_max;
  357 + #else
  358 +
348 359 // Update the parameter cache
349 360 update(logE, theta);
350 361  
351 362 // Compute maximum PSF radius (99.995% containment)
352   - double F = 0.99;
353   -
354   - // todo: For now fix maximum radius to 0.7 degree until we found a better method.
355   - // The 99% containment radius can become quite large due to the long tails of the
356   - // function
357   - double radius = 0.7*gammalib::deg2rad; //m_par_sigma * std::sqrt(2 * ( std::pow(1 - F, 1 / (1-m_par_gamma) ) -1 )* m_par_gamma);
  363 + double F = 0.99995;
  364 + double u_max = (std::pow((1.0 - F), (1.0/(1.0-m_par_gamma))) - 1.0) *
  365 + m_par_gamma;
  366 + double radius = m_par_sigma * std::sqrt(2.0 * u_max);
  367 + #endif
358 368  
359 369 // Return maximum PSF radius
360 370 return radius;
... ... @@ -398,11 +408,12 @@ void GCTAPsfKing::init_members(void)
398 408 // Initialise members
399 409 m_filename.clear();
400 410 m_psf.clear();
401   - m_par_logE = -1.0e30;
402   - m_par_theta = -1.0;
403   - m_par_norm = 0.0;
404   - m_par_gamma = 0.0;
405   - m_par_sigma = 0.0;
  411 + m_par_logE = -1.0e30;
  412 + m_par_theta = -1.0;
  413 + m_par_norm = 0.0;
  414 + m_par_gamma = 0.0;
  415 + m_par_sigma = 0.0;
  416 + m_par_sigma2 = 0.0;
406 417  
407 418 // Return
408 419 return;
... ... @@ -417,12 +428,14 @@ void GCTAPsfKing::init_members(void)
417 428 void GCTAPsfKing::copy_members(const GCTAPsfKing& psf)
418 429 {
419 430 // Copy members
420   - m_filename = psf.m_filename;
421   - m_psf = psf.m_psf;
422   - m_par_logE = psf.m_par_logE;
423   - m_par_sigma = psf.m_par_sigma;
424   - m_par_norm = psf.m_par_norm;
425   - m_par_gamma = psf.m_par_gamma;
  431 + m_filename = psf.m_filename;
  432 + m_psf = psf.m_psf;
  433 + m_par_logE = psf.m_par_logE;
  434 + m_par_theta = psf.m_par_theta;
  435 + m_par_norm = psf.m_par_norm;
  436 + m_par_gamma = psf.m_par_gamma;
  437 + m_par_sigma = psf.m_par_sigma;
  438 + m_par_sigma2 = psf.m_par_sigma2;
426 439  
427 440 // Return
428 441 return;
... ... @@ -434,9 +447,6 @@ void GCTAPsfKing::copy_members(const GCTAPsfKing&amp; psf)
434 447 ***************************************************************************/
435 448 void GCTAPsfKing::free_members(void)
436 449 {
437   - m_filename.clear();
438   - m_psf.clear();
439   -
440 450 // Return
441 451 return;
442 452 }
... ... @@ -447,6 +457,9 @@ void GCTAPsfKing::free_members(void)
447 457 *
448 458 * @param[in] logE Log10 of the true photon energy (TeV).
449 459 *
  460 + * @exception GException::invalid_value
  461 + * No valid point spread function information has been found.
  462 + *
450 463 * This method updates the PSF parameter cache. As the performance table PSF
451 464 * only depends on energy, the only parameter on which the cache values
452 465 * depend is the energy.
... ... @@ -457,20 +470,42 @@ void GCTAPsfKing::update(const double&amp; logE, const double&amp; theta) const
457 470 if (logE != m_par_logE || theta != m_par_theta) {
458 471  
459 472 // Save parameters
460   - m_par_logE = logE;
  473 + m_par_logE = logE;
461 474 m_par_theta = theta;
462 475  
463 476 // Determine sigma and gamma by interpolating between nodes
464 477 std::vector<double> pars = m_psf(logE,theta);
465 478  
466   - m_par_gamma = pars[0];
467   - m_par_sigma = pars[1];
  479 + // Throw an exception if there are not 2 parameters
  480 + if (pars.size() != 2) {
  481 + std::string msg = gammalib::str(pars.size()) + " parameters have"
  482 + " been found in the response table of the"
  483 + " King profile response function while 2"
  484 + " parameters are expected.\n"
  485 + "Possibly, the point spread function information"
  486 + " has not yet been loaded. Please load the point"
  487 + " spread function before using it.";
  488 + throw GException::invalid_value(G_UPDATE, msg);
  489 + }
  490 +
  491 + // Set parameters
  492 + m_par_gamma = pars[0];
  493 + m_par_sigma = pars[1];
  494 + m_par_sigma2 = m_par_sigma * m_par_sigma;
468 495  
469 496 // Determine normalisation for given parameters
470   - m_par_norm = 1.0 / gammalib::twopi * pow(m_par_sigma, -2)*(1.0 - 1.0 / m_par_gamma);
  497 + m_par_norm = 1.0 / gammalib::twopi * (1.0 - 1.0 / m_par_gamma) /
  498 + m_par_sigma2;
  499 +
  500 + // Optionally correct for fixed delta_max
  501 + #if defined(G_FIX_DELTA_MAX)
  502 + double u_max = (r_max*r_max) / (2.0 * m_par_sigma2);
  503 + double norm = 1.0 - std::pow((1.0 + u_max/m_par_gamma), 1.0-m_par_gamma);
  504 + m_par_norm /= norm;
  505 + #endif
  506 +
471 507 }
472 508  
473 509 // Return
474 510 return;
475 511 }
476   -
... ...
inst/cta/src/GCTAResponse.cpp
... ... @@ -53,6 +53,7 @@
53 53 #include "GCTAPsf2D.hpp"
54 54 #include "GCTAPsfVector.hpp"
55 55 #include "GCTAPsfPerfTable.hpp"
  56 +#include "GCTAPsfKing.hpp"
56 57 #include "GCTAAeff.hpp"
57 58 #include "GCTAPsf.hpp"
58 59 #include "GCTAEdisp.hpp"
... ... @@ -549,8 +550,13 @@ void GCTAResponse::load(const std::string&amp; irfname)
549 550 // Restore calibration database name
550 551 m_caldb = caldb;
551 552  
552   - // Build filename
553   - std::string filename = m_caldb + "/" + irfname + ".dat";
  553 + // Build filename. If file is not a FITS file then add ".dat" extension
  554 + // which is typical for a performance table.
  555 + std::string filename = m_caldb + "/" + irfname;
  556 + if (irfname.find_last_of(".fits") != irfname.length()-1 ||
  557 + irfname.find_last_of(".fits.gz") != irfname.length()-1) {
  558 + filename += ".dat";
  559 + }
554 560  
555 561 // Load effective area
556 562 load_aeff(filename);
... ... @@ -679,10 +685,22 @@ void GCTAResponse::load_psf(const std::string&amp; filename)
679 685 GFits file(filename);
680 686  
681 687 // If file contains a "POINT SPREAD FUNCTION" extension then load it
682   - // as CTA response table
  688 + // as either a King profile PSF or a 2D PSF
683 689 if (file.contains("POINT SPREAD FUNCTION")) {
684   - file.close();
685   - m_psf = new GCTAPsf2D(filename);
  690 + const GFitsTable& table = *file.table("POINT SPREAD FUNCTION");
  691 + if (table.contains("GAMMA") && table.contains("SIGMA")) {
  692 + file.close();
  693 + m_psf = new GCTAPsfKing(filename);
  694 + }
  695 + else if (table.contains("SCALE") && table.contains("SIGMA_1") &&
  696 + table.contains("AMPL_2") && table.contains("SIGMA_2") &&
  697 + table.contains("AMPL_3") && table.contains("SIGMA_3")) {
  698 + file.close();
  699 + m_psf = new GCTAPsf2D(filename);
  700 + }
  701 + else {
  702 + file.close();
  703 + }
686 704 }
687 705  
688 706 // ... else load it has PSF vector
... ...
inst/cta/test/test_CTA.cpp
... ... @@ -40,16 +40,18 @@
40 40 /* __ Globals ____________________________________________________________ */
41 41  
42 42 /* __ Constants __________________________________________________________ */
43   -const std::string datadir = PACKAGE_SOURCE"/inst/cta/test/data";
44   -const std::string cta_caldb = PACKAGE_SOURCE"/inst/cta/caldb";
45   -const std::string cta_irf = "kb_E_50h_v3";
46   -const std::string cta_events = datadir+"/crab_events.fits.gz";
47   -const std::string cta_cntmap = datadir+"/crab_cntmap.fits.gz";
48   -const std::string cta_bin_xml = datadir+"/obs_binned.xml";
49   -const std::string cta_unbin_xml = datadir+"/obs_unbinned.xml";
50   -const std::string cta_model_xml = datadir+"/crab.xml";
51   -const std::string cta_rsp_xml = datadir+"/rsp_models.xml";
  43 +const std::string datadir = PACKAGE_SOURCE"/inst/cta/test/data";
  44 +const std::string cta_caldb = PACKAGE_SOURCE"/inst/cta/caldb";
  45 +const std::string cta_irf = "kb_E_50h_v3";
  46 +const std::string cta_events = datadir+"/crab_events.fits.gz";
  47 +const std::string cta_cntmap = datadir+"/crab_cntmap.fits.gz";
  48 +const std::string cta_bin_xml = datadir+"/obs_binned.xml";
  49 +const std::string cta_unbin_xml = datadir+"/obs_unbinned.xml";
  50 +const std::string cta_model_xml = datadir+"/crab.xml";
  51 +const std::string cta_rsp_xml = datadir+"/rsp_models.xml";
52 52 const std::string cta_modbck_xml = datadir+"/cta_modelbg.xml";
  53 +const std::string cta_caldb_king = PACKAGE_SOURCE"/inst/cta/caldb/data/cta/e/bcf/000002";
  54 +const std::string cta_irf_king = "irf_test.fits";
53 55  
54 56  
55 57 /***********************************************************************//**
... ... @@ -64,6 +66,7 @@ void TestGCTAResponse::set(void)
64 66 append(static_cast<pfunction>(&TestGCTAResponse::test_response), "Test response");
65 67 append(static_cast<pfunction>(&TestGCTAResponse::test_response_aeff), "Test effective area");
66 68 append(static_cast<pfunction>(&TestGCTAResponse::test_response_psf), "Test PSF");
  69 + append(static_cast<pfunction>(&TestGCTAResponse::test_response_psf_king), "Test King profile PSF");
67 70 append(static_cast<pfunction>(&TestGCTAResponse::test_response_npsf), "Test integrated PSF");
68 71 append(static_cast<pfunction>(&TestGCTAResponse::test_response_irf_diffuse), "Test diffuse IRF");
69 72 append(static_cast<pfunction>(&TestGCTAResponse::test_response_npred_diffuse), "Test diffuse IRF integration");
... ... @@ -236,6 +239,44 @@ void TestGCTAResponse::test_response_psf(void)
236 239  
237 240  
238 241 /***********************************************************************//**
  242 + * @brief Test CTA King profile psf computation
  243 + *
  244 + * The Psf computation is tested by integrating numerically the Psf
  245 + * function. Integration is done in a rather simplistic way, by stepping
  246 + * radially away from the centre. The integration is done for a set of
  247 + * energies from 0.1-10 TeV.
  248 + ***************************************************************************/
  249 +void TestGCTAResponse::test_response_psf_king(void)
  250 +{
  251 + // Load response
  252 + GCTAResponse rsp;
  253 + rsp.caldb(cta_caldb_king);
  254 + rsp.load(cta_irf_king);
  255 +
  256 + // Integrate Psf
  257 + GEnergy eng;
  258 + for (double e = 0.1; e < 10.0; e *= 2.0) {
  259 + eng.TeV(e);
  260 + double r_max = rsp.psf()->delta_max(eng.log10TeV()) * gammalib::rad2deg;
  261 + double r = 0.0;
  262 + double dr = 0.0001;
  263 + int steps = int(1.0/dr);
  264 + double sum = 0.0;
  265 + for (int i = 0; i < steps; ++i) {
  266 + r += dr;
  267 + sum += rsp.psf(r * gammalib::deg2rad, 0.0, 0.0, 0.0, 0.0, eng.log10TeV()) *
  268 + gammalib::twopi * std::sin(r * gammalib::deg2rad) * dr *
  269 + gammalib::deg2rad;
  270 + }
  271 + test_value(sum, 1.0, 0.001, "PSF integration for "+eng.print());
  272 + }
  273 +
  274 + // Return
  275 + return;
  276 +}
  277 +
  278 +
  279 +/***********************************************************************//**
239 280 * @brief Test CTA npsf computation
240 281 ***************************************************************************/
241 282 void TestGCTAResponse::test_response_npsf(void)
... ... @@ -427,6 +468,30 @@ void TestGCTAResponse::test_response_npred_diffuse(void)
427 468 return;
428 469 }
429 470  
  471 +
  472 +/***********************************************************************//**
  473 + * @brief Test CTA response handling
  474 + ***************************************************************************/
  475 +void TestGCTAResponse::test_response(void)
  476 +{
  477 + // Test CTA response loading
  478 + test_try("Test CTA response loading");
  479 + try {
  480 + // Load response
  481 + GCTAResponse rsp;
  482 + rsp.caldb(cta_caldb);
  483 + rsp.load(cta_irf);
  484 + test_try_success();
  485 + }
  486 + catch (std::exception &e) {
  487 + test_try_failure(e);
  488 + }
  489 +
  490 + // Return
  491 + return;
  492 +}
  493 +
  494 +
430 495 /***********************************************************************//**
431 496 * @brief Test CTA Model Background Npred computation
432 497 *
... ... @@ -511,29 +576,6 @@ void TestGCTAModelBackground::test_modelbg_npred(void)
511 576  
512 577  
513 578 /***********************************************************************//**
514   - * @brief Test CTA response handling
515   - ***************************************************************************/
516   -void TestGCTAResponse::test_response(void)
517   -{
518   - // Test CTA response loading
519   - test_try("Test CTA response loading");
520   - try {
521   - // Load response
522   - GCTAResponse rsp;
523   - rsp.caldb(cta_caldb);
524   - rsp.load(cta_irf);
525   - test_try_success();
526   - }
527   - catch (std::exception &e) {
528   - test_try_failure(e);
529   - }
530   -
531   - // Return
532   - return;
533   -}
534   -
535   -
536   -/***********************************************************************//**
537 579 * @brief Test unbinned observation handling
538 580 ***************************************************************************/
539 581 void TestGCTAObservation::test_unbinned_obs(void)
... ...
inst/cta/test/test_CTA.hpp
... ... @@ -49,6 +49,7 @@ public:
49 49 virtual TestGCTAResponse* clone(void) const;
50 50 void test_response_aeff(void);
51 51 void test_response_psf(void);
  52 + void test_response_psf_king(void);
52 53 void test_response_npsf(void);
53 54 void test_response_irf_diffuse(void);
54 55 void test_response_npred_diffuse(void);
... ...