diff --git a/ChangeLog b/ChangeLog index 054e5f8..970eb7d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -20,6 +20,8 @@ Increase precision for diffuse model Npred computation (#1248) Implement observation definition reader/writer (#1429) Remove etrue flag from CTA background IRF (#1437) + Allow appending of empty intervals to GEbounds and GGti + Add single interval constructor to GGti 2015-01-07 Juergen Knoedlseder diff --git a/NEWS b/NEWS index 3e3d192..bec0438 100644 --- a/NEWS +++ b/NEWS @@ -75,7 +75,11 @@ None 10. Observation module ---------------------- -None +The GEbounds and GGti classes now allow appending of empty intervals (i.e. +intervals having the same start and end value). + +A single time interval constructor has been added to GGti, similar to the +one that exists for GEbounds. 11. Optimization module diff --git a/include/GGti.hpp b/include/GGti.hpp index a319054..1477d45 100644 --- a/include/GGti.hpp +++ b/include/GGti.hpp @@ -59,6 +59,7 @@ public: // Constructors and destructors GGti(void); GGti(const GGti& gti); + GGti(const GTime& tstart, const GTime& tstop); explicit GGti(const GXmlElement& xml); explicit GGti(const GTimeReference& ref); virtual ~GGti(void); diff --git a/pyext/GGti.i b/pyext/GGti.i index 4119c86..4421b3d 100644 --- a/pyext/GGti.i +++ b/pyext/GGti.i @@ -40,6 +40,7 @@ public: // Constructors and destructors GGti(void); GGti(const GGti& gti); + GGti(const GTime& tstart, const GTime& tstop); explicit GGti(const GXmlElement& xml); explicit GGti(const GTimeReference& ref); virtual ~GGti(void); diff --git a/src/obs/GGti.cpp b/src/obs/GGti.cpp index 6f108f6..007c810 100644 --- a/src/obs/GGti.cpp +++ b/src/obs/GGti.cpp @@ -38,11 +38,13 @@ #include "GXmlElement.hpp" /* __ Method name definitions ____________________________________________ */ +#define G_REDUCE "GGti::reduce(GTime&, GTime&)" #define G_REMOVE "GGti::remove(int&)" #define G_READ_XML "GGti::read(GXmlElement&)" #define G_WRITE_XML "GGti::write(GXmlElement&)" #define G_TSTART "GGti::tstart(int&)" #define G_TSTOP "GGti::tstop(int&)" +#define G_INSERT_GTI "GGti::insert_gti(int&, GTime&, GTime&)" /* __ Macros _____________________________________________________________ */ @@ -109,6 +111,28 @@ GGti::GGti(const GXmlElement& xml) /***********************************************************************//** + * @brief Single time interval constructor + * + * @param[in] tstart Start time of interval. + * @param[in] tstop Stop time of interval. + * + * Constructs Good Time Intervals from a single time interval, given by + * [p@ tstart, @p tstop]. + ***************************************************************************/ +GGti::GGti(const GTime& tstart, const GTime& tstop) +{ + // Initialise members + init_members(); + + // Append time interval + append(tstart, tstop); + + // Return + return; +} + + +/***********************************************************************//** * @brief Time reference constructor * * @param[in] ref Time reference. @@ -155,7 +179,7 @@ GGti::~GGti(void) * @param[in] gti Good Time Intervals. * @return Good Time Intervals. ***************************************************************************/ -GGti& GGti::operator= (const GGti& gti) +GGti& GGti::operator=(const GGti& gti) { // Execute only if object is not identical if (this != >i) { @@ -216,19 +240,11 @@ GGti* GGti::clone(void) const * @param[in] tstop Stop time of interval. * * Appends a Good Time Interval at the end of the container. - * - * The method does nothing if the Good Time Interval is not valid - * (i.e. @p tstart >= @p tstop). ***************************************************************************/ void GGti::append(const GTime& tstart, const GTime& tstop) { - // Continue only if time interval is valid - if (tstop > tstart) { - - // Insert GTI at end of list - insert_gti(m_num, tstart, tstop); - - } // endif: Time interval was valid + // Insert GTI at end of list + insert_gti(m_num, tstart, tstop); // Return return; @@ -244,27 +260,19 @@ void GGti::append(const GTime& tstart, const GTime& tstop) * Inserts a Good Time Interval into the container after the first interval * that has a start time smaller than @p tstart. The method implicitely * assumes that the Good Time Intervals are ordered by increasing start time. - * - * The method does nothing if the Good Time Interval is not valid - * (i.e. @p tstart >= @p tstop). ***************************************************************************/ void GGti::insert(const GTime& tstart, const GTime& tstop) { - // Continue only if time interval is valid - if (tstop > tstart) { - - // Determine index at which GTI should be inserted - int inx = 0; - for (int i = 0; i < m_num; ++i) { - if (tstart < m_start[i]) { - break; - } + // Determine index at which GTI should be inserted + int inx = 0; + for (int i = 0; i < m_num; ++i) { + if (tstart < m_start[i]) { + break; } + } - // Insert interval - insert_gti(inx, tstart, tstop); - - } // endif: Time interval was valid + // Insert interval + insert_gti(inx, tstart, tstop); // Return return; @@ -325,30 +333,22 @@ void GGti::merge(void) * that has a start time smaller than @p tstart and then merges any * overlapping or connecting Good Time Intervals. The method implicitely * assumes that the intervals are ordered by increasing start time. - * - * The method does nothing if the Good Time Interval is not valid - * (i.e. @p tstart >= @p tstop). ***************************************************************************/ void GGti::merge(const GTime& tstart, const GTime& tstop) { - // Continue only if time interval is valid - if (tstop > tstart) { - - // Determine index at which GTI should be inserted - int inx = 0; - for (int i = 0; i < m_num; ++i) { - if (tstart < m_start[i]) { - break; - } + // Determine index at which GTI should be inserted + int inx = 0; + for (int i = 0; i < m_num; ++i) { + if (tstart < m_start[i]) { + break; } + } - // Insert GTI - insert_gti(inx, tstart, tstop); - - // Merge any overlapping GTIs - merge(); + // Insert GTI + insert_gti(inx, tstart, tstop); - } // endif: Time interval was valid + // Merge any overlapping GTIs + merge(); // Return return; @@ -361,72 +361,75 @@ void GGti::merge(const GTime& tstart, const GTime& tstop) * @param[in] tstart Start time of interval. * @param[in] tstop Stop time of interval. * + * @exception GException::invalid_argument + * Start time is later than stop time + * * Reduces the Good Time Intervals to the specified interval. Reducing means * that all Good Time Intervals are dropped that fall outside the specified * interval [@p tstart, @p tstop], and Good Time Intervals will be limited * to >@p tstart and <=@p tstop in case that their boundaries are outside * [@p tstart, @p tstop]. - * - * The method does nothing if the Good Time Interval is not valid - * (i.e. @p tstart >= @p tstop). ***************************************************************************/ void GGti::reduce(const GTime& tstart, const GTime& tstop) { - // Continue only if time interval is valid - if (tstop > tstart) { + // Throw an exception if time interval is invalid + if (tstart > tstop) { + std::string msg = "Invalid time interval specified. Start time "+ + tstart.print(NORMAL)+" can not be later than " + "stop time "+tstop.print(NORMAL)+"."; + throw GException::invalid_argument(G_REDUCE, msg); + } - // Adjust existing GTIs. This will limit all GTIs to [tstart,tstop]. - // All GTIs outside [tstart,tstop] will have start > stop. The number - // of valid GTIs will also be determined. - int num = 0; - for (int i = 0; i < m_num; ++i) { - if (m_start[i] < tstart) { - m_start[i] = tstart; - } - if (m_stop[i] > tstop) { - m_stop[i] = tstop; - } - if (m_start[i] <= m_stop[i]) { - num++; - } + // Adjust existing GTIs. This will limit all GTIs to [tstart,tstop]. + // All GTIs outside [tstart,tstop] will have start > stop. The number + // of valid GTIs will also be determined. + int num = 0; + for (int i = 0; i < m_num; ++i) { + if (m_start[i] < tstart) { + m_start[i] = tstart; + } + if (m_stop[i] > tstop) { + m_stop[i] = tstop; + } + if (m_start[i] <= m_stop[i]) { + num++; } + } - // If we still have valid GTIs then allocate memory for them, copy - // over the start and stop times, and update the attributes - if (num > 0) { + // If we still have valid GTIs then allocate memory for them, copy + // over the start and stop times, and update the attributes + if (num > 0) { - // Allocate new intervals - GTime* start = new GTime[num]; - GTime* stop = new GTime[num]; + // Allocate new intervals + GTime* start = new GTime[num]; + GTime* stop = new GTime[num]; - // Copy valid intervals - for (int i = 0; i < m_num; ++i) { - if (m_start[i] <= m_stop[i]) { - start[i] = m_start[i]; - stop[i] = m_stop[i]; - } + // Copy valid intervals + for (int i = 0; i < m_num; ++i) { + if (m_start[i] <= m_stop[i]) { + start[i] = m_start[i]; + stop[i] = m_stop[i]; } + } - // Free old memory - if (m_start != NULL) delete [] m_start; - if (m_stop != NULL) delete [] m_stop; - - // Set new memory - m_start = start; - m_stop = stop; + // Free old memory + if (m_start != NULL) delete [] m_start; + if (m_stop != NULL) delete [] m_stop; - // Set attributes - m_num = num; - set_attributes(); + // Set new memory + m_start = start; + m_stop = stop; - } // endif: there were still valid GTIs + // Set attributes + m_num = num; + set_attributes(); - // ... otherwise we remove all GTIs - else { - clear(); - } + } // endif: there were still valid GTIs - } // endif: Time interval was valid + // ... otherwise we remove all GTIs + else { + clear(); + } // Return return; @@ -1103,63 +1106,69 @@ void GGti::set_attributes(void) * @param[in] tstart Start time of interval. * @param[in] tstop Stop time of interval. * + * @exception GException::invalid_argument + * Start time later than stop time + * * Inserts a Good Time Interval after the specified @p index in the Good * Time Intervals. The method does not reorder the intervals by time, * instead the client needs to determine the approriate @p index. * * Invalid parameters do not produce any exception, but are handled - * transparently. If the interval is invalid (i.e. @p tstart >= @p tstop) - * then nothing is done. If the @p index is out of the valid range, the + * transparently. If the interval is invalid (i.e. @p tstart > @p tstop) + * an exception is thrown. If the @p index is out of the valid range, the * index will be adjusted to either the first or the last element. ***************************************************************************/ void GGti::insert_gti(const int& index, const GTime& tstart, const GTime& tstop) { - // Continue only if time interval is valid - if (tstop > tstart) { - - // Set index - int inx = index; + // Throw an exception if time interval is invalid + if (tstart > tstop) { + std::string msg = "Invalid time interval specified. Start time "+ + tstart.print(NORMAL)+" can not be later than " + "stop time "+tstop.print(NORMAL)+"."; + throw GException::invalid_argument(G_INSERT_GTI, msg); + } - // If inx is out of range then adjust it - if (inx < 0) inx = 0; - if (inx > m_num) inx = m_num; + // Set index + int inx = index; - // Allocate new intervals - int num = m_num+1; - GTime* start = new GTime[num]; - GTime* stop = new GTime[num]; + // If inx is out of range then adjust it + if (inx < 0) inx = 0; + if (inx > m_num) inx = m_num; - // Copy intervals before GTI to be inserted - for (int i = 0; i < inx; ++i) { - start[i] = m_start[i]; - stop[i] = m_stop[i]; - } + // Allocate new intervals + int num = m_num+1; + GTime* start = new GTime[num]; + GTime* stop = new GTime[num]; - // Insert GTI - start[inx] = tstart; - stop[inx] = tstop; + // Copy intervals before GTI to be inserted + for (int i = 0; i < inx; ++i) { + start[i] = m_start[i]; + stop[i] = m_stop[i]; + } - // Copy intervals after GTI to be inserted - for (int i = inx+1; i < num; ++i) { - start[i] = m_start[i-1]; - stop[i] = m_stop[i-1]; - } + // Insert GTI + start[inx] = tstart; + stop[inx] = tstop; - // Free memory - if (m_start != NULL) delete [] m_start; - if (m_stop != NULL) delete [] m_stop; + // Copy intervals after GTI to be inserted + for (int i = inx+1; i < num; ++i) { + start[i] = m_start[i-1]; + stop[i] = m_stop[i-1]; + } - // Set new memory - m_start = start; - m_stop = stop; + // Free memory + if (m_start != NULL) delete [] m_start; + if (m_stop != NULL) delete [] m_stop; - // Set number of elements - m_num = num; - - // Set attributes - set_attributes(); + // Set new memory + m_start = start; + m_stop = stop; - } // endif: Time interval was valid + // Set number of elements + m_num = num; + + // Set attributes + set_attributes(); // Return return; diff --git a/test/test_GObservation.cpp b/test/test_GObservation.cpp index 6661236..edaa044 100644 --- a/test/test_GObservation.cpp +++ b/test/test_GObservation.cpp @@ -271,20 +271,21 @@ void TestGObservation::test_gti(void) // Add empty interval gti.append(GTime(1.0), GTime(1.0)); - test_value(gti.size(), 0, "GGti should have zero size."); - test_assert(gti.is_empty(), "GGti should be empty."); - test_value(gti.tstart().secs(), 0.0, 1.0e-10, "Start time should be 0."); - test_value(gti.tstop().secs(), 0.0, 1.0e-10, "Stop time should be 0."); + test_value(gti.size(), 1, "GGti should have 1 interval."); + test_assert(!gti.is_empty(), "GGti should not be empty."); + test_value(gti.tstart().secs(), 1.0, 1.0e-10, "Start time should be 1."); + test_value(gti.tstop().secs(), 1.0, 1.0e-10, "Stop time should be 1."); // Add one interval gti.append(GTime(1.0), GTime(10.0)); - test_value(gti.size(), 1, "GGti should have 1 interval."); + test_value(gti.size(), 2, "GGti should have 2 intervals."); test_assert(!gti.is_empty(), "GGti should not be empty."); test_value(gti.tstart().secs(), 1.0, 1.0e-10, "Start time should be 1."); test_value(gti.tstop().secs(), 10.0, 1.0e-10, "Stop time should be 10."); // Remove interval gti.remove(0); + gti.remove(0); test_value(gti.size(), 0, "GGti should have zero size."); test_assert(gti.is_empty(), "GGti should be empty."); test_value(gti.tstart().secs(), 0.0, 1.0e-10, "Start time should be 0.");