GammaLib 2.1.0.dev
Loading...
Searching...
No Matches
GSPIEventCube.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * GSPIEventCube.cpp - INTEGRAL/SPI event bin container class *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2020-2024 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 GSPIEventCube.hpp
23 * @brief INTEGRAL/SPI event bin container class implementation
24 * @author Juergen Knoedlseder
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include "GSPIEventCube.hpp"
32#include "GSPITools.hpp"
33#include "GSPIInstDir.hpp"
34#include "GSkyDir.hpp"
35#include "GEnergy.hpp"
36#include "GTime.hpp"
37
38/* __ Method name definitions ____________________________________________ */
39#define G_NAXIS "GSPIEventCube::naxis(int)"
40#define G_MODEL_COUNTS "GSPIEventCube::model_counts(int&)"
41#define G_SET_ENERGIES "GSPIEventCube::set_energies()"
42#define G_SET_TIMES "GSPIEventCube::set_times()"
43#define G_SET_BIN "GSPIEventCube::set_bin(int&)"
44#define G_READ_FITS "GSPIEventCube::read(GFits&)"
45#define G_READ_EBDS "GSPIEventCube::read_ebds(GFitsTable*)"
46#define G_READ_PNT "GSPIEventCube::read_pnt(GFitsTable*, GFitsTable*)"
47#define G_READ_MODELS "GSPIEventCube::read_models(GFits&)"
48#define G_PTID "GSPIEventCube::ptid(int&)"
49#define G_DIR "GSPIEventCube::dir(int&, int&)"
50#define G_SPI_X "GSPIEventCube::spi_x(int&)"
51#define G_SPI_Z "GSPIEventCube::spi_z(int&)"
52#define G_EVENT_SIZE "GSPIEventCube::event_size(int&)"
53#define G_EVENT_MODEL "GSPIEventCube::event_model(int&, int&)"
54
55/* __ Macros _____________________________________________________________ */
56
57/* __ Coding definitions _________________________________________________ */
58
59/* __ Debug definitions __________________________________________________ */
60
61
62
63/*==========================================================================
64 = =
65 = Constructors/destructors =
66 = =
67 ==========================================================================*/
68
69/***********************************************************************//**
70 * @brief Void constructor
71 *
72 * Constructs an empty INTEGRAL/SPI event cube.
73 ***************************************************************************/
75{
76 // Initialise members
78
79 // Return
80 return;
81}
82
83
84/***********************************************************************//**
85 * @brief Observation Group constructor
86 *
87 * @param[in] filename Observation Group FITS file name.
88 *
89 * Construct an INTEGRAL/SPI event cube from an Observation Group.
90 ***************************************************************************/
92{
93 // Initialise members
95
96 // Load event cube
97 load(filename);
98
99 // Return
100 return;
101}
102
103
104/***********************************************************************//**
105 * @brief Copy constructor
106 *
107 * @param[in] cube INTEGRAL/SPI event cube.
108 ***************************************************************************/
110{
111 // Initialise members
112 init_members();
113
114 // Copy members
115 copy_members(cube);
116
117 // Return
118 return;
119}
120
121
122/***********************************************************************//**
123 * @brief Destructor
124 ***************************************************************************/
126{
127 // Free members
128 free_members();
129
130 // Return
131 return;
132}
133
134
135/*==========================================================================
136 = =
137 = Operators =
138 = =
139 ==========================================================================*/
140
141/***********************************************************************//**
142 * @brief Assignment operator
143 *
144 * @param[in] cube INTEGRAL/SPI event cube.
145 * @return INTEGRAL/SPI event cube.
146 ***************************************************************************/
148{
149 // Execute only if object is not identical
150 if (this != &cube) {
151
152 // Copy base class members
153 this->GEventCube::operator=(cube);
154
155 // Free members
156 free_members();
157
158 // Initialise members
159 init_members();
160
161 // Copy members
162 copy_members(cube);
163
164 } // endif: object was not identical
165
166 // Return this object
167 return *this;
168}
169
170
171/***********************************************************************//**
172 * @brief Event bin access operator
173 *
174 * @param[in] index Event index [0,...,size()-1].
175 * @return Pointer to event bin.
176 *
177 * Returns pointer to an event bin. Note that the returned pointer is in
178 * fact always the same, but the method sets the pointers within the
179 * event bin so that they point to the appropriate information.
180 ***************************************************************************/
182{
183 // Set event bin
184 set_bin(index);
185
186 // Return pointer
187 return (&m_bin);
188}
189
190
191/***********************************************************************//**
192 * @brief Event bin access operator (const version)
193 *
194 * @param[in] index Event index [0,...,size()-1].
195 * @return Const pointer to event bin.
196 *
197 * Returns pointer to an event bin. Note that the returned pointer is in
198 * fact always the same, but the method sets the pointers within the
199 * event bin so that they point to the appropriate information.
200 ***************************************************************************/
201const GSPIEventBin* GSPIEventCube::operator[](const int& index) const
202{
203 // Set event bin (circumvent const correctness)
204 const_cast<GSPIEventCube*>(this)->set_bin(index);
205
206 // Return pointer
207 return (&m_bin);
208}
209
210
211/*==========================================================================
212 = =
213 = Public methods =
214 = =
215 ==========================================================================*/
216
217/***********************************************************************//**
218 * @brief Clear INTEGRAL/SPI event cube
219 *
220 * Clears INTEGRAL/SPI event cube by resetting all class members to an
221 * initial state. Any information that was present before will be lost.
222 ***************************************************************************/
224{
225 // Free class members (base and derived classes, derived class first)
226 free_members();
228 this->GEvents::free_members();
229
230 // Initialise members
231 this->GEvents::init_members();
233 init_members();
234
235 // Return
236 return;
237}
238
239
240/***********************************************************************//**
241 * @brief Clone event cube
242 *
243 * @return Pointer to deep copy of INTEGRAL/SPI event cube.
244 ***************************************************************************/
246{
247 return new GSPIEventCube(*this);
248}
249
250
251/***********************************************************************//**
252 * @brief Return number of bins in axis
253 *
254 * @param[in] axis Axis [0,...,dim()-1].
255 * @return Number of bins in axis.
256 *
257 * @exception GException::out_of_range
258 * Axis is out of range.
259 *
260 * Returns the number of bins along a given event cube @p axis.
261 ***************************************************************************/
262int GSPIEventCube::naxis(const int& axis) const
263{
264 // Optionally check if the axis is valid
265 #if defined(G_RANGE_CHECK)
266 if (axis < 0 || axis >= dim()) {
267 throw GException::out_of_range(G_NAXIS, "INTEGRAL/SPI event cube axis",
268 axis, dim());
269 }
270 #endif
271
272 // Setup const pointer array that points to relevant axis size
273 const int* ptr[3] = {&m_num_pt, &m_num_det, &m_num_ebin};
274
275 // Set number of bins dependent on axis
276 int naxis = *ptr[axis];
277
278 // Return result
279 return naxis;
280}
281
282
283/***********************************************************************//**
284 * @brief Load INTEGRAL/SPI event cube from Observation Group
285 *
286 * @param[in] filename Observation Group FITS file name.
287 *
288 * Loads data from an Observation Group FITS file into an INTEGRAL/SPI
289 * event cube.
290 ***************************************************************************/
291void GSPIEventCube::load(const GFilename& filename)
292{
293 #pragma omp critical(GSPIEventCube_load)
294 {
295 // Clear object
296 clear();
297
298 // Open FITS file
299 GFits fits(filename);
300
301 // Read event cube from FITS file
302 read(fits);
303
304 // Close FITS file
305 fits.close();
306 }
307
308 // Return
309 return;
310}
311
312
313/***********************************************************************//**
314 * @brief Save INTEGRAL/SPI event cube into FITS file
315 *
316 * @param[in] filename FITS file name.
317 * @param[in] clobber Overwrite existing FITS file?
318 *
319 * Saves the INTEGRAL/SPI event cube into a FITS file.
320 ***************************************************************************/
321void GSPIEventCube::save(const GFilename& filename, const bool& clobber) const
322{
323 // Create empty FITS file
324 GFits fits;
325
326 // Write event cube into FITS file
327 write(fits);
328
329 // Save FITS file
330 fits.saveto(filename, clobber);
331
332 // Close FITS file
333 fits.close();
334
335 // Return
336 return;
337}
338
339
340/***********************************************************************//**
341 * @brief Read INTEGRAL/SPI event cube from Observation Group FITS file
342 *
343 * @param[in] fits Observation Group FITS file.
344 *
345 * @exception GException::invalid_value
346 * Observation Group FITS file invalid.
347 *
348 * Reads an INTEGRAL/SPI event cube from an Observation Group FITS file.
349 * The following extension are mandatory
350 *
351 * "SPI.-EBDS-SET"
352 * "SPI.-OBS.-PNT"
353 * "SPI.-OBS.-GTI"
354 * "SPI.-OBS.-DSP"
355 * "SPI.-OBS.-DTI"
356 *
357 * Optional extensions are
358 *
359 * "SPI.-SDET-SPE"
360 * "SPI.-BMOD-DSP"
361 *
362 ***************************************************************************/
363void GSPIEventCube::read(const GFits& fits)
364{
365 // Clear object
366 clear();
367
368 // Get table pointers
369 const GFitsTable* ebds = gammalib::spi_hdu(fits, "SPI.-EBDS-SET");
370 const GFitsTable* pnt = gammalib::spi_hdu(fits, "SPI.-OBS.-PNT");
371 const GFitsTable* gti = gammalib::spi_hdu(fits, "SPI.-OBS.-GTI");
372 const GFitsTable* dsp = gammalib::spi_hdu(fits, "SPI.-OBS.-DSP");
373 const GFitsTable* dti = gammalib::spi_hdu(fits, "SPI.-OBS.-DTI");
374
375 // Throw an exception if one of the mandatory HDUs is missing
376 if (ebds == NULL) {
377 std::string msg = "Extension \"SPI.-EBDS-SET\" not found in "
378 "Observation Group FITS file \""+
379 fits.filename().url()+"\". Please specify a "
380 "valid Observation Group.";
382 }
383 if (pnt == NULL) {
384 std::string msg = "Extension \"SPI.-OBS.-PNT\" not found in "
385 "Observation Group FITS file \""+
386 fits.filename().url()+"\". Please specify a "
387 "valid Observation Group.";
389 }
390 if (gti == NULL) {
391 std::string msg = "Extension \"SPI.-OBS.-GTI\" not found in "
392 "Observation Group FITS file \""+
393 fits.filename().url()+"\". Please specify a "
394 "valid Observation Group.";
396 }
397 if (dsp == NULL) {
398 std::string msg = "Extension \"SPI.-OBS.-DSP\" not found in "
399 "Observation Group FITS file \""+
400 fits.filename().url()+"\". Please specify a "
401 "valid Observation Group.";
403 }
404 if (dti == NULL) {
405 std::string msg = "Extension \"SPI.-OBS.-DTI\" not found in "
406 "Observation Group FITS file \""+
407 fits.filename().url()+"\". Please specify a "
408 "valid Observation Group.";
410 }
411
412 // Determine dataspace dimensions from FITS tables
413 m_num_pt = dsp->integer("PT_NUM");
414 m_num_det = dsp->integer("DET_NUM");
415 m_num_ebin = dsp->integer("EBIN_NUM");
416
417 // Get number of sky and background models
418 m_num_sky = gammalib::spi_num_hdus(fits, "SPI.-SDET-SPE");
419 m_num_bgm = gammalib::spi_num_hdus(fits, "SPI.-BMOD-DSP");
420
421 // Allocate data
422 alloc_data();
423
424 // Read energy boundaries
425 read_ebds(ebds);
426
427 // Read pointing information
428 read_pnt(pnt, gti);
429
430 // Read Good Time Intervals
431 read_gti(gti);
432
433 // Read dead time information
434 read_dti(dti);
435
436 // Read detector spectra
437 read_dsp(dsp);
438
439 // Read models
440 read_models(fits);
441
442 // Free HDU pointers
443 if (ebds != NULL) delete ebds;
444 if (pnt != NULL) delete pnt;
445 if (gti != NULL) delete gti;
446 if (dsp != NULL) delete dsp;
447 if (dti != NULL) delete dti;
448
449 // Prepare event bin
450 init_bin();
451
452 // Return
453 return;
454}
455
456
457/***********************************************************************//**
458 * @brief Write INTEGRAL/SPI event cube into FITS file.
459 *
460 * @param[in] file FITS file.
461 *
462 * Writes the INTEGRAL/SPI event cube into a FITS file.
463 ***************************************************************************/
465{
466 // TODO: Implement writing of event cube FITS file
467
468 // Return
469 return;
470}
471
472
473/***********************************************************************//**
474 * @brief Return number of events in cube
475 *
476 * @return Number of events in event cube.
477 *
478 * This method returns the number of events in the event cube.
479 ***************************************************************************/
480double GSPIEventCube::number(void) const
481{
482 // Initialise result
483 double number = 0.0;
484
485 // Compute sum of all events
486 if (m_dsp_size > 0) {
487 for (int i = 0; i < m_dsp_size; ++i) {
488 number += m_counts[i];
489 }
490 }
491
492 // Return
493 return number;
494}
495
496
497/***********************************************************************//**
498 * @brief Return total ontime
499 *
500 * @return Total ontime.
501 *
502 * Returns the total ontime in the event cube. The total ontime is the sum
503 * of the ontime of all pointings and detectors, divided by the number of
504 * detectors that were active (determine by positive ontime values).
505 ***************************************************************************/
506double GSPIEventCube::ontime(void) const
507{
508 // Initialise result
509 double ontime = 0.0;
510
511 // Loop over all pointings
512 for (int ipt = 0; ipt < m_num_pt; ++ipt) {
513
514 // Initialise mean ontime and number of active detectors for this
515 // pointing
516 double mean_ontime = 0.0;
517 double num_active_det = 0.0;
518
519 // Loop over all detectors
520 for (int idet = 0; idet < m_num_det; ++idet) {
521
522 // Get row index in table
523 int irow = ipt * m_num_det + idet;
524
525 // If detector has positive ontime then count it for the mean
526 // ontime
527 if (m_ontime[irow] > 0.0) {
528 mean_ontime += m_ontime[irow];
529 num_active_det += 1.0;
530 }
531
532 } // endfor: looped over all detectors
533
534 // Compute mean ontime for this pointing
535 if (num_active_det > 0.0) {
536 mean_ontime /= num_active_det;
537 }
538 else {
539 mean_ontime = 0.0;
540 }
541
542 // Add mean ontime to total sum
543 ontime += mean_ontime;
544
545 } // endfor: looped over all pointings
546
547 // Return ontime
548 return ontime;
549}
550
551
552/***********************************************************************//**
553 * @brief Return total livetime
554 *
555 * @return Total livetime.
556 *
557 * Returns the total livetime in the event cube. The total livetime is the
558 * sum of the livetime of all pointings and detectors, divided by the number
559 * of detectors that were active (determine by positive livetime values).
560 ***************************************************************************/
561double GSPIEventCube::livetime(void) const
562{
563 // Initialise result
564 double livetime = 0.0;
565
566 // Loop over all pointings
567 for (int ipt = 0; ipt < m_num_pt; ++ipt) {
568
569 // Initialise mean livetime and number of active detectors for this
570 // pointing
571 double mean_livetime = 0.0;
572 double num_active_det = 0.0;
573
574 // Loop over all detectors
575 for (int idet = 0; idet < m_num_det; ++idet) {
576
577 // Get row index in table
578 int irow = ipt * m_num_det + idet;
579
580 // If detector has positive livetime then count it for the mean
581 // livetime
582 if (m_livetime[irow] > 0.0) {
583 mean_livetime += m_livetime[irow];
584 num_active_det += 1.0;
585 }
586
587 } // endfor: looped over all detectors
588
589 // Compute mean livetime for this pointing
590 if (num_active_det > 0.0) {
591 mean_livetime /= num_active_det;
592 }
593 else {
594 mean_livetime = 0.0;
595 }
596
597 // Add mean livetime to total sum
598 livetime += mean_livetime;
599
600 } // endfor: looped over all pointings
601
602 // Return livetime
603 return livetime;
604}
605
606
607/***********************************************************************//**
608 * @brief Return number of events in model
609 *
610 * @param[in] index Model index.
611 * @return Number of events in event cube.
612 *
613 * @exception GException::out_of_range
614 * Invalid model index
615 *
616 * Returns the total number of counts in model.
617 ***************************************************************************/
618double GSPIEventCube::model_counts(const int& index) const
619{
620 // Initialise result
621 double counts = 0.0;
622
623 // Compute total number of models
624 int num_models = m_num_sky + m_num_bgm;
625
626 // Optionally check if the model index is valid
627 #if defined(G_RANGE_CHECK)
628 if (index < 0 || index >= num_models) {
629 throw GException::out_of_range(G_MODEL_COUNTS, "Invalid model index",
630 index, num_models);
631 }
632 #endif
633
634 // Compute sum of all events in model
635 if (m_dsp_size > 0) {
636 for (int i = 0; i < m_dsp_size; ++i) {
637 counts += m_models[i*num_models + index];
638 }
639 }
640
641 // Return
642 return counts;
643}
644
645
646/***********************************************************************//**
647 * @brief Return pointing identifier
648 *
649 * @param[in] ipt Pointing index.
650 * @return Pointing identifier.
651 *
652 * @exception GException::out_of_range
653 * Invalid pointing index
654 *
655 * Returns the pointing identifier for the specified index.
656 ***************************************************************************/
657const std::string& GSPIEventCube::ptid(const int& ipt) const
658{
659 // Optionally check if the pointing index is valid
660 #if defined(G_RANGE_CHECK)
661 if (ipt < 0 || ipt >= m_num_pt) {
662 throw GException::out_of_range(G_PTID, "Invalid pointing index",
663 ipt, m_num_pt);
664 }
665 #endif
666
667 // Return
668 return (m_ptid[ipt]);
669}
670
671
672/***********************************************************************//**
673 * @brief Return instrument direction
674 *
675 * @param[in] ipt Pointing index.
676 * @param[in] idet Detector index.
677 * @return Instrument direction.
678 *
679 * @exception GException::out_of_range
680 * Invalid pointing or detector index
681 *
682 * Returns the instrument direction for the specified pointing and detector
683 * index.
684 ***************************************************************************/
685const GSPIInstDir& GSPIEventCube::dir(const int& ipt, const int& idet) const
686{
687 // Optionally check if the pointing index is valid
688 #if defined(G_RANGE_CHECK)
689 if (ipt < 0 || ipt >= m_num_pt) {
690 throw GException::out_of_range(G_DIR, "Invalid pointing index",
691 ipt, m_num_pt);
692 }
693 if (idet < 0 || idet >= m_num_det) {
694 throw GException::out_of_range(G_DIR, "Invalid detector index",
695 idet, m_num_det);
696 }
697 #endif
698
699 // Return
700 return (m_dir[ipt*m_num_det+idet]);
701}
702
703
704/***********************************************************************//**
705 * @brief Return SPI X direction (pointing direction)
706 *
707 * @param[in] ipt Pointing index.
708 * @return SPI X direction.
709 *
710 * @exception GException::out_of_range
711 * Invalid pointing index
712 *
713 * Returns the SPI X direction for the specified index. The SPI X direction
714 * is the SPI pointing direction.
715 ***************************************************************************/
716const GSkyDir& GSPIEventCube::spi_x(const int& ipt) const
717{
718 // Optionally check if the pointing index is valid
719 #if defined(G_RANGE_CHECK)
720 if (ipt < 0 || ipt >= m_num_pt) {
721 throw GException::out_of_range(G_SPI_X, "Invalid pointing index",
722 ipt, m_num_pt);
723 }
724 #endif
725
726 // Return
727 return (m_spix[ipt]);
728}
729
730
731/***********************************************************************//**
732 * @brief Return SPI Z direction
733 *
734 * @param[in] ipt Pointing index.
735 * @return SPI Z direction.
736 *
737 * @exception GException::out_of_range
738 * Invalid pointing index
739 *
740 * Returns the SPI Z direction for the specified index.
741 ***************************************************************************/
742const GSkyDir& GSPIEventCube::spi_z(const int& ipt) const
743{
744 // Optionally check if the pointing index is valid
745 #if defined(G_RANGE_CHECK)
746 if (ipt < 0 || ipt >= m_num_pt) {
747 throw GException::out_of_range(G_SPI_Z, "Invalid pointing index",
748 ipt, m_num_pt);
749 }
750 #endif
751
752 // Return
753 return (m_spiz[ipt]);
754}
755
756
757/***********************************************************************//**
758 * @brief Return size of event bin
759 *
760 * @param[in] ievent Event index.
761 * @return Size of event bin.
762 *
763 * @exception GException::out_of_range
764 * Invalid pointing index
765 *
766 * Returns bin size for event with @p index.
767 ***************************************************************************/
768const double& GSPIEventCube::event_size(const int& ievent) const
769{
770 // Optionally check if the index is valid
771 #if defined(G_RANGE_CHECK)
772 if (ievent < 0 || ievent >= size()) {
773 throw GException::out_of_range(G_EVENT_SIZE, "Event index", ievent, size());
774 }
775 #endif
776
777 // Return
778 return (m_size[ievent]);
779}
780
781
782/***********************************************************************//**
783 * @brief Return value of model for event bin
784 *
785 * @param[in] ievent Event index.
786 * @param[in] imodel Model index.
787 * @return Model value.
788 *
789 * @exception GException::out_of_range
790 * Invalid pointing index
791 *
792 * Returns value of model @p imodel for event with @p index.
793 ***************************************************************************/
794const double& GSPIEventCube::event_model(const int& ievent, const int& imodel) const
795{
796 // Compute number of models
797 int nmodels = m_num_sky + m_num_bgm;
798
799 // Optionally check if the index is valid
800 #if defined(G_RANGE_CHECK)
801 if (ievent < 0 || ievent >= size()) {
802 throw GException::out_of_range(G_EVENT_MODEL, "Event index", ievent, size());
803 }
804 #endif
805 #if defined(G_RANGE_CHECK)
806 if (imodel < 0 || imodel >= nmodels) {
807 throw GException::out_of_range(G_EVENT_MODEL, "Model index", imodel, size());
808 }
809 #endif
810
811 // Return
812 return (m_models[imodel+ievent*nmodels]);
813}
814
815
816/***********************************************************************//**
817 * @brief Print INTEGRAL/SPI event cube information
818 *
819 * @param[in] chatter Chattiness.
820 * @return String containing INTEGRAL/SPI event cube information.
821 ***************************************************************************/
822std::string GSPIEventCube::print(const GChatter& chatter) const
823{
824 // Initialise result string
825 std::string result;
826
827 // Continue only if chatter is not silent
828 if (chatter != SILENT) {
829
830 // Append header
831 result.append("=== GSPIEventCube ===");
832
833 // Append information
834 result.append("\n"+gammalib::parformat("Number of events"));
835 result.append(gammalib::str(number()));
836 result.append("\n"+gammalib::parformat("Number of elements"));
837 result.append(gammalib::str(size()));
838 result.append("\n"+gammalib::parformat("Pointings"));
839 result.append(gammalib::str(m_num_pt));
840 result.append("\n"+gammalib::parformat("Detectors"));
841 result.append(gammalib::str(m_num_det));
842 result.append("\n"+gammalib::parformat("Energy bins"));
843 result.append(gammalib::str(m_num_ebin));
844 result.append("\n"+gammalib::parformat("Sky models"));
845 result.append(gammalib::str(m_num_sky));
846 for (int i = 0; i < m_num_sky; ++i) {
847 result.append("\n"+gammalib::parformat(" Model name "+gammalib::str(i+1)));
848 result.append(m_modnames[i]);
849 result.append("\n"+gammalib::parformat(" Number of events"));
850 result.append(gammalib::str(model_counts(i)));
851 }
852 result.append("\n"+gammalib::parformat("Background models"));
853 result.append(gammalib::str(m_num_bgm));
854 for (int i = 0; i < m_num_bgm; ++i) {
855 result.append("\n"+gammalib::parformat(" Model name "+gammalib::str(i+1)));
856 result.append(m_modnames[i+m_num_sky]);
857 result.append("\n"+gammalib::parformat(" Number of events"));
858 result.append(gammalib::str(model_counts(i+m_num_sky)));
859 }
860 result.append("\n"+gammalib::parformat("Energy range"));
861 result.append(gammalib::str(emin().MeV())+" - ");
862 result.append(gammalib::str(emax().MeV())+" MeV");
863 result.append("\n"+gammalib::parformat("Ontime"));
864 result.append(gammalib::str(ontime())+" s");
865 result.append("\n"+gammalib::parformat("Livetime"));
866 result.append(gammalib::str(livetime())+" s");
867 result.append("\n"+gammalib::parformat("Time interval"));
868 result.append(tstart().utc()+" - ");
869 result.append(tstop().utc());
870
871 } // endif: chatter was not silent
872
873 // Return result
874 return result;
875}
876
877
878/*==========================================================================
879 = =
880 = Private methods =
881 = =
882 ==========================================================================*/
883
884/***********************************************************************//**
885 * @brief Initialise class members
886 ***************************************************************************/
888{
889 // Initialise members
890 m_bin.clear();
891 m_num_pt = 0;
892 m_num_det = 0;
893 m_num_ebin = 0;
894 m_num_sky = 0;
895 m_num_bgm = 0;
896 m_gti_size = 0;
897 m_dsp_size = 0;
898 m_model_size = 0;
899 m_detid = NULL;
900 m_ontime = NULL;
901 m_livetime = NULL;
902 m_counts = NULL;
903 m_stat_err = NULL;
904 m_models = NULL;
905 m_size = NULL;
906 m_dir = NULL;
907 m_time = NULL;
908 m_energy = NULL;
909 m_ewidth = NULL;
910 m_spix = NULL;
911 m_spiz = NULL;
912 m_ptid = NULL;
913
914 // Prepare event bin
915 init_bin();
916
917 // Return
918 return;
919}
920
921
922/***********************************************************************//**
923 * @brief Copy class members
924 *
925 * @param[in] cube INTEGRAL/SPI event cube.
926 *
927 * This method copies the class members from another event cube in the actual
928 * object. It also prepares the event bin member that will be returned in
929 * case of an operator access to the class.
930 ***************************************************************************/
932{
933 // Copy members. Note that the event bin is not copied as it will
934 // be initialised later. The event bin serves just as a container of
935 // pointers, hence we do not want to copy over the pointers from the
936 // original class.
937 m_num_pt = cube.m_num_pt;
938 m_num_det = cube.m_num_det;
939 m_num_ebin = cube.m_num_ebin;
940 m_num_sky = cube.m_num_sky;
941 m_num_bgm = cube.m_num_bgm;
942 m_gti_size = cube.m_gti_size;
943 m_dsp_size = cube.m_dsp_size;
945 m_modnames = cube.m_modnames;
946
947 // Copy data
948 if (m_num_ebin > 0) {
951 for (int i = 0; i < m_num_ebin; ++i) {
952 m_energy[i] = cube.m_energy[i];
953 m_ewidth[i] = cube.m_ewidth[i];
954 }
955 }
956 if (m_num_pt > 0) {
957 m_ptid = new std::string[m_num_pt];
958 m_spix = new GSkyDir[m_num_pt];
959 m_spiz = new GSkyDir[m_num_pt];
960 for (int i = 0; i < m_num_pt; ++i) {
961 m_ptid[i] = cube.m_ptid[i];
962 m_spix[i] = cube.m_spix[i];
963 m_spiz[i] = cube.m_spiz[i];
964 }
965 }
966 if (m_num_det > 0) {
967 m_detid = new int[m_num_det];
968 for (int i = 0; i < m_num_det; ++i) {
969 m_detid[i] = cube.m_detid[i];
970 }
971 }
972 if (m_gti_size > 0) {
973 m_ontime = new double[m_gti_size];
974 m_livetime = new double[m_gti_size];
975 m_time = new GTime[m_gti_size];
977 for (int i = 0; i < m_gti_size; ++i) {
978 m_ontime[i] = cube.m_ontime[i];
979 m_livetime[i] = cube.m_livetime[i];
980 m_time[i] = cube.m_time[i];
981 m_dir[i] = cube.m_dir[i];
982 }
983 }
984 if (m_dsp_size > 0) {
985 m_counts = new double[m_dsp_size];
986 m_stat_err = new double[m_dsp_size];
987 m_size = new double[m_dsp_size];
988 for (int i = 0; i < m_dsp_size; ++i) {
989 m_counts[i] = cube.m_counts[i];
990 m_stat_err[i] = cube.m_stat_err[i];
991 m_size[i] = cube.m_size[i];
992 }
993 }
994 if (m_model_size > 0) {
995 m_models = new double[m_model_size];
996 for (int i = 0; i < m_model_size; ++i) {
997 m_models[i] = cube.m_models[i];
998 }
999 }
1000
1001 // Prepare event bin
1002 init_bin();
1003
1004 // Return
1005 return;
1006}
1007
1008
1009/***********************************************************************//**
1010 * @brief Delete class members
1011 ***************************************************************************/
1013{
1014 // Delete memory
1015 if (m_detid != NULL) delete [] m_detid;
1016 if (m_ontime != NULL) delete [] m_ontime;
1017 if (m_livetime != NULL) delete [] m_livetime;
1018 if (m_counts != NULL) delete [] m_counts;
1019 if (m_stat_err != NULL) delete [] m_stat_err;
1020 if (m_models != NULL) delete [] m_models;
1021 if (m_size != NULL) delete [] m_size;
1022 if (m_dir != NULL) delete [] m_dir;
1023 if (m_time != NULL) delete [] m_time;
1024 if (m_energy != NULL) delete [] m_energy;
1025 if (m_ewidth != NULL) delete [] m_ewidth;
1026 if (m_spix != NULL) delete [] m_spix;
1027 if (m_spiz != NULL) delete [] m_spiz;
1028 if (m_ptid != NULL) delete [] m_ptid;
1029
1030 // Set pointers to free
1031 m_detid = NULL;
1032 m_ontime = NULL;
1033 m_livetime = NULL;
1034 m_counts = NULL;
1035 m_stat_err = NULL;
1036 m_models = NULL;
1037 m_size = NULL;
1038 m_dir = NULL;
1039 m_time = NULL;
1040 m_energy = NULL;
1041 m_ewidth = NULL;
1042 m_spix = NULL;
1043 m_spiz = NULL;
1044 m_ptid = NULL;
1045
1046 // Return
1047 return;
1048}
1049
1050
1051/***********************************************************************//**
1052 * @brief Allocate data
1053 ***************************************************************************/
1055{
1056 // Make sure that data is free
1057 free_members();
1058
1059 // Compute array sizes
1063
1064 // Allocate and initialise EBDS data
1065 if (m_num_ebin > 0) {
1068 for (int i = 0; i < m_num_ebin; ++i) {
1069 m_energy[i].clear();
1070 m_ewidth[i].clear();
1071 }
1072 }
1073
1074 // Allocate and initialise pointing data
1075 if (m_num_pt > 0) {
1076 m_ptid = new std::string[m_num_pt];
1077 m_spix = new GSkyDir[m_num_pt];
1078 m_spiz = new GSkyDir[m_num_pt];
1079 for (int i = 0; i < m_num_pt; ++i) {
1080 m_ptid[i].clear();
1081 m_spix[i].clear();
1082 m_spiz[i].clear();
1083 }
1084 }
1085
1086 // Allocate and initialise detector data
1087 if (m_num_det > 0) {
1088 m_detid = new int[m_num_det];
1089 for (int i = 0; i < m_num_det; ++i) {
1090 m_detid[i] = 0;
1091 }
1092 }
1093
1094 // Allocate and initialise GTI data
1095 if (m_gti_size > 0) {
1096 m_ontime = new double[m_gti_size];
1097 m_livetime = new double[m_gti_size];
1098 m_time = new GTime[m_gti_size];
1100 for (int i = 0; i < m_gti_size; ++i) {
1101 m_ontime[i] = 0.0;
1102 m_livetime[i] = 0.0;
1103 m_time[i].clear();
1104 m_dir[i].clear();
1105 }
1106 }
1107
1108 // Allocate and initialise DSP data
1109 if (m_dsp_size > 0) {
1110 m_counts = new double[m_dsp_size];
1111 m_stat_err = new double[m_dsp_size];
1112 m_size = new double[m_dsp_size];
1113 for (int i = 0; i < m_dsp_size; ++i) {
1114 m_counts[i] = 0.0;
1115 m_stat_err[i] = 0.0;
1116 m_size[i] = 0.0;
1117 }
1118 }
1119
1120 // Allocate and initialise model data
1121 if (m_model_size > 0) {
1122 m_models = new double[m_model_size];
1123 for (int i = 0; i < m_model_size; ++i) {
1124 m_models[i] = 0.0;
1125 }
1126 }
1127
1128 // Return
1129 return;
1130}
1131
1132
1133/***********************************************************************//**
1134 * @brief Read data from INTEGRAL/SPI "SPI.-EBDS-SET" extension
1135 *
1136 * @param[in] ebds Pointer to energy boundaries FITS table.
1137 *
1138 * @exception GException::invalid_value
1139 * Incompatible number of energy bins encountered
1140 *
1141 * Reads data from an INTEGRAL/SPI "SPI.-EBDS-SET" extension. The method
1142 * sets up the m_energy array and the m_ebounds member.
1143 ***************************************************************************/
1145{
1146 // Continue only if energy boundary FITS table pointer is valid
1147 if (ebds != NULL) {
1148
1149 // Read energy boundaries
1150 m_ebounds.read(*ebds);
1151
1152 // Throw an exception if the number of energy boundaries is not
1153 // consistent with DSP keyword
1154 if (m_ebounds.size() != m_num_ebin) {
1155 std::string msg = "Number of energy bins "+
1156 gammalib::str(m_ebounds.size())+" found in "
1157 "\"SPI.-EBDS-SET\" extension differes from value "+
1158 gammalib::str(m_num_det)+" of \"DET_NUM\" keyword "
1159 "in \"SPI.-OBS.-DSP\" extension. Please specify a "
1160 "valid Observation Group.";
1162 }
1163
1164 // Loop over all energy bins
1165 for (int iebin = 0; iebin < m_num_ebin; ++iebin) {
1166
1167 // Store linear mean energy and bin width
1168 m_energy[iebin] = m_ebounds.emean(iebin);
1169 m_ewidth[iebin] = m_ebounds.ewidth(iebin);
1170
1171 } // endfor: looped over all energy bins
1172
1173 } // endif: energy boundary FITS table pointer was valid
1174
1175 // Return
1176 return;
1177}
1178
1179
1180/***********************************************************************//**
1181 * @brief Read pointing information
1182 *
1183 * @param[in] pnt Pointer to pointing FITS table.
1184 * @param[in] gti Pointer to GTI FITS table.
1185 *
1186 * @exception GException::invalid_value
1187 * Incompatible PTID_SPI pointing identifiers encountered
1188 *
1189 * Reads pointing information from "SPI.-OBS.-PNT" and "SPI.-OBS.-GTI"
1190 * extensions. The method sets up the m_dir array.
1191 ***************************************************************************/
1193{
1194 // Continue only if FITS table pointers are valid
1195 if (pnt != NULL && gti != NULL) {
1196
1197 // Get relevant columns
1198 const GFitsTableCol* pnt_ptid = (*pnt)["PTID_SPI"];
1199 const GFitsTableCol* ra_spix = (*pnt)["RA_SPIX"];
1200 const GFitsTableCol* dec_spix = (*pnt)["DEC_SPIX"];
1201 const GFitsTableCol* ra_spiz = (*pnt)["RA_SPIZ"];
1202 const GFitsTableCol* dec_spiz = (*pnt)["DEC_SPIZ"];
1203 const GFitsTableCol* gti_ptid = (*gti)["PTID_SPI"];
1204 const GFitsTableCol* det_id = (*gti)["DET_ID"];
1205
1206 // Loop over all pointings
1207 for (int ipt = 0; ipt < m_num_pt; ++ipt) {
1208
1209 // Store pointing identifier
1210 m_ptid[ipt] = pnt_ptid->string(ipt);
1211
1212 // Store SPI X and Z directions
1213 m_spix[ipt].radec_deg(ra_spix->real(ipt), dec_spix->real(ipt));
1214 m_spiz[ipt].radec_deg(ra_spiz->real(ipt), dec_spiz->real(ipt));
1215
1216 // Set pointing direction
1217 GSkyDir pnt_dir;
1218 pnt_dir.radec_deg(ra_spix->real(ipt), dec_spix->real(ipt));
1219
1220 // Loop over all detectors
1221 for (int idet = 0; idet < m_num_det; ++idet) {
1222
1223 // Get row index in table
1224 int irow = ipt * m_num_det + idet;
1225
1226 // Throw an exception if the pointing identifier in the pointing
1227 // and the GTI extension is not the same
1228 if (pnt_ptid->string(ipt) != gti_ptid->string(irow)) {
1229 std::string msg = "PITD_SPI \""+pnt_ptid->string(ipt)+"\" in "
1230 "\"SPI.-OBS.-PNT\" differs from \""+
1231 gti_ptid->string(irow)+"\" in "
1232 "\"SPI.-OBS.-GTI\" extension for detector "+
1233 gammalib::str(det_id->integer(irow))+". Please "
1234 "specify a valid Observation Group.";
1236 }
1237
1238 // Store pointing direction and detector identifier
1239 m_dir[irow].dir(pnt_dir);
1240 m_dir[irow].detid(det_id->integer(irow));
1241
1242 // If this is the first pointing then store detector identifier
1243 if (ipt == 0) {
1244 m_detid[idet] = det_id->integer(irow);
1245 }
1246
1247 // ... otherwise throw an exception if the detector identifier
1248 // is not the expected one
1249 else {
1250 if (m_detid[idet] != det_id->integer(irow)) {
1251 std::string msg = "DET_ID "+gammalib::str(det_id->integer(irow))+
1252 " for pointing \""+pnt_ptid->string(ipt)+
1253 "\" differs from DET_ID "+gammalib::str(m_detid[idet])+
1254 " for pointing \""+pnt_ptid->string(0)+
1255 "\". Please specify a valid Observation Group.";
1257 }
1258 }
1259
1260 } // endfor: looped over all detectors
1261
1262 } // endfor: looped over all pointings
1263
1264 } // endif: FITS table pointers were valid
1265
1266 // Return
1267 return;
1268}
1269
1270
1271/***********************************************************************//**
1272 * @brief Read data from INTEGRAL/SPI "SPI.-OBS.-GTI" extension
1273 *
1274 * @param[in] gti Pointer to GTI FITS table.
1275 *
1276 * Reads data from an INTEGRAL/SPI "SPI.-OBS.-GTI" extension. The method
1277 * sets up the m_ontime array and the m_gti member.
1278 ***************************************************************************/
1280{
1281 // Continue only if FITS table pointer is valid
1282 if (gti != NULL) {
1283
1284 // Get relevant columns
1285 const GFitsTableCol* ontime = (*gti)["ONTIME"];
1286 const GFitsTableCol* tstart = (*gti)["TSTART"];
1287 const GFitsTableCol* tstop = (*gti)["TSTOP"];
1288
1289 // Allocate start and stop times
1290 int max_times = m_num_pt * m_num_det;
1291 GTimes t_starts;
1292 GTimes t_stops;
1293 t_starts.reserve(max_times);
1294 t_stops.reserve(max_times);
1295
1296 // Loop over all pointings
1297 for (int ipt = 0; ipt < m_num_pt; ++ipt) {
1298
1299 // Initialise minimum TSTART and maximum TSTOP for GTI (they should
1300 // all be identical and are anyways not used, but we want to have a
1301 // reasonable GTI object
1302 double t_start = 0.0;
1303 double t_stop = 0.0;
1304
1305 // Loop over all detectors
1306 for (int idet = 0; idet < m_num_det; ++idet) {
1307
1308 // Get row index in table
1309 int irow = ipt * m_num_det + idet;
1310
1311 // Store ontime
1312 m_ontime[irow] = ontime->real(irow);
1313
1314 // Compute and store mean time
1315 double ijd = 0.5 * (tstart->real(irow) + tstop->real(irow));
1316 m_time[irow] = gammalib::spi_ijd2time(ijd);
1317
1318 // Update TSTART and TSTOP (only if ontime is > 0.0 since TSTART
1319 // and TSTOP may be zero for zero ontime)
1320 if (ontime->real(irow) > 0.0) {
1321 if (t_start == 0.0 || (tstart->real(irow) < t_start)) {
1322 t_start = tstart->real(irow);
1323 }
1324 if (t_stop == 0.0 || (tstop->real(irow) > t_stop)) {
1325 t_stop = tstop->real(irow);
1326 }
1327 }
1328
1329 } // endfor: looped over all detectors
1330
1331 // Append start and stop times (only if TSTART and TSTOP are not zero)
1332 if (t_start != 0.0 && t_stop != 0.0) {
1333 t_starts.append(gammalib::spi_ijd2time(t_start));
1334 t_stops.append(gammalib::spi_ijd2time(t_stop));
1335 }
1336
1337 } // endfor: looped over all pointings
1338
1339 // Append start and stop times to GTI
1340 m_gti.append(t_starts, t_stops);
1341
1342 } // endif: FITS table pointer was valid
1343
1344 // Return
1345 return;
1346}
1347
1348
1349/***********************************************************************//**
1350 * @brief Read data from INTEGRAL/SPI "SPI.-OBS.-DTI" extension
1351 *
1352 * @param[in] dti Pointer to Dead time information FITS table.
1353 *
1354 * Reads data from an INTEGRAL/SPI "SPI.-OBS.-DTI" extension. The method
1355 * sets up the m_ontime array and the m_gti member.
1356 ***************************************************************************/
1358{
1359 // Continue only if FITS table pointer is valid
1360 if (dti != NULL) {
1361
1362 // Get relevant columns
1363 const GFitsTableCol* livetime = (*dti)["LIVETIME"];
1364
1365 // Loop over all pointings
1366 for (int ipt = 0; ipt < m_num_pt; ++ipt) {
1367
1368 // Loop over all detectors
1369 for (int idet = 0; idet < m_num_det; ++idet) {
1370
1371 // Get row index in table
1372 int irow = ipt * m_num_det + idet;
1373
1374 // Store livetime
1375 m_livetime[irow] = livetime->real(irow);
1376
1377 } // endfor: looped over all detectors
1378
1379 } // endfor: looped over all pointings
1380
1381 } // endif: FITS table pointer was valid
1382
1383 // Return
1384 return;
1385}
1386
1387
1388/***********************************************************************//**
1389 * @brief Read data from INTEGRAL/SPI "SPI.-OBS.-DSP" extension
1390 *
1391 * @param[in] dsp DSP FITS table.
1392 *
1393 * Reads data from an INTEGRAL/SPI "SPI.-OBS.-DSP" extension. The method
1394 * sets up the m_counts, m_stat_err and m_size arrays.
1395 *
1396 * Note that the computation of the m_size arrays needs ontime and energy
1397 * width information that has been previously setup in the read_ebds() and
1398 * read_gti() methods.
1399 ***************************************************************************/
1401{
1402 // Continue only if FITS table pointer is valid
1403 if (dsp != NULL) {
1404
1405 // Get relevant columns
1406 const GFitsTableCol* counts = (*dsp)["COUNTS"];
1407 const GFitsTableCol* stat_err = (*dsp)["STAT_ERR"];
1408
1409 // Loop over all pointings
1410 for (int ipt = 0; ipt < m_num_pt; ++ipt) {
1411
1412 // Loop over all detectors
1413 for (int idet = 0; idet < m_num_det; ++idet) {
1414
1415 // Get row index in table
1416 int irow = ipt * m_num_det + idet;
1417
1418 // Set start index in destination arrays
1419 int index = irow * m_num_ebin;
1420
1421 // Copy energy bins
1422 for (int iebin = 0; iebin < m_num_ebin; ++iebin, ++index) {
1423 m_counts[index] = counts->real(irow, iebin);
1424 m_stat_err[index] = stat_err->real(irow, iebin);
1425 m_size[index] = m_livetime[irow] * m_ewidth[iebin].MeV();
1426 }
1427
1428 } // endfor: looped over all detectors
1429
1430 } // endfor: looped over all pointings
1431
1432 } // endif: FITS table pointer was valid
1433
1434 // Return
1435 return;
1436}
1437
1438
1439/***********************************************************************//**
1440 * @brief Read models from INTEGRAL/SPI Observation Group
1441 *
1442 * @param[in] fits Observation Group FITS file.
1443 ***************************************************************************/
1445{
1446 // Clear model names
1447 m_modnames.clear();
1448
1449 // Initialise model index
1450 int imodel = 0;
1451
1452 // Compute total number of models
1453 int num_models = m_num_sky + m_num_bgm;
1454
1455 // Loop over all sky models
1456 for (int i = 0; i < m_num_sky; ++i, ++imodel) {
1457
1458 // Get FITS table
1459 const GFitsTable* model = gammalib::spi_hdu(fits, "SPI.-SDET-SPE", i+1);
1460
1461 // Throw an exception if the FITS table is missing
1462 if (model == NULL) {
1463 std::string msg = "Extension \"SPI.-SDET-SPE\" version "+
1464 gammalib::str(i+1)+" not found in Observation "
1465 "Group FITS file \""+fits.filename().url()+
1466 "\". Please specify a valid Observation Group.";
1468 }
1469
1470 // Get model name
1471 std::string name = "MODEL" + gammalib::str(imodel+1);
1472 if (model->has_card("SOURCEID")) {
1473 name = model->string("SOURCEID");
1474 }
1475 m_modnames.push_back(name);
1476
1477 // Get relevant columns
1478 const GFitsTableCol* counts = (*model)["COUNTS"];
1479
1480 // Loop over all pointings
1481 for (int ipt = 0; ipt < m_num_pt; ++ipt) {
1482
1483 // Loop over all detectors
1484 for (int idet = 0; idet < m_num_det; ++idet) {
1485
1486 // Get row index in model table
1487 int irow = ipt * m_num_det + idet;
1488
1489 // Set start index in destination array
1490 int index = irow * m_num_ebin;
1491
1492 // Copy energy bins
1493 for (int iebin = 0; iebin < m_num_ebin; ++iebin, ++index) {
1494 m_models[index*num_models + imodel] = counts->real(irow, iebin);
1495 }
1496
1497 } // endfor: looped over all detectors
1498
1499 } // endfor: looped over all pointings
1500
1501 } // endfor: looped over all sky models
1502
1503 // Loop over all background models
1504 for (int i = 0; i < m_num_bgm; ++i, ++imodel) {
1505
1506 // Get FITS table
1507 const GFitsTable* model = gammalib::spi_hdu(fits, "SPI.-BMOD-DSP", i+1);
1508
1509 // Throw an exception if the FITS table is missing
1510 if (model == NULL) {
1511 std::string msg = "Extension \"SPI.-BMOD-DSP\" version "+
1512 gammalib::str(i+1)+" not found in Observation "
1513 "Group FITS file \""+fits.filename().url()+
1514 "\". Please specify a valid Observation Group.";
1516 }
1517
1518 // Get model name
1519 std::string name = "MODEL" + gammalib::str(imodel+1);
1520 if (model->has_card("BKGNAME")) {
1521 name = model->string("BKGNAME");
1522 }
1523 m_modnames.push_back(name);
1524
1525 // Get relevant columns
1526 const GFitsTableCol* counts = (*model)["COUNTS"];
1527
1528 // Loop over all pointings
1529 for (int ipt = 0; ipt < m_num_pt; ++ipt) {
1530
1531 // Loop over all detectors
1532 for (int idet = 0; idet < m_num_det; ++idet) {
1533
1534 // Get row index in model table
1535 int irow = ipt * m_num_det + idet;
1536
1537 // Set start index in destination array
1538 int index = irow * m_num_ebin;
1539
1540 // Copy energy bins
1541 for (int iebin = 0; iebin < m_num_ebin; ++iebin, ++index) {
1542 m_models[index*num_models + imodel] = counts->real(irow, iebin);
1543 }
1544
1545 } // endfor: looped over all detectors
1546
1547 } // endfor: looped over all pointings
1548
1549 } // endfor: looped over all background models
1550
1551 // Return
1552 return;
1553}
1554
1555
1556/***********************************************************************//**
1557 * @brief Initialise event bin
1558 *
1559 * Initialises the event bin. All fixed content is set here, the content
1560 * that depends on the bin index is set by the set_bin() method which is
1561 * called before any event bin access.
1562 ***************************************************************************/
1564{
1565 // Prepare event bin
1567 m_bin.m_index = 0; //!< Set by set_bin method
1568 m_bin.m_ipt = 0; //!< Set by set_bin method
1569 m_bin.m_idir = 0; //!< Set by set_bin method
1570 m_bin.m_iebin = 0; //!< Set by set_bin method
1572 m_bin.m_dir = NULL; //!< Set by set_bin method
1573 m_bin.m_time = NULL; //!< Set by set_bin method
1574 m_bin.m_energy = NULL; //!< Set by set_bin method
1575 m_bin.m_counts = NULL; //!< Set by set_bin method
1576 m_bin.m_ontime = NULL; //!< Set by set_bin method
1577 m_bin.m_livetime = NULL; //!< Set by set_bin method
1578 m_bin.m_size = NULL; //!< Set by set_bin method
1579 m_bin.m_models = NULL; //!< Set by set_bin method
1580
1581 // Return
1582 return;
1583}
1584
1585
1586/***********************************************************************//**
1587 * @brief Set event bin
1588 *
1589 * @param[in] index Event index [0,...,size()[.
1590 *
1591 * @exception GException::out_of_range
1592 * Event index is outside valid range.
1593 *
1594 * Sets the pointers of the event bin to the event cube cell that corresponds
1595 * to the specified @p index.
1596 *
1597 * The event bin is in fact physically stored in the event cube, and only a
1598 * single event bin is indeed allocated. This method sets up the pointers in
1599 * the event bin so that a client can easily access the information of
1600 * individual bins as if they were stored in an array.
1601 ***************************************************************************/
1602void GSPIEventCube::set_bin(const int& index)
1603{
1604 // Optionally check if the index is valid
1605 #if defined(G_RANGE_CHECK)
1606 if (index < 0 || index >= size()) {
1607 throw GException::out_of_range(G_SET_BIN, "Event index", index, size());
1608 }
1609 #endif
1610
1611 // Set indices
1612 m_bin.m_index = index;
1613 m_bin.m_idir = index / m_num_ebin;
1615 m_bin.m_iebin = index % m_num_ebin;
1616
1617 // Set GSPIEventBin pointers
1626
1627 // Return
1628 return;
1629}
#define G_SET_BIN
#define G_NAXIS
#define G_DIR
Energy value class definition.
#define G_READ_FITS
#define G_READ_MODELS
#define G_MODEL_COUNTS
#define G_READ_EBDS
#define G_SPI_Z
#define G_PTID
#define G_EVENT_MODEL
#define G_SPI_X
#define G_EVENT_SIZE
#define G_READ_PNT
INTEGRAL/SPI event bin container class definition.
INTEGRAL/SPI instrument direction class definition.
Definition of INTEGRAL/SPI tools.
Sky direction class interface definition.
Time class interface definition.
GChatter
Definition GTypemaps.hpp:33
@ SILENT
Definition GTypemaps.hpp:34
GEnergy ewidth(const int &index) const
Returns energy interval width.
void read(const GFitsTable &table)
Read energy boundaries from FITS table.
Definition GEbounds.cpp:761
GEnergy emean(const int &index) const
Returns mean energy for a given energy interval.
int size(void) const
Return number of energy boundaries.
Definition GEbounds.hpp:163
Class that handles energies in a unit independent way.
Definition GEnergy.hpp:48
double MeV(void) const
Return energy in MeV.
Definition GEnergy.cpp:342
void clear(void)
Clear instance.
Definition GEnergy.cpp:267
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 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
std::string url(void) const
Return Uniform Resource Locator (URL)
bool has_card(const int &cardno) const
Check existence of header card.
Definition GFitsHDU.hpp:233
std::string string(const std::string &keyname) const
Return card value as string.
Definition GFitsHDU.hpp:410
int integer(const std::string &keyname) const
Return card value as integer.
Definition GFitsHDU.hpp:436
Abstract interface for FITS table column.
virtual int integer(const int &row, const int &inx=0) const =0
virtual double real(const int &row, const int &inx=0) const =0
virtual std::string string(const int &row, const int &inx=0) const =0
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
void close(void)
Close FITS file.
Definition GFits.cpp:1342
const GFilename & filename(void) const
Return FITS filename.
Definition GFits.hpp:313
void append(const GTime &tstart, const GTime &tstop)
Append Good Time Interval.
Definition GGti.cpp:270
INTEGRAL/SPI event bin class.
virtual void clear(void)
Clear INTEGRAL/SPI event bin.
int m_index
Dataspace index.
GSPIInstDir * m_dir
Pointer to direction of bin.
GTime * m_time
Pointer to time of bin.
GEnergy * m_energy
Pointer to energy of bin.
double * m_counts
Pointer to number of counts.
int m_num_models
Number of models in bin.
int m_iebin
Energy bin index.
void free_members(void)
Delete class members.
double * m_ontime
Pointer to ontime of bin.
int m_idir
Direction index.
double * m_livetime
Pointer to livetime of bin.
double * m_size
Pointer to size of bin.
int m_ipt
Pointing index.
double * m_models
Pointer to models of bin.
INTEGRAL/SPI event bin container class.
void copy_members(const GSPIEventCube &cube)
Copy class members.
virtual void clear(void)
Clear INTEGRAL/SPI event cube.
void init_members(void)
Initialise class members.
void read_pnt(const GFitsTable *pnt, const GFitsTable *gti)
Read pointing information.
GSkyDir * m_spiz
SPI Z axis array.
GSkyDir * m_spix
SPI X axis array.
int m_model_size
Size of model arrays.
const GSPIInstDir & dir(const int &ipt, const int &idet) const
Return instrument direction.
const double & event_model(const int &ievent, const int &imodel) const
Return value of model for event bin.
const GSkyDir & spi_z(const int &ipt) const
Return SPI Z direction.
const double & event_size(const int &ievent) const
Return size of event bin.
double * m_livetime
Livetime array.
virtual double number(void) const
Return number of events in cube.
GSPIEventBin m_bin
Actual event bin.
void read_models(const GFits &file)
Read models from INTEGRAL/SPI Observation Group.
GTime * m_time
Time array.
virtual ~GSPIEventCube(void)
Destructor.
void read_dti(const GFitsTable *dti)
Read data from INTEGRAL/SPI "SPI.-OBS.-DTI" extension.
virtual int dim(void) const
Return event cube dimension.
void read_dsp(const GFitsTable *dsp)
Read data from INTEGRAL/SPI "SPI.-OBS.-DSP" extension.
virtual void save(const GFilename &filename, const bool &clobber=false) const
Save INTEGRAL/SPI event cube into FITS file.
virtual int naxis(const int &axis) const
Return number of bins in axis.
void free_members(void)
Delete class members.
double livetime(void) const
Return total livetime.
virtual int size(void) const
Return event cube size.
void init_bin(void)
Initialise event bin.
GEnergy * m_energy
Energy array.
int m_num_pt
Number of pointings.
std::vector< std::string > m_modnames
Model names.
const std::string & ptid(const int &ipt) const
Return pointing identifier.
void set_bin(const int &index)
Set event bin.
virtual GSPIEventCube & operator=(const GSPIEventCube &cube)
Assignment operator.
double ontime(void) const
Return total ontime.
virtual void load(const GFilename &filename)
Load INTEGRAL/SPI event cube from Observation Group.
virtual void write(GFits &file) const
Write INTEGRAL/SPI event cube into FITS file.
double * m_size
Event bin size array.
GSPIInstDir * m_dir
Event direction array.
void read_gti(const GFitsTable *gti)
Read data from INTEGRAL/SPI "SPI.-OBS.-GTI" extension.
void alloc_data(void)
Allocate data.
int m_gti_size
Size of GTI arrays.
int m_num_sky
Number of sky models.
int * m_detid
Detector ID of event cube ADD!!!!
int m_num_ebin
Number of energy bins.
virtual GSPIEventBin * operator[](const int &index)
Event bin access operator.
virtual std::string print(const GChatter &chatter=NORMAL) const
Print INTEGRAL/SPI event cube information.
int m_num_det
Number of detectors.
int m_num_bgm
Number of background models.
double * m_counts
Counts array.
double * m_stat_err
Statistical error array.
double * m_ontime
Ontime array.
std::string * m_ptid
Pointing identifiers.
GSPIEventCube(void)
Void constructor.
virtual GSPIEventCube * clone(void) const
Clone event cube.
int m_dsp_size
Size of DSP arrays.
virtual void read(const GFits &file)
Read INTEGRAL/SPI event cube from Observation Group FITS file.
GEnergy * m_ewidth
Energy bin width array.
double * m_models
Models array.
double model_counts(const int &index) const
Return number of events in model.
const GSkyDir & spi_x(const int &ipt) const
Return SPI X direction (pointing direction)
void read_ebds(const GFitsTable *ebds)
Read data from INTEGRAL/SPI "SPI.-EBDS-SET" extension.
INTEGRAL/SPI instrument direction class.
virtual void clear(void)
Clear INTEGRAL/SPI instrument direction.
void dir(const GSkyDir &dir)
Set pointing direction.
void detid(const int &detid)
Set detector identifier.
Sky direction class.
Definition GSkyDir.hpp:62
void radec_deg(const double &ra, const double &dec)
Set equatorial sky direction (degrees)
Definition GSkyDir.cpp:245
void clear(void)
Clear sky direction.
Definition GSkyDir.cpp:185
Time class.
Definition GTime.hpp:55
void clear(void)
Clear time.
Definition GTime.cpp:252
Time container class.
Definition GTimes.hpp:45
void append(const GTime &time)
Append time to container.
Definition GTimes.cpp:216
void reserve(const int &num)
Reserve memory for times in container.
Definition GTimes.cpp:331
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition GTools.cpp:1162
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition GTools.cpp:508
int spi_num_hdus(const GFits &fits, const std::string &extname)
Return number of HDU versions.
GTime spi_ijd2time(const double &ijd)
Convert IJD to GTime.
const GFitsTable * spi_hdu(const GFits &fits, const std::string &extname, const int &extver=1)
Return FITS table.
Definition GSPITools.cpp:57