GammaLib  2.1.0.dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
GSPIEventCube.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * GSPIEventCube.cpp - INTEGRAL/SPI event bin container class *
3  * ----------------------------------------------------------------------- *
4  * copyright (C) 2020-2022 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 
53 /* __ Macros _____________________________________________________________ */
54 
55 /* __ Coding definitions _________________________________________________ */
56 
57 /* __ Debug definitions __________________________________________________ */
58 
59 
60 
61 /*==========================================================================
62  = =
63  = Constructors/destructors =
64  = =
65  ==========================================================================*/
66 
67 /***********************************************************************//**
68  * @brief Void constructor
69  *
70  * Constructs an empty INTEGRAL/SPI event cube.
71  ***************************************************************************/
73 {
74  // Initialise members
75  init_members();
76 
77  // Return
78  return;
79 }
80 
81 
82 /***********************************************************************//**
83  * @brief Observation Group constructor
84  *
85  * @param[in] filename Observation Group FITS file name.
86  *
87  * Construct an INTEGRAL/SPI event cube from an Observation Group.
88  ***************************************************************************/
90 {
91  // Initialise members
92  init_members();
93 
94  // Load event cube
95  load(filename);
96 
97  // Return
98  return;
99 }
100 
101 
102 /***********************************************************************//**
103  * @brief Copy constructor
104  *
105  * @param[in] cube INTEGRAL/SPI event cube.
106  ***************************************************************************/
108 {
109  // Initialise members
110  init_members();
111 
112  // Copy members
113  copy_members(cube);
114 
115  // Return
116  return;
117 }
118 
119 
120 /***********************************************************************//**
121  * @brief Destructor
122  ***************************************************************************/
124 {
125  // Free members
126  free_members();
127 
128  // Return
129  return;
130 }
131 
132 
133 /*==========================================================================
134  = =
135  = Operators =
136  = =
137  ==========================================================================*/
138 
139 /***********************************************************************//**
140  * @brief Assignment operator
141  *
142  * @param[in] cube INTEGRAL/SPI event cube.
143  * @return INTEGRAL/SPI event cube.
144  ***************************************************************************/
146 {
147  // Execute only if object is not identical
148  if (this != &cube) {
149 
150  // Copy base class members
151  this->GEventCube::operator=(cube);
152 
153  // Free members
154  free_members();
155 
156  // Initialise members
157  init_members();
158 
159  // Copy members
160  copy_members(cube);
161 
162  } // endif: object was not identical
163 
164  // Return this object
165  return *this;
166 }
167 
168 
169 /***********************************************************************//**
170  * @brief Event bin access operator
171  *
172  * @param[in] index Event index [0,...,size()-1].
173  * @return Pointer to event bin.
174  *
175  * Returns pointer to an event bin. Note that the returned pointer is in
176  * fact always the same, but the method sets the pointers within the
177  * event bin so that they point to the appropriate information.
178  ***************************************************************************/
180 {
181  // Set event bin
182  set_bin(index);
183 
184  // Return pointer
185  return (&m_bin);
186 }
187 
188 
189 /***********************************************************************//**
190  * @brief Event bin access operator (const version)
191  *
192  * @param[in] index Event index [0,...,size()-1].
193  * @return Const pointer to event bin.
194  *
195  * Returns pointer to an event bin. Note that the returned pointer is in
196  * fact always the same, but the method sets the pointers within the
197  * event bin so that they point to the appropriate information.
198  ***************************************************************************/
199 const GSPIEventBin* GSPIEventCube::operator[](const int& index) const
200 {
201  // Set event bin (circumvent const correctness)
202  const_cast<GSPIEventCube*>(this)->set_bin(index);
203 
204  // Return pointer
205  return (&m_bin);
206 }
207 
208 
209 /*==========================================================================
210  = =
211  = Public methods =
212  = =
213  ==========================================================================*/
214 
215 /***********************************************************************//**
216  * @brief Clear INTEGRAL/SPI event cube
217  *
218  * Clears INTEGRAL/SPI event cube by resetting all class members to an
219  * initial state. Any information that was present before will be lost.
220  ***************************************************************************/
222 {
223  // Free class members (base and derived classes, derived class first)
224  free_members();
225  this->GEventCube::free_members();
226  this->GEvents::free_members();
227 
228  // Initialise members
229  this->GEvents::init_members();
230  this->GEventCube::init_members();
231  init_members();
232 
233  // Return
234  return;
235 }
236 
237 
238 /***********************************************************************//**
239  * @brief Clone event cube
240  *
241  * @return Pointer to deep copy of INTEGRAL/SPI event cube.
242  ***************************************************************************/
244 {
245  return new GSPIEventCube(*this);
246 }
247 
248 
249 /***********************************************************************//**
250  * @brief Return number of bins in axis
251  *
252  * @param[in] axis Axis [0,...,dim()-1].
253  * @return Number of bins in axis.
254  *
255  * @exception GException::out_of_range
256  * Axis is out of range.
257  *
258  * Returns the number of bins along a given event cube @p axis.
259  ***************************************************************************/
260 int GSPIEventCube::naxis(const int& axis) const
261 {
262  // Optionally check if the axis is valid
263  #if defined(G_RANGE_CHECK)
264  if (axis < 0 || axis >= dim()) {
265  throw GException::out_of_range(G_NAXIS, "INTEGRAL/SPI event cube axis",
266  axis, dim());
267  }
268  #endif
269 
270  // Setup const pointer array that points to relevant axis size
271  const int* ptr[3] = {&m_num_pt, &m_num_det, &m_num_ebin};
272 
273  // Set number of bins dependent on axis
274  int naxis = *ptr[axis];
275 
276  // Return result
277  return naxis;
278 }
279 
280 
281 /***********************************************************************//**
282  * @brief Load INTEGRAL/SPI event cube from Observation Group
283  *
284  * @param[in] filename Observation Group FITS file name.
285  *
286  * Loads data from an Observation Group FITS file into an INTEGRAL/SPI
287  * event cube.
288  ***************************************************************************/
289 void GSPIEventCube::load(const GFilename& filename)
290 {
291  #pragma omp critical(GSPIEventCube_load)
292  {
293  // Clear object
294  clear();
295 
296  // Open FITS file
297  GFits fits(filename);
298 
299  // Read event cube from FITS file
300  read(fits);
301 
302  // Close FITS file
303  fits.close();
304  }
305 
306  // Return
307  return;
308 }
309 
310 
311 /***********************************************************************//**
312  * @brief Save INTEGRAL/SPI event cube into FITS file
313  *
314  * @param[in] filename FITS file name.
315  * @param[in] clobber Overwrite existing FITS file?
316  *
317  * Saves the INTEGRAL/SPI event cube into a FITS file.
318  ***************************************************************************/
319 void GSPIEventCube::save(const GFilename& filename, const bool& clobber) const
320 {
321  // Create empty FITS file
322  GFits fits;
323 
324  // Write event cube into FITS file
325  write(fits);
326 
327  // Save FITS file
328  fits.saveto(filename, clobber);
329 
330  // Close FITS file
331  fits.close();
332 
333  // Return
334  return;
335 }
336 
337 
338 /***********************************************************************//**
339  * @brief Read INTEGRAL/SPI event cube from Observation Group FITS file
340  *
341  * @param[in] fits Observation Group FITS file.
342  *
343  * @exception GException::invalid_value
344  * Observation Group FITS file invalid.
345  *
346  * Reads an INTEGRAL/SPI event cube from an Observation Group FITS file.
347  * The following extension are mandatory
348  *
349  * "SPI.-EBDS-SET"
350  * "SPI.-OBS.-PNT"
351  * "SPI.-OBS.-GTI"
352  * "SPI.-OBS.-DSP"
353  * "SPI.-OBS.-DTI"
354  *
355  * Optional extensions are
356  *
357  * "SPI.-SDET-SPE"
358  * "SPI.-BMOD-DSP"
359  *
360  ***************************************************************************/
361 void GSPIEventCube::read(const GFits& fits)
362 {
363  // Clear object
364  clear();
365 
366  // Get table pointers
367  const GFitsTable* ebds = gammalib::spi_hdu(fits, "SPI.-EBDS-SET");
368  const GFitsTable* pnt = gammalib::spi_hdu(fits, "SPI.-OBS.-PNT");
369  const GFitsTable* gti = gammalib::spi_hdu(fits, "SPI.-OBS.-GTI");
370  const GFitsTable* dsp = gammalib::spi_hdu(fits, "SPI.-OBS.-DSP");
371  const GFitsTable* dti = gammalib::spi_hdu(fits, "SPI.-OBS.-DTI");
372 
373  // Throw an exception if one of the mandatory HDUs is missing
374  if (ebds == NULL) {
375  std::string msg = "Extension \"SPI.-EBDS-SET\" not found in "
376  "Observation Group FITS file \""+
377  fits.filename().url()+"\". Please specify a "
378  "valid Observation Group.";
380  }
381  if (pnt == NULL) {
382  std::string msg = "Extension \"SPI.-OBS.-PNT\" not found in "
383  "Observation Group FITS file \""+
384  fits.filename().url()+"\". Please specify a "
385  "valid Observation Group.";
387  }
388  if (gti == NULL) {
389  std::string msg = "Extension \"SPI.-OBS.-GTI\" not found in "
390  "Observation Group FITS file \""+
391  fits.filename().url()+"\". Please specify a "
392  "valid Observation Group.";
394  }
395  if (dsp == NULL) {
396  std::string msg = "Extension \"SPI.-OBS.-DSP\" not found in "
397  "Observation Group FITS file \""+
398  fits.filename().url()+"\". Please specify a "
399  "valid Observation Group.";
401  }
402  if (dti == NULL) {
403  std::string msg = "Extension \"SPI.-OBS.-DTI\" not found in "
404  "Observation Group FITS file \""+
405  fits.filename().url()+"\". Please specify a "
406  "valid Observation Group.";
408  }
409 
410  // Determine dataspace dimensions from FITS tables
411  m_num_pt = dsp->integer("PT_NUM");
412  m_num_det = dsp->integer("DET_NUM");
413  m_num_ebin = dsp->integer("EBIN_NUM");
414 
415  // Get number of sky and background models
416  m_num_sky = gammalib::spi_num_hdus(fits, "SPI.-SDET-SPE");
417  m_num_bgm = gammalib::spi_num_hdus(fits, "SPI.-BMOD-DSP");
418 
419  // Allocate data
420  alloc_data();
421 
422  // Read energy boundaries
423  read_ebds(ebds);
424 
425  // Read pointing information
426  read_pnt(pnt, gti);
427 
428  // Read Good Time Intervals
429  read_gti(gti);
430 
431  // Read dead time information
432  read_dti(dti);
433 
434  // Read detector spectra
435  read_dsp(dsp);
436 
437  // Read models
438  read_models(fits);
439 
440  // Free HDU pointers
441  if (ebds != NULL) delete ebds;
442  if (pnt != NULL) delete pnt;
443  if (gti != NULL) delete gti;
444  if (dsp != NULL) delete dsp;
445  if (dti != NULL) delete dti;
446 
447  // Prepare event bin
448  init_bin();
449 
450  // Return
451  return;
452 }
453 
454 
455 /***********************************************************************//**
456  * @brief Write INTEGRAL/SPI event cube into FITS file.
457  *
458  * @param[in] file FITS file.
459  *
460  * Writes the INTEGRAL/SPI event cube into a FITS file.
461  ***************************************************************************/
462 void GSPIEventCube::write(GFits& file) const
463 {
464  // TODO: Here you have to implement the interface between the class and
465  // the event cube FITS file.
466 
467  // Return
468  return;
469 }
470 
471 
472 /***********************************************************************//**
473  * @brief Return number of events in cube
474  *
475  * @return Number of events in event cube.
476  *
477  * This method returns the number of events in the event cube rounded to the
478  * nearest integer.
479  ***************************************************************************/
480 int 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 int(number+0.5);
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  ***************************************************************************/
506 double 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  ***************************************************************************/
561 double 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  ***************************************************************************/
618 double 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  ***************************************************************************/
657 const 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  ***************************************************************************/
685 const 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  ***************************************************************************/
716 const 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  ***************************************************************************/
742 const 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 Print INTEGRAL/SPI event cube information
759  *
760  * @param[in] chatter Chattiness.
761  * @return String containing INTEGRAL/SPI event cube information.
762  ***************************************************************************/
763 std::string GSPIEventCube::print(const GChatter& chatter) const
764 {
765  // Initialise result string
766  std::string result;
767 
768  // Continue only if chatter is not silent
769  if (chatter != SILENT) {
770 
771  // Append header
772  result.append("=== GSPIEventCube ===");
773 
774  // Append information
775  result.append("\n"+gammalib::parformat("Number of events"));
776  result.append(gammalib::str(number()));
777  result.append("\n"+gammalib::parformat("Number of elements"));
778  result.append(gammalib::str(size()));
779  result.append("\n"+gammalib::parformat("Pointings"));
780  result.append(gammalib::str(m_num_pt));
781  result.append("\n"+gammalib::parformat("Detectors"));
782  result.append(gammalib::str(m_num_det));
783  result.append("\n"+gammalib::parformat("Energy bins"));
784  result.append(gammalib::str(m_num_ebin));
785  result.append("\n"+gammalib::parformat("Sky models"));
786  result.append(gammalib::str(m_num_sky));
787  for (int i = 0; i < m_num_sky; ++i) {
788  result.append("\n"+gammalib::parformat(" Model name "+gammalib::str(i+1)));
789  result.append(m_modnames[i]);
790  result.append("\n"+gammalib::parformat(" Number of events"));
791  result.append(gammalib::str(model_counts(i)));
792  }
793  result.append("\n"+gammalib::parformat("Background models"));
794  result.append(gammalib::str(m_num_bgm));
795  for (int i = 0; i < m_num_bgm; ++i) {
796  result.append("\n"+gammalib::parformat(" Model name "+gammalib::str(i+1)));
797  result.append(m_modnames[i+m_num_sky]);
798  result.append("\n"+gammalib::parformat(" Number of events"));
799  result.append(gammalib::str(model_counts(i+m_num_sky)));
800  }
801  result.append("\n"+gammalib::parformat("Energy range"));
802  result.append(gammalib::str(emin().MeV())+" - ");
803  result.append(gammalib::str(emax().MeV())+" MeV");
804  result.append("\n"+gammalib::parformat("Ontime"));
805  result.append(gammalib::str(ontime())+" s");
806  result.append("\n"+gammalib::parformat("Livetime"));
807  result.append(gammalib::str(livetime())+" s");
808  result.append("\n"+gammalib::parformat("Time interval"));
809  result.append(tstart().utc()+" - ");
810  result.append(tstop().utc());
811 
812  } // endif: chatter was not silent
813 
814  // Return result
815  return result;
816 }
817 
818 
819 /*==========================================================================
820  = =
821  = Private methods =
822  = =
823  ==========================================================================*/
824 
825 /***********************************************************************//**
826  * @brief Initialise class members
827  ***************************************************************************/
829 {
830  // Initialise members
831  m_bin.clear();
832  m_num_pt = 0;
833  m_num_det = 0;
834  m_num_ebin = 0;
835  m_num_sky = 0;
836  m_num_bgm = 0;
837  m_gti_size = 0;
838  m_dsp_size = 0;
839  m_model_size = 0;
840  m_ontime = NULL;
841  m_livetime = NULL;
842  m_counts = NULL;
843  m_stat_err = NULL;
844  m_models = NULL;
845  m_size = NULL;
846  m_dir = NULL;
847  m_time = NULL;
848  m_energy = NULL;
849  m_ewidth = NULL;
850  m_spix = NULL;
851  m_spiz = NULL;
852  m_ptid = NULL;
853 
854  // Prepare event bin
855  init_bin();
856 
857  // Return
858  return;
859 }
860 
861 
862 /***********************************************************************//**
863  * @brief Copy class members
864  *
865  * @param[in] cube INTEGRAL/SPI event cube.
866  *
867  * This method copies the class members from another event cube in the actual
868  * object. It also prepares the event bin member that will be returned in
869  * case of an operator access to the class.
870  ***************************************************************************/
872 {
873  // Copy members. Note that the event bin is not copied as it will
874  // be initialised later. The event bin serves just as a container of
875  // pointers, hence we do not want to copy over the pointers from the
876  // original class.
877  m_num_pt = cube.m_num_pt;
878  m_num_det = cube.m_num_det;
879  m_num_ebin = cube.m_num_ebin;
880  m_num_sky = cube.m_num_sky;
881  m_num_bgm = cube.m_num_bgm;
882  m_gti_size = cube.m_gti_size;
883  m_dsp_size = cube.m_dsp_size;
884  m_model_size = cube.m_model_size;
885  m_modnames = cube.m_modnames;
886 
887  // Copy data
888  if (m_num_ebin > 0) {
889  m_energy = new GEnergy[m_num_ebin];
890  m_ewidth = new GEnergy[m_num_ebin];
891  for (int i = 0; i < m_num_ebin; ++i) {
892  m_energy[i] = cube.m_energy[i];
893  m_ewidth[i] = cube.m_ewidth[i];
894  }
895  }
896  if (m_num_pt > 0) {
897  m_ptid = new std::string[m_num_pt];
898  m_spix = new GSkyDir[m_num_pt];
899  m_spiz = new GSkyDir[m_num_pt];
900  for (int i = 0; i < m_num_pt; ++i) {
901  m_ptid[i] = cube.m_ptid[i];
902  m_spix[i] = cube.m_spix[i];
903  m_spiz[i] = cube.m_spiz[i];
904  }
905  }
906  if (m_gti_size > 0) {
907  m_ontime = new double[m_gti_size];
908  m_livetime = new double[m_gti_size];
909  m_time = new GTime[m_gti_size];
911  for (int i = 0; i < m_gti_size; ++i) {
912  m_ontime[i] = cube.m_ontime[i];
913  m_livetime[i] = cube.m_livetime[i];
914  m_time[i] = cube.m_time[i];
915  m_dir[i] = cube.m_dir[i];
916  }
917  }
918  if (m_dsp_size > 0) {
919  m_counts = new double[m_dsp_size];
920  m_stat_err = new double[m_dsp_size];
921  m_size = new double[m_dsp_size];
922  for (int i = 0; i < m_dsp_size; ++i) {
923  m_counts[i] = cube.m_counts[i];
924  m_stat_err[i] = cube.m_stat_err[i];
925  m_size[i] = cube.m_size[i];
926  }
927  }
928  if (m_model_size > 0) {
929  m_models = new double[m_model_size];
930  for (int i = 0; i < m_model_size; ++i) {
931  m_models[i] = cube.m_models[i];
932  }
933  }
934 
935  // Prepare event bin
936  init_bin();
937 
938  // Return
939  return;
940 }
941 
942 
943 /***********************************************************************//**
944  * @brief Delete class members
945  ***************************************************************************/
947 {
948  // Delete memory
949  if (m_ontime != NULL) delete [] m_ontime;
950  if (m_livetime != NULL) delete [] m_livetime;
951  if (m_counts != NULL) delete [] m_counts;
952  if (m_stat_err != NULL) delete [] m_stat_err;
953  if (m_models != NULL) delete [] m_models;
954  if (m_size != NULL) delete [] m_size;
955  if (m_dir != NULL) delete [] m_dir;
956  if (m_time != NULL) delete [] m_time;
957  if (m_energy != NULL) delete [] m_energy;
958  if (m_ewidth != NULL) delete [] m_ewidth;
959  if (m_spix != NULL) delete [] m_spix;
960  if (m_spiz != NULL) delete [] m_spiz;
961  if (m_ptid != NULL) delete [] m_ptid;
962 
963  // Set pointers to free
964  m_ontime = NULL;
965  m_livetime = NULL;
966  m_counts = NULL;
967  m_stat_err = NULL;
968  m_models = NULL;
969  m_size = NULL;
970  m_dir = NULL;
971  m_time = NULL;
972  m_energy = NULL;
973  m_ewidth = NULL;
974  m_spix = NULL;
975  m_spiz = NULL;
976  m_ptid = NULL;
977 
978  // Return
979  return;
980 }
981 
982 
983 /***********************************************************************//**
984  * @brief Allocate data
985  ***************************************************************************/
987 {
988  // Make sure that data is free
989  free_members();
990 
991  // Compute array sizes
995 
996  // Allocate and initialise EBDS data
997  if (m_num_ebin > 0) {
998  m_energy = new GEnergy[m_num_ebin];
999  m_ewidth = new GEnergy[m_num_ebin];
1000  for (int i = 0; i < m_num_ebin; ++i) {
1001  m_energy[i].clear();
1002  m_ewidth[i].clear();
1003  }
1004  }
1005 
1006  // Allocate and initialise pointing data
1007  if (m_num_pt > 0) {
1008  m_ptid = new std::string[m_num_pt];
1009  m_spix = new GSkyDir[m_num_pt];
1010  m_spiz = new GSkyDir[m_num_pt];
1011  for (int i = 0; i < m_num_pt; ++i) {
1012  m_ptid[i].clear();
1013  m_spix[i].clear();
1014  m_spiz[i].clear();
1015  }
1016  }
1017 
1018  // Allocate and initialise GTI data
1019  if (m_gti_size > 0) {
1020  m_ontime = new double[m_gti_size];
1021  m_livetime = new double[m_gti_size];
1022  m_time = new GTime[m_gti_size];
1023  m_dir = new GSPIInstDir[m_gti_size];
1024  for (int i = 0; i < m_gti_size; ++i) {
1025  m_ontime[i] = 0.0;
1026  m_livetime[i] = 0.0;
1027  m_time[i].clear();
1028  m_dir[i].clear();
1029  }
1030  }
1031 
1032  // Allocate and initialise DSP data
1033  if (m_dsp_size > 0) {
1034  m_counts = new double[m_dsp_size];
1035  m_stat_err = new double[m_dsp_size];
1036  m_size = new double[m_dsp_size];
1037  for (int i = 0; i < m_dsp_size; ++i) {
1038  m_counts[i] = 0.0;
1039  m_stat_err[i] = 0.0;
1040  m_size[i] = 0.0;
1041  }
1042  }
1043 
1044  // Allocate and initialise model data
1045  if (m_model_size > 0) {
1046  m_models = new double[m_model_size];
1047  for (int i = 0; i < m_model_size; ++i) {
1048  m_models[i] = 0.0;
1049  }
1050  }
1051 
1052  // Return
1053  return;
1054 }
1055 
1056 
1057 /***********************************************************************//**
1058  * @brief Read data from INTEGRAL/SPI "SPI.-EBDS-SET" extension
1059  *
1060  * @param[in] ebds Pointer to energy boundaries FITS table.
1061  *
1062  * @exception GException::invalid_value
1063  * Incompatible number of energy bins encountered
1064  *
1065  * Reads data from an INTEGRAL/SPI "SPI.-EBDS-SET" extension. The method
1066  * sets up the m_energy array and the m_ebounds member.
1067  ***************************************************************************/
1069 {
1070  // Continue only if energy boundary FITS table pointer is valid
1071  if (ebds != NULL) {
1072 
1073  // Read energy boundaries
1074  m_ebounds.read(*ebds);
1075 
1076  // Throw an exception if the number of energy boundaries is not
1077  // consistent with DSP keyword
1078  if (m_ebounds.size() != m_num_ebin) {
1079  std::string msg = "Number of energy bins "+
1080  gammalib::str(m_ebounds.size())+" found in "
1081  "\"SPI.-EBDS-SET\" extension differes from value "+
1082  gammalib::str(m_num_det)+" of \"DET_NUM\" keyword "
1083  "in \"SPI.-OBS.-DSP\" extension. Please specify a "
1084  "valid Observation Group.";
1086  }
1087 
1088  // Loop over all energy bins
1089  for (int iebin = 0; iebin < m_num_ebin; ++iebin) {
1090 
1091  // Store linear mean energy and bin width
1092  m_energy[iebin] = m_ebounds.emean(iebin);
1093  m_ewidth[iebin] = m_ebounds.ewidth(iebin);
1094 
1095  } // endfor: looped over all energy bins
1096 
1097  } // endif: energy boundary FITS table pointer was valid
1098 
1099  // Return
1100  return;
1101 }
1102 
1103 
1104 /***********************************************************************//**
1105  * @brief Read pointing information
1106  *
1107  * @param[in] pnt Pointer to pointing FITS table.
1108  * @param[in] gti Pointer to GTI FITS table.
1109  *
1110  * @exception GException::invalid_value
1111  * Incompatible PTID_SPI pointing identifiers encountered
1112  *
1113  * Reads pointing information from "SPI.-OBS.-PNT" and "SPI.-OBS.-GTI"
1114  * extensions. The method sets up the m_dir array.
1115  ***************************************************************************/
1116 void GSPIEventCube::read_pnt(const GFitsTable* pnt, const GFitsTable* gti)
1117 {
1118  // Continue only if FITS table pointers are valid
1119  if (pnt != NULL && gti != NULL) {
1120 
1121  // Get relevant columns
1122  const GFitsTableCol* pnt_ptid = (*pnt)["PTID_SPI"];
1123  const GFitsTableCol* ra_spix = (*pnt)["RA_SPIX"];
1124  const GFitsTableCol* dec_spix = (*pnt)["DEC_SPIX"];
1125  const GFitsTableCol* ra_spiz = (*pnt)["RA_SPIZ"];
1126  const GFitsTableCol* dec_spiz = (*pnt)["DEC_SPIZ"];
1127  const GFitsTableCol* gti_ptid = (*gti)["PTID_SPI"];
1128  const GFitsTableCol* det_id = (*gti)["DET_ID"];
1129 
1130  // Loop over all pointings
1131  for (int ipt = 0; ipt < m_num_pt; ++ipt) {
1132 
1133  // Store pointing identifier
1134  m_ptid[ipt] = pnt_ptid->string(ipt);
1135 
1136  // Store SPI X and Z directions
1137  m_spix[ipt].radec_deg(ra_spix->real(ipt), dec_spix->real(ipt));
1138  m_spiz[ipt].radec_deg(ra_spiz->real(ipt), dec_spiz->real(ipt));
1139 
1140  // Set pointing direction
1141  GSkyDir pnt_dir;
1142  pnt_dir.radec_deg(ra_spix->real(ipt), dec_spix->real(ipt));
1143 
1144  // Loop over all detectors
1145  for (int idet = 0; idet < m_num_det; ++idet) {
1146 
1147  // Get row index in table
1148  int irow = ipt * m_num_det + idet;
1149 
1150  // Throw an exception if the pointing identifier in the pointing
1151  // and the GTI extension is not the same
1152  if (pnt_ptid->string(ipt) != gti_ptid->string(irow)) {
1153  std::string msg = "PITD_SPI \""+pnt_ptid->string(ipt)+"\" in "
1154  "\"SPI.-OBS.-PNT\" differs from \""+
1155  gti_ptid->string(irow)+"\" in "
1156  "\"SPI.-OBS.-GTI\" extension for detector "+
1157  gammalib::str(det_id->integer(irow))+". Please "
1158  "specify a valid Observation Group.";
1160  }
1161 
1162  // Store pointing direction and detector identifier
1163  m_dir[irow].dir(pnt_dir);
1164  m_dir[irow].detid(det_id->integer(irow));
1165 
1166  } // endfor: looped over all detectors
1167 
1168  } // endfor: looped over all pointings
1169 
1170  } // endif: FITS table pointers were valid
1171 
1172  // Return
1173  return;
1174 }
1175 
1176 
1177 /***********************************************************************//**
1178  * @brief Read data from INTEGRAL/SPI "SPI.-OBS.-GTI" extension
1179  *
1180  * @param[in] gti Pointer to GTI FITS table.
1181  *
1182  * Reads data from an INTEGRAL/SPI "SPI.-OBS.-GTI" extension. The method
1183  * sets up the m_ontime array and the m_gti member.
1184  ***************************************************************************/
1186 {
1187  // Continue only if FITS table pointer is valid
1188  if (gti != NULL) {
1189 
1190  // Get relevant columns
1191  const GFitsTableCol* ontime = (*gti)["ONTIME"];
1192  const GFitsTableCol* tstart = (*gti)["TSTART"];
1193  const GFitsTableCol* tstop = (*gti)["TSTOP"];
1194 
1195  // Loop over all pointings
1196  for (int ipt = 0; ipt < m_num_pt; ++ipt) {
1197 
1198  // Initialise minimum TSTART and maximum TSTOP for GTI (they should
1199  // all be identical and are anyways not used, but we want to have a
1200  // reasonable GTI object
1201  double t_start = 0.0;
1202  double t_stop = 0.0;
1203 
1204  // Loop over all detectors
1205  for (int idet = 0; idet < m_num_det; ++idet) {
1206 
1207  // Get row index in table
1208  int irow = ipt * m_num_det + idet;
1209 
1210  // Store ontime
1211  m_ontime[irow] = ontime->real(irow);
1212 
1213  // Compute and store mean time
1214  double ijd = 0.5 * (tstart->real(irow) + tstop->real(irow));
1215  m_time[irow] = gammalib::spi_ijd2time(ijd);
1216 
1217  // Update TSTART and TSTOP (only if ontime is > 0.0 since TSTART
1218  // and TSTOP may be zero for zero ontime)
1219  if (ontime->real(irow) > 0.0) {
1220  if (t_start == 0.0 || (tstart->real(irow) < t_start)) {
1221  t_start = tstart->real(irow);
1222  }
1223  if (t_stop == 0.0 || (tstop->real(irow) > t_stop)) {
1224  t_stop = tstop->real(irow);
1225  }
1226  }
1227 
1228  } // endfor: looped over all detectors
1229 
1230  // Append GTI (only if TSTART and TSTOP are not zero)
1231  if (t_start != 0.0 && t_stop != 0.0) {
1233  gammalib::spi_ijd2time(t_stop));
1234  }
1235 
1236  } // endfor: looped over all pointings
1237 
1238  } // endif: FITS table pointer was valid
1239 
1240  // Return
1241  return;
1242 }
1243 
1244 
1245 /***********************************************************************//**
1246  * @brief Read data from INTEGRAL/SPI "SPI.-OBS.-DTI" extension
1247  *
1248  * @param[in] dti Pointer to Dead time information FITS table.
1249  *
1250  * Reads data from an INTEGRAL/SPI "SPI.-OBS.-DTI" extension. The method
1251  * sets up the m_ontime array and the m_gti member.
1252  ***************************************************************************/
1254 {
1255  // Continue only if FITS table pointer is valid
1256  if (dti != NULL) {
1257 
1258  // Get relevant columns
1259  const GFitsTableCol* livetime = (*dti)["LIVETIME"];
1260 
1261  // Loop over all pointings
1262  for (int ipt = 0; ipt < m_num_pt; ++ipt) {
1263 
1264  // Loop over all detectors
1265  for (int idet = 0; idet < m_num_det; ++idet) {
1266 
1267  // Get row index in table
1268  int irow = ipt * m_num_det + idet;
1269 
1270  // Store livetime
1271  m_livetime[irow] = livetime->real(irow);
1272 
1273  } // endfor: looped over all detectors
1274 
1275  } // endfor: looped over all pointings
1276 
1277  } // endif: FITS table pointer was valid
1278 
1279  // Return
1280  return;
1281 }
1282 
1283 
1284 /***********************************************************************//**
1285  * @brief Read data from INTEGRAL/SPI "SPI.-OBS.-DSP" extension
1286  *
1287  * @param[in] dsp DSP FITS table.
1288  *
1289  * Reads data from an INTEGRAL/SPI "SPI.-OBS.-DSP" extension. The method
1290  * sets up the m_counts, m_stat_err and m_size arrays.
1291  *
1292  * Note that the computation of the m_size arrays needs ontime and energy
1293  * width information that has been previously setup in the read_ebds() and
1294  * read_gti() methods.
1295  ***************************************************************************/
1297 {
1298  // Continue only if FITS table pointer is valid
1299  if (dsp != NULL) {
1300 
1301  // Get relevant columns
1302  const GFitsTableCol* counts = (*dsp)["COUNTS"];
1303  const GFitsTableCol* stat_err = (*dsp)["STAT_ERR"];
1304 
1305  // Loop over all pointings
1306  for (int ipt = 0; ipt < m_num_pt; ++ipt) {
1307 
1308  // Loop over all detectors
1309  for (int idet = 0; idet < m_num_det; ++idet) {
1310 
1311  // Get row index in table
1312  int irow = ipt * m_num_det + idet;
1313 
1314  // Set start index in destination arrays
1315  int index = irow * m_num_ebin;
1316 
1317  // Copy energy bins
1318  for (int iebin = 0; iebin < m_num_ebin; ++iebin, ++index) {
1319  m_counts[index] = counts->real(irow, iebin);
1320  m_stat_err[index] = stat_err->real(irow, iebin);
1321  m_size[index] = m_livetime[irow] * m_ewidth[iebin].MeV();
1322  }
1323 
1324  } // endfor: looped over all detectors
1325 
1326  } // endfor: looped over all pointings
1327 
1328  } // endif: FITS table pointer was valid
1329 
1330  // Return
1331  return;
1332 }
1333 
1334 
1335 /***********************************************************************//**
1336  * @brief Read models from INTEGRAL/SPI Observation Group
1337  *
1338  * @param[in] fits Observation Group FITS file.
1339  ***************************************************************************/
1341 {
1342  // Clear model names
1343  m_modnames.clear();
1344 
1345  // Initialise model index
1346  int imodel = 0;
1347 
1348  // Compute total number of models
1349  int num_models = m_num_sky + m_num_bgm;
1350 
1351  // Loop over all sky models
1352  for (int i = 0; i < m_num_sky; ++i, ++imodel) {
1353 
1354  // Get FITS table
1355  const GFitsTable* model = gammalib::spi_hdu(fits, "SPI.-SDET-SPE", i+1);
1356 
1357  // Throw an exception if the FITS table is missing
1358  if (model == NULL) {
1359  std::string msg = "Extension \"SPI.-SDET-SPE\" version "+
1360  gammalib::str(i+1)+" not found in Observation "
1361  "Group FITS file \""+fits.filename().url()+
1362  "\". Please specify a valid Observation Group.";
1364  }
1365 
1366  // Get model name
1367  std::string name = "MODEL" + gammalib::str(imodel+1);
1368  if (model->has_card("SOURCEID")) {
1369  name = model->string("SOURCEID");
1370  }
1371  m_modnames.push_back(name);
1372 
1373  // Get relevant columns
1374  const GFitsTableCol* counts = (*model)["COUNTS"];
1375 
1376  // Loop over all pointings
1377  for (int ipt = 0; ipt < m_num_pt; ++ipt) {
1378 
1379  // Loop over all detectors
1380  for (int idet = 0; idet < m_num_det; ++idet) {
1381 
1382  // Get row index in model table
1383  int irow = ipt * m_num_det + idet;
1384 
1385  // Set start index in destination array
1386  int index = irow * m_num_ebin;
1387 
1388  // Copy energy bins
1389  for (int iebin = 0; iebin < m_num_ebin; ++iebin, ++index) {
1390  m_models[index*num_models + imodel] = counts->real(irow, iebin);
1391  }
1392 
1393  } // endfor: looped over all detectors
1394 
1395  } // endfor: looped over all pointings
1396 
1397  } // endfor: looped over all sky models
1398 
1399  // Loop over all background models
1400  for (int i = 0; i < m_num_bgm; ++i, ++imodel) {
1401 
1402  // Get FITS table
1403  const GFitsTable* model = gammalib::spi_hdu(fits, "SPI.-BMOD-DSP", i+1);
1404 
1405  // Throw an exception if the FITS table is missing
1406  if (model == NULL) {
1407  std::string msg = "Extension \"SPI.-BMOD-DSP\" version "+
1408  gammalib::str(i+1)+" not found in Observation "
1409  "Group FITS file \""+fits.filename().url()+
1410  "\". Please specify a valid Observation Group.";
1412  }
1413 
1414  // Get model name
1415  std::string name = "MODEL" + gammalib::str(imodel+1);
1416  if (model->has_card("BKGNAME")) {
1417  name = model->string("BKGNAME");
1418  }
1419  m_modnames.push_back(name);
1420 
1421  // Get relevant columns
1422  const GFitsTableCol* counts = (*model)["COUNTS"];
1423 
1424  // Loop over all pointings
1425  for (int ipt = 0; ipt < m_num_pt; ++ipt) {
1426 
1427  // Loop over all detectors
1428  for (int idet = 0; idet < m_num_det; ++idet) {
1429 
1430  // Get row index in model table
1431  int irow = ipt * m_num_det + idet;
1432 
1433  // Set start index in destination array
1434  int index = irow * m_num_ebin;
1435 
1436  // Copy energy bins
1437  for (int iebin = 0; iebin < m_num_ebin; ++iebin, ++index) {
1438  m_models[index*num_models + imodel] = counts->real(irow, iebin);
1439  }
1440 
1441  } // endfor: looped over all detectors
1442 
1443  } // endfor: looped over all pointings
1444 
1445  } // endfor: looped over all background models
1446 
1447  // Return
1448  return;
1449 }
1450 
1451 
1452 /***********************************************************************//**
1453  * @brief Initialise event bin
1454  *
1455  * Initialises the event bin. All fixed content is set here, the content
1456  * that depends on the bin index is set by the set_bin() method which is
1457  * called before any event bin access.
1458  ***************************************************************************/
1460 {
1461  // Prepare event bin
1462  m_bin.free_members();
1463  m_bin.m_index = 0; //!< Set by set_bin method
1464  m_bin.m_ipt = 0; //!< Set by set_bin method
1465  m_bin.m_idir = 0; //!< Set by set_bin method
1466  m_bin.m_iebin = 0; //!< Set by set_bin method
1468  m_bin.m_dir = NULL; //!< Set by set_bin method
1469  m_bin.m_time = NULL; //!< Set by set_bin method
1470  m_bin.m_energy = NULL; //!< Set by set_bin method
1471  m_bin.m_counts = NULL; //!< Set by set_bin method
1472  m_bin.m_ontime = NULL; //!< Set by set_bin method
1473  m_bin.m_livetime = NULL; //!< Set by set_bin method
1474  m_bin.m_size = NULL; //!< Set by set_bin method
1475  m_bin.m_models = NULL; //!< Set by set_bin method
1476 
1477  // Return
1478  return;
1479 }
1480 
1481 
1482 /***********************************************************************//**
1483  * @brief Set event bin
1484  *
1485  * @param[in] index Event index [0,...,size()[.
1486  *
1487  * @exception GException::out_of_range
1488  * Event index is outside valid range.
1489  *
1490  * Sets the pointers of the event bin to the event cube cell that corresponds
1491  * to the specified @p index.
1492  *
1493  * The event bin is in fact physically stored in the event cube, and only a
1494  * single event bin is indeed allocated. This method sets up the pointers in
1495  * the event bin so that a client can easily access the information of
1496  * individual bins as if they were stored in an array.
1497  ***************************************************************************/
1498 void GSPIEventCube::set_bin(const int& index)
1499 {
1500  // Optionally check if the index is valid
1501  #if defined(G_RANGE_CHECK)
1502  if (index < 0 || index >= size()) {
1503  throw GException::out_of_range(G_SET_BIN, "Event index", index, size());
1504  }
1505  #endif
1506 
1507  // Set indices
1508  m_bin.m_index = index;
1509  m_bin.m_idir = index / m_num_ebin;
1511  m_bin.m_iebin = index % m_num_ebin;
1512 
1513  // Set GSPIEventBin pointers
1522 
1523  // Return
1524  return;
1525 }
GEnergy * m_energy
Pointer to energy of bin.
const GGti & gti(void) const
Return Good Time Intervals.
Definition: GEvents.hpp:134
GSPIInstDir * m_dir
Pointer to direction of bin.
virtual void read(const GFits &file)
Read INTEGRAL/SPI event cube from Observation Group FITS file.
void init_members(void)
Initialise class members.
Definition: GEventCube.cpp:143
bool has_card(const int &cardno) const
Check existence of header card.
Definition: GFitsHDU.hpp:233
double * m_livetime
Livetime array.
const GSkyDir & spi_z(const int &ipt) const
Return SPI Z direction.
double * m_models
Models array.
Energy value class definition.
const GSkyDir & spi_x(const int &ipt) const
Return SPI X direction (pointing direction)
virtual std::string print(const GChatter &chatter=NORMAL) const
Print INTEGRAL/SPI event cube information.
double * m_livetime
Pointer to livetime of bin.
int m_ipt
Pointing index.
#define G_SET_BIN
int m_num_pt
Number of pointings.
const GSPIInstDir & dir(const int &ipt, const int &idet) const
Return instrument direction.
Sky direction class interface definition.
virtual GSPIEventCube * clone(void) const
Clone event cube.
GSPIInstDir * m_dir
Event direction array.
int size(void) const
Return number of energy boundaries.
Definition: GEbounds.hpp:163
GTime * m_time
Time array.
void init_members(void)
Initialise class members.
Definition: GEvents.cpp:176
void free_members(void)
Delete class members.
Definition: GEventCube.cpp:165
GSPIEventCube(void)
Void constructor.
const GFilename & filename(void) const
Return FITS filename.
Definition: GFits.hpp:313
#define G_SPI_Z
virtual GEventCube & operator=(const GEventCube &cube)
Assignment operator.
Definition: GEventCube.cpp:104
void read_models(const GFits &file)
Read models from INTEGRAL/SPI Observation Group.
void init_bin(void)
Initialise event bin.
virtual void clear(void)
Clear INTEGRAL/SPI instrument direction.
const GTime & tstop(void) const
Return stop time.
Definition: GEvents.hpp:158
int m_num_bgm
Number of background models.
int m_model_size
Size of model arrays.
void clear(void)
Clear time.
Definition: GTime.cpp:252
GEbounds m_ebounds
Energy boundaries covered by events.
Definition: GEvents.hpp:111
#define G_READ_EBDS
GSPIEventBin m_bin
Actual event bin.
int m_idir
Direction index.
INTEGRAL/SPI event bin container class definition.
double MeV(void) const
Return energy in MeV.
Definition: GEnergy.cpp:321
void read(const GFitsTable &table)
Read energy boundaries from FITS table.
Definition: GEbounds.cpp:761
Time class.
Definition: GTime.hpp:55
void detid(const int &detid)
Set detector identifier.
FITS file class.
Definition: GFits.hpp:63
double * m_counts
Counts array.
int spi_num_hdus(const GFits &fits, const std::string &extname)
Return number of HDU versions.
Definition: GSPITools.cpp:166
void read_dsp(const GFitsTable *dsp)
Read data from INTEGRAL/SPI &quot;SPI.-OBS.-DSP&quot; extension.
GEnergy emean(const int &index) const
Returns mean energy for a given energy interval.
Definition: GEbounds.cpp:1095
virtual void clear(void)
Clear INTEGRAL/SPI event bin.
virtual void load(const GFilename &filename)
Load INTEGRAL/SPI event cube from Observation Group.
int m_dsp_size
Size of DSP arrays.
#define G_READ_FITS
void dir(const GSkyDir &dir)
Set pointing direction.
int m_index
Dataspace index.
GEnergy * m_ewidth
Energy bin width array.
GEnergy ewidth(const int &index) const
Returns energy interval width.
Definition: GEbounds.cpp:1154
void append(const GTime &tstart, const GTime &tstop)
Append Good Time Interval.
Definition: GGti.cpp:269
void copy_members(const GSPIEventCube &cube)
Copy class members.
INTEGRAL/SPI instrument direction class.
Definition: GSPIInstDir.hpp:52
int m_gti_size
Size of GTI arrays.
virtual std::string string(const int &row, const int &inx=0) const =0
GTime spi_ijd2time(const double &ijd)
Convert IJD to GTime.
Definition: GSPITools.cpp:225
#define G_MODEL_COUNTS
#define G_NAXIS
void free_members(void)
Delete class members.
INTEGRAL/SPI event bin container class.
void saveto(const GFilename &filename, const bool &clobber=false)
Saves to specified FITS file.
Definition: GFits.cpp:1293
void free_members(void)
Delete class members.
double * m_ontime
Pointer to ontime of bin.
void read_gti(const GFitsTable *gti)
Read data from INTEGRAL/SPI &quot;SPI.-OBS.-GTI&quot; extension.
void read_pnt(const GFitsTable *pnt, const GFitsTable *gti)
Read pointing information.
GSkyDir * m_spix
SPI X axis array.
#define G_SPI_X
virtual GSPIEventBin * operator[](const int &index)
Event bin access operator.
Filename class.
Definition: GFilename.hpp:62
void free_members(void)
Delete class members.
Definition: GEvents.cpp:206
Abstract interface for FITS table column.
void read_ebds(const GFitsTable *ebds)
Read data from INTEGRAL/SPI &quot;SPI.-EBDS-SET&quot; extension.
const GFitsTable * spi_hdu(const GFits &fits, const std::string &extname, const int &extver=1)
Return FITS table.
Definition: GSPITools.cpp:57
std::vector< std::string > m_modnames
Model names.
virtual void clear(void)
Clear INTEGRAL/SPI event cube.
Abstract interface for FITS table.
Definition: GFitsTable.hpp:44
double livetime(void) const
Return total livetime.
GGti m_gti
Good time intervals covered by events.
Definition: GEvents.hpp:112
virtual void save(const GFilename &filename, const bool &clobber=false) const
Save INTEGRAL/SPI event cube into FITS file.
virtual GSPIEventCube & operator=(const GSPIEventCube &cube)
Assignment operator.
GChatter
Definition: GTypemaps.hpp:33
int integer(const std::string &keyname) const
Return card value as integer.
Definition: GFitsHDU.hpp:436
double * m_size
Event bin size array.
virtual int size(void) const
Return event cube size.
double * m_size
Pointer to size of bin.
void radec_deg(const double &ra, const double &dec)
Set equatorial sky direction (degrees)
Definition: GSkyDir.cpp:224
double * m_ontime
Ontime array.
void init_members(void)
Initialise class members.
void read_dti(const GFitsTable *dti)
Read data from INTEGRAL/SPI &quot;SPI.-OBS.-DTI&quot; extension.
const std::string & ptid(const int &ipt) const
Return pointing identifier.
std::string url(void) const
Return Uniform Resource Locator (URL)
Definition: GFilename.hpp:189
void clear(void)
Clear sky direction.
Definition: GSkyDir.cpp:164
double * m_models
Pointer to models of bin.
virtual int integer(const int &row, const int &inx=0) const =0
GSkyDir * m_spiz
SPI Z axis array.
virtual double real(const int &row, const int &inx=0) const =0
void alloc_data(void)
Allocate data.
const GEnergy & emin(void) const
Return minimum energy.
Definition: GEvents.hpp:170
virtual void write(GFits &file) const
Write INTEGRAL/SPI event cube into FITS file.
int m_num_sky
Number of sky models.
GTime * m_time
Pointer to time of bin.
double * m_counts
Pointer to number of counts.
std::string string(const std::string &keyname) const
Return card value as string.
Definition: GFitsHDU.hpp:410
int m_iebin
Energy bin index.
INTEGRAL/SPI event bin class.
#define G_DIR
double ontime(void) const
Return total ontime.
#define G_PTID
std::string * m_ptid
Pointing identifiers.
virtual int naxis(const int &axis) const
Return number of bins in axis.
GEnergy * m_energy
Energy array.
int m_num_ebin
Number of energy bins.
virtual int number(void) const
Return number of events in cube.
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition: GTools.cpp:1143
virtual ~GSPIEventCube(void)
Destructor.
const GTime & tstart(void) const
Return start time.
Definition: GEvents.hpp:146
#define G_READ_PNT
Sky direction class.
Definition: GSkyDir.hpp:62
Abstract event bin container class.
Definition: GEventCube.hpp:46
void close(void)
Close FITS file.
Definition: GFits.cpp:1342
#define G_READ_MODELS
void set_bin(const int &index)
Set event bin.
Time class interface definition.
const GEnergy & emax(void) const
Return maximum energy.
Definition: GEvents.hpp:182
Definition of INTEGRAL/SPI tools.
INTEGRAL/SPI instrument direction class definition.
double * m_stat_err
Statistical error array.
void clear(void)
Clear instance.
Definition: GEnergy.cpp:261
int m_num_models
Number of models in bin.
int m_num_det
Number of detectors.
double model_counts(const int &index) const
Return number of events in model.
virtual int dim(void) const
Return event cube dimension.
Class that handles energies in a unit independent way.
Definition: GEnergy.hpp:48
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition: GTools.cpp:489