Commit a3ed1fd1cf08f614f11e276e5fab2369f7fb3cde
1 parent
7d605f42
Set maximum CTA King PSF radius to 2 degrees (#2112)
The maximum radius of the King PSF has been increased from 0.7 to 2 degrees to cope with some extreme cases. Now also the maximum PSF radius is computed for a given energy so that if the PSF is smaller than the maximum radius of 2 degrees a smaller region of interest will be used for the computation.
Showing
4 changed files
with
109 additions
and
87 deletions
ChangeLog
| 1 | -2017-05-14 | 1 | +2017-06-06 |
| 2 | 2 | ||
| 3 | * Version 1.3.0 released | 3 | * Version 1.3.0 released |
| 4 | ========================= | 4 | ========================= |
| 5 | 5 | ||
| 6 | + Increase maximum CTA King PSF radius to 2 degrees (#2112) | ||
| 6 | Correct set names of spatial GLON/GLAT model parameters (#2113) | 7 | Correct set names of spatial GLON/GLAT model parameters (#2113) |
| 7 | Support "BKG" as name of CTA background template | 8 | Support "BKG" as name of CTA background template |
| 8 | Scale optimizer convergence criterion with step size (#2022) | 9 | Scale optimizer convergence criterion with step size (#2022) |
NEWS
| 1 | New Features and Important Changes in GammaLib 1.3.0.dev1 | 1 | New Features and Important Changes in GammaLib 1.3.0.dev1 |
| 2 | 2 | ||
| 3 | -14 May 2017 | 3 | +6 June 2017 |
| 4 | 4 | ||
| 5 | 5 | ||
| 6 | 1. Introduction | 6 | 1. Introduction |
| @@ -268,6 +268,11 @@ avoid FITS file pointer exceptions (#2021). | @@ -268,6 +268,11 @@ avoid FITS file pointer exceptions (#2021). | ||
| 268 | The CTA background template HDUCLAS2 was changed from "BGD" to "BKG". Both strings | 268 | The CTA background template HDUCLAS2 was changed from "BGD" to "BKG". Both strings |
| 269 | are supported by GammaLib. | 269 | are supported by GammaLib. |
| 270 | 270 | ||
| 271 | +The maximum radius of the King PSF has been increased from 0.7 to 2 degrees to cope | ||
| 272 | +with some extreme cases. Now also the maximum PSF radius is computed for a given | ||
| 273 | +energy so that if the PSF is smaller than the maximum radius of 2 degrees a smaller | ||
| 274 | +region of interest will be used for the computation (#2112). | ||
| 275 | + | ||
| 271 | 276 | ||
| 272 | 21. COMPTEL interface | 277 | 21. COMPTEL interface |
| 273 | --------------------- | 278 | --------------------- |
inst/cta/include/GCTAPsfKing.hpp
| @@ -111,10 +111,11 @@ public: | @@ -111,10 +111,11 @@ public: | ||
| 111 | 111 | ||
| 112 | private: | 112 | private: |
| 113 | // Methods | 113 | // Methods |
| 114 | - void init_members(void); | ||
| 115 | - void copy_members(const GCTAPsfKing& psf); | ||
| 116 | - void free_members(void); | ||
| 117 | - void update(const double& logE, const double& theta) const; | 114 | + void init_members(void); |
| 115 | + void copy_members(const GCTAPsfKing& psf); | ||
| 116 | + void free_members(void); | ||
| 117 | + void update(const double& logE, const double& theta) const; | ||
| 118 | + double r_max(const double& logE, const double& theta) const; | ||
| 118 | 119 | ||
| 119 | // Members | 120 | // Members |
| 120 | GFilename m_filename; //!< Name of Aeff response file | 121 | GFilename m_filename; //!< Name of Aeff response file |
| @@ -131,6 +132,7 @@ private: | @@ -131,6 +132,7 @@ private: | ||
| 131 | mutable double m_par_sigma; //!< King profile sigma (radians) | 132 | mutable double m_par_sigma; //!< King profile sigma (radians) |
| 132 | mutable double m_par_sigma2; //!< King profile sigma squared | 133 | mutable double m_par_sigma2; //!< King profile sigma squared |
| 133 | mutable double m_par_gamma; //!< King profile gamma parameter | 134 | mutable double m_par_gamma; //!< King profile gamma parameter |
| 135 | + mutable double m_par_rmax; //!< Maximum PSF radius | ||
| 134 | }; | 136 | }; |
| 135 | 137 | ||
| 136 | 138 |
inst/cta/src/GCTAPsfKing.cpp
| @@ -49,14 +49,11 @@ | @@ -49,14 +49,11 @@ | ||
| 49 | /* __ Macros _____________________________________________________________ */ | 49 | /* __ Macros _____________________________________________________________ */ |
| 50 | 50 | ||
| 51 | /* __ Coding definitions _________________________________________________ */ | 51 | /* __ Coding definitions _________________________________________________ */ |
| 52 | -#define G_FIX_DELTA_MAX | ||
| 53 | #define G_SMOOTH_PSF | 52 | #define G_SMOOTH_PSF |
| 54 | 53 | ||
| 55 | /* __ Debug definitions __________________________________________________ */ | 54 | /* __ Debug definitions __________________________________________________ */ |
| 56 | 55 | ||
| 57 | /* __ Constants __________________________________________________________ */ | 56 | /* __ Constants __________________________________________________________ */ |
| 58 | -const double r_max = 0.7 * gammalib::deg2rad; // Maximum delta for fixed | ||
| 59 | - // delta_max computation | ||
| 60 | 57 | ||
| 61 | 58 | ||
| 62 | /*========================================================================== | 59 | /*========================================================================== |
| @@ -198,51 +195,42 @@ double GCTAPsfKing::operator()(const double& delta, | @@ -198,51 +195,42 @@ double GCTAPsfKing::operator()(const double& delta, | ||
| 198 | const double& azimuth, | 195 | const double& azimuth, |
| 199 | const bool& etrue) const | 196 | const bool& etrue) const |
| 200 | { | 197 | { |
| 201 | - #if defined(G_FIX_DELTA_MAX) | ||
| 202 | #if defined(G_SMOOTH_PSF) | 198 | #if defined(G_SMOOTH_PSF) |
| 203 | // Set ramp down radius | 199 | // Set ramp down radius |
| 204 | - static const double ramp_down = 0.95 * r_max; | ||
| 205 | - static const double norm_down = 1.0 / (r_max - ramp_down); | ||
| 206 | - #endif | 200 | + static const double ramp_down = 0.95 * m_par_rmax; |
| 201 | + static const double norm_down = 1.0 / (m_par_rmax - ramp_down); | ||
| 207 | #endif | 202 | #endif |
| 208 | 203 | ||
| 209 | // Initialise PSF value | 204 | // Initialise PSF value |
| 210 | double psf = 0.0; | 205 | double psf = 0.0; |
| 211 | 206 | ||
| 212 | - // Compile option: set PSF to zero outside delta_max | ||
| 213 | - #if defined(G_FIX_DELTA_MAX) | ||
| 214 | - if (delta <= r_max) { | ||
| 215 | - #endif | ||
| 216 | - | ||
| 217 | // Update the parameter cache | 207 | // Update the parameter cache |
| 218 | update(logE, theta); | 208 | update(logE, theta); |
| 219 | 209 | ||
| 220 | - // Continue only if normalization is positive | ||
| 221 | - if (m_par_norm > 0.0) { | ||
| 222 | - | ||
| 223 | - // Compute PSF value | ||
| 224 | - double arg = delta / m_par_sigma; | ||
| 225 | - double arg2 = arg * arg; | ||
| 226 | - psf = m_par_norm * | ||
| 227 | - std::pow((1.0 + 1.0 / (2.0 * m_par_gamma) * arg2), -m_par_gamma); | ||
| 228 | - | ||
| 229 | - // If we are at large offset angles, add a smooth ramp down to | ||
| 230 | - // avoid steps in the log-likelihood computation | ||
| 231 | - #if defined(G_FIX_DELTA_MAX) | ||
| 232 | - #if defined(G_SMOOTH_PSF) | ||
| 233 | - if (delta > ramp_down) { | ||
| 234 | - double x = norm_down * (delta - ramp_down); | ||
| 235 | - psf *= 1.0 - x * x; | ||
| 236 | - } | ||
| 237 | - #endif | ||
| 238 | - #endif | 210 | + // Continue only if delta is smaller than PSF radius |
| 211 | + if (delta <= m_par_rmax) { | ||
| 212 | + | ||
| 213 | + // Continue only if normalization is positive | ||
| 214 | + if (m_par_norm > 0.0) { | ||
| 215 | + | ||
| 216 | + // Compute PSF value | ||
| 217 | + double arg = delta / m_par_sigma; | ||
| 218 | + double arg2 = arg * arg; | ||
| 219 | + psf = m_par_norm * | ||
| 220 | + std::pow((1.0 + 1.0 / (2.0 * m_par_gamma) * arg2), -m_par_gamma); | ||
| 221 | + | ||
| 222 | + // If we are at large offset angles, add a smooth ramp down to | ||
| 223 | + // avoid steps in the log-likelihood computation | ||
| 224 | + #if defined(G_SMOOTH_PSF) | ||
| 225 | + if (delta > ramp_down) { | ||
| 226 | + double x = norm_down * (delta - ramp_down); | ||
| 227 | + psf *= 1.0 - x * x; | ||
| 228 | + } | ||
| 229 | + #endif | ||
| 239 | 230 | ||
| 240 | - } // endif: normalization was positive | 231 | + } // endif: normalization was positive |
| 241 | 232 | ||
| 242 | - // Compile option: set PSF to zero outside delta_max | ||
| 243 | - #if defined(G_FIX_DELTA_MAX) | ||
| 244 | - } | ||
| 245 | - #endif | 233 | + } // endif: PSF radius was smaller than PSF radius |
| 246 | 234 | ||
| 247 | // Return PSF | 235 | // Return PSF |
| 248 | return psf; | 236 | return psf; |
| @@ -488,22 +476,17 @@ double GCTAPsfKing::mc(GRan& ran, | @@ -488,22 +476,17 @@ double GCTAPsfKing::mc(GRan& ran, | ||
| 488 | // Compute exponent | 476 | // Compute exponent |
| 489 | double exponent = 1.0 / (1.0-m_par_gamma); | 477 | double exponent = 1.0 / (1.0-m_par_gamma); |
| 490 | 478 | ||
| 491 | - // Compile option: sample until delta <= r_max | ||
| 492 | - #if defined(G_FIX_DELTA_MAX) | 479 | + // Sample until delta <= m_par_rmax |
| 493 | do { | 480 | do { |
| 494 | - #endif | ||
| 495 | 481 | ||
| 496 | - // Get uniform random number | ||
| 497 | - double u = ran.uniform(); | 482 | + // Get uniform random number |
| 483 | + double u = ran.uniform(); | ||
| 498 | 484 | ||
| 499 | - // Draw random offset using inversion sampling | ||
| 500 | - double u_max = (std::pow((1.0 - u), exponent) - 1.0) * m_par_gamma; | ||
| 501 | - delta = m_par_sigma * std::sqrt(2.0 * u_max); | 485 | + // Draw random offset using inversion sampling |
| 486 | + double u_max = (std::pow((1.0 - u), exponent) - 1.0) * m_par_gamma; | ||
| 487 | + delta = m_par_sigma * std::sqrt(2.0 * u_max); | ||
| 502 | 488 | ||
| 503 | - // Compile option: sample until delta <= r_max | ||
| 504 | - #if defined(G_FIX_DELTA_MAX) | ||
| 505 | - } while (delta > r_max); | ||
| 506 | - #endif | 489 | + } while (delta > m_par_rmax); |
| 507 | 490 | ||
| 508 | } // endif: normalization was positive | 491 | } // endif: normalization was positive |
| 509 | 492 | ||
| @@ -537,25 +520,13 @@ double GCTAPsfKing::delta_max(const double& logE, | @@ -537,25 +520,13 @@ double GCTAPsfKing::delta_max(const double& logE, | ||
| 537 | // Initialise PSF radius | 520 | // Initialise PSF radius |
| 538 | double radius = 0.0; | 521 | double radius = 0.0; |
| 539 | 522 | ||
| 540 | - // Compile option: use fixed maximum delta | ||
| 541 | - #if defined(G_FIX_DELTA_MAX) | ||
| 542 | - radius = r_max; | ||
| 543 | - #else | ||
| 544 | - | ||
| 545 | // Update the parameter cache | 523 | // Update the parameter cache |
| 546 | update(logE, theta); | 524 | update(logE, theta); |
| 547 | 525 | ||
| 548 | - // Continue only if normalization is positive | 526 | + // Compute radius if normalization is positive |
| 549 | if (m_par_norm > 0.0) { | 527 | if (m_par_norm > 0.0) { |
| 550 | - | ||
| 551 | - // Compute maximum PSF radius (99.995% containment) | ||
| 552 | - double F = 0.99995; | ||
| 553 | - double u_max = (std::pow((1.0 - F), (1.0/(1.0-m_par_gamma))) - 1.0) * | ||
| 554 | - m_par_gamma; | ||
| 555 | - radius = m_par_sigma * std::sqrt(2.0 * u_max); | ||
| 556 | - | ||
| 557 | - } // endif: King profile parameters were valid | ||
| 558 | - #endif | 528 | + radius = r_max(logE, theta); |
| 529 | + } | ||
| 559 | 530 | ||
| 560 | // Return maximum PSF radius | 531 | // Return maximum PSF radius |
| 561 | return radius; | 532 | return radius; |
| @@ -687,6 +658,7 @@ void GCTAPsfKing::init_members(void) | @@ -687,6 +658,7 @@ void GCTAPsfKing::init_members(void) | ||
| 687 | m_par_gamma = 0.0; | 658 | m_par_gamma = 0.0; |
| 688 | m_par_sigma = 0.0; | 659 | m_par_sigma = 0.0; |
| 689 | m_par_sigma2 = 0.0; | 660 | m_par_sigma2 = 0.0; |
| 661 | + m_par_rmax = 0.0; | ||
| 690 | 662 | ||
| 691 | // Return | 663 | // Return |
| 692 | return; | 664 | return; |
| @@ -713,6 +685,7 @@ void GCTAPsfKing::copy_members(const GCTAPsfKing& psf) | @@ -713,6 +685,7 @@ void GCTAPsfKing::copy_members(const GCTAPsfKing& psf) | ||
| 713 | m_par_gamma = psf.m_par_gamma; | 685 | m_par_gamma = psf.m_par_gamma; |
| 714 | m_par_sigma = psf.m_par_sigma; | 686 | m_par_sigma = psf.m_par_sigma; |
| 715 | m_par_sigma2 = psf.m_par_sigma2; | 687 | m_par_sigma2 = psf.m_par_sigma2; |
| 688 | + m_par_rmax = psf.m_par_rmax; | ||
| 716 | 689 | ||
| 717 | // Return | 690 | // Return |
| 718 | return; | 691 | return; |
| @@ -738,10 +711,15 @@ void GCTAPsfKing::free_members(void) | @@ -738,10 +711,15 @@ void GCTAPsfKing::free_members(void) | ||
| 738 | * This method updates the PSF parameter cache. As the performance table PSF | 711 | * This method updates the PSF parameter cache. As the performance table PSF |
| 739 | * only depends on energy, the only parameter on which the cache values | 712 | * only depends on energy, the only parameter on which the cache values |
| 740 | * depend is the energy. If the PSF parameters are invalid the m_par_norm | 713 | * depend is the energy. If the PSF parameters are invalid the m_par_norm |
| 741 | - * member will be set to zero. | 714 | + * member will be set to zero. Valid PSF parameters are \f$\gamma > 1\f$ and |
| 715 | + * \f$\simga > 0\f$. | ||
| 742 | ***************************************************************************/ | 716 | ***************************************************************************/ |
| 743 | void GCTAPsfKing::update(const double& logE, const double& theta) const | 717 | void GCTAPsfKing::update(const double& logE, const double& theta) const |
| 744 | { | 718 | { |
| 719 | + // Maximum PSF radius in radians. We set the maximum radius to 2 degrees | ||
| 720 | + // since it's hard to imaging that a PSF will ever be larger. | ||
| 721 | + const double r_max = 2.0 * gammalib::deg2rad; | ||
| 722 | + | ||
| 745 | // Only compute PSF parameters if arguments have changed | 723 | // Only compute PSF parameters if arguments have changed |
| 746 | if (logE != m_par_logE || theta != m_par_theta) { | 724 | if (logE != m_par_logE || theta != m_par_theta) { |
| 747 | 725 | ||
| @@ -758,31 +736,38 @@ void GCTAPsfKing::update(const double& logE, const double& theta) const | @@ -758,31 +736,38 @@ void GCTAPsfKing::update(const double& logE, const double& theta) const | ||
| 758 | m_par_sigma = pars[m_inx_sigma]; | 736 | m_par_sigma = pars[m_inx_sigma]; |
| 759 | m_par_sigma2 = m_par_sigma * m_par_sigma; | 737 | m_par_sigma2 = m_par_sigma * m_par_sigma; |
| 760 | 738 | ||
| 761 | - // Check for parameter sanity | ||
| 762 | - if (m_par_gamma <= 0.0 || m_par_sigma <= 0.0) { | 739 | + // Check for parameter sanity. The King function is not defined for |
| 740 | + // gamma values equal or smaller than one and non-positive sigma | ||
| 741 | + // values. If this is the case we set the normalization and the | ||
| 742 | + // maximum radius to zero ... | ||
| 743 | + if (m_par_gamma <= 1.0 || m_par_sigma <= 0.0) { | ||
| 763 | m_par_norm = 0.0; | 744 | m_par_norm = 0.0; |
| 764 | - /* | ||
| 765 | - std::string msg = "King function parameters gamma="+ | ||
| 766 | - gammalib::str(m_par_gamma)+" or sigma="+ | ||
| 767 | - gammalib::str(m_par_sigma)+" are not positive " | ||
| 768 | - "for logE="+gammalib::str(logE)+" and theta="+ | ||
| 769 | - gammalib::str(theta)+". Setting normalization " | ||
| 770 | - "to zero."; | ||
| 771 | - gammalib::warning(G_UPDATE, msg); | ||
| 772 | - */ | 745 | + m_par_rmax = 0.0; |
| 773 | } | 746 | } |
| 747 | + | ||
| 748 | + // ... otherwise we compute the normalization | ||
| 774 | else { | 749 | else { |
| 775 | 750 | ||
| 776 | // Determine normalisation for given parameters | 751 | // Determine normalisation for given parameters |
| 777 | m_par_norm = 1.0 / gammalib::twopi * (1.0 - 1.0 / m_par_gamma) / | 752 | m_par_norm = 1.0 / gammalib::twopi * (1.0 - 1.0 / m_par_gamma) / |
| 778 | m_par_sigma2; | 753 | m_par_sigma2; |
| 779 | 754 | ||
| 780 | - // Optionally correct for fixed delta_max | ||
| 781 | - #if defined(G_FIX_DELTA_MAX) | ||
| 782 | - double u_max = (r_max*r_max) / (2.0 * m_par_sigma2); | ||
| 783 | - double norm = 1.0 - std::pow((1.0 + u_max/m_par_gamma), 1.0-m_par_gamma); | ||
| 784 | - m_par_norm /= norm; | ||
| 785 | - #endif | 755 | + // Determine maximum PSF radius |
| 756 | + m_par_rmax = this->r_max(logE, theta); | ||
| 757 | + | ||
| 758 | + // Make sure that radius is smaller than 2 degrees | ||
| 759 | + if (m_par_rmax > r_max) { | ||
| 760 | + | ||
| 761 | + // Restrict PSF radius to 2 degrees | ||
| 762 | + m_par_rmax = r_max; | ||
| 763 | + | ||
| 764 | + // Correct PSF normalization for restriction | ||
| 765 | + double u_max = (m_par_rmax*m_par_rmax) / (2.0 * m_par_sigma2); | ||
| 766 | + double norm = 1.0 - std::pow((1.0 + u_max/m_par_gamma), | ||
| 767 | + (1.0-m_par_gamma)); | ||
| 768 | + m_par_norm /= norm; | ||
| 769 | + | ||
| 770 | + } // endif: restricted PSF radius | ||
| 786 | 771 | ||
| 787 | } // endif: King profile parameters were valid | 772 | } // endif: King profile parameters were valid |
| 788 | 773 | ||
| @@ -791,3 +776,32 @@ void GCTAPsfKing::update(const double& logE, const double& theta) const | @@ -791,3 +776,32 @@ void GCTAPsfKing::update(const double& logE, const double& theta) const | ||
| 791 | // Return | 776 | // Return |
| 792 | return; | 777 | return; |
| 793 | } | 778 | } |
| 779 | + | ||
| 780 | + | ||
| 781 | +/***********************************************************************//** | ||
| 782 | + * @brief Return maximum size of PSF (radians) | ||
| 783 | + * | ||
| 784 | + * @param[in] logE Log10 of the true photon energy (TeV). | ||
| 785 | + * @param[in] theta Offset angle in camera system (rad). | ||
| 786 | + * | ||
| 787 | + * Determine the radius beyond which the PSF becomes negligible. This radius | ||
| 788 | + * is set by this method to where the containment fraction become 99.995% | ||
| 789 | + * which equals \f$5 \times \sigma\f$ of a Gaussian width. | ||
| 790 | + * | ||
| 791 | + * This method requires the m_par_gamma and m_par_sigma to be set to valid | ||
| 792 | + * values. | ||
| 793 | + ***************************************************************************/ | ||
| 794 | +double GCTAPsfKing::r_max(const double& logE, | ||
| 795 | + const double& theta) const | ||
| 796 | +{ | ||
| 797 | + // Set 99.995% containment fraction | ||
| 798 | + const double F = 0.99995; | ||
| 799 | + | ||
| 800 | + // Compute maximum PSF radius for containment fraction | ||
| 801 | + double u_max = (std::pow((1.0 - F), (1.0/(1.0-m_par_gamma))) - 1.0) * | ||
| 802 | + m_par_gamma; | ||
| 803 | + double radius = m_par_sigma * std::sqrt(2.0 * u_max); | ||
| 804 | + | ||
| 805 | + // Return maximum PSF radius | ||
| 806 | + return radius; | ||
| 807 | +} |