GammaLib 2.0.0
Loading...
Searching...
No Matches
GLATEventCube.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GLATEventCube.cpp - Fermi/LAT event cube class *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2009-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 GLATEventCube.cpp
23 * @brief Fermi/LAT event cube class implementation
24 * @author Juergen Knoedlseder
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include "GException.hpp"
32#include "GTools.hpp"
33#include "GFilename.hpp"
34#include "GFitsImage.hpp"
35#include "GFitsTable.hpp"
36#include "GLATEventCube.hpp"
37
38/* __ Method name definitions ____________________________________________ */
39#define G_NAXIS "GLATEventCube::naxis(int)"
40#define G_DIFFNAME "GLATEventCube::diffname(int&)"
41#define G_DIFFRSP "GLATEventCube::diffrsp(int&)"
42#define G_READ_SRCMAP "GLATEventCube::read_srcmap(GFitsImage&)"
43#define G_SET_DIRECTIONS "GLATEventCube::set_directions()"
44#define G_SET_ENERGIES "GLATEventCube::set_energies()"
45#define G_SET_TIMES "GLATEventCube::set_times()"
46#define G_SET_BIN "GLATEventCube::set_bin(int&)"
47
48/* __ Macros _____________________________________________________________ */
49
50/* __ Coding definitions _________________________________________________ */
51#define G_MISSING_WCS_KLUDGE //!< Handle source maps with missing WCS
52
53/* __ Debug definitions __________________________________________________ */
54
55
56/*==========================================================================
57 = =
58 = Constructors/destructors =
59 = =
60 ==========================================================================*/
61
62/***********************************************************************//**
63 * @brief Void constructor
64 ***************************************************************************/
66{
67 // Initialise members
69
70 // Return
71 return;
72}
73
74
75/***********************************************************************//**
76 * @brief File name constructor
77 *
78 * @param[in] filename Counts cube filename.
79 *
80 * Construct event cube object by loading the events from a FITS file.
81 ***************************************************************************/
83{
84 // Initialise members
86
87 // Load counts cube
88 load(filename);
89
90 // Return
91 return;
92}
93
94
95/***********************************************************************//**
96 * @brief Copy constructor
97 *
98 * @param[in] cube LAT event cube.
99 ***************************************************************************/
101{
102 // Initialise members
103 init_members();
104
105 // Copy members
106 copy_members(cube);
107
108 // Return
109 return;
110}
111
112
113/***********************************************************************//**
114 * @brief Destructor
115 ***************************************************************************/
117{
118 // Free members
119 free_members();
120
121 // Return
122 return;
123}
124
125
126/*==========================================================================
127 = =
128 = Operators =
129 = =
130 ==========================================================================*/
131
132/***********************************************************************//**
133 * @brief Assignment operator
134 *
135 * @param[in] cube LAT event cube.
136 * @return LAT event cube.
137 ***************************************************************************/
139{
140 // Execute only if object is not identical
141 if (this != &cube) {
142
143 // Copy base class members
144 this->GEventCube::operator=(cube);
145
146 // Free members
147 free_members();
148
149 // Initialise members
150 init_members();
151
152 // Copy members
153 copy_members(cube);
154
155 } // endif: object was not identical
156
157 // Return this object
158 return *this;
159}
160
161
162/***********************************************************************//**
163 * @brief Event bin access operator
164 *
165 * @param[in] index Event index [0,...,size()-1].
166 * @return Pointer to event bin.
167 *
168 * Returns pointer to an event bin.
169 ***************************************************************************/
171{
172 // Set event bin
173 set_bin(index);
174
175 // Return pointer
176 return (&m_bin);
177}
178
179
180/***********************************************************************//**
181 * @brief Event bin access operator (const version)
182 *
183 * @param[in] index Event index [0,...,size()-1].
184 * @return Pointer to event bin.
185 *
186 * Returns pointer to an event bin.
187 ***************************************************************************/
188const GLATEventBin* GLATEventCube::operator[](const int& index) const
189{
190 // Set event bin (circumvent const correctness)
191 const_cast<GLATEventCube*>(this)->set_bin(index);
192
193 // Return pointer
194 return (&m_bin);
195}
196
197
198/*==========================================================================
199 = =
200 = Public methods =
201 = =
202 ==========================================================================*/
203
204/***********************************************************************//**
205 * @brief Clear instance
206 *
207 * This method properly resets the object to an initial state.
208 ***************************************************************************/
210{
211 // Free class members (base and derived classes, derived class first)
212 free_members();
214 this->GEvents::free_members();
215
216 // Initialise members
217 this->GEvents::init_members();
219 init_members();
220
221 // Return
222 return;
223}
224
225
226/***********************************************************************//**
227 * @brief Clone instance
228 *
229 * @return Deep copy of LAT event cube.
230 ***************************************************************************/
232{
233 return new GLATEventCube(*this);
234}
235
236
237/***********************************************************************//**
238 * @brief Return number of bins in event cube
239 *
240 * @return Number of bins in event cube.
241 ***************************************************************************/
242int GLATEventCube::size(void) const
243{
244 // Compute number of bins
245 int nbins = m_map.npix() * m_map.nmaps();
246
247 // Return number of bins
248 return nbins;
249}
250
251
252/***********************************************************************//**
253 * @brief Return dimension of event cube
254 *
255 * @return Number of dimensions in event cube (either 2 or 3).
256 ***************************************************************************/
257int GLATEventCube::dim(void) const
258{
259 // Compute dimension from sky map
260 int dim = (m_map.nmaps() > 1) ? 3 : 2;
261
262 // Return dimension
263 return dim;
264}
265
266
267/***********************************************************************//**
268 * @brief Return number of bins in axis
269 *
270 * @param[in] axis Axis [0,...,dim()-1]
271 * @return Number of bins in specified axis
272 *
273 * @exception GException::out_of_range
274 * Axis is out of range.
275 *
276 * Returns the number of bins along a given event cube @p axis.
277 ***************************************************************************/
278int GLATEventCube::naxis(const int& axis) const
279{
280 // Optionally check if the axis is valid
281 #if defined(G_RANGE_CHECK)
282 if (axis < 0 || axis >= dim()) {
283 throw GException::out_of_range(G_NAXIS, "LAT event cube axis",
284 axis, dim());
285 }
286 #endif
287
288 // Set result
289 int naxis = 0;
290 switch (axis) {
291 case 0:
292 naxis = m_map.nx();
293 break;
294 case 1:
295 naxis = m_map.ny();
296 break;
297 case 2:
298 naxis = m_map.npix();
299 break;
300 }
301
302 // Return result
303 return naxis;
304}
305
306
307/***********************************************************************//**
308 * @brief Load LAT event cube from FITS file
309 *
310 * @param[in] filename FITS file name.
311 ***************************************************************************/
312void GLATEventCube::load(const GFilename& filename)
313{
314 // Open FITS file
315 GFits fits(filename);
316
317 // Read event cube from FITS file
318 read(fits);
319
320 // Close FITS file
321 fits.close();
322
323 // Return
324 return;
325}
326
327
328/***********************************************************************//**
329 * @brief Save LAT event cube into FITS file
330 *
331 * @param[in] filename FITS file name.
332 * @param[in] clobber Overwrite existing FITS file? (default: false)
333 *
334 * Save the LAT event cube into FITS file.
335 ***************************************************************************/
336void GLATEventCube::save(const GFilename& filename,
337 const bool& clobber) const
338{
339 // Create empty FITS file
340 GFits fits;
341
342 // Write event cube into FITS file
343 write(fits);
344
345 // Save FITS file
346 fits.saveto(filename, clobber);
347
348 // Return
349 return;
350}
351
352
353/***********************************************************************//**
354 * @brief Read LAT event cube from FITS file.
355 *
356 * @param[in] fits FITS file.
357 *
358 * It is assumed that the counts map resides in the primary extension of the
359 * FITS file, the energy boundaries reside in the `EBOUNDS` extension and the
360 * Good Time Intervals reside in the `GTI` extension. The method clears the
361 * object before loading, thus any events residing in the object before
362 * loading will be lost.
363 ***************************************************************************/
364void GLATEventCube::read(const GFits& fits)
365{
366 // Clear object
367 clear();
368
369 // Get HDUs
370 const GFitsImage& hdu_cntmap = *fits.image("Primary");
371 const GFitsTable& hdu_ebounds = *fits.table(gammalib::extname_ebounds);
372 const GFitsTable& hdu_gti = *fits.table(gammalib::extname_gti);
373
374 // Load counts map
375 read_cntmap(hdu_cntmap);
376
377 // Load energy boundaries
378 read_ebds(hdu_ebounds);
379
380 // Load GTIs
381 read_gti(hdu_gti);
382
383 // Load additional source maps
384 for (int i = 1; i < fits.size(); ++i) {
385
386 // Only consider image extensions
387 if (fits.at(i)->exttype() == GFitsHDU::HT_IMAGE) {
388
389 // Get FITS image
390 const GFitsImage& hdu_srcmap = *fits.image(i);
391
392 // Handle files that do not have WCS in their additional
393 // source map extensions
394 #if defined(G_MISSING_WCS_KLUDGE)
395 std::string keys[] = {"CTYPE1", "CTYPE2", "CTYPE3",
396 "CRPIX1", "CRPIX2", "CRPIX3",
397 "CRVAL1", "CRVAL2", "CRVAL3",
398 "CDELT1", "CDELT2", "CDELT3",
399 "CUNIT1", "CUNIT2", "CUNIT3",
400 "CROTA2"};
401 for (int i = 0; i < 16; ++i) {
402 if (!hdu_srcmap.has_card(keys[i])) {
403 const_cast<GFitsImage&>(hdu_srcmap).card(hdu_cntmap.card(keys[i]));
404 }
405 }
406 #endif
407
408 // Read source map
409 read_srcmap(hdu_srcmap);
410
411 } // endif: extension is an image
412
413 } // endfor: looped over additional source maps
414
415 // Return
416 return;
417}
418
419
420/***********************************************************************//**
421 * @brief Write LAT event cube into FITS file
422 *
423 * @param[in] fits FITS file.
424 ***************************************************************************/
426{
427 // Write cube
428 m_map.write(fits);
429
430 // Write energy boundaries
431 ebounds().write(fits);
432
433 // Write Good Time intervals
434 gti().write(fits);
435
436 // Write additional source maps
437 for (int i = 0; i < m_srcmap.size(); ++i) {
438 m_srcmap[i]->write(fits);
439 }
440
441 // Return
442 return;
443}
444
445
446/***********************************************************************//**
447 * @brief Return number of events in cube
448 *
449 * @return Total number of events in event cube.
450 ***************************************************************************/
452{
453 // Initialise result
454 double number = 0.0;
455
456 // Get pointer on skymap pixels
457 const double* pixels = m_map.pixels();
458
459 // Sum event cube
460 if (size() > 0 && pixels != NULL) {
461 for (int i = 0; i < size(); ++i) {
462 number += pixels[i];
463 }
464 }
465
466 // Return
467 return int(number+0.5);
468}
469
470
471/***********************************************************************//**
472 * @brief Set event cube from sky map
473 ***************************************************************************/
475{
476 // Store sky map
477 m_map = map;
478
479 // Compute sky directions
481
482 // Return
483 return;
484}
485
486
487/***********************************************************************//**
488 * @brief Print event cube information
489 *
490 * @param[in] chatter Chattiness.
491 * @return String containing event cube information.
492 ***************************************************************************/
493std::string GLATEventCube::print(const GChatter& chatter) const
494{
495 // Initialise result string
496 std::string result;
497
498 // Continue only if chatter is not silent
499 if (chatter != SILENT) {
500
501 // Append header
502 result.append("=== GLATEventCube ===");
503
504 // Append information
505 result.append("\n"+gammalib::parformat("Number of elements") +
507 result.append("\n"+gammalib::parformat("Number of pixels"));
508 result.append(gammalib::str(m_map.nx()) +
509 " x " +
511 result.append("\n"+gammalib::parformat("Number of energy bins") +
513 result.append("\n"+gammalib::parformat("Number of events") +
515
516 // Append time interval
517 result.append("\n"+gammalib::parformat("Time interval"));
518 if (gti().size() > 0) {
519 result.append(gammalib::str(tstart().secs()) +
520 " - " +
521 gammalib::str(tstop().secs())+" sec");
522 }
523 else {
524 result.append("not defined");
525 }
526
527 // Append energy range
528 result.append("\n"+gammalib::parformat("Energy range"));
529 if (ebounds().size() > 0) {
530 result.append(emin().print()+" - "+emax().print(chatter));
531 }
532 else {
533 result.append("not defined");
534 }
535
536 // Append detailed information
537 GChatter reduced_chatter = gammalib::reduce(chatter);
538 if (reduced_chatter > SILENT) {
539
540 // Append sky projection
541 if (m_map.projection() != NULL) {
542 result.append("\n"+m_map.projection()->print(reduced_chatter));
543 }
544
545 // Append source maps
546 result.append("\n"+gammalib::parformat("Number of source maps"));
547 result.append(gammalib::str(m_srcmap.size()));
548 for (int i = 0; i < m_srcmap.size(); ++i) {
549 result.append("\n"+gammalib::parformat(" "+m_srcmap_names[i]));
550 result.append(gammalib::str(m_srcmap[i]->nx()));
551 result.append(" x ");
552 result.append(gammalib::str(m_srcmap[i]->ny()));
553 result.append(" x ");
554 result.append(gammalib::str(m_srcmap[i]->nmaps()));
555 }
556
557 }
558
559 } // endif: chatter was not silent
560
561 // Return result
562 return result;
563}
564
565
566/***********************************************************************//**
567 * @brief Return name of diffuse model
568 *
569 * @param[in] index Diffuse model index [0,...,ndiffrsp()-1].
570 * @return Name of diffuse model.
571 *
572 * @exception GException::out_of_range
573 * Model index out of valid range.
574 *
575 * Returns name of diffuse model.
576 ***************************************************************************/
577std::string GLATEventCube::diffname(const int& index) const
578{
579 // Optionally check if the index is valid
580 #if defined(G_RANGE_CHECK)
581 if (index < 0 || index >= ndiffrsp()) {
582 throw GException::out_of_range(G_DIFFNAME, "Diffuse model index",
583 index, ndiffrsp());
584 }
585 #endif
586
587 // Return
588 return m_srcmap_names[index];
589}
590
591
592/***********************************************************************//**
593 * @brief Return diffuse response map
594 *
595 * @param[in] index Diffuse model index [0,...,ndiffrsp()-1].
596 * @return Pointer to diffuse response map.
597 *
598 * @exception GException::out_of_range
599 * Model index out of valid range.
600 *
601 * Returns pointer to diffuse model sky map.
602 ***************************************************************************/
603GSkyMap* GLATEventCube::diffrsp(const int& index) const
604{
605 // Optionally check if the index is valid
606 #if defined(G_RANGE_CHECK)
607 if (index < 0 || index >= ndiffrsp()) {
608 throw GException::out_of_range(G_DIFFRSP, "Diffuse model index",
609 index, ndiffrsp());
610 }
611 #endif
612
613 // Return
614 return m_srcmap[index];
615}
616
617
618/***********************************************************************//**
619 * @brief Computes the maximum radius (in degrees) around a given source
620 * direction that fits spatially into the event cube
621 *
622 * @param[in] srcDir Source direction.
623 * @return Maximum radius in degrees that fully fits into event cube.
624 *
625 * By computing the sky directions of the event cube boundaries, the maximum
626 * radius is computed that fits fully within the event cube. This method is
627 * used for PSF normalization.
628 ***************************************************************************/
629double GLATEventCube::maxrad(const GSkyDir& srcDir) const
630{
631 // Initialise radius
632 double radius = 0.0;
633
634 // Continue only if sky direction is within sky map
635 if (m_map.contains(srcDir)) {
636
637 // Set to largest possible radius
638 radius = 180.0;
639
640 // Move along upper edge in longitude
641 int iy = 0;
642 for (int ix = 0; ix < nx(); ++ix) {
643 GSkyPixel pixel = GSkyPixel(double(ix), double(iy));
644 double distance = m_map.pix2dir(pixel).dist_deg(srcDir);
645 if (distance < radius) {
646 radius = distance;
647 }
648 }
649
650 // Move along lower edge in longitude
651 iy = ny()-1;
652 for (int ix = 0; ix < nx(); ++ix) {
653 GSkyPixel pixel = GSkyPixel(double(ix), double(iy));
654 double distance = m_map.pix2dir(pixel).dist_deg(srcDir);
655 if (distance < radius) {
656 radius = distance;
657 }
658 }
659
660 // Move along left edge in latitude
661 int ix = 0;
662 for (int iy = 0; iy < ny(); ++iy) {
663 GSkyPixel pixel = GSkyPixel(double(ix), double(iy));
664 double distance = m_map.pix2dir(pixel).dist_deg(srcDir);
665 if (distance < radius) {
666 radius = distance;
667 }
668 }
669
670 // Move along right edge in latitude
671 ix = nx()-1;
672 for (int iy = 0; iy < ny(); ++iy) {
673 GSkyPixel pixel = GSkyPixel(double(ix), double(iy));
674 double distance = m_map.pix2dir(pixel).dist_deg(srcDir);
675 if (distance < radius) {
676 radius = distance;
677 }
678 }
679
680 } // endif: sky direction within sky map
681
682 // Return radius
683 return radius;
684}
685
686
687/*==========================================================================
688 = =
689 = Private methods =
690 = =
691 ==========================================================================*/
692
693/***********************************************************************//**
694 * @brief Initialise class members
695 ***************************************************************************/
697{
698 // Initialise members
699 m_bin.clear();
700 m_map.clear();
701 m_time.clear();
702 m_srcmap.clear();
703 m_srcmap_names.clear();
704 m_enodes.clear();
705 m_dirs.clear();
706 m_solidangle.clear();
707 m_energies.clear();
708 m_ewidth.clear();
709 m_ontime = 0.0;
710
711 // Return
712 return;
713}
714
715
716/***********************************************************************//**
717 * @brief Copy class members
718 *
719 * @param[in] cube Fermi/LAT event cube.
720 ***************************************************************************/
722{
723 // Copy Fermi/LAT specific attributes
724 m_bin = cube.m_bin;
725 m_map = cube.m_map;
726 m_time = cube.m_time;
727 m_ontime = cube.m_ontime;
728 m_enodes = cube.m_enodes;
729 m_dirs = cube.m_dirs;
731 m_energies = cube.m_energies;
732 m_ewidth = cube.m_ewidth;
733
734 // Clone source maps and copy source map names
735 m_srcmap.clear();
736 for (int i = 0; i < cube.m_srcmap.size(); ++i) {
737 m_srcmap.push_back(cube.m_srcmap[i]->clone());
738 }
740
741 // Return
742 return;
743}
744
745
746/***********************************************************************//**
747 * @brief Delete class members
748 ***************************************************************************/
750{
751 // Release source maps
752 for (int i = 0; i < m_srcmap.size(); ++i) {
753 if (m_srcmap[i] != NULL) delete m_srcmap[i];
754 m_srcmap[i] = NULL;
755 }
756 m_srcmap.clear();
757 m_srcmap_names.clear();
758
759 // Return
760 return;
761}
762
763
764/***********************************************************************//**
765 * @brief Read Fermi/LAT counts map from HDU.
766 *
767 * @param[in] hdu Image HDU.
768 *
769 * This method reads a Fermi/LAT counts map from a FITS image. The counts map
770 * is stored in a GSkyMap object, and a pointer is set up to access the
771 * pixels individually. Recall that skymap pixels are stored in the order
772 * (ix,iy,ebin).
773 ***************************************************************************/
775{
776 // Load counts map as sky map
777 m_map.read(hdu);
778
779 // Set sky directions
781
782 // Return
783 return;
784}
785
786
787/***********************************************************************//**
788 * @brief Read LAT source map from HDU.
789 *
790 * @param[in] hdu Image HDU.
791 *
792 * @exception GException::invalid_argument
793 * Source map in @p hdu is not compatible with event cube.
794 *
795 * This method reads a LAT source map from a FITS image. The source map is
796 * stored in a GSkyMap object and is given in units of counts/pixel/MeV.
797 ***************************************************************************/
799{
800 // Allocate skymap
801 GSkyMap* map = new GSkyMap;
802
803 // Read skymap
804 map->read(hdu);
805
806 // Check that source map sky projection is consistent with counts
807 // map sky projection
808 if (*(m_map.projection()) != *(map->projection())) {
809 std::string msg = "Specified source map projection in HDU \""+
810 hdu.extname()+"\" is incompatible with map projection "
811 "of the event cube. Please specify a compatible "
812 "map projection.";
814 }
815
816 // Check that source map dimension is consistent with counts map
817 // dimension
818 if (m_map.nx() != map->nx() ||
819 m_map.ny() != map->ny()) {
820 std::string msg = "Number of pixels ("+gammalib::str(map->nx())+","+
821 gammalib::str(map->ny())+") in source map in HDU \""+
822 hdu.extname()+"\" is not compatible with number of "
823 "pixels ("+gammalib::str(m_map.nx())+","+
824 gammalib::str(m_map.ny())+") in the event cube. "
825 "Please specify a source map of compatible size.";
827 }
828
829 // Check that source map has required number of energy bins
830 if (m_map.nmaps()+1 != map->nmaps()) {
831 std::string msg = "Number of maps ("+gammalib::str(map->nmaps())+")"+
832 " in source map in HDU \""+hdu.extname()+"\" is not "
833 "compatible with number of energy bin boundaries ("+
834 gammalib::str(m_map.nmaps()+1)+") of the event cube. "
835 "Please specify a source map of compatible size.";
837 }
838
839 // Append source map to list of maps
840 m_srcmap.push_back(map);
841 m_srcmap_names.push_back(hdu.extname());
842
843 // Return
844 return;
845}
846
847
848/***********************************************************************//**
849 * @brief Read energy boundaries from HDU.
850 *
851 * @param[in] hdu Energy boundaries table.
852 *
853 * Read the energy boundaries from the HDU.
854 *
855 * @todo Energy bounds read method should take const GFitsTable* as argument
856 ***************************************************************************/
858{
859 // Read energy boundaries
860 m_ebounds.read(hdu);
861
862 // Set log mean energies and energy widths
863 set_energies();
864
865 // Return
866 return;
867}
868
869
870/***********************************************************************//**
871 * @brief Read GTIs from HDU.
872 *
873 * @param[in] hdu GTI table.
874 *
875 * Reads the Good Time Intervals from the GTI extension. Since the Fermi
876 * LAT Science Tools do not set corrently the time reference for source
877 * maps, the method automatically adds this missing information so that
878 * the time reference is set correctly. The time reference that is assumed
879 * for Fermi LAT is
880 *
881 * MJDREFI 51910
882 * MJDREFF 0.00074287037037037
883 *
884 ***************************************************************************/
886{
887 // Work on a local copy of the HDU to make the kluge work
888 GFitsTable* hdu_local = hdu.clone();
889
890 // Kluge: modify HDU table in case that the MJDREF header keyword is
891 // blank. This happens for Fermi LAT source maps since the Science
892 // Tools do not properly write out the time reference. We hard-code
893 // here the Fermi LAT time reference to circumvent the problem.
894 if (hdu.has_card("MJDREF")) {
895 if (gammalib::strip_whitespace(hdu.string("MJDREF")).empty()) {
896 const_cast<GFitsHeader&>(hdu_local->header()).remove("MJDREF");
897 hdu_local->card("MJDREFI", 51910,
898 "Integer part of MJD reference");
899 hdu_local->card("MJDREFF", 0.00074287037037037,
900 "Fractional part of MJD reference");
901 }
902 }
903
904 // Read Good Time Intervals
905 m_gti.read(*hdu_local);
906
907 // Set time
908 set_times();
909
910 // Return
911 return;
912}
913
914
915/***********************************************************************//**
916 * @brief Set sky directions and solid angles of events cube.
917 *
918 * @exception GException::invalid_value
919 * No sky pixels found in event cube.
920 *
921 * This method computes the sky directions and solid angles for all event
922 * cube pixels. Sky directions are stored in an array of GLATInstDir objects
923 * while solid angles are stored in units of sr in a double precision array.
924 ***************************************************************************/
926{
927 // Throw an exception if we have no sky pixels
928 if (npix() < 1) {
929 std::string msg = "LAT event cube contains no sky pixels. Please "
930 "provide a valid LAT event cube.";
932 }
933
934 // Clear old pixel directions and solid angle
935 m_dirs.clear();
936 m_solidangle.clear();
937
938 // Reserve space for pixel directions and solid angles
939 m_dirs.reserve(npix());
940 m_solidangle.reserve(npix());
941
942 // Set pixel directions and solid angles
943 for (int iy = 0; iy < ny(); ++iy) {
944 for (int ix = 0; ix < nx(); ++ix) {
945 GSkyPixel pixel = GSkyPixel(double(ix), double(iy));
946 m_dirs.push_back(GLATInstDir(m_map.pix2dir(pixel)));
947 m_solidangle.push_back(m_map.solidangle(pixel));
948 }
949 }
950
951 // Return
952 return;
953}
954
955
956/***********************************************************************//**
957 * @brief Set log mean energies and energy widths of event cube.
958 *
959 * @exception GException::invalid_value
960 * No energy boundaries found in event cube.
961 *
962 * This method computes the log mean energies and the energy widths of the
963 * event cube. The log mean energies and energy widths are stored unit
964 * independent in arrays of GEnergy objects.
965 ***************************************************************************/
967{
968 // Throw an error if we have no energy bins
969 if (ebins() < 1) {
970 std::string msg = "LAT event cube contains no energy bins. Please "
971 "provide a valid LAT event cube.";
973 }
974
975 // Clear old bin energies and energy widths
976 m_energies.clear();
977 m_ewidth.clear();
978 m_enodes.clear();
979
980 // Reserve space for bin energies and energy widths
981 m_energies.reserve(ebins());
982 m_ewidth.reserve(ebins());
983
984 // Setup bin energies, energy widths and energy nodes
985 for (int i = 0; i < ebins(); ++i) {
986 m_energies.push_back(ebounds().elogmean(i));
987 m_ewidth.push_back(ebounds().emax(i) - ebounds().emin(i));
988 m_enodes.append(log10(ebounds().emin(i).MeV()));
989 }
990 m_enodes.append(log10(ebounds().emax(ebins()-1).MeV()));
991
992 // Return
993 return;
994}
995
996
997/***********************************************************************//**
998 * @brief Set mean event time and ontime of event cube
999 *
1000 * @exception GException::invalid_value
1001 * No Good Time Intervals found.
1002 *
1003 * Computes the mean time of the event cube by taking the mean between start
1004 * and stop time. Computes also the ontime by summing up of all good time
1005 * intervals.
1006 *
1007 * @todo Could add a more sophisticated mean event time computation that
1008 * weights by the length of the GTIs, yet so far we do not really use
1009 * the mean event time, hence there is no rush to implement this.
1010 ***************************************************************************/
1012{
1013 // Throw an error if GTI is empty
1014 if (m_gti.size() < 1) {
1015 std::string msg = "No Good Time Intervals have been found in event "
1016 "cube. Every LAT event cube needs a definition "
1017 "of the Good Time Intervals.";
1019 }
1020
1021 // Compute mean time
1022 m_time = m_gti.tstart() + 0.5 * (m_gti.tstop() - m_gti.tstart());
1023
1024 // Set ontime
1025 m_ontime = m_gti.ontime();
1026
1027 // Return
1028 return;
1029}
1030
1031
1032/***********************************************************************//**
1033 * @brief Set event bin
1034 *
1035 * @param[in] index Event index [0,...,size()-1].
1036 *
1037 * @exception GException::out_of_range
1038 * Event index is outside valid range.
1039 * @exception GException::invalid_value
1040 * Energy vectors have not been set up.
1041 * Sky directions and solid angles vectors have not been set up.
1042 *
1043 * This method provides the event attributes to the event bin. The event bin
1044 * is in fact physically stored in the event cube, and only a single event
1045 * bin is indeed allocated. This method sets up the pointers in the event
1046 * bin so that a client can easily access the information of individual bins
1047 * as if they were stored in an array.
1048 ***************************************************************************/
1049void GLATEventCube::set_bin(const int& index)
1050{
1051 // Optionally check if the index is valid
1052 #if defined(G_RANGE_CHECK)
1053 if (index < 0 || index >= size()) {
1054 throw GException::out_of_range(G_SET_BIN, "Event index", index, size());
1055 }
1056 #endif
1057
1058 // Check for the existence of energies and energy widths
1059 if (m_energies.size() != ebins() || m_ewidth.size() != ebins()) {
1060 std::string msg = "Number of energy bins ("+gammalib::str(ebins())+
1061 ") is incompatible with size of energies ("+
1062 gammalib::str(m_energies.size())+") an/or size of "
1063 "energy widths ("+gammalib::str(m_ewidth.size())+
1064 "). Please provide an correctly initialised event "
1065 "cube.";
1067 }
1068
1069 // Check for the existence of sky directions and solid angles
1070 if (m_dirs.size() != npix() || m_solidangle.size() != npix()) {
1071 std::string msg = "Number of sky pixels ("+gammalib::str(npix())+
1072 ") is incompatible with size of sky directions ("+
1073 gammalib::str(m_dirs.size())+") and/or size of "
1074 "solid angles ("+gammalib::str(m_solidangle.size())+
1075 "). Please provide an correctly initialised event "
1076 "cube.";
1078 }
1079
1080 // Get pixel and energy bin indices.
1081 m_bin.m_index = index;
1082 m_bin.m_ipix = index % npix();
1083 m_bin.m_ieng = index / npix();
1084
1085 // Set pointers
1086 m_bin.m_cube = this;
1087 m_bin.m_counts = const_cast<double*>(&(m_map.pixels()[index]));
1089 m_bin.m_time = &m_time;
1094
1095 // Return
1096 return;
1097}
#define G_SET_TIMES
#define G_SET_ENERGIES
#define G_SET_BIN
#define G_NAXIS
#define G_SET_DIRECTIONS
Exception handler interface definition.
Filename class interface definition.
Abstract FITS image base class definition.
FITS table abstract base class interface definition.
#define G_DIFFNAME
#define G_DIFFRSP
#define G_READ_SRCMAP
Fermi/LAT event cube class definition.
Gammalib tools definition.
GChatter
Definition GTypemaps.hpp:33
@ SILENT
Definition GTypemaps.hpp:34
GVector log10(const GVector &vector)
Computes base10 logarithm of vector elements.
Definition GVector.cpp:1295
const GEnergy & emax(void) const
Return maximum energy of all intervals.
Definition GEbounds.hpp:199
void read(const GFitsTable &table)
Read energy boundaries from FITS table.
Definition GEbounds.cpp:761
GEnergy elogmean(const int &index) const
Returns logarithmic mean energy for a given energy interval.
const GEnergy & emin(void) const
Return minimum energy of all intervals.
Definition GEbounds.hpp:187
void write(GFits &file, const std::string &extname=gammalib::extname_ebounds, const std::string &unit="keV") const
Write energy boundaries into FITS object.
Definition GEbounds.cpp:816
Abstract event bin container class.
void free_members(void)
Delete class members.
void init_members(void)
Initialise class members.
virtual GEventCube & operator=(const GEventCube &cube)
Assignment operator.
void free_members(void)
Delete class members.
Definition GEvents.cpp:206
GGti m_gti
Good time intervals covered by events.
Definition GEvents.hpp:112
const GTime & tstart(void) const
Return start time.
Definition GEvents.hpp:146
GEbounds m_ebounds
Energy boundaries covered by events.
Definition GEvents.hpp:111
const GGti & gti(void) const
Return Good Time Intervals.
Definition GEvents.hpp:134
void init_members(void)
Initialise class members.
Definition GEvents.cpp:176
const GTime & tstop(void) const
Return stop time.
Definition GEvents.hpp:158
const GEbounds & ebounds(void) const
Return energy boundaries.
Definition GEvents.hpp:122
const GEnergy & emax(void) const
Return maximum energy.
Definition GEvents.hpp:182
const GEnergy & emin(void) const
Return minimum energy.
Definition GEvents.hpp:170
Filename class.
Definition GFilename.hpp:62
virtual HDUType exttype(void) const =0
const GFitsHeader & header(void) const
Return extension header.
Definition GFitsHDU.hpp:205
bool has_card(const int &cardno) const
Check existence of header card.
Definition GFitsHDU.hpp:233
const std::string & extname(void) const
Return extension name.
Definition GFitsHDU.hpp:162
std::string string(const std::string &keyname) const
Return card value as string.
Definition GFitsHDU.hpp:410
GFitsHeaderCard & card(const int &cardno)
Return header card.
Definition GFitsHDU.hpp:259
Interface for FITS header class.
Abstract FITS image base class.
Abstract interface for FITS table.
virtual GFitsTable * clone(void) const =0
Clones object.
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
GFitsHDU * at(const int &extno)
Get pointer to HDU.
Definition GFits.cpp:233
GFitsTable * table(const int &extno)
Get pointer to table HDU.
Definition GFits.cpp:482
void write(GFits &fits, const std::string &extname=gammalib::extname_gti) const
Write Good Time Intervals and time reference into FITS object.
Definition GGti.cpp:796
const GTime & tstop(void) const
Returns latest stop time in Good Time Intervals.
Definition GGti.hpp:207
void read(const GFitsTable &table)
Read Good Time Intervals and time reference from FITS table.
Definition GGti.cpp:753
int size(void) const
Return number of Good Time Intervals.
Definition GGti.hpp:154
const double & ontime(void) const
Returns ontime.
Definition GGti.hpp:240
const GTime & tstart(void) const
Returns earliest start time in Good Time Intervals.
Definition GGti.hpp:194
Fermi/LAT event bin class.
GEnergy * m_ewidth
Pointer to energy width of bin.
int m_index
Actual skymap index.
GLATEventCube * m_cube
Event cube back pointer.
double * m_solidangle
Pointer to solid angle of pixel (sr)
int m_ipix
Actual spatial index.
double * m_ontime
Pointer to ontime of bin (seconds)
int m_ieng
Actual energy index.
double * m_counts
Pointer to number of counts.
virtual void clear(void)
Clear event bin.
GEnergy * m_energy
Pointer to bin energy.
GLATInstDir * m_dir
Pointer to bin direction.
GTime * m_time
Pointer to bin time.
Fermi/LAT event cube class.
GLATEventBin m_bin
Actual energy bin.
virtual GLATEventCube * clone(void) const
Clone instance.
double maxrad(const GSkyDir &dir) const
Computes the maximum radius (in degrees) around a given source direction that fits spatially into the...
GLATEventCube(void)
Void constructor.
virtual void clear(void)
Clear instance.
std::vector< GSkyMap * > m_srcmap
Pointers to source maps.
virtual ~GLATEventCube(void)
Destructor.
virtual void set_energies(void)
Set log mean energies and energy widths of event cube.
void copy_members(const GLATEventCube &cube)
Copy class members.
void set_directions(void)
Set sky directions and solid angles of events cube.
virtual std::string print(const GChatter &chatter=NORMAL) const
Print event cube information.
virtual int number(void) const
Return number of events in cube.
const GSkyMap & map(void) const
Return event cube sky map.
virtual int dim(void) const
Return dimension of event cube.
virtual void save(const GFilename &filename, const bool &clobber=false) const
Save LAT event cube into FITS file.
void read_gti(const GFitsTable &hdu)
Read GTIs from HDU.
virtual void load(const GFilename &filename)
Load LAT event cube from FITS file.
int npix(void) const
Return number of pixels in event cube sky map.
GTime m_time
Event cube mean time.
int ndiffrsp(void) const
Return number of diffuse model components.
virtual void set_times(void)
Set mean event time and ontime of event cube.
virtual int size(void) const
Return number of bins in event cube.
virtual int naxis(const int &axis) const
Return number of bins in axis.
void free_members(void)
Delete class members.
std::vector< double > m_solidangle
Array of solid angles (sr)
std::vector< GEnergy > m_energies
Array of log mean energies.
int ny(void) const
Return number of bins in Y direction.
void read_cntmap(const GFitsImage &hdu)
Read Fermi/LAT counts map from HDU.
int nx(void) const
Return number of bins in X direction.
virtual void read(const GFits &file)
Read LAT event cube from FITS file.
void read_srcmap(const GFitsImage &hdu)
Read LAT source map from HDU.
virtual void write(GFits &file) const
Write LAT event cube into FITS file.
std::vector< GLATInstDir > m_dirs
Array of event directions.
GNodeArray m_enodes
Energy nodes.
void read_ebds(const GFitsTable &hdu)
Read energy boundaries from HDU.
GSkyMap * diffrsp(const int &index) const
Return diffuse response map.
int ebins(void) const
Return number of energy bins in event cube.
GSkyMap m_map
Counts map stored as sky map.
std::string diffname(const int &index) const
Return name of diffuse model.
double m_ontime
Event cube ontime (sec)
std::vector< std::string > m_srcmap_names
Source map names.
std::vector< GEnergy > m_ewidth
Array of energy bin widths.
virtual GLATEventBin * operator[](const int &index)
Event bin access operator.
void set_bin(const int &index)
Set event bin.
virtual GLATEventCube & operator=(const GLATEventCube &cube)
Assignment operator.
void init_members(void)
Initialise class members.
Fermi/LAT instrument direction class.
void clear(void)
Clear node array.
void append(const double &node)
Append one node to array.
Sky direction class.
Definition GSkyDir.hpp:62
double dist_deg(const GSkyDir &dir) const
Compute angular distance between sky directions in degrees.
Definition GSkyDir.hpp:286
Sky map class.
Definition GSkyMap.hpp:89
double solidangle(const int &index) const
Returns solid angle of pixel.
Definition GSkyMap.cpp:1858
const int & nmaps(void) const
Returns number of maps.
Definition GSkyMap.hpp:389
void clear(void)
Clear instance.
Definition GSkyMap.cpp:1100
const int & nx(void) const
Returns number of pixels in x coordinate.
Definition GSkyMap.hpp:361
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
const int & ny(void) const
Returns number of pixels in y coordinate.
Definition GSkyMap.hpp:377
const GSkyProjection * projection(void) const
Returns pointer to sky projection.
Definition GSkyMap.hpp:463
GFitsHDU * write(GFits &file, const std::string &extname="") const
Write sky map into FITS file.
Definition GSkyMap.cpp:2697
GSkyDir pix2dir(const GSkyPixel &pixel) const
Returns sky direction of pixel.
Definition GSkyMap.cpp:1360
bool contains(const GSkyDir &dir) const
Checks if sky direction falls in map.
Definition GSkyMap.cpp:2023
const double * pixels(void) const
Returns pointer to pixel data.
Definition GSkyMap.hpp:475
Sky map pixel class.
Definition GSkyPixel.hpp:74
virtual std::string print(const GChatter &chatter=NORMAL) const =0
Print content of object.
void clear(void)
Clear time.
Definition GTime.cpp:252
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition GTools.cpp:1143
const std::string extname_ebounds
Definition GEbounds.hpp:44
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition GTools.cpp:489
std::string strip_whitespace(const std::string &arg)
Strip leading and trailing whitespace from string.
Definition GTools.cpp:80
GChatter reduce(const GChatter &chatter)
Reduce chattiness by one level.
Definition GTypemaps.hpp:65
const std::string extname_gti
Definition GGti.hpp:44