Commit f9cdd63373dca6b76c40b73c2a5f460d6b049e82
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.
Showing
7 changed files
with
269 additions
and
164 deletions
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& GCTAPsfKing::operator=(const GCTAPsfKing& 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& 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& 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& 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& 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& 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& 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& 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& logE, const double& 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& 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& 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); | ... | ... |