GammaLib  1.7.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-2019 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 (int i = 0; i < m_num; ++i) {
294  if (tstart < m_start[i]) {
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  // Return
347  return;
348 }
349 
350 
351 /***********************************************************************//**
352  * @brief Merge Good Time Interval into container
353  *
354  * @param[in] tstart Start time of interval.
355  * @param[in] tstop Stop time of interval.
356  *
357  * Inserts a Good Time Interval into the container after the first interval
358  * that has a start time smaller than @p tstart and then merges any
359  * overlapping or connecting Good Time Intervals. The method implicitely
360  * assumes that the intervals are ordered by increasing start time.
361  ***************************************************************************/
362 void GGti::merge(const GTime& tstart, const GTime& tstop)
363 {
364  // Determine index at which GTI should be inserted
365  int inx = 0;
366  for (int i = 0; i < m_num; ++i) {
367  if (tstart < m_start[i]) {
368  break;
369  }
370  }
371 
372  // Insert GTI
373  insert_gti(inx, tstart, tstop);
374 
375  // Merge any overlapping GTIs
376  merge();
377 
378  // Return
379  return;
380 }
381 
382 
383 /***********************************************************************//**
384  * @brief Reduce Good Time Intervals to specified interval
385  *
386  * @param[in] tstart Start time of interval.
387  * @param[in] tstop Stop time of interval.
388  *
389  * @exception GException::invalid_argument
390  * Start time is later than stop time
391  *
392  * Reduces the Good Time Intervals to the specified interval. Reducing means
393  * that all Good Time Intervals are dropped that fall outside the specified
394  * interval [@p tstart, @p tstop], and Good Time Intervals will be limited
395  * to >@p tstart and <=@p tstop in case that their boundaries are outside
396  * [@p tstart, @p tstop].
397  ***************************************************************************/
398 void GGti::reduce(const GTime& tstart, const GTime& tstop)
399 {
400  // Throw an exception if time interval is invalid
401  if (tstart > tstop) {
402  std::string msg = "Invalid time interval specified. Start time "+
403  tstart.print(NORMAL)+" can not be later than "
404  "stop time "+tstop.print(NORMAL)+".";
406  }
407 
408  // Adjust existing GTIs. This will limit all GTIs to [tstart,tstop].
409  // All GTIs outside [tstart,tstop] will have start > stop. The number
410  // of valid GTIs will also be determined.
411  int num = 0;
412  for (int i = 0; i < m_num; ++i) {
413  if (m_start[i] < tstart) {
414  m_start[i] = tstart;
415  }
416  if (m_stop[i] > tstop) {
417  m_stop[i] = tstop;
418  }
419  if (m_start[i] <= m_stop[i]) {
420  num++;
421  }
422  }
423 
424  // If we still have valid GTIs then allocate memory for them, copy
425  // over the start and stop times, and update the attributes
426  if (num > 0) {
427 
428  // Allocate new intervals
429  GTime* start = new GTime[num];
430  GTime* stop = new GTime[num];
431 
432  // Copy valid intervals
433  for (int i = 0; i < m_num; ++i) {
434  if (m_start[i] <= m_stop[i]) {
435  start[i] = m_start[i];
436  stop[i] = m_stop[i];
437  }
438  }
439 
440  // Free old memory
441  if (m_start != NULL) delete [] m_start;
442  if (m_stop != NULL) delete [] m_stop;
443 
444  // Set new memory
445  m_start = start;
446  m_stop = stop;
447 
448  // Set attributes
449  m_num = num;
450  set_attributes();
451 
452  } // endif: there were still valid GTIs
453 
454  // ... otherwise we remove all GTIs
455  else {
456  clear();
457  }
458 
459  // Return
460  return;
461 }
462 
463 
464 /***********************************************************************//**
465  * @brief Remove Good Time Interval
466  *
467  * @param[in] index Good Time Interval index (0,...,size()-1).
468  *
469  * Removes Good Time Interval at @p index from the container. All intervals
470  * after the specified @p index are moved forward by one position.
471  *
472  * Note that the method does not actually reduce the memory size but just
473  * updates the information on the number of elements in the array.
474  ***************************************************************************/
475 void GGti::remove(const int& index)
476 {
477  #if defined(G_RANGE_CHECK)
478  // If index is outside boundary then throw an error
479  if (index < 0 || index >= m_num) {
480  throw GException::out_of_range(G_REMOVE, index, 0, m_num-1);
481  }
482  #endif
483 
484  // Move all elements located after index forward
485  for (int i = index+1; i < m_num; ++i) {
486  m_start[i-1] = m_start[i];
487  m_stop[i-1] = m_stop[i];
488  }
489 
490  // Reduce number of elements by one
491  m_num--;
492 
493  // Update attributes
494  set_attributes();
495 
496  // Return
497  return;
498 }
499 
500 
501 /***********************************************************************//**
502  * @brief Append Good Time Intervals
503  *
504  * @param[in] gti Good Time Intervals.
505  *
506  * Append Good Time Intervals to the container. The method performs automatic
507  * time reference conversion in case that the specified Good Time Intervals
508  * @p gti have a time reference that differs from that of the current
509  * instance.
510  ***************************************************************************/
511 void GGti::extend(const GGti& gti)
512 {
513  // Do nothing if Good Time Intervals are empty
514  if (!gti.is_empty()) {
515 
516  // Allocate new intervals
517  int num = m_num+gti.size();
518  GTime* start = new GTime[num];
519  GTime* stop = new GTime[num];
520 
521  // Initialise index
522  int inx = 0;
523 
524  // Copy existing intervals
525  for (; inx < m_num; ++inx) {
526  start[inx] = m_start[inx];
527  stop[inx] = m_stop[inx];
528  }
529 
530  // Append intervals. Convert to GTI reference on the fly.
531  for (int i = 0; i < gti.size(); ++i, ++inx) {
532  double tstart = gti.m_start[i].convert(m_reference);
533  double tstop = gti.m_stop[i].convert(m_reference);
534  start[inx].set(tstart, m_reference);
535  stop[inx].set(tstop, m_reference);
536  }
537 
538  // Free memory
539  if (m_start != NULL) delete [] m_start;
540  if (m_stop != NULL) delete [] m_stop;
541 
542  // Set new memory
543  m_start = start;
544  m_stop = stop;
545 
546  // Set number of elements
547  m_num = num;
548 
549  // Set attributes
550  set_attributes();
551 
552  } // endif: Good Time Intervals were not empty
553 
554  // Return
555  return;
556 }
557 
558 
559 
560 /***********************************************************************//**
561  * @brief Load Good Time Intervals from FITS file
562  *
563  * @param[in] filename FITS filename.
564  *
565  * Loads the Good Time Intervals from FITS file.
566  *
567  * If no extension name is provided in the @p filename, the Good Time
568  * Intervals are loaded from the `GTI` extension.
569  ***************************************************************************/
570 void GGti::load(const GFilename& filename)
571 {
572  // Open FITS file
573  GFits fits(filename);
574 
575  // Get GTI table
576  const GFitsTable& table = *fits.table(filename.extname(gammalib::extname_gti));
577 
578  // Read GTI from table
579  read(table);
580 
581  // Close FITS file
582  fits.close();
583 
584  // Return
585  return;
586 }
587 
588 
589 /***********************************************************************//**
590  * @brief Save Good Time Intervals into FITS file
591  *
592  * @param[in] filename FITS filename.
593  * @param[in] clobber Overwrite an existing Good Time Interval extension?
594  *
595  * Saves Good Time Intervals into a FITS file. If a file with the given
596  * @p filename does not yet exist it will be created, otherwise the method
597  * opens the existing file. Good Time Intervals can only be appended to an
598  * existing file if the @p clobber flag is set to `true` (otherwise an
599  * exception is thrown).
600  *
601  * The method will append a binary FITS table containing the Good Time
602  * Intervals to the FITS file. The extension name can be specified as part
603  * of the @p filename. For example the @p filename
604  *
605  * myfile.fits[GOOD TIME INTERVALS]
606  *
607  * will save the Good Time Intervals in the `GOOD TIME INTERVALS` extension
608  * of the `myfile.fits` file. If the extension exists already in the file it
609  * will be replaced, otherwise a new extension will be created. If no
610  * extension name is provided, the method will use `GTI` as the default
611  * extension name for Good Time Intervals.
612  ***************************************************************************/
613 void GGti::save(const GFilename& filename, const bool& clobber) const
614 {
615  // Open or create FITS file (without extension name since the requested
616  // extension may not yet exist in the file)
617  GFits fits(filename.url(), true);
618 
619  // Write GTI to FITS object
620  write(fits, filename.extname(gammalib::extname_gti));
621 
622  // Save to file
623  fits.save(clobber);
624 
625  // Return
626  return;
627 }
628 
629 
630 /***********************************************************************//**
631  * @brief Read Good Time Intervals and time reference from FITS table
632  *
633  * @param[in] table FITS table.
634  *
635  * Reads the Good Time Intervals and time reference from a FITS table. The
636  * start and stop times of the Good Time Intervals are read from the "START"
637  * and "STOP" columns.
638  ***************************************************************************/
639 void GGti::read(const GFitsTable& table)
640 {
641  // Clear object
642  clear();
643 
644  // Read time reference
645  m_reference.read(table);
646 
647  // Extract GTI information from FITS table
648  m_num = table.integer("NAXIS2");
649  if (m_num > 0) {
650 
651  // Set GTIs
652  m_start = new GTime[m_num];
653  m_stop = new GTime[m_num];
654  for (int i = 0; i < m_num; ++i) {
655  m_start[i].set(table["START"]->real(i), m_reference);
656  m_stop[i].set(table["STOP"]->real(i), m_reference);
657  }
658 
659  // Set attributes
660  set_attributes();
661 
662  }
663 
664  // Return
665  return;
666 }
667 
668 
669 /***********************************************************************//**
670  * @brief Write Good Time Intervals and time reference into FITS object
671  *
672  * @param[in] fits FITS file.
673  * @param[in] extname GTI extension name.
674  *
675  * Writes Good Time Intervals and time reference into a FITS object. If an
676  * extension with the same name does already exist in the FITS object, the
677  * values in that extension will be replaced.
678  *
679  * The start and stop tims of the Good Time Intervals will be written into
680  * double precision columns named `START` and `STOP`.
681  ***************************************************************************/
682 void GGti::write(GFits& fits, const std::string& extname) const
683 {
684  // Create GTI columns
685  GFitsTableDoubleCol cstart("START", m_num);
686  GFitsTableDoubleCol cstop("STOP", m_num);
687 
688  // Fill GTI columns in specified time reference
689  for (int i = 0; i < m_num; ++i) {
690  cstart(i) = m_start[i].convert(m_reference);
691  cstop(i) = m_stop[i].convert(m_reference);
692  }
693 
694  // Create GTI table
695  GFitsBinTable table(m_num);
696  table.append(cstart);
697  table.append(cstop);
698  table.extname(extname);
699 
700  // Write time reference into table
701  m_reference.write(table);
702 
703  // If the FITS object contains already an extension with the same
704  // name then remove now this extension
705  if (fits.contains(extname)) {
706  fits.remove(extname);
707  }
708 
709  // Append GTI table to FITS file
710  fits.append(table);
711 
712  // Return
713  return;
714 }
715 
716 
717 /***********************************************************************//**
718  * @brief Read Good Time Intervals from XML element
719  *
720  * @param[in] xml XML element.
721  *
722  * @exception GException::invalid_value
723  * Invalid XML format encountered.
724  *
725  * Read Good Time Intervals from an XML element. The format of the Good Time
726  * Intervals is either
727  *
728  * <parameter name="GoodTimeIntervals" file="..."/>
729  *
730  * in case that the information is stored in a FITS file, or
731  *
732  * <parameter name="GoodTimeIntervals" tmin="..." tmax="..."/>
733  *
734  * if the Good Time Intervals should be constructed from a start and stop
735  * time (the units of the @a tmin and @a tmax parameters are seconds). In the
736  * latter case, the method also expects that the time reference is provided
737  * as parameter in the @p xml element.
738  ***************************************************************************/
739 void GGti::read(const GXmlElement& xml)
740 {
741  // Clear energy boundaries
742  clear();
743 
744  // Get GTI parameter
745  const GXmlElement* par = gammalib::xml_get_par(G_READ_XML, xml, "GoodTimeIntervals");
746 
747  // If we have a "file" attribute then load GTIs from file ...
748  if (par->has_attribute("file")) {
749 
750  // Get filename
751  std::string filename = par->attribute("file");
752 
753  // Load GTIs from file
754  load(filename);
755 
756  // Store filename (we need to do this after loading as the
757  // load method calls the read method that clears the object
758  m_xml_filename = filename;
759 
760  }
761 
762  // ... otherwise if "tmin" and "tmax" attributes are found then set
763  // the GTIs from these attributes and also read the time reference
764  // from the XML file
765  else if (par->has_attribute("tmin") && par->has_attribute("tmax")) {
766 
767  // Read time reference first (needed before reading times!)
768  m_reference.read(xml);
769 
770  // Create GTI from "tmin" and "tmax" attributes
771  double tmin = gammalib::todouble(par->attribute("tmin"));
772  double tmax = gammalib::todouble(par->attribute("tmax"));
773  append(GTime(tmin, m_reference), GTime(tmax, m_reference));
774 
775  }
776 
777  // ... otherwise throw an exception
778  else {
779  std::string msg = "Attributes \"file\" or \"tmin\" and \"tmax\" not "
780  "found in XML parameter \"GoodTimeIntervals\". "
781  "Please verify the observation definition XML "
782  "file.";
784  }
785 
786  // Return
787  return;
788 }
789 
790 
791 /***********************************************************************//**
792  * @brief Write Good Time Intervals into XML element
793  *
794  * @param[in] xml XML element.
795  *
796  * Writes Good Time Intervals into an XML element. The format of the Good
797  * Time Intervals is
798  *
799  * <parameter name="GoodTimeIntervals" file="..."/>
800  *
801  * if a file name has been specified previously upon reading from an XML
802  * file. In that case, the method will also write the Good Time Intervals to
803  * the specified file. If no file name is available, the method will write
804  * the first start and the last stop time of the Good Time Intervals in the
805  * format
806  *
807  * <parameter name="GoodTimeIntervals" tmin="..." tmax="..."/>
808  *
809  * The units of the @a tmin and @a tmax parameters are seconds. In that case,
810  * the time reference is also written into the XML element.
811  *
812  * This method does nothing if the Good Time Intervals are empty.
813  ***************************************************************************/
814 void GGti::write(GXmlElement& xml) const
815 {
816  // Continue only if there are GTIs
817  if (!is_empty()) {
818 
819  // Get parameter
820  GXmlElement* par =
821  gammalib::xml_need_par(G_WRITE_XML, xml, "GoodTimeIntervals");
822 
823  // If we have a file name then write the "file" attribute ...
824  if (!m_xml_filename.is_empty()) {
825 
826  // Write "file" attribute
827  par->attribute("file", m_xml_filename);
828 
829  // Write GTI file
830  save(m_xml_filename, true);
831 
832  }
833 
834  // ... otherwise write "tmin" and "tmax" attributes and write the
835  // time reference
836  else {
837 
838  // Write time interval
839  par->attribute("tmin", gammalib::str(tstart().convert(m_reference)));
840  par->attribute("tmax", gammalib::str(tstop().convert(m_reference)));
841 
842  // Write time reference
843  m_reference.write(xml);
844 
845  }
846 
847  } // endif: GTIs were not empty
848 
849  // Return
850  return;
851 }
852 
853 
854 /***********************************************************************//**
855  * @brief Returns start time for a given Good Time Interval
856  *
857  * @param[in] index Good Time Interval index (0,...,size()-1).
858  *
859  * @exception GException::out_of_range
860  * Specified index is out of range.
861  ***************************************************************************/
862 const GTime& GGti::tstart(const int& index) const
863 {
864  #if defined(G_RANGE_CHECK)
865  // If index is outside boundary then throw an error
866  if (index < 0 || index >= m_num) {
867  throw GException::out_of_range(G_TSTART, index, 0, m_num-1);
868  }
869  #endif
870 
871  // Return
872  return (m_start[index]);
873 }
874 
875 
876 /***********************************************************************//**
877  * @brief Returns stop time for a given Good Time Interval
878  *
879  * @param[in] index Good Time Interval index (0,...,size()-1).
880  *
881  * @exception GException::out_of_range
882  * Specified index is out of range.
883  ***************************************************************************/
884 const GTime& GGti::tstop(const int& index) const
885 {
886  #if defined(G_RANGE_CHECK)
887  // If index is outside boundary then throw an error
888  if (index < 0 || index >= m_num) {
889  throw GException::out_of_range(G_TSTOP, index, 0, m_num-1);
890  }
891  #endif
892 
893  // Return
894  return (m_stop[index]);
895 }
896 
897 
898 /***********************************************************************//**
899  * @brief Computes overlap of time interval with GTIs
900  *
901  * @param[in] tstart Start time of interval.
902  * @param[in] tstop Stop time of interval.
903  * @return Overlap (seconds).
904  *
905  * Returns the overlap of time interval with GTIs in seconds.
906  ***************************************************************************/
907 double GGti::overlap(const GTime& tstart, const GTime& tstop) const
908 {
909  // Initialise overlap
910  double overlap = 0.0;
911 
912  // Compute the overlap
913  for (int i = 0; i < m_num; ++i) {
914  if (m_start[i] < tstart) {
915  if (m_stop[i] > tstart) {
916  if (m_stop[i] > tstop) {
917  overlap += tstop - tstart;
918  }
919  else {
920  overlap += m_stop[i] - tstart;
921  }
922  }
923  }
924  else if (m_stop[i] > tstop) {
925  if (m_start[i] < tstop) {
926  overlap += tstop - m_start[i];
927  }
928  }
929  else {
930  overlap += m_stop[i] - m_start[i];
931  }
932  }
933 
934  // Return
935  return overlap;
936 }
937 
938 
939 /***********************************************************************//**
940  * @brief Checks whether Good Time Intervals contains time
941  *
942  * @param[in] time Time to be checked.
943  *
944  * Checks if a given @p time falls in at least one of the Good Time
945  * Intervals. The method exits when the first matching interval has been
946  * found.
947  *
948  * Since this method may be called repeadetly while scanning an ordered list
949  * of time it is most efficient to start the search always at the index where
950  * the last search was successful.
951  ***************************************************************************/
952 bool GGti::contains(const GTime& time) const
953 {
954  // Initialise test
955  bool found = false;
956 
957  // Start GTIs search from the last successful index
958  for (int i = m_last_index; i < m_num; ++i) {
959  if (time >= m_start[i] && time <= m_stop[i]) {
960  found = true;
961  m_last_index = i;
962  break;
963  }
964  }
965 
966  // If no GTI has been found then search now from the start of the list
967  if (!found) {
968  for (int i = 0; i < m_last_index; ++i) {
969  if (time >= m_start[i] && time <= m_stop[i]) {
970  found = true;
971  m_last_index = i;
972  break;
973  }
974  }
975  }
976 
977  // Return result
978  return found;
979 }
980 
981 
982 /***********************************************************************//**
983  * @brief Print Good Time Intervals
984  *
985  * @param[in] chatter Chattiness.
986  * @return String containing Good Time Interval information.
987  ***************************************************************************/
988 std::string GGti::print(const GChatter& chatter) const
989 {
990  // Initialise result string
991  std::string result;
992 
993  // Continue only if chatter is not silent
994  if (chatter != SILENT) {
995 
996  // Append header
997  result.append("=== GGti ===");
998 
999  // Append GTI information
1000  result.append("\n"+gammalib::parformat("Number of intervals"));
1001  result.append(gammalib::str(size()));
1002  result.append("\n"+gammalib::parformat("Ontime"));
1003  result.append(gammalib::str(ontime())+" sec");
1004  result.append("\n"+gammalib::parformat("Elapsed time"));
1005  result.append(gammalib::str(telapse())+" sec");
1006  result.append("\n"+gammalib::parformat("MJD range"));
1007  result.append(gammalib::str(tstart().mjd()));
1008  result.append(" - ");
1009  result.append(gammalib::str(tstop().mjd()));
1010  result.append(" "+reference().timeunit());
1011  result.append(" ("+reference().timesys()+")");
1012  result.append("\n"+gammalib::parformat("UTC range"));
1013  result.append(tstart().utc());
1014  result.append(" - ");
1015  result.append(tstop().utc());
1016  result.append(" "+reference().timeunit());
1017  result.append(" ("+reference().timesys()+")");
1018 
1019  // Append reference MJD
1020  result.append("\n"+gammalib::parformat("Reference MJD"));
1021  result.append(gammalib::str(reference().mjdref()));
1022 
1023  // EXPLICIT: Append time reference information
1024  if (chatter >= EXPLICIT) {
1025  result.append("\n"+reference().print(chatter));
1026  }
1027 
1028  // Optionally append XML filename
1029  if (!m_xml_filename.is_empty()) {
1030  result.append("\n"+gammalib::parformat("File name"));
1031  result.append(m_xml_filename);
1032  }
1033 
1034  } // endif: chatter was not silent
1035 
1036  // Return result
1037  return result;
1038 }
1039 
1040 
1041 /*==========================================================================
1042  = =
1043  = Private methods =
1044  = =
1045  ==========================================================================*/
1046 
1047 /***********************************************************************//**
1048  * @brief Initialise class members
1049  ***************************************************************************/
1051 {
1052  // Initialise members
1053  m_num = 0;
1054  m_tstart.clear();
1055  m_tstop.clear();
1057  m_ontime = 0.0;
1058  m_telapse = 0.0;
1059  m_start = NULL;
1060  m_stop = NULL;
1061 
1062  // Initialise computation cache
1063  m_last_index = 0;
1064 
1065  // Initialise time reference with native reference
1066  GTime time;
1067  m_reference = time.reference();
1068 
1069  // Return
1070  return;
1071 }
1072 
1073 
1074 /***********************************************************************//**
1075  * @brief Copy class members
1076  *
1077  * @param[in] gti Good Time Intervals.
1078  ***************************************************************************/
1079 void GGti::copy_members(const GGti& gti)
1080 {
1081  // Copy attributes
1082  m_num = gti.m_num;
1083  m_tstart = gti.m_tstart;
1084  m_tstop = gti.m_tstop;
1085  m_ontime = gti.m_ontime;
1086  m_telapse = gti.m_telapse;
1087  m_reference = gti.m_reference;
1089 
1090  // Copy start/stop times
1091  if (m_num > 0) {
1092  m_start = new GTime[m_num];
1093  m_stop = new GTime[m_num];
1094  for (int i = 0; i < m_num; ++i) {
1095  m_start[i] = gti.m_start[i];
1096  m_stop[i] = gti.m_stop[i];
1097  }
1098  }
1099 
1100  // Copy computation cache
1101  m_last_index = gti.m_last_index;
1102 
1103  // Return
1104  return;
1105 }
1106 
1107 
1108 /***********************************************************************//**
1109  * @brief Delete class members
1110  ***************************************************************************/
1112 {
1113  // Free memory
1114  if (m_start != NULL) delete [] m_start;
1115  if (m_stop != NULL) delete [] m_stop;
1116 
1117  // Signal free pointers
1118  m_start = NULL;
1119  m_stop = NULL;
1120 
1121  // Return
1122  return;
1123 }
1124 
1125 
1126 /***********************************************************************//**
1127  * @brief Set class attributes
1128  *
1129  * Compute the following class attributes:
1130  *
1131  * m_tstart - Earliest start time of GTIs
1132  * m_stop - Latest stop time of GTIs
1133  * m_telapse - Latest stop time minus earliest start time of GTIs [sec]
1134  * m_ontime - Sum of all intervals [sec]
1135  ***************************************************************************/
1137 {
1138  // If there are intervals then determine the start and stop time
1139  // from these intervals ...
1140  if (m_num > 0) {
1141  m_tstart = m_start[0];
1142  m_tstop = m_stop[0];
1143  for (int i = 1; i < m_num; ++i) {
1144  if (m_start[i] < m_tstart) m_tstart = m_start[i];
1145  if (m_stop[i] > m_tstop) m_tstop = m_stop[i];
1146  }
1147  }
1148 
1149  // ... otherwise clear the start and stop time
1150  else {
1151  m_tstart.clear();
1152  m_tstop.clear();
1153  }
1154 
1155  // Set attributes
1157  m_ontime = 0.0;
1158  for (int i = 0; i < m_num; ++i) {
1159  m_ontime += (m_stop[i].secs() - m_start[i].secs());
1160  }
1161 
1162  // Return
1163  return;
1164 }
1165 
1166 
1167 /***********************************************************************//**
1168  * @brief Insert Good Time Interval
1169  *
1170  * @param[in] index Index after which interval is inserted.
1171  * @param[in] tstart Start time of interval.
1172  * @param[in] tstop Stop time of interval.
1173  *
1174  * @exception GException::invalid_argument
1175  * Start time later than stop time
1176  *
1177  * Inserts a Good Time Interval after the specified @p index in the Good
1178  * Time Intervals. The method does not reorder the intervals by time,
1179  * instead the client needs to determine the approriate @p index.
1180  *
1181  * Invalid parameters do not produce any exception, but are handled
1182  * transparently. If the interval is invalid (i.e. @p tstart > @p tstop)
1183  * an exception is thrown. If the @p index is out of the valid range, the
1184  * index will be adjusted to either the first or the last element.
1185  ***************************************************************************/
1186 void GGti::insert_gti(const int& index, const GTime& tstart, const GTime& tstop)
1187 {
1188  // Throw an exception if time interval is invalid
1189  if (tstart > tstop) {
1190  std::string msg = "Invalid time interval specified. Start time "+
1191  tstart.print(NORMAL)+" can not be later than "
1192  "stop time "+tstop.print(NORMAL)+".";
1194  }
1195 
1196  // Set index
1197  int inx = index;
1198 
1199  // If inx is out of range then adjust it
1200  if (inx < 0) inx = 0;
1201  if (inx > m_num) inx = m_num;
1202 
1203  // Allocate new intervals
1204  int num = m_num+1;
1205  GTime* start = new GTime[num];
1206  GTime* stop = new GTime[num];
1207 
1208  // Copy intervals before GTI to be inserted
1209  for (int i = 0; i < inx; ++i) {
1210  start[i] = m_start[i];
1211  stop[i] = m_stop[i];
1212  }
1213 
1214  // Insert GTI
1215  start[inx] = tstart;
1216  stop[inx] = tstop;
1217 
1218  // Copy intervals after GTI to be inserted
1219  for (int i = inx+1; i < num; ++i) {
1220  start[i] = m_start[i-1];
1221  stop[i] = m_stop[i-1];
1222  }
1223 
1224  // Free memory
1225  if (m_start != NULL) delete [] m_start;
1226  if (m_stop != NULL) delete [] m_stop;
1227 
1228  // Set new memory
1229  m_start = start;
1230  m_stop = stop;
1231 
1232  // Set number of elements
1233  m_num = num;
1234 
1235  // Set attributes
1236  set_attributes();
1237 
1238  // Return
1239  return;
1240 }
virtual ~GGti(void)
Destructor.
Definition: GGti.cpp:185
bool contains(const GTime &time) const
Checks whether Good Time Intervals contains time.
Definition: GGti.cpp:952
FITS table double column class interface definition.
double m_ontime
Sum of GTIs durations (in seconds)
Definition: GGti.hpp:123
GFitsTable * table(const int &extno)
Get pointer to table HDU.
Definition: GFits.cpp:472
int m_last_index
Last index for containment test.
Definition: GGti.hpp:131
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:1143
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:274
#define G_WRITE_XML
Definition: GGti.cpp:45
XML element node class interface definition.
GFilename m_xml_filename
XML filename.
Definition: GGti.hpp:128
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:47
#define G_REMOVE
Definition: GGti.cpp:43
void clear(void)
Clear time.
Definition: GTime.cpp:251
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:1111
GTimeReference m_reference
Time reference.
Definition: GGti.hpp:127
Time class.
Definition: GTime.hpp:54
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:1186
std::string print(const GChatter &chatter=NORMAL) const
Print Good Time Intervals.
Definition: GGti.cpp:988
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:1050
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:153
double m_telapse
Time between start of first GTI and stop of last GTI (in seconds)
Definition: GGti.hpp:124
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:613
void clear(void)
Clear Good Time Intervals.
Definition: GGti.cpp:237
int m_num
Number of Good Time Intervals.
Definition: GGti.hpp:120
void remove(const int &extno)
Remove HDU from FITS file.
Definition: GFits.cpp:848
const GXmlAttribute * attribute(const int &index) const
Return attribute.
void load(const GFilename &filename)
Load Good Time Intervals from FITS file.
Definition: GGti.cpp:570
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:1513
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:475
std::string print(const GChatter &chatter=NORMAL) const
Print time.
Definition: GTime.cpp:1161
Good Time Interval class.
Definition: GGti.hpp:62
const GTime & tstop(void) const
Returns latest stop time in Good Time Intervals.
Definition: GGti.hpp:206
const std::string & extname(void) const
Return extension name.
Definition: GFitsHDU.hpp:162
void set_attributes(void)
Set class attributes.
Definition: GGti.cpp:1136
const GTime & tstart(void) const
Returns earliest start time in Good Time Intervals.
Definition: GGti.hpp:193
GTime m_tstart
Start time of Good Time Intervals.
Definition: GGti.hpp:121
#define G_TSTOP
Definition: GGti.cpp:47
const double & secs(void) const
Return time in seconds in native reference (TT)
Definition: GTime.hpp:153
void copy_members(const GGti &gti)
Copy class members.
Definition: GGti.cpp:1079
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:907
GTime m_tstop
Stop time of Good Time Intervals.
Definition: GGti.hpp:122
void read(const GFitsTable &table)
Read Good Time Intervals and time reference from FITS table.
Definition: GGti.cpp:639
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:665
Implements a time reference.
FITS binary table class definition.
GTime * m_stop
Array of stop times.
Definition: GGti.hpp:126
std::string parformat(const std::string &s, const int &indent=0)
Convert string in parameter format.
Definition: GTools.cpp:1022
const double & telapse(void) const
Returns elapsed time.
Definition: GGti.hpp:223
bool is_empty(void) const
Signal if there are no Good Time Intervals.
Definition: GGti.hpp:165
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:682
GTime * m_start
Array of start times.
Definition: GGti.hpp:125
void close(void)
Close FITS file.
Definition: GFits.cpp:1314
void set(const double &time, const GTimeReference &ref)
Set time given in specified reference.
Definition: GTime.cpp:978
void extend(const GGti &gti)
Append Good Time Intervals.
Definition: GGti.cpp:511
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:1562
const double & ontime(void) const
Returns ontime.
Definition: GGti.hpp:239
double convert(const GTimeReference &ref) const
Return time in specified reference.
Definition: GTime.cpp:671
FITS table double column.
void reduce(const GTime &tstart, const GTime &tstop)
Reduce Good Time Intervals to specified interval.
Definition: GGti.cpp:398
Filename class interface definition.
double todouble(const std::string &arg)
Convert string into double precision value.
Definition: GTools.cpp:805
std::string str(const unsigned short int &value)
Convert unsigned short integer value into string.
Definition: GTools.cpp:413
FITS table abstract base class interface definition.
void merge(void)
Merge all overlapping Good Time Intervals.
Definition: GGti.cpp:317