GammaLib 2.0.0
Loading...
Searching...
No Matches
GCTAPsf2D.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GCTAPsf2D.cpp - CTA 2D point spread function class *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2012-2021 by Juergen Knoedlseder *
5 * ----------------------------------------------------------------------- *
6 * *
7 * This program is free software: you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation, either version 3 of the License, or *
10 * (at your option) any later version. *
11 * *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
16 * *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19 * *
20 ***************************************************************************/
21/**
22 * @file GCTAPsf2D.hpp
23 * @brief CTA 2D point spread function class implementation
24 * @author Juergen Knoedlseder
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include <cmath>
32#include "GTools.hpp"
33#include "GMath.hpp"
34#include "GException.hpp"
35#include "GFilename.hpp"
36#include "GRan.hpp"
37#include "GFits.hpp"
38#include "GFitsBinTable.hpp"
39#include "GCTAPsf2D.hpp"
40#include "GCTASupport.hpp"
41
42/* __ Method name definitions ____________________________________________ */
43#define G_READ "GCTAPsf2D::read(GFitsTable&)"
44#define G_CONTAINMENT_RADIUS "GCTAPsf2D::containment_radius(double&,"\
45 " double&, double&, double&, double&, double&, bool&)"
46
47/* __ Macros _____________________________________________________________ */
48
49/* __ Coding definitions _________________________________________________ */
50#define G_SMOOTH_PSF
51
52/* __ Debug definitions __________________________________________________ */
53
54/* __ Constants __________________________________________________________ */
55
56
57/*==========================================================================
58 = =
59 = Constructors/destructors =
60 = =
61 ==========================================================================*/
62
63/***********************************************************************//**
64 * @brief Void constructor
65 *
66 * Constructs empty point spread function.
67 ***************************************************************************/
69{
70 // Initialise class members
72
73 // Return
74 return;
75}
76
77
78/***********************************************************************//**
79 * @brief File constructor
80 *
81 * @param[in] filename FITS file name.
82 *
83 * Constructs point spread function from a FITS file.
84 ***************************************************************************/
86{
87 // Initialise class members
89
90 // Load point spread function from file
92
93 // Return
94 return;
95}
96
97
98/***********************************************************************//**
99 * @brief Copy constructor
100 *
101 * @param[in] psf Point spread function.
102 *
103 * Constructs point spread function by copying from another point spread
104 * function.
105 ***************************************************************************/
107{
108 // Initialise class members
109 init_members();
110
111 // Copy members
112 copy_members(psf);
113
114 // Return
115 return;
116}
117
118
119/***********************************************************************//**
120 * @brief Destructor
121 *
122 * Destructs point spread function.
123 ***************************************************************************/
125{
126 // Free members
127 free_members();
128
129 // Return
130 return;
131}
132
133
134/*==========================================================================
135 = =
136 = Operators =
137 = =
138 ==========================================================================*/
139
140/***********************************************************************//**
141 * @brief Assignment operator
142 *
143 * @param[in] psf Point spread function.
144 * @return Point spread function.
145 *
146 * Assigns point spread function.
147 ***************************************************************************/
149{
150 // Execute only if object is not identical
151 if (this != &psf) {
152
153 // Copy base class members
154 this->GCTAPsf::operator=(psf);
155
156 // Free members
157 free_members();
158
159 // Initialise private members
160 init_members();
161
162 // Copy members
163 copy_members(psf);
164
165 } // endif: object was not identical
166
167 // Return this object
168 return *this;
169}
170
171
172/***********************************************************************//**
173 * @brief Return point spread function (in units of sr^-1)
174 *
175 * @param[in] delta Angular separation between true and measured photon
176 * directions (rad).
177 * @param[in] logE Log10 of the true photon energy (TeV).
178 * @param[in] theta Offset angle in camera system (rad). Defaults to 0.0.
179 * @param[in] phi Azimuth angle in camera system (rad). Not used.
180 * @param[in] zenith Zenith angle in Earth system (rad). Not used.
181 * @param[in] azimuth Azimuth angle in Earth system (rad). Not used.
182 * @param[in] etrue Use true energy (true/false). Not used.
183 *
184 * Returns the point spread function for a given angular separation in units
185 * of sr^-1 for a given energy and offset angle.
186 ***************************************************************************/
187double GCTAPsf2D::operator()(const double& delta,
188 const double& logE,
189 const double& theta,
190 const double& phi,
191 const double& zenith,
192 const double& azimuth,
193 const bool& etrue) const
194{
195 #if defined(G_SMOOTH_PSF)
196 // Compute offset so that PSF goes to 0 at 5 times the sigma value. This
197 // is a kluge to get a PSF that smoothly goes to zero at the edge, which
198 // prevents steps or kinks in the log-likelihood function.
199 static const double offset = std::exp(-0.5*5.0*5.0);
200 #endif
201
202 // Initialise PSF value
203 double psf = 0.0;
204
205 // Update the parameter cache
206 update(logE, theta);
207
208 // Continue only if normalization is positive
209 if (m_norm > 0.0) {
210
211 // Compute distance squared
212 double delta2 = delta * delta;
213
214 // Compute Psf value
215 #if defined(G_SMOOTH_PSF)
216 psf = std::exp(m_width1 * delta2) - offset;
217 if (m_norm2 > 0.0) {
218 psf += (std::exp(m_width2 * delta2)-offset) * m_norm2;
219 }
220 if (m_norm3 > 0.0) {
221 psf += (std::exp(m_width3 * delta2)-offset) * m_norm3;
222 }
223 #else
224 psf = std::exp(m_width1 * delta2);
225 if (m_norm2 > 0.0) {
226 psf += std::exp(m_width2 * delta2) * m_norm2;
227 }
228 if (m_norm3 > 0.0) {
229 psf += std::exp(m_width3 * delta2) * m_norm3;
230 }
231 #endif
232 psf *= m_norm;
233
234 #if defined(G_SMOOTH_PSF)
235 // Make sure that PSF is non-negative
236 if (psf < 0.0) {
237 psf = 0.0;
238 }
239 #endif
240
241 } // endif: normalization was positive
242
243 // Return PSF
244 return psf;
245}
246
247
248/*==========================================================================
249 = =
250 = Public methods =
251 = =
252 ==========================================================================*/
253
254/***********************************************************************//**
255 * @brief Clear point spread function
256 *
257 * Clears point spread function.
258 ***************************************************************************/
260{
261 // Free class members
262 free_members();
263 this->GCTAPsf::free_members();
264
265 // Initialise members
266 this->GCTAPsf::init_members();
267 init_members();
268
269 // Return
270 return;
271}
272
273
274/***********************************************************************//**
275 * @brief Clone point spread functions
276 *
277 * @return Deep copy of point spread function.
278 *
279 * Returns a pointer to a deep copy of the point spread function.
280 ***************************************************************************/
282{
283 return new GCTAPsf2D(*this);
284}
285
286
287/***********************************************************************//**
288 * @brief Read point spread function from FITS table
289 *
290 * @param[in] table FITS table.
291 *
292 * @exception GException::invalid_value
293 * Response table is not two-dimensional.
294 *
295 * Reads the point spread function form the FITS @p table. The following
296 * column names are mandatory:
297 *
298 * ENERG_LO - Energy lower bin boundaries
299 * ENERG_HI - Energy upper bin boundaries
300 * THETA_LO - Offset angle lower bin boundaries
301 * THETA_HI - Offset angle upper bin boundaries
302 * SIGMA_1 - 1st Gaussian sigma
303 * AMPL_2 - 2nd Gaussian relative amplitude
304 * SIGMA_2 - 2nd Gaussian sigma
305 * AMPL_3 - 3rd Gaussian relative amplitude
306 * SIGMA_3 - 3rd Gaussian sigma
307 *
308 * The data are stored in the m_psf member. The energy axis will be set to
309 * log10, the offset angle axis to radians.
310 ***************************************************************************/
311void GCTAPsf2D::read(const GFitsTable& table)
312{
313 // Clear response table
314 m_psf.clear();
315
316 // Read PSF table
318
319 // Get mandatory indices (throw exception if not found)
320 m_inx_energy = m_psf.axis("ENERG");
321 m_inx_theta = m_psf.axis("THETA");
322 m_inx_sigma1 = m_psf.table("SIGMA_1");
323 m_inx_ampl2 = m_psf.table("AMPL_2");
324 m_inx_sigma2 = m_psf.table("SIGMA_2");
325 m_inx_ampl3 = m_psf.table("AMPL_3");
326 m_inx_sigma3 = m_psf.table("SIGMA_3");
327
328 // Throw an exception if the table is not two-dimensional
329 if (m_psf.axes() != 2) {
330 std::string msg = "Expected two-dimensional point spread function "
331 "response table but found "+
333 " dimensions. Please specify a two-dimensional "
334 "point spread function.";
336 }
337
338 // Set energy axis to logarithmic scale
340
341 // Set offset angle axis to radians
343
344 // Convert sigma parameters to radians
348
349 // Return
350 return;
351}
352
353
354/***********************************************************************//**
355 * @brief Write point spread function into FITS binary table
356 *
357 * @param[in] table FITS binary table.
358 *
359 * Writes point spread function into FITS binary @p table.
360 *
361 * @todo Add necessary keywords.
362 ***************************************************************************/
364{
365 // Create a copy of the response table
367
368 // Convert sigma parameters back to degrees (only if there are tables)
369 if (psf.tables() > 0) {
373 }
374
375 // Write response table
376 psf.write(table);
377
378 // Return
379 return;
380}
381
382
383/***********************************************************************//**
384 * @brief Load point spread function from FITS file
385 *
386 * @param[in] filename FITS file name.
387 *
388 * Loads the point spread function from a FITS file.
389 *
390 * If no extension name is given the method scans the `HDUCLASS` keywords
391 * of all extensions and loads the background from the first extension
392 * for which `HDUCLAS4=PSF_3GAUSS`.
393 *
394 * Otherwise, the background will be loaded from the `POINT SPREAD FUNCTION`
395 * extension.
396 ***************************************************************************/
397void GCTAPsf2D::load(const GFilename& filename)
398{
399 // Open FITS file
400 GFits fits(filename);
401
402 // Get the default extension name. If no GADF compliant name was found
403 // then set the default extension name to "POINT SPREAD FUNCTION".
404 std::string extname = gammalib::gadf_hduclas4(fits, "PSF_3GAUSS");
405 if (extname.empty()) {
407 }
408
409 // Get PSF table
410 const GFitsTable& table = *fits.table(filename.extname(extname));
411
412 // Read PSF from table
413 read(table);
414
415 // Close FITS file
416 fits.close();
417
418 // Store filename
420
421 // Return
422 return;
423}
424
425
426/***********************************************************************//**
427 * @brief Save point spread function table into FITS file
428 *
429 * @param[in] filename FITS file name.
430 * @param[in] clobber Overwrite existing file?
431 *
432 * Save the point spread function into a FITS file.
433 *
434 * If no extension name is provided, the point spread function will be saved
435 * into the `POINT SPREAD FUNCTION` extension.
436 ***************************************************************************/
437void GCTAPsf2D::save(const GFilename& filename, const bool& clobber) const
438{
439 // Get extension name
440 std::string extname = filename.extname(gammalib::extname_cta_psf2d);
441
442 // Open or create FITS file (without extension name since the requested
443 // extension may not yet exist in the file)
444 GFits fits(filename.url(), true);
445
446 // Remove extension if it exists already
447 if (fits.contains(extname)) {
448 fits.remove(extname);
449 }
450
451 // Create binary table
453
454 // Write the background table
455 write(table);
456
457 // Set binary table extension name
458 table.extname(extname);
459
460 // Append table to FITS file
461 fits.append(table);
462
463 // Save to file
464 fits.save(clobber);
465
466 // Return
467 return;
468}
469
470
471/***********************************************************************//**
472 * @brief Simulate PSF offset (radians)
473 *
474 * @param[in] ran Random number generator.
475 * @param[in] logE Log10 of the true photon energy (TeV).
476 * @param[in] theta Offset angle in camera system (rad).
477 * @param[in] phi Azimuth angle in camera system (rad). Not used.
478 * @param[in] zenith Zenith angle in Earth system (rad). Not used.
479 * @param[in] azimuth Azimuth angle in Earth system (rad). Not used.
480 * @param[in] etrue Use true energy (true/false). Not used.
481 *
482 * Draws a random offset for a three component Gaussian PSF.
483 ***************************************************************************/
484double GCTAPsf2D::mc(GRan& ran,
485 const double& logE,
486 const double& theta,
487 const double& phi,
488 const double& zenith,
489 const double& azimuth,
490 const bool& etrue) const
491{
492 // Update the parameter cache
493 update(logE, theta);
494
495 // Select in which Gaussian we are
496 double sigma = m_sigma1;
497 double sum1 = m_sigma1;
498 double sum2 = m_sigma2 * m_norm2;
499 double sum3 = m_sigma3 * m_norm3;
500 double sum = sum1 + sum2 + sum3;
501 double u = ran.uniform() * sum;
502 if (sum2 > 0.0 && u >= sum2) {
503 sigma = m_sigma3;
504 }
505 else if (sum1 > 0.0 && u >= sum1) {
506 sigma = m_sigma2;
507 }
508
509 // Now draw from the selected Gaussian
510 double delta = sigma * ran.chisq2();
511
512 // Return PSF offset
513 return delta;
514}
515
516
517/***********************************************************************//**
518 * @brief Return maximum size of PSF (radians)
519 *
520 * @param[in] logE Log10 of the true photon energy (TeV).
521 * @param[in] theta Offset angle in camera system (rad). Not used.
522 * @param[in] phi Azimuth angle in camera system (rad). Not used.
523 * @param[in] zenith Zenith angle in Earth system (rad). Not used.
524 * @param[in] azimuth Azimuth angle in Earth system (rad). Not used.
525 * @param[in] etrue Use true energy (true/false). Not used.
526 *
527 * Determine the radius beyond which the PSF becomes negligible. This radius
528 * is set by this method to \f$5 \times \sigma\f$, where \f$\sigma\f$ is the
529 * Gaussian width of the largest PSF component.
530 ***************************************************************************/
531double GCTAPsf2D::delta_max(const double& logE,
532 const double& theta,
533 const double& phi,
534 const double& zenith,
535 const double& azimuth,
536 const bool& etrue) const
537{
538 // Update the parameter cache
539 update(logE, theta);
540
541 // Compute maximum sigma
542 double sigma = m_sigma1;
543 if (m_sigma2 > sigma) sigma = m_sigma2;
544 if (m_sigma3 > sigma) sigma = m_sigma3;
545
546 // Compute maximum PSF radius
547 double radius = 5.0 * sigma;
548
549 // Return maximum PSF radius
550 return radius;
551}
552
553
554/***********************************************************************//**
555 * @brief Return the radius that contains a fraction of the events (radians)
556 *
557 * @param[in] fraction of events (0.0 < fraction < 1.0)
558 * @param[in] logE Log10 of the true photon energy (TeV).
559 * @param[in] theta Offset angle in camera system (rad).
560 * @param[in] phi Azimuth angle in camera system (rad). Not used.
561 * @param[in] zenith Zenith angle in Earth system (rad). Not used.
562 * @param[in] azimuth Azimuth angle in Earth system (rad). Not used.
563 * @param[in] etrue Use true energy (true/false). Not used.
564 * @return Containment radius (radians).
565 *
566 * @exception GException::invalid_argument
567 * Invalid fraction specified.
568 *
569 * Uses the Newton-Raphson method to find which 'a' solves the equation:
570 *
571 * \f[
572 *
573 * fraction = m\_norm * \left( e^{m\_width1 * a^2} +
574 * m\_norm2 * e^{m\_width2 * a^2} +
575 * m\_norm3 * e^{m\_width3 * a^2} \right)
576 *
577 * \f]
578 *
579 * Calculate the radius from the center that contains @p fraction of the
580 * events (@p fraction * 100. = Containment % ). Fraction must be
581 *
582 * \f[
583 * 0.0 < fraction < 1.0
584 * \f]
585 ***************************************************************************/
586double GCTAPsf2D::containment_radius(const double& fraction,
587 const double& logE,
588 const double& theta,
589 const double& phi,
590 const double& zenith,
591 const double& azimuth,
592 const bool& etrue) const
593{
594 // Set maximum number of Newton-Raphson loops before giving up and
595 // required accuracy
596 const int itermax = 20;
597 const double convergence = 1.0e-6;
598
599 // Check input argument
600 if (fraction <= 0.0 || fraction >= 1.0) {
601 std::string message = "Containment fraction "+
602 gammalib::str(fraction)+" must be between " +
603 "0.0 and 1.0, not inclusive.";
605 }
606
607 // Update the parameter cache
608 update(logE, theta);
609
610 // Set minimum and maximum radius (avoid starting at zero radius)
611 double amax = delta_max(logE, theta, phi, zenith, azimuth, etrue);
612 double amin = 0.000001 * amax;
613
614 // Set initial radius to start Newton's method
615 double a = 0.20 * amax;
616
617 // Set normalisation constants
618 double norm1 = (m_width1 != 0.0) ? -gammalib::pi/m_width1 : 0.0;
619 double norm2 = (m_width2 != 0.0) ? -gammalib::pi/m_width2 * m_norm2 : 0.0;
620 double norm3 = (m_width3 != 0.0) ? -gammalib::pi/m_width3 * m_norm3 : 0.0;
621
622 // Do the Newton-Raphson loops
623 int iter = 0;
624 for (; iter < itermax; ++iter) {
625
626 // Compute square of test radius
627 double a2 = a*a;
628
629 // Precompute exponentials
630 double exp1 = std::exp(m_width1 * a2);
631 double exp2 = std::exp(m_width2 * a2);
632 double exp3 = std::exp(m_width3 * a2);
633
634 // Calculate f(a)
635 double fa = 0.0;
636 fa += norm1 * (1.0 - exp1);
637 fa += norm2 * (1.0 - exp2);
638 fa += norm3 * (1.0 - exp3);
639 fa *= m_norm;
640 fa -= fraction;
641
642 // If we've met the desired accuracy then exit the loop
643 if (std::abs(fa) < convergence) {
644 break;
645 }
646
647 // Calculate f'(a)
648 double fp = 0.0;
649 fp += norm1 * exp1 * m_width1;
650 fp += norm2 * exp2 * m_width2;
651 fp += norm3 * exp3 * m_width3;
652 fp *= -2.0 * a * m_norm;
653
654 // Calculate next point via x+1 = x - f(a) / f'(a)
655 if (fp != 0.0) {
656 a -= fa / fp;
657 if (a < amin) {
658 a = amin;
659 }
660 if (a > amax) {
661 a = amax;
662 }
663 }
664 else {
665 break;
666 }
667
668 } // endfor: Newton-Raphson loops
669
670 // Warn the user if we didn't converge
671 if (iter == itermax-1) {
672 std::string msg = "Unable to converge within " +
673 gammalib::str(convergence)+" of the root in less "
674 "than "+gammalib::str(itermax)+" iterations." ;
676 }
677
678 // Return containment radius
679 return a;
680}
681
682
683/***********************************************************************//**
684 * @brief Print point spread function information
685 *
686 * @param[in] chatter Chattiness.
687 * @return String containing point spread function information.
688 ***************************************************************************/
689std::string GCTAPsf2D::print(const GChatter& chatter) const
690{
691 // Initialise result string
692 std::string result;
693
694 // Continue only if chatter is not silent
695 if (chatter != SILENT) {
696
697 // Append header
698 result.append("=== GCTAPsf2D ===");
699 result.append("\n"+gammalib::parformat("Filename")+m_filename);
700
701 // Initialise information
702 int nebins = 0;
703 int nthetabins = 0;
704 double emin = 0.0;
705 double emax = 0.0;
706 double omin = 0.0;
707 double omax = 0.0;
708
709 // Extract information if there are axes in the response table
710 if (m_psf.axes() > 0) {
711 nebins = m_psf.axis_bins(m_inx_energy);
712 nthetabins = m_psf.axis_bins(m_inx_theta);
713 emin = m_psf.axis_lo(m_inx_energy,0);
714 emax = m_psf.axis_hi(m_inx_energy,nebins-1);
715 omin = m_psf.axis_lo(m_inx_theta,0);
716 omax = m_psf.axis_hi(m_inx_theta,nthetabins-1);
717 }
718
719 // Append information
720 result.append("\n"+gammalib::parformat("Number of energy bins") +
721 gammalib::str(nebins));
722 result.append("\n"+gammalib::parformat("Number of offset bins") +
723 gammalib::str(nthetabins));
724 result.append("\n"+gammalib::parformat("Energy range"));
725 result.append(gammalib::str(emin)+" - "+gammalib::str(emax)+" TeV");
726 result.append("\n"+gammalib::parformat("Offset angle range"));
727 result.append(gammalib::str(omin)+" - "+gammalib::str(omax)+" deg");
728
729 } // endif: chatter was not silent
730
731 // Return result
732 return result;
733}
734
735
736/*==========================================================================
737 = =
738 = Private methods =
739 = =
740 ==========================================================================*/
741
742/***********************************************************************//**
743 * @brief Initialise class members
744 ***************************************************************************/
746{
747 // Initialise members
749 m_psf.clear();
750 m_inx_energy = 0;
751 m_inx_theta = 1;
752 m_inx_sigma1 = 0;
753 m_inx_ampl2 = 1;
754 m_inx_sigma2 = 2;
755 m_inx_ampl3 = 3;
756 m_inx_sigma3 = 4;
757 m_par_logE = -1.0e30;
758 m_par_theta = -1.0;
759 m_norm = 1.0;
760 m_norm2 = 0.0;
761 m_norm3 = 0.0;
762 m_sigma1 = 0.0;
763 m_sigma2 = 0.0;
764 m_sigma3 = 0.0;
765 m_width1 = 0.0;
766 m_width2 = 0.0;
767 m_width3 = 0.0;
768
769 // Return
770 return;
771}
772
773
774/***********************************************************************//**
775 * @brief Copy class members
776 *
777 * @param[in] psf Point spread function.
778 ***************************************************************************/
780{
781 // Copy members
783 m_psf = psf.m_psf;
793 m_norm = psf.m_norm;
794 m_norm2 = psf.m_norm2;
795 m_norm3 = psf.m_norm3;
796 m_sigma1 = psf.m_sigma1;
797 m_sigma2 = psf.m_sigma2;
798 m_sigma3 = psf.m_sigma3;
799 m_width1 = psf.m_width1;
800 m_width2 = psf.m_width2;
801 m_width3 = psf.m_width3;
802
803 // Return
804 return;
805}
806
807
808/***********************************************************************//**
809 * @brief Delete class members
810 ***************************************************************************/
812{
813 // Return
814 return;
815}
816
817
818/***********************************************************************//**
819 * @brief Update PSF parameter cache
820 *
821 * @param[in] logE Log10 of the true photon energy (TeV).
822 * @param[in] theta Offset angle in camera system (rad).
823 *
824 * This method updates the PSF parameter cache.
825 ***************************************************************************/
826void GCTAPsf2D::update(const double& logE, const double& theta) const
827{
828 // Only compute PSF parameters if arguments have changed
829 if (logE != m_par_logE || theta != m_par_theta) {
830
831 // Save parameters
832 m_par_logE = logE;
833 m_par_theta = theta;
834
835 // Interpolate response parameters
836 std::vector<double> pars = (m_inx_energy == 0) ? m_psf(logE, theta) :
837 m_psf(theta, logE);
838
839 // Set Gaussian sigmas
840 m_sigma1 = pars[m_inx_sigma1];
841 m_sigma2 = pars[m_inx_sigma2];
842 m_sigma3 = pars[m_inx_sigma3];
843
844 // Set width parameters
845 double sigma1 = m_sigma1 * m_sigma1;
846 double sigma2 = m_sigma2 * m_sigma2;
847 double sigma3 = m_sigma3 * m_sigma3;
848
849 // Compute Gaussian 1
850 if (sigma1 > 0.0) {
851 m_width1 = -0.5 / sigma1;
852 }
853 else {
854 m_width1 = 0.0;
855 }
856
857 // Compute Gaussian 2
858 if (sigma2 > 0.0) {
859 m_width2 = -0.5 / sigma2;
860 m_norm2 = pars[m_inx_ampl2];
861 }
862 else {
863 m_width2 = 0.0;
864 m_norm2 = 0.0;
865 }
866
867 // Compute Gaussian 3
868 if (sigma3 > 0.0) {
869 m_width3 = -0.5 / sigma3;
870 m_norm3 = pars[m_inx_ampl3];
871 }
872 else {
873 m_width3 = 0.0;
874 m_norm3 = 0.0;
875 }
876
877 // Compute global normalization parameter
878 double integral = gammalib::twopi *
879 (sigma1 + sigma2*m_norm2 + sigma3*m_norm3);
880 m_norm = (integral > 0.0) ? 1.0 / integral : 0.0;
881
882 }
883
884 // Return
885 return;
886}
#define G_READ
#define G_CONTAINMENT_RADIUS
Definition GCTAPsf2D.cpp:44
CTA 2D point spread function class definition.
Definition of support function used by CTA classes.
Exception handler interface definition.
Filename class interface definition.
FITS binary table class definition.
FITS file class interface definition.
Mathematical function definitions.
Random number generator class definition.
Gammalib tools definition.
GChatter
Definition GTypemaps.hpp:33
@ SILENT
Definition GTypemaps.hpp:34
double sum(const GVector &vector)
Computes vector sum.
Definition GVector.cpp:944
CTA 2D point spread function class.
Definition GCTAPsf2D.hpp:54
int m_inx_sigma2
2nd Gaussian sigma
GCTAPsf2D & operator=(const GCTAPsf2D &psf)
Assignment operator.
double m_sigma3
Gaussian 3 sigma.
int m_inx_sigma3
3nd Gaussian sigma
double m_sigma2
Gaussian 2 sigma.
double m_par_theta
Cache offset angle.
double m_norm3
Gaussian 3 normalization.
void init_members(void)
Initialise class members.
GCTAPsf2D * clone(void) const
Clone point spread functions.
const GCTAResponseTable & table(void) const
Return response table.
void copy_members(const GCTAPsf2D &psf)
Copy class members.
double m_sigma1
Gaussian 1 sigma.
std::string print(const GChatter &chatter=NORMAL) const
Print point spread function information.
double m_norm2
Gaussian 2 normalization.
GCTAResponseTable m_psf
PSF response table.
double m_par_logE
Cache energy.
void free_members(void)
Delete class members.
double m_norm
Global normalization.
GFilename m_filename
Name of Aeff response file.
void save(const GFilename &filename, const bool &clobber=false) const
Save point spread function table into FITS file.
double m_width3
Gaussian 3 width.
int m_inx_theta
Theta index.
GFilename filename(void) const
Return filename.
void load(const GFilename &filename)
Load point spread function from FITS file.
double operator()(const double &delta, const double &logE, const double &theta=0.0, const double &phi=0.0, const double &zenith=0.0, const double &azimuth=0.0, const bool &etrue=true) const
Return point spread function (in units of sr^-1)
int m_inx_sigma1
1st Gaussian sigma
double m_width2
Gaussian 2 width.
void read(const GFitsTable &table)
Read point spread function from FITS table.
double containment_radius(const double &fraction, const double &logE, const double &theta=0.0, const double &phi=0.0, const double &zenith=0.0, const double &azimuth=0.0, const bool &etrue=true) const
Return the radius that contains a fraction of the events (radians)
double m_width1
Gaussian 1 width.
void update(const double &logE, const double &theta) const
Update PSF parameter cache.
GCTAPsf2D(void)
Void constructor.
Definition GCTAPsf2D.cpp:68
int m_inx_energy
Energy index.
int m_inx_ampl3
3nd Gaussian relative amplitude
virtual ~GCTAPsf2D(void)
Destructor.
void write(GFitsBinTable &table) const
Write point spread function into FITS binary table.
void clear(void)
Clear point spread function.
double delta_max(const double &logE, const double &theta=0.0, const double &phi=0.0, const double &zenith=0.0, const double &azimuth=0.0, const bool &etrue=true) const
Return maximum size of PSF (radians)
int m_inx_ampl2
2nd Gaussian relative amplitude
double mc(GRan &ran, const double &logE, const double &theta=0.0, const double &phi=0.0, const double &zenith=0.0, const double &azimuth=0.0, const bool &etrue=true) const
Simulate PSF offset (radians)
Abstract base class for the CTA point spread function.
Definition GCTAPsf.hpp:47
void free_members(void)
Delete class members.
Definition GCTAPsf.cpp:164
void init_members(void)
Initialise class members.
Definition GCTAPsf.cpp:142
GCTAPsf & operator=(const GCTAPsf &psf)
Assignment operator.
Definition GCTAPsf.cpp:106
CTA response table class.
void read(const GFitsTable &table)
Read response table from FITS table HDU.
int table(const std::string &name) const
Determine index of table.
void axis_log10(const int &axis)
Set nodes for a logarithmic (base 10) axis.
const int & tables(void) const
Return number of tables.
void axis_radians(const int &axis)
Set nodes for a radians axis.
int axis(const std::string &name) const
Determine index of an axis.
const int & axes(void) const
Return number of axes of the tables.
void write(GFitsTable &table) const
Write response table into FITS table HDU.
int axis_bins(const int &axis) const
Return number bins in an axis.
const double & axis_hi(const int &axis, const int &bin) const
Return upper bin boundary for bin in axis.
void scale(const int &table, const double &scale)
Scale table.
void clear(void)
Clear response table.
const double & axis_lo(const int &axis, const int &bin) const
Return lower bin boundary for bin in axis.
Filename class.
Definition GFilename.hpp:62
std::string url(void) const
Return Uniform Resource Locator (URL)
std::string extname(const std::string &defaultname="") const
Return extension name.
void clear(void)
Clear file name.
FITS binary table class.
Abstract interface for FITS table.
FITS file class.
Definition GFits.hpp:63
bool contains(const int &extno) const
Check if HDU exists in FITS file.
Definition GFits.hpp:282
GFitsHDU * append(const GFitsHDU &hdu)
Append HDU to FITS file.
Definition GFits.cpp:678
void close(void)
Close FITS file.
Definition GFits.cpp:1342
void remove(const int &extno)
Remove HDU from FITS file.
Definition GFits.cpp:862
void save(const bool &clobber=false)
Saves FITS file.
Definition GFits.cpp:1178
GFitsTable * table(const int &extno)
Get pointer to table HDU.
Definition GFits.cpp:482
Random number generator class.
Definition GRan.hpp:44
double chisq2(void)
Returns Chi2 deviates for 2 degrees of freedom.
Definition GRan.cpp:370
double uniform(void)
Returns random double precision floating value in range 0 to 1.
Definition GRan.cpp:242
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition GTools.cpp:1143
const std::string extname_cta_psf2d
Definition GCTAPsf2D.hpp:42
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition GTools.cpp:489
const double pi
Definition GMath.hpp:35
const double deg2rad
Definition GMath.hpp:43
std::string gadf_hduclas4(const GFits &fits, const std::string &hduclas4)
Return extension name for GADF response table of given HDU class 4.
void warning(const std::string &origin, const std::string &message)
Emits warning.
Definition GTools.cpp:1386
const double twopi
Definition GMath.hpp:36
const double rad2deg
Definition GMath.hpp:44