Commit a3ed1fd1cf08f614f11e276e5fab2369f7fb3cde

Authored by Jürgen Knödlseder
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.
ChangeLog
1   -2017-05-14
  1 +2017-06-06
2 2  
3 3 * Version 1.3.0 released
4 4 =========================
5 5  
  6 + Increase maximum CTA King PSF radius to 2 degrees (#2112)
6 7 Correct set names of spatial GLON/GLAT model parameters (#2113)
7 8 Support "BKG" as name of CTA background template
8 9 Scale optimizer convergence criterion with step size (#2022)
... ...
1 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 6 1. Introduction
... ... @@ -268,6 +268,11 @@ avoid FITS file pointer exceptions (#2021).
268 268 The CTA background template HDUCLAS2 was changed from "BGD" to "BKG". Both strings
269 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 277 21. COMPTEL interface
273 278 ---------------------
... ...
inst/cta/include/GCTAPsfKing.hpp
... ... @@ -111,10 +111,11 @@ public:
111 111  
112 112 private:
113 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 120 // Members
120 121 GFilename m_filename; //!< Name of Aeff response file
... ... @@ -131,6 +132,7 @@ private:
131 132 mutable double m_par_sigma; //!< King profile sigma (radians)
132 133 mutable double m_par_sigma2; //!< King profile sigma squared
133 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 49 /* __ Macros _____________________________________________________________ */
50 50  
51 51 /* __ Coding definitions _________________________________________________ */
52   -#define G_FIX_DELTA_MAX
53 52 #define G_SMOOTH_PSF
54 53  
55 54 /* __ Debug definitions __________________________________________________ */
56 55  
57 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&amp; delta,
198 195 const double& azimuth,
199 196 const bool& etrue) const
200 197 {
201   - #if defined(G_FIX_DELTA_MAX)
202 198 #if defined(G_SMOOTH_PSF)
203 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 202 #endif
208 203  
209 204 // Initialise PSF value
210 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 207 // Update the parameter cache
218 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 235 // Return PSF
248 236 return psf;
... ... @@ -488,22 +476,17 @@ double GCTAPsfKing::mc(GRan&amp; ran,
488 476 // Compute exponent
489 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 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 491 } // endif: normalization was positive
509 492  
... ... @@ -537,25 +520,13 @@ double GCTAPsfKing::delta_max(const double&amp; logE,
537 520 // Initialise PSF radius
538 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 523 // Update the parameter cache
546 524 update(logE, theta);
547 525  
548   - // Continue only if normalization is positive
  526 + // Compute radius if normalization is positive
549 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 531 // Return maximum PSF radius
561 532 return radius;
... ... @@ -687,6 +658,7 @@ void GCTAPsfKing::init_members(void)
687 658 m_par_gamma = 0.0;
688 659 m_par_sigma = 0.0;
689 660 m_par_sigma2 = 0.0;
  661 + m_par_rmax = 0.0;
690 662  
691 663 // Return
692 664 return;
... ... @@ -713,6 +685,7 @@ void GCTAPsfKing::copy_members(const GCTAPsfKing&amp; psf)
713 685 m_par_gamma = psf.m_par_gamma;
714 686 m_par_sigma = psf.m_par_sigma;
715 687 m_par_sigma2 = psf.m_par_sigma2;
  688 + m_par_rmax = psf.m_par_rmax;
716 689  
717 690 // Return
718 691 return;
... ... @@ -738,10 +711,15 @@ void GCTAPsfKing::free_members(void)
738 711 * This method updates the PSF parameter cache. As the performance table PSF
739 712 * only depends on energy, the only parameter on which the cache values
740 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 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 723 // Only compute PSF parameters if arguments have changed
746 724 if (logE != m_par_logE || theta != m_par_theta) {
747 725  
... ... @@ -758,31 +736,38 @@ void GCTAPsfKing::update(const double&amp; logE, const double&amp; theta) const
758 736 m_par_sigma = pars[m_inx_sigma];
759 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 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 749 else {
775 750  
776 751 // Determine normalisation for given parameters
777 752 m_par_norm = 1.0 / gammalib::twopi * (1.0 - 1.0 / m_par_gamma) /
778 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 772 } // endif: King profile parameters were valid
788 773  
... ... @@ -791,3 +776,32 @@ void GCTAPsfKing::update(const double&amp; logE, const double&amp; theta) const
791 776 // Return
792 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 +}
... ...