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 | * This program is free software: you can redistribute it and/or modify * | 7 | * This program is free software: you can redistribute it and/or modify * |
| @@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
| 20 | ***************************************************************************/ | 20 | ***************************************************************************/ |
| 21 | /** | 21 | /** |
| 22 | * @file GCTAPsfKing.hpp | 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 | * @author Michael Mayer | 24 | * @author Michael Mayer |
| 25 | */ | 25 | */ |
| 26 | 26 | ||
| @@ -48,7 +48,7 @@ class GCTAPsfKing : public GCTAPsf { | @@ -48,7 +48,7 @@ class GCTAPsfKing : public GCTAPsf { | ||
| 48 | public: | 48 | public: |
| 49 | // Constructors and destructors | 49 | // Constructors and destructors |
| 50 | GCTAPsfKing(void); | 50 | GCTAPsfKing(void); |
| 51 | - GCTAPsfKing(const std::string& filename); | 51 | + explicit GCTAPsfKing(const std::string& filename); |
| 52 | GCTAPsfKing(const GCTAPsfKing& psf); | 52 | GCTAPsfKing(const GCTAPsfKing& psf); |
| 53 | virtual ~GCTAPsfKing(void); | 53 | virtual ~GCTAPsfKing(void); |
| 54 | 54 | ||
| @@ -63,24 +63,24 @@ public: | @@ -63,24 +63,24 @@ public: | ||
| 63 | const bool& etrue = true) const; | 63 | const bool& etrue = true) const; |
| 64 | 64 | ||
| 65 | // Implemented pure virtual methods | 65 | // Implemented pure virtual methods |
| 66 | - void clear(void); | 66 | + void clear(void); |
| 67 | GCTAPsfKing* clone(void) const; | 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 | private: | 86 | private: |
| @@ -91,15 +91,30 @@ private: | @@ -91,15 +91,30 @@ private: | ||
| 91 | void update(const double& logE, const double& theta) const; | 91 | void update(const double& logE, const double& theta) const; |
| 92 | 92 | ||
| 93 | // Members | 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 | #endif /* GCTAPsfKing_HPP */ | 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 | * This program is free software: you can redistribute it and/or modify * | 7 | * This program is free software: you can redistribute it and/or modify * |
| @@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
| 20 | ***************************************************************************/ | 20 | ***************************************************************************/ |
| 21 | /** | 21 | /** |
| 22 | * @file GCTAPsfKing.i | 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 | * @author Michael Mayer | 24 | * @author Michael Mayer |
| 25 | */ | 25 | */ |
| 26 | %{ | 26 | %{ |
| @@ -39,11 +39,10 @@ | @@ -39,11 +39,10 @@ | ||
| 39 | * of energy as determined from a FITS table. | 39 | * of energy as determined from a FITS table. |
| 40 | ***************************************************************************/ | 40 | ***************************************************************************/ |
| 41 | class GCTAPsfKing : public GCTAPsf { | 41 | class GCTAPsfKing : public GCTAPsf { |
| 42 | - | ||
| 43 | public: | 42 | public: |
| 44 | // Constructors and destructors | 43 | // Constructors and destructors |
| 45 | GCTAPsfKing(void); | 44 | GCTAPsfKing(void); |
| 46 | - GCTAPsfKing(const std::string& filename); | 45 | + explicit GCTAPsfKing(const std::string& filename); |
| 47 | GCTAPsfKing(const GCTAPsfKing& psf); | 46 | GCTAPsfKing(const GCTAPsfKing& psf); |
| 48 | virtual ~GCTAPsfKing(void); | 47 | virtual ~GCTAPsfKing(void); |
| 49 | 48 | ||
| @@ -57,24 +56,23 @@ public: | @@ -57,24 +56,23 @@ public: | ||
| 57 | const bool& etrue = true) const; | 56 | const bool& etrue = true) const; |
| 58 | 57 | ||
| 59 | // Implemented pure virtual methods | 58 | // Implemented pure virtual methods |
| 60 | - void clear(void); | 59 | + void clear(void); |
| 61 | GCTAPsfKing* clone(void) const; | 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,4 +80,7 @@ public: | ||
| 82 | * @brief GCTAPsfKing class extension | 80 | * @brief GCTAPsfKing class extension |
| 83 | ***************************************************************************/ | 81 | ***************************************************************************/ |
| 84 | %extend GCTAPsfKing { | 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 | * This program is free software: you can redistribute it and/or modify * | 7 | * This program is free software: you can redistribute it and/or modify * |
| @@ -19,8 +19,8 @@ | @@ -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 | * @author Michael Mayer | 24 | * @author Michael Mayer |
| 25 | */ | 25 | */ |
| 26 | 26 | ||
| @@ -35,15 +35,18 @@ | @@ -35,15 +35,18 @@ | ||
| 35 | #include "GCTAException.hpp" | 35 | #include "GCTAException.hpp" |
| 36 | 36 | ||
| 37 | /* __ Method name definitions ____________________________________________ */ | 37 | /* __ Method name definitions ____________________________________________ */ |
| 38 | -#define G_LOAD "GCTAPsfKing::load(std::string&)" | 38 | +#define G_UPDATE "GCTAPsfKing::update(double&, double&)" |
| 39 | 39 | ||
| 40 | /* __ Macros _____________________________________________________________ */ | 40 | /* __ Macros _____________________________________________________________ */ |
| 41 | 41 | ||
| 42 | /* __ Coding definitions _________________________________________________ */ | 42 | /* __ Coding definitions _________________________________________________ */ |
| 43 | +#define G_FIX_DELTA_MAX | ||
| 43 | 44 | ||
| 44 | /* __ Debug definitions __________________________________________________ */ | 45 | /* __ Debug definitions __________________________________________________ */ |
| 45 | 46 | ||
| 46 | /* __ Constants __________________________________________________________ */ | 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,16 +172,21 @@ GCTAPsfKing& GCTAPsfKing::operator=(const GCTAPsfKing& psf) | ||
| 169 | * of sr^-1 for a given energy. | 172 | * of sr^-1 for a given energy. |
| 170 | ***************************************************************************/ | 173 | ***************************************************************************/ |
| 171 | double GCTAPsfKing::operator()(const double& delta, | 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 | // Initialise PSF value | 182 | // Initialise PSF value |
| 180 | double psf = 0.0; | 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 | // Update the parameter cache | 190 | // Update the parameter cache |
| 183 | update(logE, theta); | 191 | update(logE, theta); |
| 184 | 192 | ||
| @@ -186,10 +194,18 @@ double GCTAPsfKing::operator()(const double& delta, | @@ -186,10 +194,18 @@ double GCTAPsfKing::operator()(const double& delta, | ||
| 186 | if (m_par_norm > 0.0) { | 194 | if (m_par_norm > 0.0) { |
| 187 | 195 | ||
| 188 | // Compute PSF value | 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 | } // endif: normalization was positive | 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 | // Return PSF | 209 | // Return PSF |
| 194 | return psf; | 210 | return psf; |
| 195 | } | 211 | } |
| @@ -249,10 +265,10 @@ void GCTAPsfKing::load(const std::string& filename) | @@ -249,10 +265,10 @@ void GCTAPsfKing::load(const std::string& filename) | ||
| 249 | GFits file(filename); | 265 | GFits file(filename); |
| 250 | 266 | ||
| 251 | // Get PSF table | 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 | // Read PSF table | 270 | // Read PSF table |
| 255 | - m_psf.read(*table); | 271 | + m_psf.read(table); |
| 256 | 272 | ||
| 257 | // Set energy axis to logarithmic scale | 273 | // Set energy axis to logarithmic scale |
| 258 | m_psf.axis_log10(0); | 274 | m_psf.axis_log10(0); |
| @@ -260,7 +276,7 @@ void GCTAPsfKing::load(const std::string& filename) | @@ -260,7 +276,7 @@ void GCTAPsfKing::load(const std::string& filename) | ||
| 260 | // Set offset angle axis to radians | 276 | // Set offset angle axis to radians |
| 261 | m_psf.axis_radians(1); | 277 | m_psf.axis_radians(1); |
| 262 | 278 | ||
| 263 | - // Convert sigma parameters to radians | 279 | + // Convert sigma parameter to radians |
| 264 | m_psf.scale(1, gammalib::deg2rad); | 280 | m_psf.scale(1, gammalib::deg2rad); |
| 265 | 281 | ||
| 266 | // Close PSF FITS file | 282 | // Close PSF FITS file |
| @@ -275,18 +291,6 @@ void GCTAPsfKing::load(const std::string& filename) | @@ -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 | * @brief Simulate PSF offset (radians) | 294 | * @brief Simulate PSF offset (radians) |
| 291 | * | 295 | * |
| 292 | * @param[in] ran Random number generator. | 296 | * @param[in] ran Random number generator. |
| @@ -300,12 +304,12 @@ std::string GCTAPsfKing::filename(void) const | @@ -300,12 +304,12 @@ std::string GCTAPsfKing::filename(void) const | ||
| 300 | * Draws a random offset for the King Profile | 304 | * Draws a random offset for the King Profile |
| 301 | ***************************************************************************/ | 305 | ***************************************************************************/ |
| 302 | double GCTAPsfKing::mc(GRan& ran, | 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 | // Initialise random offset | 314 | // Initialise random offset |
| 311 | double delta = 0.0; | 315 | double delta = 0.0; |
| @@ -317,7 +321,9 @@ double GCTAPsfKing::mc(GRan& ran, | @@ -317,7 +321,9 @@ double GCTAPsfKing::mc(GRan& ran, | ||
| 317 | double u = ran.uniform(); | 321 | double u = ran.uniform(); |
| 318 | 322 | ||
| 319 | // Draw random offset using inversion sampling | 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 | // Return PSF offset | 328 | // Return PSF offset |
| 323 | return delta; | 329 | return delta; |
| @@ -335,26 +341,30 @@ double GCTAPsfKing::mc(GRan& ran, | @@ -335,26 +341,30 @@ double GCTAPsfKing::mc(GRan& ran, | ||
| 335 | * @param[in] etrue Use true energy (true/false). Not used. | 341 | * @param[in] etrue Use true energy (true/false). Not used. |
| 336 | * | 342 | * |
| 337 | * Determine the radius beyond which the PSF becomes negligible. This radius | 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 | double GCTAPsfKing::delta_max(const double& logE, | 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 | // Update the parameter cache | 359 | // Update the parameter cache |
| 349 | update(logE, theta); | 360 | update(logE, theta); |
| 350 | 361 | ||
| 351 | // Compute maximum PSF radius (99.995% containment) | 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 | // Return maximum PSF radius | 369 | // Return maximum PSF radius |
| 360 | return radius; | 370 | return radius; |
| @@ -398,11 +408,12 @@ void GCTAPsfKing::init_members(void) | @@ -398,11 +408,12 @@ void GCTAPsfKing::init_members(void) | ||
| 398 | // Initialise members | 408 | // Initialise members |
| 399 | m_filename.clear(); | 409 | m_filename.clear(); |
| 400 | m_psf.clear(); | 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 | // Return | 418 | // Return |
| 408 | return; | 419 | return; |
| @@ -417,12 +428,14 @@ void GCTAPsfKing::init_members(void) | @@ -417,12 +428,14 @@ void GCTAPsfKing::init_members(void) | ||
| 417 | void GCTAPsfKing::copy_members(const GCTAPsfKing& psf) | 428 | void GCTAPsfKing::copy_members(const GCTAPsfKing& psf) |
| 418 | { | 429 | { |
| 419 | // Copy members | 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 | // Return | 440 | // Return |
| 428 | return; | 441 | return; |
| @@ -434,9 +447,6 @@ void GCTAPsfKing::copy_members(const GCTAPsfKing& psf) | @@ -434,9 +447,6 @@ void GCTAPsfKing::copy_members(const GCTAPsfKing& psf) | ||
| 434 | ***************************************************************************/ | 447 | ***************************************************************************/ |
| 435 | void GCTAPsfKing::free_members(void) | 448 | void GCTAPsfKing::free_members(void) |
| 436 | { | 449 | { |
| 437 | - m_filename.clear(); | ||
| 438 | - m_psf.clear(); | ||
| 439 | - | ||
| 440 | // Return | 450 | // Return |
| 441 | return; | 451 | return; |
| 442 | } | 452 | } |
| @@ -447,6 +457,9 @@ void GCTAPsfKing::free_members(void) | @@ -447,6 +457,9 @@ void GCTAPsfKing::free_members(void) | ||
| 447 | * | 457 | * |
| 448 | * @param[in] logE Log10 of the true photon energy (TeV). | 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 | * This method updates the PSF parameter cache. As the performance table PSF | 463 | * This method updates the PSF parameter cache. As the performance table PSF |
| 451 | * only depends on energy, the only parameter on which the cache values | 464 | * only depends on energy, the only parameter on which the cache values |
| 452 | * depend is the energy. | 465 | * depend is the energy. |
| @@ -457,20 +470,42 @@ void GCTAPsfKing::update(const double& logE, const double& theta) const | @@ -457,20 +470,42 @@ void GCTAPsfKing::update(const double& logE, const double& theta) const | ||
| 457 | if (logE != m_par_logE || theta != m_par_theta) { | 470 | if (logE != m_par_logE || theta != m_par_theta) { |
| 458 | 471 | ||
| 459 | // Save parameters | 472 | // Save parameters |
| 460 | - m_par_logE = logE; | 473 | + m_par_logE = logE; |
| 461 | m_par_theta = theta; | 474 | m_par_theta = theta; |
| 462 | 475 | ||
| 463 | // Determine sigma and gamma by interpolating between nodes | 476 | // Determine sigma and gamma by interpolating between nodes |
| 464 | std::vector<double> pars = m_psf(logE,theta); | 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 | // Determine normalisation for given parameters | 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 | // Return | 509 | // Return |
| 474 | return; | 510 | return; |
| 475 | } | 511 | } |
| 476 | - |
inst/cta/src/GCTAResponse.cpp
| @@ -53,6 +53,7 @@ | @@ -53,6 +53,7 @@ | ||
| 53 | #include "GCTAPsf2D.hpp" | 53 | #include "GCTAPsf2D.hpp" |
| 54 | #include "GCTAPsfVector.hpp" | 54 | #include "GCTAPsfVector.hpp" |
| 55 | #include "GCTAPsfPerfTable.hpp" | 55 | #include "GCTAPsfPerfTable.hpp" |
| 56 | +#include "GCTAPsfKing.hpp" | ||
| 56 | #include "GCTAAeff.hpp" | 57 | #include "GCTAAeff.hpp" |
| 57 | #include "GCTAPsf.hpp" | 58 | #include "GCTAPsf.hpp" |
| 58 | #include "GCTAEdisp.hpp" | 59 | #include "GCTAEdisp.hpp" |
| @@ -549,8 +550,13 @@ void GCTAResponse::load(const std::string& irfname) | @@ -549,8 +550,13 @@ void GCTAResponse::load(const std::string& irfname) | ||
| 549 | // Restore calibration database name | 550 | // Restore calibration database name |
| 550 | m_caldb = caldb; | 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 | // Load effective area | 561 | // Load effective area |
| 556 | load_aeff(filename); | 562 | load_aeff(filename); |
| @@ -679,10 +685,22 @@ void GCTAResponse::load_psf(const std::string& filename) | @@ -679,10 +685,22 @@ void GCTAResponse::load_psf(const std::string& filename) | ||
| 679 | GFits file(filename); | 685 | GFits file(filename); |
| 680 | 686 | ||
| 681 | // If file contains a "POINT SPREAD FUNCTION" extension then load it | 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 | if (file.contains("POINT SPREAD FUNCTION")) { | 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 | // ... else load it has PSF vector | 706 | // ... else load it has PSF vector |
inst/cta/test/test_CTA.cpp
| @@ -40,16 +40,18 @@ | @@ -40,16 +40,18 @@ | ||
| 40 | /* __ Globals ____________________________________________________________ */ | 40 | /* __ Globals ____________________________________________________________ */ |
| 41 | 41 | ||
| 42 | /* __ Constants __________________________________________________________ */ | 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 | const std::string cta_modbck_xml = datadir+"/cta_modelbg.xml"; | 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,6 +66,7 @@ void TestGCTAResponse::set(void) | ||
| 64 | append(static_cast<pfunction>(&TestGCTAResponse::test_response), "Test response"); | 66 | append(static_cast<pfunction>(&TestGCTAResponse::test_response), "Test response"); |
| 65 | append(static_cast<pfunction>(&TestGCTAResponse::test_response_aeff), "Test effective area"); | 67 | append(static_cast<pfunction>(&TestGCTAResponse::test_response_aeff), "Test effective area"); |
| 66 | append(static_cast<pfunction>(&TestGCTAResponse::test_response_psf), "Test PSF"); | 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 | append(static_cast<pfunction>(&TestGCTAResponse::test_response_npsf), "Test integrated PSF"); | 70 | append(static_cast<pfunction>(&TestGCTAResponse::test_response_npsf), "Test integrated PSF"); |
| 68 | append(static_cast<pfunction>(&TestGCTAResponse::test_response_irf_diffuse), "Test diffuse IRF"); | 71 | append(static_cast<pfunction>(&TestGCTAResponse::test_response_irf_diffuse), "Test diffuse IRF"); |
| 69 | append(static_cast<pfunction>(&TestGCTAResponse::test_response_npred_diffuse), "Test diffuse IRF integration"); | 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,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 | * @brief Test CTA npsf computation | 280 | * @brief Test CTA npsf computation |
| 240 | ***************************************************************************/ | 281 | ***************************************************************************/ |
| 241 | void TestGCTAResponse::test_response_npsf(void) | 282 | void TestGCTAResponse::test_response_npsf(void) |
| @@ -427,6 +468,30 @@ void TestGCTAResponse::test_response_npred_diffuse(void) | @@ -427,6 +468,30 @@ void TestGCTAResponse::test_response_npred_diffuse(void) | ||
| 427 | return; | 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 | * @brief Test CTA Model Background Npred computation | 496 | * @brief Test CTA Model Background Npred computation |
| 432 | * | 497 | * |
| @@ -511,29 +576,6 @@ void TestGCTAModelBackground::test_modelbg_npred(void) | @@ -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 | * @brief Test unbinned observation handling | 579 | * @brief Test unbinned observation handling |
| 538 | ***************************************************************************/ | 580 | ***************************************************************************/ |
| 539 | void TestGCTAObservation::test_unbinned_obs(void) | 581 | void TestGCTAObservation::test_unbinned_obs(void) |
inst/cta/test/test_CTA.hpp
| @@ -49,6 +49,7 @@ public: | @@ -49,6 +49,7 @@ public: | ||
| 49 | virtual TestGCTAResponse* clone(void) const; | 49 | virtual TestGCTAResponse* clone(void) const; |
| 50 | void test_response_aeff(void); | 50 | void test_response_aeff(void); |
| 51 | void test_response_psf(void); | 51 | void test_response_psf(void); |
| 52 | + void test_response_psf_king(void); | ||
| 52 | void test_response_npsf(void); | 53 | void test_response_npsf(void); |
| 53 | void test_response_irf_diffuse(void); | 54 | void test_response_irf_diffuse(void); |
| 54 | void test_response_npred_diffuse(void); | 55 | void test_response_npred_diffuse(void); |