GammaLib 2.0.0
Loading...
Searching...
No Matches
GCTACubePsf.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GCTACubePsf.cpp - CTA cube analysis point spread function class *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2014-2018 by Chia-Chun Lu *
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 GCTACubePsf.cpp
23 * @brief CTA cube analysis point spread function class implementation
24 * @author Chia-Chun Lu
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include "GTools.hpp"
32#include "GMath.hpp"
33#include "GLog.hpp"
34#include "GObservations.hpp"
35#include "GSkyRegionCircle.hpp"
36#include "GCTACubePsf.hpp"
37#include "GCTAObservation.hpp"
38#include "GCTAResponseIrf.hpp"
39#include "GCTAEventList.hpp"
40#include "GCTAEventCube.hpp"
41
42/* __ Method name definitions ____________________________________________ */
43#define G_SET "GCTACubePsf::set(GCTAObservation&)"
44#define G_FILL "GCTACubePsf::fill(GObservations&, GLog*)"
45#define G_FILL_CUBE "GCTACubePsf::fill_cube(GCTAObservation&, GSkyMap*, "\
46 "GLog*)"
47
48/* __ Macros _____________________________________________________________ */
49
50/* __ Coding definitions _________________________________________________ */
51#define G_SMOOTH_PSF //!< Guarantee no singularities
52#define G_QUADRATIC_BINNING //!< Use quadratic delta spacing
53
54/* __ Debug definitions __________________________________________________ */
55
56/* __ Constants __________________________________________________________ */
57
58
59/*==========================================================================
60 = =
61 = Constructors/destructors =
62 = =
63 ==========================================================================*/
64
65/***********************************************************************//**
66 * @brief Void constructor
67 ***************************************************************************/
69{
70 // Initialise class members
72
73 // Return
74 return;
75}
76
77
78/***********************************************************************//**
79 * @brief Copy constructor
80 *
81 * @param[in] cube Point spread function.
82 ***************************************************************************/
84{
85 // Initialise class members
87
88 // Copy members
90
91 // Return
92 return;
93}
94
95
96/***********************************************************************//**
97 * @brief File constructor
98 *
99 * @param[in] filename PSF cube filename.
100 *
101 * Construct PSF cube by loading the information from a PSF cube file.
102 ***************************************************************************/
104{
105 // Initialise class members
106 init_members();
107
108 // Load PSF cube from file
109 load(filename);
110
111 // Return
112 return;
113}
114
115
116/***********************************************************************//**
117 * @brief Event cube constructor
118 *
119 * @param[in] cube Event cube.
120 * @param[in] dmax Maximum delta (deg).
121 * @param[in] ndbins Number of delta bins.
122 *
123 * Construct PSF cube using the same binning and sky projection that is
124 * used for the event cube.
125 ***************************************************************************/
126GCTACubePsf::GCTACubePsf(const GCTAEventCube& cube, const double& dmax,
127 const int& ndbins)
128{
129 // Initialise class members
130 init_members();
131
132 // Store energy boundaries
133 m_energies.set(cube.ebounds());
134
135 // Set GNodeArray used for interpolation
136 set_eng_axis();
137
138 // Set delta node array
139 m_deltas.clear();
140 for (int i = 0; i < ndbins; ++i) {
141 #if defined(G_QUADRATIC_BINNING)
142 double binsize = std::sqrt(dmax) / double(ndbins);
143 double delta = binsize * (double(i) + 0.5); // avoid central singularity
144 delta *= delta;
145 #else
146 double binsize = dmax / double(ndbins);
147 double delta = binsize * (double(i) + 0.5); // avoid central singularity
148 #endif
149 m_deltas.append(delta);
150 }
151
152 // Set delta node array for computation
154
155 // Compute number of sky maps
156 int nmaps = m_energies.size() * m_deltas.size();
157
158 // Set PSF cube to event cube
159 m_cube = cube.counts();
160
161 // Set appropriate number of skymaps
162 m_cube.nmaps(nmaps);
163
164 // Set cube shape
166
167 // Set all PSF cube pixels to zero as we want to have a clean map
168 // upon construction
169 m_cube = 0.0;
170
171 // Return
172 return;
173
174}
175
176
177/***********************************************************************//**
178 * @brief PSF cube constructor
179 *
180 * @param[in] wcs World Coordinate System.
181 * @param[in] coords Coordinate System (CEL or GAL).
182 * @param[in] x X coordinate of sky map centre (deg).
183 * @param[in] y Y coordinate of sky map centre (deg).
184 * @param[in] dx Pixel size in x direction at centre (deg/pixel).
185 * @param[in] dy Pixel size in y direction at centre (deg/pixel).
186 * @param[in] nx Number of pixels in x direction.
187 * @param[in] ny Number of pixels in y direction.
188 * @param[in] energies Energies.
189 * @param[in] dmax Maximum delta (deg).
190 * @param[in] ndbins Number of delta bins.
191 *
192 * Constructs a PSF cube by specifying the sky map grid and the energies.
193 ***************************************************************************/
194GCTACubePsf::GCTACubePsf(const std::string& wcs,
195 const std::string& coords,
196 const double& x,
197 const double& y,
198 const double& dx,
199 const double& dy,
200 const int& nx,
201 const int& ny,
202 const GEnergies& energies,
203 const double& dmax,
204 const int& ndbins)
205{
206 // Initialise class members
207 init_members();
208
209 // Store energies
211
212 // Set energy node array
213 set_eng_axis();
214
215 // Set delta node array
216 m_deltas.clear();
217 for (int i = 0; i < ndbins; ++i) {
218 #if defined(G_QUADRATIC_BINNING)
219 double binsize = std::sqrt(dmax) / double(ndbins);
220 double delta = binsize * (double(i) + 0.5); // avoid central singularity
221 delta *= delta;
222 #else
223 double binsize = dmax / double(ndbins);
224 double delta = binsize * (double(i) + 0.5); // avoid central singularity
225 #endif
226 m_deltas.append(delta);
227 }
228
229 // Set delta node array for computation
231
232 // Compute number of sky maps
233 int nmaps = m_energies.size() * m_deltas.size();
234
235 // Create sky map
236 m_cube = GSkyMap(wcs, coords, x, y, dx, dy, nx, ny, nmaps);
237
238 // Set cube shape
240
241 // Return
242 return;
243}
244
245
246/***********************************************************************//**
247 * @brief Destructor
248 ***************************************************************************/
250{
251 // Free members
252 free_members();
253
254 // Return
255 return;
256}
257
258
259/*==========================================================================
260 = =
261 = Operators =
262 = =
263 ==========================================================================*/
264
265/***********************************************************************//**
266 * @brief Assignment operator
267 *
268 * @param[in] cube Mean PSF cube.
269 * @return Mean PSF cube.
270 ***************************************************************************/
272{
273 // Execute only if object is not identical
274 if (this != &cube) {
275
276 // Free members
277 free_members();
278
279 // Initialise private members
280 init_members();
281
282 // Copy members
284
285 } // endif: object was not identical
286
287 // Return this object
288 return *this;
289}
290
291
292/***********************************************************************//**
293 * @brief Return point spread function (in units of sr\f$^{-1}\f$)
294 *
295 * @param[in] dir Coordinate of the true photon position.
296 * @param[in] delta Angular separation between true and measured photon
297 * directions (rad).
298 * @param[in] energy Energy of the true photon.
299 * @return point spread function (in units of sr\f$^{-1}\f$)
300 *
301 * Returns the point spread function for a given angular separation in units
302 * of sr^-1 for a given energy and coordinate.
303 ***************************************************************************/
305 const double& delta,
306 const GEnergy& energy) const
307{
308 // Update indices and weighting factors for interpolation
309 update(delta, energy.log10TeV());
310
311 // Perform bi-linear interpolation
312 double psf = m_wgt1 * m_cube(dir, m_inx1) +
313 m_wgt2 * m_cube(dir, m_inx2) +
314 m_wgt3 * m_cube(dir, m_inx3) +
315 m_wgt4 * m_cube(dir, m_inx4);
316
317 // Make sure that PSF does not become negative
318 if (psf < 0.0) {
319 psf = 0.0;
320 }
321
322 // Return PSF
323 return psf;
324}
325
326
327/*==========================================================================
328 = =
329 = Public methods =
330 = =
331 ==========================================================================*/
332
333/***********************************************************************//**
334 * @brief Clear instance
335 *
336 * This method properly resets the object to an initial state.
337 ***************************************************************************/
339{
340 // Free class members
341 free_members();
342
343 // Initialise members
344 init_members();
345
346 // Return
347 return;
348}
349
350
351/***********************************************************************//**
352 * @brief Clone instance
353 *
354 * @return Deep copy of mean PSF instance.
355 ***************************************************************************/
357{
358 return new GCTACubePsf(*this);
359}
360
361
362/***********************************************************************//**
363 * @brief Set PSF cube from one CTA observation
364 *
365 * @param[in] obs CTA observation.
366 *
367 * Sets the PSF cube for one CTA observation.
368 ***************************************************************************/
370{
371 // Clear PSF cube
372 clear_cube();
373
374 // Fill PSF cube
375 fill_cube(obs);
376
377 // Compile option: guarantee smooth Psf
378 #if defined(G_SMOOTH_PSF)
380 #endif
381
382 // Return
383 return;
384}
385
386
387/***********************************************************************//**
388 * @brief Fill PSF cube from observation container
389 *
390 * @param[in] obs Observation container.
391 * @param[in] log Pointer towards logger.
392 *
393 * Sets the PSF cube from all CTA observations in the observation container.
394 ***************************************************************************/
396{
397 // Clear PSF cube
398 clear_cube();
399
400 // Initialise skymap for exposure weight accumulation
401 GSkyMap exposure(m_cube);
402
403 // Loop over all observations in container
404 for (int i = 0; i < obs.size(); ++i) {
405
406 // Get observation and continue only if it is a CTA observation
407 const GCTAObservation* cta = dynamic_cast<const GCTAObservation*>
408 (obs[i]);
409
410 // Skip observation if it's not CTA
411 if (cta == NULL) {
412 if (log != NULL) {
413 *log << "Skipping ";
414 *log << obs[i]->instrument();
415 *log << " observation ";
416 *log << "\"" << obs[i]->name() << "\"";
417 *log << " (id=" << obs[i]->id() << ")" << std::endl;
418 }
419 continue;
420 }
421
422 // Skip observation if we have a binned observation
423 if (cta->eventtype() == "CountsCube") {
424 if (log != NULL) {
425 *log << "Skipping binned ";
426 *log << cta->instrument();
427 *log << " observation ";
428 *log << "\"" << cta->name() << "\"";
429 *log << " (id=" << cta->id() << ")" << std::endl;
430 }
431 continue;
432 }
433
434 // Fill PSF cube
435 fill_cube(*cta, &exposure, log);
436
437 } // endfor: looped over observations
438
439 // Compute mean PSF cube by dividing though the weights
440 for (int pixel = 0; pixel < m_cube.npix(); ++pixel) {
441 for (int iebin = 0; iebin < m_energies.size(); ++iebin) {
442 if (exposure(pixel, iebin) > 0.0) {
443 double norm = 1.0 / exposure(pixel, iebin);
444 for (int idelta = 0; idelta < m_deltas.size(); ++idelta) {
445 int imap = offset(idelta, iebin);
446 m_cube(pixel, imap) *= norm;
447 }
448 }
449 else {
450 for (int idelta = 0; idelta < m_deltas.size(); ++idelta) {
451 int imap = offset(idelta, iebin);
452 m_cube(pixel, imap) = 0.0;
453 }
454 }
455 }
456 }
457
458 // Compile option: guarantee smooth Psf
459 #if defined(G_SMOOTH_PSF)
461 #endif
462
463 // Return
464 return;
465}
466
467
468/***********************************************************************//**
469 * @brief Read PSF cube from FITS object
470 *
471 * @param[in] fits FITS object.
472 *
473 * Read the PSF cube from a FITS object.
474 ***************************************************************************/
475void GCTACubePsf::read(const GFits& fits)
476{
477 // Clear object
478 clear();
479
480 // Get HDUs
481 const GFitsImage& hdu_psfcube = *fits.image("Primary");
482 const GFitsTable& hdu_energies = *fits.table(gammalib::extname_energies);
483 const GFitsTable& hdu_deltas = *fits.table(gammalib::extname_deltas);
484
485 // Read cube
486 m_cube.read(hdu_psfcube);
487
488 // Read energies
489 m_energies.read(hdu_energies);
490
491 // Read delta nodes
492 m_deltas.read(hdu_deltas);
493
494 // Set delta node array for computation
496
497 // Set energy node array
498 set_eng_axis();
499
500 // Compile option: guarantee smooth Psf
501 #if defined(G_SMOOTH_PSF)
503 #endif
504
505 // Return
506 return;
507}
508
509
510/***********************************************************************//**
511 * @brief Write CTA PSF cube into FITS object.
512 *
513 * @param[in] fits FITS object.
514 *
515 * Write the CTA PSF cube into a FITS object.
516 ***************************************************************************/
517void GCTACubePsf::write(GFits& fits) const
518{
519 // Write cube
520 m_cube.write(fits);
521
522 // Get last HDU and write attributes
523 if (fits.size() > 0) {
524 GFitsHDU& hdu = *fits[fits.size()-1];
525 hdu.card("BUNIT", "sr**(-1)", "Unit of PSF cube");
526 }
527
528 // Write energies
529 m_energies.write(fits);
530
531 // Write delta nodes
533
534 // Set the nodes unit to "deg"
535 (*fits.table(gammalib::extname_deltas))["Value"]->unit("deg");
536
537 // Return
538 return;
539}
540
541
542/***********************************************************************//**
543 * @brief Load PSF cube from FITS file
544 *
545 * @param[in] filename Performance table file name.
546 *
547 * Loads the PSF cube from a FITS file into the object.
548 ***************************************************************************/
549void GCTACubePsf::load(const GFilename& filename)
550{
551 // Put into OpenMP criticial zone
552 #pragma omp critical(GCTACubePsf_load)
553 {
554
555 // Open FITS file
556 GFits fits(filename);
557
558 // Read PSF cube
559 read(fits);
560
561 // Close FITS file
562 fits.close();
563
564 // Store filename
566
567 } // end of OpenMP critical zone
568
569 // Return
570 return;
571}
572
573
574/***********************************************************************//**
575 * @brief Save PSF cube into FITS file
576 *
577 * @param[in] filename PSF cube FITS file name.
578 * @param[in] clobber Overwrite existing file?
579 *
580 * Save the PSF cube into a FITS file.
581 ***************************************************************************/
582void GCTACubePsf::save(const GFilename& filename, const bool& clobber) const
583{
584 // Put into OpenMP criticial zone
585 #pragma omp critical(GCTACubePsf_save)
586 {
587
588 // Create FITS file
589 GFits fits;
590
591 // Write PSF cube
592 write(fits);
593
594 // Save FITS file
595 fits.saveto(filename, clobber);
596
597 // Close Edisp file
598 fits.close();
599
600 } // end of OpenMP critical zone
601
602 // Store filename
604
605 // Return
606 return;
607}
608
609
610/***********************************************************************//**
611 * @brief Print PSF cube information
612 *
613 * @param[in] chatter Chattiness.
614 * @return String containing PSF cube information.
615 ***************************************************************************/
616std::string GCTACubePsf::print(const GChatter& chatter) const
617{
618 // Initialise result string
619 std::string result;
620
621 // Continue only if chatter is not silent
622 if (chatter != SILENT) {
623
624 // Append header
625 result.append("=== GCTACubePsf ===");
626
627 // Append information
628 result.append("\n"+gammalib::parformat("Filename")+m_filename);
629
630 // Append energies
631 if (m_energies.size() > 0) {
632 result.append("\n"+m_energies.print(chatter));
633 }
634 else {
635 result.append("\n"+gammalib::parformat("Energies") +
636 "not defined");
637 }
638
639 // Append number of delta bins
640 result.append("\n"+gammalib::parformat("Number of delta bins") +
642
643 // Append delta range
644 result.append("\n"+gammalib::parformat("Delta range"));
645 if (m_deltas.size() > 0) {
646 result.append(gammalib::str(m_deltas[0]));
647 result.append(" - ");
648 result.append(gammalib::str(m_deltas[m_deltas.size()-1]));
649 result.append(" deg");
650 }
651 else {
652 result.append("not defined");
653 }
654
655 // Append skymap definition
656 result.append("\n"+m_cube.print(chatter));
657
658 } // endif: chatter was not silent
659
660 // Return result
661 return result;
662}
663
664
665/*==========================================================================
666 = =
667 = Private methods =
668 = =
669 ==========================================================================*/
670
671/***********************************************************************//**
672 * @brief Initialise class members
673 ***************************************************************************/
675{
676 // Initialise members
678 m_cube.clear();
681 m_deltas.clear();
683 m_quadratic_binning = false;
684
685 // Initialise cache
686 m_inx1 = 0;
687 m_inx2 = 0;
688 m_inx3 = 0;
689 m_inx4 = 0;
690 m_wgt1 = 0.0;
691 m_wgt2 = 0.0;
692 m_wgt3 = 0.0;
693 m_wgt4 = 0.0;
694
695 // Return
696 return;
697}
698
699
700/***********************************************************************//**
701 * @brief Copy class members
702 *
703 * @param[in] cube PSF cube.
704 ***************************************************************************/
706{
707 // Copy members
708 m_filename = cube.m_filename;
709 m_cube = cube.m_cube;
710 m_energies = cube.m_energies;
711 m_elogmeans = cube.m_elogmeans;
712 m_deltas = cube.m_deltas;
713 m_deltas_cache = cube.m_deltas_cache;
714 m_quadratic_binning = cube.m_quadratic_binning;
715
716 // Copy cache
717 m_inx1 = cube.m_inx1;
718 m_inx2 = cube.m_inx2;
719 m_inx3 = cube.m_inx3;
720 m_inx4 = cube.m_inx4;
721 m_wgt1 = cube.m_wgt1;
722 m_wgt2 = cube.m_wgt2;
723 m_wgt3 = cube.m_wgt3;
724 m_wgt4 = cube.m_wgt4;
725
726 // Return
727 return;
728}
729
730/***********************************************************************//**
731 * @brief Delete class members
732 ***************************************************************************/
734{
735 // Return
736 return;
737}
738
739
740/***********************************************************************//**
741 * @brief Clear all pixels in the PSF cube
742 ***************************************************************************/
744{
745 // Loop over all maps
746 for (int imap = 0; imap < m_cube.nmaps(); ++imap) {
747
748 // Loop over all pixels in sky map
749 for (int pixel = 0; pixel < m_cube.npix(); ++pixel) {
750
751 // Reset cube value to zero
752 m_cube(pixel, imap) = 0.0;
753
754 } // endfor: looped over all pixels
755
756 } // endfor: looped over maps
757
758 // Return
759 return;
760}
761
762
763/***********************************************************************//**
764 * @brief Fill PSF cube for one observation
765 *
766 * @param[in] obs Observation.
767 * @param[in] exposure Pointer towards exposure map.
768 * @param[in] log Pointer towards logger.
769 *
770 * @exception GException::invalid_value
771 * No RoI or response found in CTA observation.
772 ***************************************************************************/
774 GSkyMap* exposure,
775 GLog* log)
776{
777 // Only continue if we have an event list
778 if (obs.eventtype() == "EventList") {
779
780 // Extract pointing direction, energy boundaries and ROI from
781 // observation
782 GSkyDir pnt = obs.pointing().dir();
783 GEbounds obs_ebounds = obs.ebounds();
784 GCTARoi roi = obs.roi();
785
786 // Check for RoI sanity
787 if (!roi.is_valid()) {
788 std::string msg = "No RoI information found in "+obs.instrument()+
789 " observation \""+obs.name()+"\". Run ctselect "
790 "to specify an RoI for this observation.";
792 }
793
794 // Convert RoI into a circular region for overlap checking
795 GSkyRegionCircle roi_reg(roi.centre().dir(), roi.radius());
796
797 // Extract response from observation
798 const GCTAResponseIrf* rsp = dynamic_cast<const GCTAResponseIrf*>
799 (obs.response());
800 if (rsp == NULL) {
801 std::string msg = "No valid instrument response function found in "+
802 obs.instrument()+" observation \""+obs.name()+
803 "\". Please specify the instrument response "
804 "function for this observation.";
806 }
807
808 // Skip observation if livetime is zero
809 if (obs.livetime() == 0.0) {
810 if (log != NULL) {
811 *log << "Skipping unbinned ";
812 *log << obs.instrument();
813 *log << " observation ";
814 *log << "\"" << obs.name() << "\"";
815 *log << " (id=" << obs.id() << ") due to zero livetime";
816 *log << std::endl;
817 }
818 }
819
820 // Skip observation if observation is outside the bounds of the cube
821 else if (!m_cube.overlaps(roi_reg)) {
822 if (log != NULL) {
823 *log << "Skipping unbinned ";
824 *log << obs.instrument();
825 *log << " observation ";
826 *log << "\"" << obs.name() << "\"";
827 *log << " (id=" << obs.id() << ") since it does not overlap ";
828 *log << "with the point spread function cube.";
829 *log << std::endl;
830 }
831 }
832
833 // ... otherwise continue
834 else {
835
836 // Announce observation usage
837 if (log != NULL) {
838 *log << "Including ";
839 *log << obs.instrument();
840 *log << " observation \"" << obs.name();
841 *log << "\" (id=" << obs.id() << ")";
842 *log << " in point spread function cube computation." << std::endl;
843 }
844
845 // Loop over all pixels in sky map
846 for (int pixel = 0; pixel < m_cube.npix(); ++pixel) {
847
848 // Get pixel sky direction
849 GSkyDir dir = m_cube.inx2dir(pixel);
850
851 // Skip pixel if it is outside the RoI
852 if (roi.centre().dir().dist_deg(dir) > roi.radius()) {
853 continue;
854 }
855
856 // Compute theta angle with respect to pointing direction in
857 // radians
858 double theta = pnt.dist(dir);
859
860 // Loop over all energy bins
861 for (int iebin = 0; iebin < m_energies.size(); ++iebin) {
862
863 // Get logE/TeV
864 double logE = m_energies[iebin].log10TeV();
865
866 // Compute exposure weight. If no exposure map is
867 // specified, the weight is one. Otherwise, the weight
868 // is the effective area for this offset angle and
869 // source energy times the livetime of the observation.
870 double weight = 1.0;
871 if (exposure != NULL) {
872 weight = rsp->aeff(theta, 0.0, 0.0, 0.0, logE) *
873 obs.livetime();
874 (*exposure)(pixel, iebin) += weight;
875 }
876
877 // Loop over delta values
878 for (int idelta = 0; idelta < m_deltas.size(); ++idelta) {
879
880 // Compute delta in radians
881 double delta = m_deltas[idelta] * gammalib::deg2rad;
882
883 // Set map index
884 int imap = offset(idelta, iebin);
885
886 // Add on PSF cube
887 m_cube(pixel, imap) +=
888 rsp->psf(delta, theta, 0.0, 0.0, 0.0, logE) * weight;
889
890 } // endfor: looped over delta bins
891
892 } // endfor: looped over energy bins
893
894 } // endfor: looped over all pixels
895
896 } // endelse: livetime was not zero
897
898 } // endif: observation contained an event list
899
900 // Return
901 return;
902}
903
904
905/***********************************************************************//**
906 * @brief Update PSF parameter cache
907 *
908 * @param[in] delta Angular separation between true and measured photon
909 * directions (radians).
910 * @param[in] logE Log10 true photon energy (TeV).
911 *
912 * This method updates the PSF parameter cache.
913 ***************************************************************************/
914void GCTACubePsf::update(const double& delta, const double& logE) const
915{
916 // Set node array for delta interpolation
918 m_deltas_cache.set_value(std::sqrt(delta));
919 }
920 else {
922 }
923
924 // Set node array for energy interpolation
926
927 // Set indices for bi-linear interpolation
932
933 // Set weighting factors for bi-linear interpolation
938
939 // Return
940 return;
941}
942
943
944/***********************************************************************//**
945 * @brief Set nodes for delta axis in radians
946 *
947 * Set the delta axis nodes in radians. If a quadratic binning is detected,
948 * the axis is set to sqrt(delta) so that a linear interpolation scheme
949 * can be used which is much faster than a quadratic scheme.
950 *
951 * @todo Check that none of the axis boundaries is non-positive.
952 ***************************************************************************/
954{
955 // Initialise computation members
957 m_quadratic_binning = false;
958
959 // Set up a linear array that represents the square root of the delta
960 // values. If this array corresponds within some numerical precision
961 // to the actual delta values, will will use these values for the
962 // interpolation (the m_quadratic_binning member will be set to true).
963 // Otherwise, the original delta values will be kept and the
964 // m_quadratic_binning member will be set to false.
965 int ndbins = m_deltas.size();
966 if (ndbins > 1) {
967 m_quadratic_binning = true;
968 double binsize = (std::sqrt(m_deltas[ndbins-1] * gammalib::deg2rad) -
969 std::sqrt(m_deltas[0] * gammalib::deg2rad)) /
970 double(ndbins-1);
971 for (int i = 0; i < ndbins; ++i) {
972 double delta = binsize * (double(i) + 0.5);
973 double diff = std::abs(delta*delta-m_deltas[i] * gammalib::deg2rad);
974 if (diff > 1.0e-6) {
975 m_quadratic_binning = false;
976 break;
977 }
978 m_deltas_cache.append(delta);
979 }
980 }
981
982 // If we do not have square root binning then use the original values
983 // but convert them to radians
984 if (!m_quadratic_binning) {
986 for (int i = 0; i < m_deltas.size(); ++i) {
988 }
989 }
990
991 // Return
992 return;
993}
994
995
996/***********************************************************************//**
997 * @brief Set nodes for a logarithmic (base 10) energy axis
998 *
999 *
1000 * Set axis nodes so that each node is the logarithmic mean of the lower and
1001 * upper energy boundary, i.e.
1002 * \f[ n_i = \log \sqrt{{\rm LO}_i \times {\rm HI}_i} \f]
1003 * where
1004 * \f$n_i\f$ is node \f$i\f$,
1005 * \f${\rm LO}_i\f$ is the lower bin boundary for bin \f$i\f$, and
1006 * \f${\rm HI}_i\f$ is the upper bin boundary for bin \f$i\f$.
1007 *
1008 * @todo Check that none of the axis boundaries is non-positive.
1009 ***************************************************************************/
1011{
1012 // Get number of bins
1013 int bins = m_energies.size();
1014
1015 // Clear node array
1017
1018 // Compute nodes
1019 for (int i = 0; i < bins; ++i) {
1020
1021 // Get logE/TeV
1022 m_elogmeans.append(m_energies[i].log10TeV());
1023
1024 } // endfor: looped over energy bins
1025
1026 // Return
1027 return;
1028}
1029
1030
1031/***********************************************************************//**
1032 * @brief Pad the last delta bins with zero
1033 *
1034 * Zero padding of the last delta bins assures that the Psf goes to zero
1035 * without any step at the last delta value.
1036 ***************************************************************************/
1038{
1039 // Continue only if there are delta bins
1040 if (m_deltas.size() > 2) {
1041
1042 // Set first delta bin to value of second bin (capped Psf)
1043 for (int iebin = 0; iebin < m_energies.size(); ++iebin) {
1044 int isrc = offset(1, iebin);
1045 int idst = offset(0, iebin);
1046 for (int pixel = 0; pixel < m_cube.npix(); ++pixel) {
1047 m_cube(pixel, idst) = m_cube(pixel, isrc);
1048 }
1049 }
1050
1051 // Get index of last delta bin
1052 int idelta = m_deltas.size()-1;
1053
1054 // Pad mean PSF with zeros in the last delta bin
1055 for (int iebin = 0; iebin < m_energies.size(); ++iebin) {
1056 int imap = offset(idelta, iebin);
1057 for (int pixel = 0; pixel < m_cube.npix(); ++pixel) {
1058 m_cube(pixel, imap) = 0.0;
1059 }
1060 }
1061
1062 } // endif: there were bins to pad
1063
1064 // Return
1065 return;
1066}
#define G_FILL_CUBE
CTA cube analysis point spread function class definition.
CTA event bin container class interface definition.
CTA event list class interface definition.
CTA observation class interface definition.
CTA instrument response function class definition.
Information logger class definition.
Mathematical function definitions.
Observations container class interface definition.
Circular sky region class interface definition.
Gammalib tools definition.
GChatter
Definition GTypemaps.hpp:33
@ SILENT
Definition GTypemaps.hpp:34
double norm(const GVector &vector)
Computes vector norm.
Definition GVector.cpp:864
GVector log(const GVector &vector)
Computes natural logarithm of vector elements.
Definition GVector.cpp:1274
CTA point spread function for cube analysis.
int m_inx2
Index of lower left node.
GNodeArray m_deltas
Delta bins (deg) for the PSF cube.
void read(const GFits &fits)
Read PSF cube from FITS object.
void set(const GCTAObservation &obs)
Set PSF cube from one CTA observation.
int offset(const int &idelta, const int &iebin) const
Return map offset.
void write(GFits &file) const
Write CTA PSF cube into FITS object.
int m_inx1
Index of upper left node.
GCTACubePsf * clone(void) const
Clone instance.
double m_wgt1
Weight of upper left node.
bool m_quadratic_binning
Internal binning is linear.
GEnergies m_energies
Energy values for the PSF cube.
void fill(const GObservations &obs, GLog *log=NULL)
Fill PSF cube from observation container.
std::string print(const GChatter &chatter=NORMAL) const
Print PSF cube information.
void save(const GFilename &filename, const bool &clobber=false) const
Save PSF cube into FITS file.
double m_wgt3
Weight of upper right node.
int m_inx4
Index of lower right node.
void update(const double &delta, const double &logE) const
Update PSF parameter cache.
void fill_cube(const GCTAObservation &obs, GSkyMap *exposure=NULL, GLog *log=NULL)
Fill PSF cube for one observation.
void load(const GFilename &filename)
Load PSF cube from FITS file.
void set_delta_axis(void)
Set nodes for delta axis in radians.
void copy_members(const GCTACubePsf &cube)
Copy class members.
void init_members(void)
Initialise class members.
int m_inx3
Index of upper right node.
GFilename m_filename
Filename.
void clear_cube(void)
Clear all pixels in the PSF cube.
GCTACubePsf & operator=(const GCTACubePsf &cube)
Assignment operator.
void set_eng_axis(void)
Set nodes for a logarithmic (base 10) energy axis.
void free_members(void)
Delete class members.
GSkyMap m_cube
PSF cube.
const GFilename & filename(void) const
Return exposure cube filename.
GNodeArray m_elogmeans
Mean log10TeV energy for the PSF cube.
double operator()(const GSkyDir &dir, const double &delta, const GEnergy &energy) const
Return point spread function (in units of sr )
virtual ~GCTACubePsf(void)
Destructor.
double m_wgt2
Weight of lower left node.
GNodeArray m_deltas_cache
Internal delta bins (rad)
void set_to_smooth(void)
Pad the last delta bins with zero.
GCTACubePsf(void)
Void constructor.
void clear(void)
Clear instance.
const GSkyMap & cube(void) const
Return psf cube sky map.
double m_wgt4
Weight of lower right node.
const GEnergies & energies(void) const
Return energies.
CTA event bin container class.
void dir(const GSkyDir &dir)
Set sky direction.
CTA observation class.
void pointing(const GCTAPointing &pointing)
Set CTA pointing.
virtual double livetime(void) const
Return livetime.
std::string eventtype(void) const
Return event type string.
virtual std::string instrument(void) const
Return instrument name.
GCTARoi roi(void) const
Get Region of Interest.
GEbounds ebounds(void) const
Get energy boundaries.
virtual void response(const GResponse &rsp)
Set response function.
CTA instrument response function class.
const GCTAAeff * aeff(void) const
Return pointer to effective area response.
const GCTAPsf * psf(void) const
Return pointer to point spread function.
Interface for the CTA region of interest class.
Definition GCTARoi.hpp:49
const double & radius(void) const
Returns radius of region of interest in degrees.
Definition GCTARoi.hpp:125
bool is_valid(void) const
Checks if RoI is valid.
Definition GCTARoi.hpp:152
const GCTAInstDir & centre(void) const
Returns region of interest centre.
Definition GCTARoi.hpp:111
Energy boundaries container class.
Definition GEbounds.hpp:60
Energy container class.
Definition GEnergies.hpp:60
std::string print(const GChatter &chatter=NORMAL) const
Print energy container information.
void read(const GFitsTable &table)
Read energies from FITS table.
void clear(void)
Clear energy container.
int size(void) const
Return number of energies in container.
void set(const GEbounds &ebounds)
Set energies from energy boundaries.
void write(GFits &file, const std::string &extname=gammalib::extname_energies) const
Write energies into FITS object.
Class that handles energies in a unit independent way.
Definition GEnergy.hpp:48
double log10TeV(void) const
Return log10 of energy in TeV.
Definition GEnergy.cpp:457
Filename class.
Definition GFilename.hpp:62
void clear(void)
Clear file name.
Abstract FITS extension base class.
Definition GFitsHDU.hpp:51
GFitsHeaderCard & card(const int &cardno)
Return header card.
Definition GFitsHDU.hpp:259
Abstract FITS image base class.
Abstract interface for FITS table.
FITS file class.
Definition GFits.hpp:63
void saveto(const GFilename &filename, const bool &clobber=false)
Saves to specified FITS file.
Definition GFits.cpp:1293
int size(void) const
Return number of HDUs in FITS file.
Definition GFits.hpp:237
GFitsImage * image(const int &extno)
Get pointer to image HDU.
Definition GFits.cpp:368
void close(void)
Close FITS file.
Definition GFits.cpp:1342
GFitsTable * table(const int &extno)
Get pointer to table HDU.
Definition GFits.cpp:482
Information logger interface definition.
Definition GLog.hpp:62
void set_value(const double &value) const
Set indices and weighting factors for interpolation.
const int & inx_right(void) const
Returns right node index.
const int & inx_left(void) const
Returns left node index.
const double & wgt_right(void) const
Returns right node weight.
const double & wgt_left(void) const
Returns left node weight.
void clear(void)
Clear node array.
int size(void) const
Return number of nodes in node array.
void write(GFits &fits, const std::string &extname="NODES") const
Write nodes into FITS object.
void append(const double &node)
Append one node to array.
void read(const GFitsTable &table)
Read nodes from FITS table.
void name(const std::string &name)
Set observation name.
void id(const std::string &id)
Set observation identifier.
Observation container class.
int size(void) const
Return number of observations in container.
Sky direction class.
Definition GSkyDir.hpp:62
double dist(const GSkyDir &dir) const
Compute angular distance between sky directions in radians.
Definition GSkyDir.hpp:271
Sky map class.
Definition GSkyMap.hpp:89
const int & nmaps(void) const
Returns number of maps.
Definition GSkyMap.hpp:389
void clear(void)
Clear instance.
Definition GSkyMap.cpp:1100
GSkyDir inx2dir(const int &index) const
Returns sky direction of pixel.
Definition GSkyMap.cpp:1331
void read(const GFitsHDU &hdu)
Read skymap from FITS HDU.
Definition GSkyMap.cpp:2664
const int & npix(void) const
Returns number of pixels.
Definition GSkyMap.hpp:345
GNdarray counts(void) const
Returns array with total number of counts for count maps.
Definition GSkyMap.cpp:1496
GFitsHDU * write(GFits &file, const std::string &extname="") const
Write sky map into FITS file.
Definition GSkyMap.cpp:2697
const std::vector< int > & shape(void) const
Returns shape of maps.
Definition GSkyMap.hpp:401
bool overlaps(const GSkyRegion &region) const
Checks whether a region overlaps with this map.
Definition GSkyMap.cpp:2102
std::string print(const GChatter &chatter=NORMAL) const
Print sky map.
Definition GSkyMap.cpp:2787
Interface for the circular sky region class.
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition GTools.cpp:1143
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition GTools.cpp:489
const double deg2rad
Definition GMath.hpp:43
const std::string extname_deltas
const std::string extname_energies
Definition GEnergies.hpp:44