GammaLib  2.1.0.dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
GGti.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * GGti.cpp - Good time interval class *
3  * ----------------------------------------------------------------------- *
4  * copyright (C) 2008-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 GGti.cpp
23  * @brief Good time interval class implementation.
24  * @author Juergen Knoedlseder
25  */
26 
27 /* __ Includes ___________________________________________________________ */
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 #include "GException.hpp"
32 #include "GTools.hpp"
33 #include "GFilename.hpp"
34 #include "GGti.hpp"
35 #include "GFits.hpp"
36 #include "GFitsTable.hpp"
37 #include "GFitsBinTable.hpp"
38 #include "GFitsTableDoubleCol.hpp"
39 #include "GXmlElement.hpp"
40 
41 /* __ Method name definitions ____________________________________________ */
42 #define G_REDUCE "GGti::reduce(GTime&, GTime&)"
43 #define G_REMOVE "GGti::remove(int&)"
44 #define G_READ_XML "GGti::read(GXmlElement&)"
45 #define G_WRITE_XML "GGti::write(GXmlElement&)"
46 #define G_TSTART "GGti::tstart(int&)"
47 #define G_TSTOP "GGti::tstop(int&)"
48 #define G_INSERT_GTI "GGti::insert_gti(int&, GTime&, GTime&)"
49 
50 /* __ Macros _____________________________________________________________ */
51 
52 /* __ Coding definitions _________________________________________________ */
53 
54 /* __ Debug definitions __________________________________________________ */
55 
56 
57 /*==========================================================================
58  = =
59  = Constructors/destructors =
60  = =
61  ==========================================================================*/
62 
63 /***********************************************************************//**
64  * @brief Void constructor
65  *
66  * Constructs empty Good Time Intervals.
67  ***************************************************************************/
69 {
70  // Initialise class members
71  init_members();
72 
73  // Return
74  return;
75 }
76 
77 
78 /***********************************************************************//**
79  * @brief FITS file constructor
80  *
81  * @param[in] filename FITS file name.
82  *
83  * Constructs Good Time Intervals from a FITS file.
84  ***************************************************************************/
85 GGti::GGti(const GFilename& filename)
86 {
87  // Initialise members
88  init_members();
89 
90  // Load FITS file
91  load(filename);
92 
93  // Return
94  return;
95 }
96 
97 
98 /***********************************************************************//**
99  * @brief Copy constructor
100  *
101  * @param[in] gti Good Time Intervals.
102  *
103  * Constructs Good Time Intervals by copying other Good Time Intervals.
104  ***************************************************************************/
105 GGti::GGti(const GGti& gti)
106 {
107  // Initialise class members
108  init_members();
109 
110  // Copy members
111  copy_members(gti);
112 
113  // Return
114  return;
115 }
116 
117 
118 /***********************************************************************//**
119  * @brief XML element constructor
120  *
121  * @param[in] xml XML element.
122  *
123  * Constructs Good Time Intervals from an XML element.
124  ***************************************************************************/
126 {
127  // Initialise members
128  init_members();
129 
130  // Read Good Time Intervals from XML element
131  read(xml);
132 
133  // Return
134  return;
135 }
136 
137 
138 /***********************************************************************//**
139  * @brief Single time interval constructor
140  *
141  * @param[in] tstart Start time of interval.
142  * @param[in] tstop Stop time of interval.
143  *
144  * Constructs Good Time Intervals from a single time interval, given by
145  * [p@ tstart, @p tstop].
146  ***************************************************************************/
147 GGti::GGti(const GTime& tstart, const GTime& tstop)
148 {
149  // Initialise members
150  init_members();
151 
152  // Append time interval
153  append(tstart, tstop);
154 
155  // Return
156  return;
157 }
158 
159 
160 /***********************************************************************//**
161  * @brief Time reference constructor
162  *
163  * @param[in] ref Time reference.
164  *
165  * Constructs Good Time Intervals using a specific time reference. The time
166  * reference will be used when writing the Good Time Intervals into a FITS
167  * file.
168  ***************************************************************************/
170 {
171  // Initialise class members
172  init_members();
173 
174  // Set time reference
175  this->reference(ref);
176 
177  // Return
178  return;
179 }
180 
181 
182 /***********************************************************************//**
183  * @brief Destructor
184  ***************************************************************************/
186 {
187  // Free members
188  free_members();
189 
190  // Return
191  return;
192 }
193 
194 
195 /*==========================================================================
196  = =
197  = Operators =
198  = =
199  ==========================================================================*/
200 
201 /***********************************************************************//**
202  * @brief Assignment operator
203  *
204  * @param[in] gti Good Time Intervals.
205  * @return Good Time Intervals.
206  ***************************************************************************/
208 {
209  // Execute only if object is not identical
210  if (this != &gti) {
211 
212  // Free members
213  free_members();
214 
215  // Initialise private members
216  init_members();
217 
218  // Copy members
219  copy_members(gti);
220 
221  } // endif: object was not identical
222 
223  // Return this object
224  return *this;
225 }
226 
227 
228 /*==========================================================================
229  = =
230  = Public methods =
231  = =
232  ==========================================================================*/
233 
234 /***********************************************************************//**
235  * @brief Clear Good Time Intervals
236  ***************************************************************************/
237 void GGti::clear(void)
238 {
239  // Free members
240  free_members();
241 
242  // Initialise private members
243  init_members();
244 
245  // Return
246  return;
247 }
248 
249 
250 /***********************************************************************//**
251  * @brief Clone Good Time Intervals
252  *
253  * @return Pointer to deep copy of Good Time Intervals.
254  ***************************************************************************/
255 GGti* GGti::clone(void) const
256 {
257  return new GGti(*this);
258 }
259 
260 
261 /***********************************************************************//**
262  * @brief Append Good Time Interval
263  *
264  * @param[in] tstart Start time of interval.
265  * @param[in] tstop Stop time of interval.
266  *
267  * Appends a Good Time Interval at the end of the container.
268  ***************************************************************************/
269 void GGti::append(const GTime& tstart, const GTime& tstop)
270 {
271  // Insert GTI at end of list
272  insert_gti(m_num, tstart, tstop);
273 
274  // Return
275  return;
276 }
277 
278 
279 /***********************************************************************//**
280  * @brief Insert Good Time Interval
281  *
282  * @param[in] tstart Start time of interval.
283  * @param[in] tstop Stop time of interval.
284  *
285  * Inserts a Good Time Interval into the container after the first interval
286  * that has a start time smaller than @p tstart. The method implicitely
287  * assumes that the Good Time Intervals are ordered by increasing start time.
288  ***************************************************************************/
289 void GGti::insert(const GTime& tstart, const GTime& tstop)
290 {
291  // Determine index at which GTI should be inserted
292  int inx = 0;
293  for (; inx < m_num; ++inx) {
294  if (tstart < m_start[inx]) {
295  break;
296  }
297  }
298 
299  // Insert interval
300  insert_gti(inx, tstart, tstop);
301 
302  // Return
303  return;
304 }
305 
306 
307 /***********************************************************************//**
308  * @brief Merge all overlapping Good Time Intervals
309  *
310  * Merges all overlapping or connecting successive Good Time Intervals. The
311  * method implicitely assumes that the intervals are ordered by increasing
312  * start time.
313  *
314  * Note that the method does not actually reduce the memory size but just
315  * updates the information on the number of elements in the array.
316  ***************************************************************************/
317 void GGti::merge(void)
318 {
319  // Find overlaps
320  int i = 0;
321  int num = m_num;
322  while (i < num-1) {
323 
324  // If GTI overlaps with following one then merge both GTIs, move
325  // all remaining GTIs one position up, and reduce number of elements
326  if (m_start[i+1] <= m_stop[i]) {
327  m_start[i] = (m_start[i] < m_start[i+1]) ? m_start[i] : m_start[i+1];
328  m_stop[i] = (m_stop[i] > m_stop[i+1]) ? m_stop[i] : m_stop[i+1];
329  for (int k = i+2; k < num; ++k) {
330  m_start[k-1] = m_start[k];
331  m_stop[k-1] = m_stop[k];
332  }
333  num--;
334  }
335 
336  // Otherwise increment GTI index
337  else {
338  i++;
339  }
340 
341  } // endwhile: there were still GTIs to check
342 
343  // Update number of elements in GTI
344  m_num = num;
345 
346  // Update attributes
347  set_attributes();
348 
349  // Return
350  return;
351 }
352 
353 
354 /***********************************************************************//**
355  * @brief Merge Good Time Interval into container
356  *
357  * @param[in] tstart Start time of interval.
358  * @param[in] tstop Stop time of interval.
359  *
360  * Inserts a Good Time Interval into the container after the first interval
361  * that has a start time smaller than @p tstart and then merges any
362  * overlapping or connecting Good Time Intervals. The method implicitely
363  * assumes that the intervals are ordered by increasing start time.
364  ***************************************************************************/
365 void GGti::merge(const GTime& tstart, const GTime& tstop)
366 {
367  // Determine index at which GTI should be inserted
368  int inx = 0;
369  for (int i = 0; i < m_num; ++i) {
370  if (tstart < m_start[i]) {
371  break;
372  }
373  }
374 
375  // Insert GTI
376  insert_gti(inx, tstart, tstop);
377 
378  // Merge any overlapping GTIs
379  merge();
380 
381  // Return
382  return;
383 }
384 
385 
386 /***********************************************************************//**
387  * @brief Reduce Good Time Intervals to specified interval
388  *
389  * @param[in] tstart Start time of interval.
390  * @param[in] tstop Stop time of interval.
391  *
392  * @exception GException::invalid_argument
393  * Start time is later than stop time
394  *
395  * Reduces the Good Time Intervals to the specified interval. Reducing means
396  * that all Good Time Intervals are dropped that fall outside the specified
397  * interval [@p tstart, @p tstop], and Good Time Intervals will be limited
398  * to >@p tstart and <=@p tstop in case that their boundaries are outside
399  * [@p tstart, @p tstop].
400  ***************************************************************************/
401 void GGti::reduce(const GTime& tstart, const GTime& tstop)
402 {
403  // Throw an exception if time interval is invalid
404  if (tstart > tstop) {
405  std::string msg = "Invalid time interval specified. Start time "+
406  tstart.print(NORMAL)+" can not be later than "
407  "stop time "+tstop.print(NORMAL)+".";
409  }
410 
411  // Adjust existing GTIs. This will limit all GTIs to [tstart,tstop].
412  // All GTIs outside [tstart,tstop] will have start > stop. The number
413  // of valid GTIs will also be determined.
414  int num = 0;
415  for (int i = 0; i < m_num; ++i) {
416  if (m_start[i] < tstart) {
417  m_start[i] = tstart;
418  }
419  if (m_stop[i] > tstop) {
420  m_stop[i] = tstop;
421  }
422  if (m_start[i] <= m_stop[i]) {
423  num++;
424  }
425  }
426 
427  // If we still have valid GTIs then allocate memory for them, copy
428  // over the start and stop times, and update the attributes
429  if (num > 0) {
430 
431  // Allocate new intervals
432  GTime* start = new GTime[num];
433  GTime* stop = new GTime[num];
434 
435  // Copy valid intervals
436  for (int i = 0; i < m_num; ++i) {
437  if (m_start[i] <= m_stop[i]) {
438  start[i] = m_start[i];
439  stop[i] = m_stop[i];
440  }
441  }
442 
443  // Free old memory
444  if (m_start != NULL) delete [] m_start;
445  if (m_stop != NULL) delete [] m_stop;
446 
447  // Set new memory
448  m_start = start;
449  m_stop = stop;
450 
451  // Set attributes
452  m_num = num;
453  set_attributes();
454 
455  } // endif: there were still valid GTIs
456 
457  // ... otherwise we remove all GTIs
458  else {
459  clear();
460  }
461 
462  // Return
463  return;
464 }
465 
466 
467 /***********************************************************************//**
468  * @brief Reduce Good Time Intervals to specified intervals
469  *
470  * @param[in] gti Good Time Intervals.
471  *
472  * Reduces the Good Time Intervals to the specified intervals. Reducing means
473  * that the resulting Good Time Intervals are the intersection between the
474  * initial Good Time Intervals and the specified Good Time Intervals.
475  *
476  * Specifically, all Good Time Intervals are dropped that do not overlap
477  * with one of the specified intervals, and overlapping intervals will be
478  * reduced to the overlapping time intervals, eventually splitting a Good
479  * Time Interval into several overlapping intervals.
480  ***************************************************************************/
481 void GGti::reduce(const GGti& gti)
482 {
483  // Determine maximum size of reduced Good Time Intervals. Continue only
484  // if the size if positive
485  int size = m_num + gti.m_num;
486  if (size > 0) {
487 
488  // Initialise tstart and tstop vectors for resulting Good Time
489  // Intervals
490  std::vector<GTime> tstart_reduced;
491  std::vector<GTime> tstop_reduced;
492  tstart_reduced.reserve(size);
493  tstop_reduced.reserve(size);
494 
495  // Loop over all GTIs and reduce them to the specified intervals
496  for (int i = 0; i < m_num; ++i) {
497 
498  // Loop over all intervals to which the Good Time Intervals
499  // should be reduced
500  for (int k = 0; k < gti.size(); ++k) {
501 
502  // If GTI starts after interval then skip
503  if (m_start[i] >= gti.m_stop[k]) {
504  continue;
505  }
506 
507  // ... otherwise if GTI stops before interval then skip
508  else if (m_stop[i] <= gti.m_start[k]) {
509  continue;
510  }
511 
512  // ... otherwise there is an overlap and we reduce the
513  // interval to the overlapping interval. If this results
514  // in a positive interval we append the interval to the
515  // vector of reduced start and stop times
516  else {
517  GTime tstart = m_start[i];
518  GTime tstop = m_stop[i];
519  if (tstart < gti.m_start[k]) {
520  tstart = gti.m_start[k];
521  }
522  if (tstop > gti.m_stop[k]) {
523  tstop = gti.m_stop[k];
524  }
525  if (tstop > tstart) {
526  tstart_reduced.push_back(tstart);
527  tstop_reduced.push_back(tstop);
528  }
529  }
530 
531  } // endfor: looped over intervals
532 
533  } // endfor: looped over GTIs
534 
535  // If there are reduced GTIs then allocate memory for them, set
536  // the start and stop times, and update the attributes
537  int num = tstart_reduced.size();
538  if (num > 0) {
539 
540  // Allocate new intervals
541  GTime* start = new GTime[num];
542  GTime* stop = new GTime[num];
543 
544  // Set intervals
545  for (int i = 0; i < num; ++i) {
546  start[i] = tstart_reduced[i];
547  stop[i] = tstop_reduced[i];
548  }
549 
550  // Free old memory
551  if (m_start != NULL) delete [] m_start;
552  if (m_stop != NULL) delete [] m_stop;
553 
554  // Set new memory
555  m_start = start;
556  m_stop = stop;
557 
558  // Set attributes
559  m_num = num;
560  set_attributes();
561 
562  } // endif: there were still valid GTIs
563 
564  // ... otherwise we remove all GTIs
565  else {
566  clear();
567  }
568 
569  } // endif: there were elements to be reduced
570 
571  // Return
572  return;
573 }
574 
575 
576 /***********************************************************************//**
577  * @brief Remove Good Time Interval
578  *
579  * @param[in] index Good Time Interval index [0,...,size()[.
580  *
581  * Removes Good Time Interval at @p index from the container. All intervals
582  * after the specified @p index are moved forward by one position.
583  *
584  * Note that the method does not actually reduce the memory size but just
585  * updates the information on the number of elements in the array.
586  ***************************************************************************/
587 void GGti::remove(const int& index)
588 {
589  #if defined(G_RANGE_CHECK)
590  // If index is outside boundary then throw an error
591  if (index < 0 || index >= m_num) {
592  throw GException::out_of_range(G_REMOVE, "Good Time Interval index",
593  index, m_num);
594  }
595  #endif
596 
597  // Move all elements located after index forward
598  for (int i = index+1; i < m_num; ++i) {
599  m_start[i-1] = m_start[i];
600  m_stop[i-1] = m_stop[i];
601  }
602 
603  // Reduce number of elements by one
604  m_num--;
605 
606  // Update attributes
607  set_attributes();
608 
609  // Return
610  return;
611 }
612 
613 
614 /***********************************************************************//**
615  * @brief Append Good Time Intervals
616  *
617  * @param[in] gti Good Time Intervals.
618  *
619  * Append Good Time Intervals to the container. The method performs automatic
620  * time reference conversion in case that the specified Good Time Intervals
621  * @p gti have a time reference that differs from that of the current
622  * instance.
623  ***************************************************************************/
624 void GGti::extend(const GGti& gti)
625 {
626  // Do nothing if Good Time Intervals are empty
627  if (!gti.is_empty()) {
628 
629  // Allocate new intervals
630  int num = m_num+gti.size();
631  GTime* start = new GTime[num];
632  GTime* stop = new GTime[num];
633 
634  // Initialise index
635  int inx = 0;
636 
637  // Copy existing intervals
638  for (; inx < m_num; ++inx) {
639  start[inx] = m_start[inx];
640  stop[inx] = m_stop[inx];
641  }
642 
643  // Append intervals. Convert to GTI reference on the fly.
644  for (int i = 0; i < gti.size(); ++i, ++inx) {
645  double tstart = gti.m_start[i].convert(m_reference);
646  double tstop = gti.m_stop[i].convert(m_reference);
647  start[inx].set(tstart, m_reference);
648  stop[inx].set(tstop, m_reference);
649  }
650 
651  // Free memory
652  if (m_start != NULL) delete [] m_start;
653  if (m_stop != NULL) delete [] m_stop;
654 
655  // Set new memory
656  m_start = start;
657  m_stop = stop;
658 
659  // Set number of elements
660  m_num = num;
661 
662  // Set attributes
663  set_attributes();
664 
665  } // endif: Good Time Intervals were not empty
666 
667  // Return
668  return;
669 }
670 
671 
672 
673 /***********************************************************************//**
674  * @brief Load Good Time Intervals from FITS file
675  *
676  * @param[in] filename FITS filename.
677  *
678  * Loads the Good Time Intervals from FITS file.
679  *
680  * If no extension name is provided in the @p filename, the Good Time
681  * Intervals are loaded from the `GTI` extension.
682  ***************************************************************************/
683 void GGti::load(const GFilename& filename)
684 {
685  // Open FITS file
686  GFits fits(filename);
687 
688  // Get GTI table
689  const GFitsTable& table =
690  *fits.table(filename.extname(gammalib::extname_gti));
691 
692  // Read GTI from table
693  read(table);
694 
695  // Close FITS file
696  fits.close();
697 
698  // Return
699  return;
700 }
701 
702 
703 /***********************************************************************//**
704  * @brief Save Good Time Intervals into FITS file
705  *
706  * @param[in] filename FITS filename.
707  * @param[in] clobber Overwrite an existing Good Time Interval extension?
708  *
709  * Saves Good Time Intervals into a FITS file. If a file with the given
710  * @p filename does not yet exist it will be created, otherwise the method
711  * opens the existing file. Good Time Intervals can only be appended to an
712  * existing file if the @p clobber flag is set to `true` (otherwise an
713  * exception is thrown).
714  *
715  * The method will append a binary FITS table containing the Good Time
716  * Intervals to the FITS file. The extension name can be specified as part
717  * of the @p filename. For example the @p filename
718  *
719  * myfile.fits[GOOD TIME INTERVALS]
720  *
721  * will save the Good Time Intervals in the `GOOD TIME INTERVALS` extension
722  * of the `myfile.fits` file. If the extension exists already in the file it
723  * will be replaced, otherwise a new extension will be created. If no
724  * extension name is provided, the method will use `GTI` as the default
725  * extension name for Good Time Intervals.
726  ***************************************************************************/
727 void GGti::save(const GFilename& filename, const bool& clobber) const
728 {
729  // Open or create FITS file (without extension name since the requested
730  // extension may not yet exist in the file)
731  GFits fits(filename.url(), true);
732 
733  // Write GTI to FITS object
734  write(fits, filename.extname(gammalib::extname_gti));
735 
736  // Save to file
737  fits.save(clobber);
738 
739  // Return
740  return;
741 }
742 
743 
744 /***********************************************************************//**
745  * @brief Read Good Time Intervals and time reference from FITS table
746  *
747  * @param[in] table FITS table.
748  *
749  * Reads the Good Time Intervals and time reference from a FITS table. The
750  * start and stop times of the Good Time Intervals are read from the "START"
751  * and "STOP" columns.
752  ***************************************************************************/
753 void GGti::read(const GFitsTable& table)
754 {
755  // Clear object
756  clear();
757 
758  // Read time reference
759  m_reference.read(table);
760 
761  // Extract GTI information from FITS table
762  m_num = table.integer("NAXIS2");
763  if (m_num > 0) {
764 
765  // Set GTIs
766  m_start = new GTime[m_num];
767  m_stop = new GTime[m_num];
768  for (int i = 0; i < m_num; ++i) {
769  m_start[i].set(table["START"]->real(i), m_reference);
770  m_stop[i].set(table["STOP"]->real(i), m_reference);
771  }
772 
773  // Set attributes
774  set_attributes();
775 
776  }
777 
778  // Return
779  return;
780 }
781 
782 
783 /***********************************************************************//**
784  * @brief Write Good Time Intervals and time reference into FITS object
785  *
786  * @param[in] fits FITS file.
787  * @param[in] extname GTI extension name.
788  *
789  * Writes Good Time Intervals and time reference into a FITS object. If an
790  * extension with the same name does already exist in the FITS object, the
791  * values in that extension will be replaced.
792  *
793  * The start and stop tims of the Good Time Intervals will be written into
794  * double precision columns named `START` and `STOP`.
795  ***************************************************************************/
796 void GGti::write(GFits& fits, const std::string& extname) const
797 {
798  // Create GTI columns
799  GFitsTableDoubleCol cstart("START", m_num);
800  GFitsTableDoubleCol cstop("STOP", m_num);
801 
802  // Fill GTI columns in specified time reference
803  for (int i = 0; i < m_num; ++i) {
804  cstart(i) = m_start[i].convert(m_reference);
805  cstop(i) = m_stop[i].convert(m_reference);
806  }
807 
808  // Create GTI table
809  GFitsBinTable table(m_num);
810  table.append(cstart);
811  table.append(cstop);
812  table.extname(extname);
813 
814  // Write time reference into table
815  m_reference.write(table);
816 
817  // If the FITS object contains already an extension with the same
818  // name then remove now this extension
819  if (fits.contains(extname)) {
820  fits.remove(extname);
821  }
822 
823  // Append GTI table to FITS file
824  fits.append(table);
825 
826  // Return
827  return;
828 }
829 
830 
831 /***********************************************************************//**
832  * @brief Read Good Time Intervals from XML element
833  *
834  * @param[in] xml XML element.
835  *
836  * @exception GException::invalid_value
837  * Invalid XML format encountered.
838  *
839  * Read Good Time Intervals from an XML element. The format of the Good Time
840  * Intervals is either
841  *
842  * <parameter name="GoodTimeIntervals" file="..."/>
843  *
844  * in case that the information is stored in a FITS file, or
845  *
846  * <parameter name="GoodTimeIntervals" tmin="..." tmax="..."/>
847  *
848  * if the Good Time Intervals should be constructed from a start and stop
849  * time (the units of the @a tmin and @a tmax parameters are seconds). In the
850  * latter case, the method also expects that the time reference is provided
851  * as parameter in the @p xml element.
852  ***************************************************************************/
853 void GGti::read(const GXmlElement& xml)
854 {
855  // Clear energy boundaries
856  clear();
857 
858  // Get GTI parameter
859  const GXmlElement* par = gammalib::xml_get_par(G_READ_XML, xml, "GoodTimeIntervals");
860 
861  // If we have a "file" attribute then load GTIs from file ...
862  if (par->has_attribute("file")) {
863 
864  // Get filename
865  std::string filename = par->attribute("file");
866 
867  // Load GTIs from file
868  load(filename);
869 
870  // Store filename (we need to do this after loading as the
871  // load method calls the read method that clears the object
872  m_xml_filename = filename;
873 
874  }
875 
876  // ... otherwise if "tmin" and "tmax" attributes are found then set
877  // the GTIs from these attributes and also read the time reference
878  // from the XML file
879  else if (par->has_attribute("tmin") && par->has_attribute("tmax")) {
880 
881  // Read time reference first (needed before reading times!)
882  m_reference.read(xml);
883 
884  // Create GTI from "tmin" and "tmax" attributes
885  double tmin = gammalib::todouble(par->attribute("tmin"));
886  double tmax = gammalib::todouble(par->attribute("tmax"));
887  append(GTime(tmin, m_reference), GTime(tmax, m_reference));
888 
889  }
890 
891  // ... otherwise throw an exception
892  else {
893  std::string msg = "Attributes \"file\" or \"tmin\" and \"tmax\" not "
894  "found in XML parameter \"GoodTimeIntervals\". "
895  "Please verify the observation definition XML "
896  "file.";
898  }
899 
900  // Return
901  return;
902 }
903 
904 
905 /***********************************************************************//**
906  * @brief Write Good Time Intervals into XML element
907  *
908  * @param[in] xml XML element.
909  *
910  * Writes Good Time Intervals into an XML element. The format of the Good
911  * Time Intervals is
912  *
913  * <parameter name="GoodTimeIntervals" file="..."/>
914  *
915  * if a file name has been specified previously upon reading from an XML
916  * file. In that case, the method will also write the Good Time Intervals to
917  * the specified file. If no file name is available, the method will write
918  * the first start and the last stop time of the Good Time Intervals in the
919  * format
920  *
921  * <parameter name="GoodTimeIntervals" tmin="..." tmax="..."/>
922  *
923  * The units of the @a tmin and @a tmax parameters are seconds. In that case,
924  * the time reference is also written into the XML element.
925  *
926  * This method does nothing if the Good Time Intervals are empty.
927  ***************************************************************************/
928 void GGti::write(GXmlElement& xml) const
929 {
930  // Continue only if there are GTIs
931  if (!is_empty()) {
932 
933  // Get parameter
934  GXmlElement* par =
935  gammalib::xml_need_par(G_WRITE_XML, xml, "GoodTimeIntervals");
936 
937  // If we have a file name then write the "file" attribute ...
938  if (!m_xml_filename.is_empty()) {
939 
940  // Write "file" attribute
941  par->attribute("file", m_xml_filename);
942 
943  // Write GTI file
944  save(m_xml_filename, true);
945 
946  }
947 
948  // ... otherwise write "tmin" and "tmax" attributes and write the
949  // time reference
950  else {
951 
952  // Write time interval
953  par->attribute("tmin", gammalib::str(tstart().convert(m_reference)));
954  par->attribute("tmax", gammalib::str(tstop().convert(m_reference)));
955 
956  // Write time reference
957  m_reference.write(xml);
958 
959  }
960 
961  } // endif: GTIs were not empty
962 
963  // Return
964  return;
965 }
966 
967 
968 /***********************************************************************//**
969  * @brief Returns start time for a given Good Time Interval
970  *
971  * @param[in] index Good Time Interval index [0,...,size()[.
972  * @return Start time.
973  *
974  * @exception GException::out_of_range
975  * Specified index is out of range.
976  ***************************************************************************/
977 const GTime& GGti::tstart(const int& index) const
978 {
979  #if defined(G_RANGE_CHECK)
980  // If index is outside boundary then throw an error
981  if (index < 0 || index >= m_num) {
982  throw GException::out_of_range(G_TSTART, "Good Time Interval index",
983  index, m_num);
984  }
985  #endif
986 
987  // Return
988  return (m_start[index]);
989 }
990 
991 
992 /***********************************************************************//**
993  * @brief Returns stop time for a given Good Time Interval
994  *
995  * @param[in] index Good Time Interval index [0,...,size()[.
996  * @return Stop time.
997  *
998  * @exception GException::out_of_range
999  * Specified index is out of range.
1000  ***************************************************************************/
1001 const GTime& GGti::tstop(const int& index) const
1002 {
1003  #if defined(G_RANGE_CHECK)
1004  // If index is outside boundary then throw an error
1005  if (index < 0 || index >= m_num) {
1006  throw GException::out_of_range(G_TSTOP, "Good Time Interval index",
1007  index, m_num);
1008  }
1009  #endif
1010 
1011  // Return
1012  return (m_stop[index]);
1013 }
1014 
1015 
1016 /***********************************************************************//**
1017  * @brief Computes overlap of time interval with GTIs
1018  *
1019  * @param[in] tstart Start time of interval.
1020  * @param[in] tstop Stop time of interval.
1021  * @return Overlap (seconds).
1022  *
1023  * Returns the overlap of time interval with GTIs in seconds.
1024  ***************************************************************************/
1025 double GGti::overlap(const GTime& tstart, const GTime& tstop) const
1026 {
1027  // Initialise overlap
1028  double overlap = 0.0;
1029 
1030  // Compute the overlap
1031  for (int i = 0; i < m_num; ++i) {
1032  if (m_start[i] < tstart) {
1033  if (m_stop[i] > tstart) {
1034  if (m_stop[i] > tstop) {
1035  overlap += tstop - tstart;
1036  }
1037  else {
1038  overlap += m_stop[i] - tstart;
1039  }
1040  }
1041  }
1042  else if (m_stop[i] > tstop) {
1043  if (m_start[i] < tstop) {
1044  overlap += tstop - m_start[i];
1045  }
1046  }
1047  else {
1048  overlap += m_stop[i] - m_start[i];
1049  }
1050  }
1051 
1052  // Return
1053  return overlap;
1054 }
1055 
1056 
1057 /***********************************************************************//**
1058  * @brief Checks whether Good Time Intervals contains time
1059  *
1060  * @param[in] time Time to be checked.
1061  *
1062  * Checks if a given @p time falls in at least one of the Good Time
1063  * Intervals. The method exits when the first matching interval has been
1064  * found.
1065  *
1066  * Since this method may be called repeadetly while scanning an ordered list
1067  * of time it is most efficient to start the search always at the index where
1068  * the last search was successful.
1069  ***************************************************************************/
1070 bool GGti::contains(const GTime& time) const
1071 {
1072  // Initialise test
1073  bool found = false;
1074 
1075  // Start GTIs search from the last successful index
1076  for (int i = m_last_index; i < m_num; ++i) {
1077  if (time >= m_start[i] && time <= m_stop[i]) {
1078  found = true;
1079  m_last_index = i;
1080  break;
1081  }
1082  }
1083 
1084  // If no GTI has been found then search now from the start of the list
1085  if (!found) {
1086  for (int i = 0; i < m_last_index; ++i) {
1087  if (time >= m_start[i] && time <= m_stop[i]) {
1088  found = true;
1089  m_last_index = i;
1090  break;
1091  }
1092  }
1093  }
1094 
1095  // Return result
1096  return found;
1097 }
1098 
1099 
1100 /***********************************************************************//**
1101  * @brief Print Good Time Intervals
1102  *
1103  * @param[in] chatter Chattiness.
1104  * @return String containing Good Time Interval information.
1105  ***************************************************************************/
1106 std::string GGti::print(const GChatter& chatter) const
1107 {
1108  // Initialise result string
1109  std::string result;
1110 
1111  // Continue only if chatter is not silent
1112  if (chatter != SILENT) {
1113 
1114  // Append header
1115  result.append("=== GGti ===");
1116 
1117  // Append GTI information
1118  result.append("\n"+gammalib::parformat("Number of intervals"));
1119  result.append(gammalib::str(size()));
1120  result.append("\n"+gammalib::parformat("Ontime"));
1121  result.append(gammalib::str(ontime())+" sec");
1122  result.append("\n"+gammalib::parformat("Elapsed time"));
1123  result.append(gammalib::str(telapse())+" sec");
1124  result.append("\n"+gammalib::parformat("MJD range"));
1125  result.append(gammalib::str(tstart().mjd()));
1126  result.append(" - ");
1127  result.append(gammalib::str(tstop().mjd()));
1128  result.append(" "+reference().timeunit());
1129  result.append(" ("+reference().timesys()+")");
1130  result.append("\n"+gammalib::parformat("UTC range"));
1131  result.append(tstart().utc());
1132  result.append(" - ");
1133  result.append(tstop().utc());
1134  result.append(" "+reference().timeunit());
1135  result.append(" ("+reference().timesys()+")");
1136 
1137  // Append reference MJD
1138  result.append("\n"+gammalib::parformat("Reference MJD"));
1139  result.append(gammalib::str(reference().mjdref()));
1140 
1141  // EXPLICIT: Append time reference information
1142  if (chatter >= EXPLICIT) {
1143  result.append("\n"+reference().print(chatter));
1144  }
1145 
1146  // Optionally append XML filename
1147  if (!m_xml_filename.is_empty()) {
1148  result.append("\n"+gammalib::parformat("File name"));
1149  result.append(m_xml_filename);
1150  }
1151 
1152  } // endif: chatter was not silent
1153 
1154  // Return result
1155  return result;
1156 }
1157 
1158 
1159 /*==========================================================================
1160  = =
1161  = Private methods =
1162  = =
1163  ==========================================================================*/
1164 
1165 /***********************************************************************//**
1166  * @brief Initialise class members
1167  ***************************************************************************/
1169 {
1170  // Initialise members
1171  m_num = 0;
1172  m_tstart.clear();
1173  m_tstop.clear();
1175  m_ontime = 0.0;
1176  m_telapse = 0.0;
1177  m_start = NULL;
1178  m_stop = NULL;
1179 
1180  // Initialise computation cache
1181  m_last_index = 0;
1182 
1183  // Initialise time reference with native reference
1184  GTime time;
1185  m_reference = time.reference();
1186 
1187  // Return
1188  return;
1189 }
1190 
1191 
1192 /***********************************************************************//**
1193  * @brief Copy class members
1194  *
1195  * @param[in] gti Good Time Intervals.
1196  ***************************************************************************/
1197 void GGti::copy_members(const GGti& gti)
1198 {
1199  // Copy attributes
1200  m_num = gti.m_num;
1201  m_tstart = gti.m_tstart;
1202  m_tstop = gti.m_tstop;
1203  m_ontime = gti.m_ontime;
1204  m_telapse = gti.m_telapse;
1205  m_reference = gti.m_reference;
1207 
1208  // Copy start/stop times
1209  if (m_num > 0) {
1210  m_start = new GTime[m_num];
1211  m_stop = new GTime[m_num];
1212  for (int i = 0; i < m_num; ++i) {
1213  m_start[i] = gti.m_start[i];
1214  m_stop[i] = gti.m_stop[i];
1215  }
1216  }
1217 
1218  // Copy computation cache
1219  m_last_index = gti.m_last_index;
1220 
1221  // Return
1222  return;
1223 }
1224 
1225 
1226 /***********************************************************************//**
1227  * @brief Delete class members
1228  ***************************************************************************/
1230 {
1231  // Free memory
1232  if (m_start != NULL) delete [] m_start;
1233  if (m_stop != NULL) delete [] m_stop;
1234 
1235  // Signal free pointers
1236  m_start = NULL;
1237  m_stop = NULL;
1238 
1239  // Return
1240  return;
1241 }
1242 
1243 
1244 /***********************************************************************//**
1245  * @brief Set class attributes
1246  *
1247  * Compute the following class attributes:
1248  *
1249  * m_tstart - Earliest start time of GTIs
1250  * m_stop - Latest stop time of GTIs
1251  * m_telapse - Latest stop time minus earliest start time of GTIs [sec]
1252  * m_ontime - Sum of all intervals [sec]
1253  ***************************************************************************/
1255 {
1256  // If there are intervals then determine the start and stop time
1257  // from these intervals ...
1258  if (m_num > 0) {
1259  m_tstart = m_start[0];
1260  m_tstop = m_stop[0];
1261  for (int i = 1; i < m_num; ++i) {
1262  if (m_start[i] < m_tstart) m_tstart = m_start[i];
1263  if (m_stop[i] > m_tstop) m_tstop = m_stop[i];
1264  }
1265  }
1266 
1267  // ... otherwise clear the start and stop time
1268  else {
1269  m_tstart.clear();
1270  m_tstop.clear();
1271  }
1272 
1273  // Set attributes
1275  m_ontime = 0.0;
1276  for (int i = 0; i < m_num; ++i) {
1277  m_ontime += (m_stop[i].secs() - m_start[i].secs());
1278  }
1279 
1280  // Return
1281  return;
1282 }
1283 
1284 
1285 /***********************************************************************//**
1286  * @brief Insert Good Time Interval
1287  *
1288  * @param[in] index Index at which interval is inserted.
1289  * @param[in] tstart Start time of interval.
1290  * @param[in] tstop Stop time of interval.
1291  *
1292  * @exception GException::invalid_argument
1293  * Start time later than stop time
1294  *
1295  * Inserts a Good Time Interval at the specified @p index in the Good
1296  * Time Intervals. The method does not reorder the intervals by time,
1297  * instead the client needs to determine the approriate @p index.
1298  *
1299  * Invalid parameters do not produce any exception, but are handled
1300  * transparently. If the interval is invalid (i.e. @p tstart > @p tstop)
1301  * an exception is thrown. If the @p index is out of the valid range, the
1302  * index will be adjusted to either the first or the last element.
1303  ***************************************************************************/
1304 void GGti::insert_gti(const int& index, const GTime& tstart, const GTime& tstop)
1305 {
1306  // Throw an exception if time interval is invalid
1307  if (tstart > tstop) {
1308  std::string msg = "Invalid time interval specified. Start time "+
1309  tstart.print(NORMAL)+" can not be later than "
1310  "stop time "+tstop.print(NORMAL)+".";
1312  }
1313 
1314  // Set index
1315  int inx = index;
1316 
1317  // If inx is out of range then adjust it
1318  if (inx < 0) inx = 0;
1319  if (inx > m_num) inx = m_num;
1320 
1321  // Allocate new intervals
1322  int num = m_num+1;
1323  GTime* start = new GTime[num];
1324  GTime* stop = new GTime[num];
1325 
1326  // Copy intervals before GTI to be inserted
1327  for (int i = 0; i < inx; ++i) {
1328  start[i] = m_start[i];
1329  stop[i] = m_stop[i];
1330  }
1331 
1332  // Insert GTI
1333  start[inx] = tstart;
1334  stop[inx] = tstop;
1335 
1336  // Copy intervals after GTI to be inserted
1337  for (int i = inx+1; i < num; ++i) {
1338  start[i] = m_start[i-1];
1339  stop[i] = m_stop[i-1];
1340  }
1341 
1342  // Free memory
1343  if (m_start != NULL) delete [] m_start;
1344  if (m_stop != NULL) delete [] m_stop;
1345 
1346  // Set new memory
1347  m_start = start;
1348  m_stop = stop;
1349 
1350  // Set number of elements
1351  m_num = num;
1352 
1353  // Set attributes
1354  set_attributes();
1355 
1356  // Return
1357  return;
1358 }
virtual ~GGti(void)
Destructor.
Definition: GGti.cpp:185
bool contains(const GTime &time) const
Checks whether Good Time Intervals contains time.
Definition: GGti.cpp:1070
FITS table double column class interface definition.
double m_ontime
Sum of GTIs durations (in seconds)
Definition: GGti.hpp:124
GFitsTable * table(const int &extno)
Get pointer to table HDU.
Definition: GFits.cpp:482
int m_last_index
Last index for containment test.
Definition: GGti.hpp:132
bool contains(const int &extno) const
Check if HDU exists in FITS file.
Definition: GFits.hpp:282
GTimeReference reference(void) const
Returns native time reference.
Definition: GTime.cpp:1170
void insert(const GTime &tstart, const GTime &tstop)
Insert Good Time Interval.
Definition: GGti.cpp:289
const GTimeReference & reference(void) const
Return time reference for Good Time Intervals.
Definition: GGti.hpp:275
#define G_WRITE_XML
Definition: GGti.cpp:45
XML element node class interface definition.
GFilename m_xml_filename
XML filename.
Definition: GGti.hpp:129
void write(GFitsHDU &hdu) const
Write time reference into FITS header.
#define G_INSERT_GTI
Definition: GGti.cpp:48
void read(const GFitsHDU &hdu)
Read time reference from FITS header.
#define G_TSTART
Definition: GGti.cpp:46
bool is_empty(void) const
Signal if filename is empty.
Definition: GFilename.hpp:160
XML element node class.
Definition: GXmlElement.hpp:48
#define G_REMOVE
Definition: GGti.cpp:43
void clear(void)
Clear time.
Definition: GTime.cpp:252
std::string extname(const std::string &defaultname="") const
Return extension name.
Definition: GFilename.cpp:385
GFitsTableCol * append(const GFitsTableCol &column)
Append column to the table.
Definition: GFitsTable.hpp:147
void free_members(void)
Delete class members.
Definition: GGti.cpp:1229
GTimeReference m_reference
Time reference.
Definition: GGti.hpp:128
Time class.
Definition: GTime.hpp:55
Gammalib tools definition.
FITS file class.
Definition: GFits.hpp:63
const std::string extname_gti
Definition: GGti.hpp:44
FITS file class interface definition.
void insert_gti(const int &index, const GTime &tstart, const GTime &tstop)
Insert Good Time Interval.
Definition: GGti.cpp:1304
std::string print(const GChatter &chatter=NORMAL) const
Print Good Time Intervals.
Definition: GGti.cpp:1106
GGti * clone(void) const
Clone Good Time Intervals.
Definition: GGti.cpp:255
#define G_REDUCE
Definition: GGti.cpp:42
void init_members(void)
Initialise class members.
Definition: GGti.cpp:1168
void append(const GTime &tstart, const GTime &tstop)
Append Good Time Interval.
Definition: GGti.cpp:269
Good time interval class interface definition.
GGti(void)
Void constructor.
Definition: GGti.cpp:68
int size(void) const
Return number of Good Time Intervals.
Definition: GGti.hpp:154
double m_telapse
Time between start of first GTI and stop of last GTI (in seconds)
Definition: GGti.hpp:125
GGti & operator=(const GGti &gti)
Assignment operator.
Definition: GGti.cpp:207
void save(const GFilename &filename, const bool &clobber=false) const
Save Good Time Intervals into FITS file.
Definition: GGti.cpp:727
void clear(void)
Clear Good Time Intervals.
Definition: GGti.cpp:237
int m_num
Number of Good Time Intervals.
Definition: GGti.hpp:121
void remove(const int &extno)
Remove HDU from FITS file.
Definition: GFits.cpp:862
const GXmlAttribute * attribute(const int &index) const
Return attribute.
void load(const GFilename &filename)
Load Good Time Intervals from FITS file.
Definition: GGti.cpp:683
Filename class.
Definition: GFilename.hpp:62
bool has_attribute(const std::string &name) const
Check if element has a given attribute.
GXmlElement * xml_need_par(const std::string &origin, GXmlElement &xml, const std::string &name)
Return pointer to parameter with given name in XML element.
Definition: GTools.cpp:1637
Abstract interface for FITS table.
Definition: GFitsTable.hpp:44
GChatter
Definition: GTypemaps.hpp:33
int integer(const std::string &keyname) const
Return card value as integer.
Definition: GFitsHDU.hpp:436
void remove(const int &index)
Remove Good Time Interval.
Definition: GGti.cpp:587
std::string print(const GChatter &chatter=NORMAL) const
Print time.
Definition: GTime.cpp:1188
Good Time Interval class.
Definition: GGti.hpp:62
const GTime & tstop(void) const
Returns latest stop time in Good Time Intervals.
Definition: GGti.hpp:207
const std::string & extname(void) const
Return extension name.
Definition: GFitsHDU.hpp:162
void set_attributes(void)
Set class attributes.
Definition: GGti.cpp:1254
const GTime & tstart(void) const
Returns earliest start time in Good Time Intervals.
Definition: GGti.hpp:194
GTime m_tstart
Start time of Good Time Intervals.
Definition: GGti.hpp:122
#define G_TSTOP
Definition: GGti.cpp:47
const double & secs(void) const
Return time in seconds in native reference (TT)
Definition: GTime.hpp:156
void copy_members(const GGti &gti)
Copy class members.
Definition: GGti.cpp:1197
std::string url(void) const
Return Uniform Resource Locator (URL)
Definition: GFilename.hpp:189
void clear(void)
Clear file name.
Definition: GFilename.cpp:188
double overlap(const GTime &tstart, const GTime &tstop) const
Computes overlap of time interval with GTIs.
Definition: GGti.cpp:1025
GTime m_tstop
Stop time of Good Time Intervals.
Definition: GGti.hpp:123
void read(const GFitsTable &table)
Read Good Time Intervals and time reference from FITS table.
Definition: GGti.cpp:753
FITS binary table class.
#define G_READ_XML
Definition: GGti.cpp:44
Exception handler interface definition.
GFitsHDU * append(const GFitsHDU &hdu)
Append HDU to FITS file.
Definition: GFits.cpp:678
Implements a time reference.
FITS binary table class definition.
GTime * m_stop
Array of stop times.
Definition: GGti.hpp:127
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition: GTools.cpp:1143
const double & telapse(void) const
Returns elapsed time.
Definition: GGti.hpp:224
bool is_empty(void) const
Signal if there are no Good Time Intervals.
Definition: GGti.hpp:166
void write(GFits &fits, const std::string &extname=gammalib::extname_gti) const
Write Good Time Intervals and time reference into FITS object.
Definition: GGti.cpp:796
GTime * m_start
Array of start times.
Definition: GGti.hpp:126
void close(void)
Close FITS file.
Definition: GFits.cpp:1342
void set(const double &time, const GTimeReference &ref)
Set time given in specified reference.
Definition: GTime.cpp:1005
void extend(const GGti &gti)
Append Good Time Intervals.
Definition: GGti.cpp:624
const GXmlElement * xml_get_par(const std::string &origin, const GXmlElement &xml, const std::string &name)
Return pointer to parameter with given name in XML element.
Definition: GTools.cpp:1689
const double & ontime(void) const
Returns ontime.
Definition: GGti.hpp:240
double convert(const GTimeReference &ref) const
Return time in specified reference.
Definition: GTime.cpp:698
FITS table double column.
void reduce(const GTime &tstart, const GTime &tstop)
Reduce Good Time Intervals to specified interval.
Definition: GGti.cpp:401
Filename class interface definition.
double todouble(const std::string &arg)
Convert string into double precision value.
Definition: GTools.cpp:926
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition: GTools.cpp:489
FITS table abstract base class interface definition.
void merge(void)
Merge all overlapping Good Time Intervals.
Definition: GGti.cpp:317