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