18using Mantid::Types::Core::DateAndTime;
26const bool ROI_USE{
true};
27const bool ROI_IGNORE{
false};
30void assert_increasing(
const DateAndTime &startTime,
const DateAndTime &stopTime) {
31 if (!
bool(startTime < stopTime)) {
32 std::stringstream msg;
33 msg << startTime <<
" and " << stopTime <<
" are not in increasing order";
34 throw std::runtime_error(msg.str());
70TimeROI::TimeROI(
const Types::Core::DateAndTime &startTime,
const Types::Core::DateAndTime &stopTime) {
71 this->
addROI(startTime, stopTime);
77 this->
addROI(DateAndTime(startTime), DateAndTime(stopTime));
83void TimeROI::addROI(
const Types::Core::DateAndTime &startTime,
const Types::Core::DateAndTime &stopTime) {
84 assert_increasing(startTime, stopTime);
86 if ((this->
empty()) || (startTime >
m_roi.back())) {
88 m_roi.push_back(startTime);
89 m_roi.push_back(stopTime);
92 }
else if ((startTime <=
m_roi.front()) && stopTime >=
m_roi.back()) {
95 m_roi.push_back(startTime);
96 m_roi.push_back(stopTime);
97 }
else if (stopTime <
m_roi.front() || startTime >
m_roi.back()) {
102 std::vector<TimeInterval> output;
103 bool union_added =
false;
105 if (overlaps(roi_to_add, interval)) {
108 roi_to_add = calculate_union(roi_to_add, interval);
109 }
else if (interval < roi_to_add) {
110 output.push_back(interval);
111 }
else if (interval > roi_to_add) {
113 output.push_back(roi_to_add);
116 output.push_back(interval);
118 throw std::runtime_error(
"encountered supposedly imposible place in TimeROI::addROI");
122 output.push_back(roi_to_add);
124 for (
const auto interval : output) {
125 m_roi.push_back(interval.start());
126 m_roi.push_back(interval.stop());
135 this->
addROI(DateAndTime(startTime), DateAndTime(stopTime));
143 if (!
m_roi.empty() &&
m_roi.back() == startTime)
144 m_roi.back() = stopTime;
146 m_roi.push_back(startTime);
147 m_roi.push_back(stopTime);
152 this->
addMask(DateAndTime(startTime), DateAndTime(stopTime));
161void TimeROI::addMask(
const Types::Core::DateAndTime &startTime,
const Types::Core::DateAndTime &stopTime) {
162 assert_increasing(startTime, stopTime);
165 g_log.
debug(
"TimeROI::addMask to an empty object is ignored");
167 g_log.
debug(
"TimeROI::addMask to ignored region");
168 }
else if ((startTime <=
m_roi.front()) && (stopTime >=
m_roi.back())) {
171 }
else if ((startTime <=
m_roi.front()) && (stopTime <
m_roi.back())) {
173 auto iter = std::upper_bound(
m_roi.begin(),
m_roi.end(), stopTime);
174 const auto newValue = std::max(
m_roi.front(), stopTime);
177 if (
m_roi.size() % 2 == 0) {
178 if (newValue >
m_roi.front())
179 *(
m_roi.begin()) = newValue;
183 }
else if ((startTime >
m_roi.front()) && (stopTime >=
m_roi.back())) {
185 auto iter = std::upper_bound(
m_roi.begin(),
m_roi.end(), startTime);
186 const auto newValue = std::min(*iter, startTime);
189 if (
m_roi.size() % 2 == 0) {
192 if (newValue ==
m_roi.back()) {
197 m_roi.push_back(newValue);
201 g_log.
debug(
"TimeROI::addMask cutting notch in existing ROI");
207 std::vector<TimeInterval> output;
210 for (std::size_t i = 0; i < roiSize; i += 2) {
222 for (
const auto &interval : output) {
223 m_roi.push_back(interval.start());
224 m_roi.push_back(interval.stop());
233 this->
addMask(DateAndTime(startTime), DateAndTime(stopTime));
241 const Types::Core::DateAndTime &stopTime)
const {
243 if ((startTime >
m_roi.back()) || (stopTime <=
m_roi.front()))
247 const auto iterStart = std::lower_bound(
m_roi.cbegin(),
m_roi.cend(), startTime);
248 const auto iterStop = std::lower_bound(iterStart,
m_roi.cend(), stopTime);
250 if (std::distance(iterStart, iterStop) > 0)
262 const Types::Core::DateAndTime &stopTime)
const {
265 if (startTime >=
m_roi.back())
267 if (stopTime <
m_roi.front())
270 const auto iterStart = std::lower_bound(
m_roi.cbegin(),
m_roi.cend(), startTime);
271 const auto iterStop = std::lower_bound(iterStart,
m_roi.cend(), stopTime);
273 if (std::distance(iterStart, iterStop) > 0)
291 if (time <
m_roi.front() || time >=
m_roi.back())
296 const auto iterUpper = std::upper_bound(
m_roi.cbegin(),
m_roi.cend(), time);
297 if (std::distance(
m_roi.cbegin(), iterUpper) % 2 == 0)
312 }
else if (time >
m_roi.back()) {
313 throw std::runtime_error(
"Requesting effective time after the end of the TimeROI");
318 auto iter = std::lower_bound(
m_roi.begin(),
m_roi.end(), time);
330 throw std::runtime_error(
"cannot return time from empty TimeROI");
331 return m_roi.front();
337 throw std::runtime_error(
"cannot return time from empty TimeROI");
348 std::vector<std::pair<size_t, size_t>> indices;
351 indices.emplace_back(0, std::numeric_limits<size_t>::max());
354 indices.reserve(
m_roi.size() / 2);
358 for (
size_t i = 0; i <
m_roi.size(); i += 2) {
359 const auto start = std::lower_bound(times.cbegin(), times.cend(),
m_roi[i]);
360 if (start != times.cend()) {
361 const auto stop = std::lower_bound(times.cbegin(), times.cend(),
m_roi[i + 1]);
362 if (stop != times.cend())
363 indices.emplace_back(std::distance(times.cbegin(), start), std::distance(times.cbegin(), stop));
365 indices.emplace_back(std::distance(times.cbegin(), start), std::numeric_limits<size_t>::max());
375 std::set<DateAndTime> times_set;
376 times_set.insert(this->
m_roi.cbegin(), this->m_roi.cend());
377 times_set.insert(other.m_roi.cbegin(), other.m_roi.cend());
380 std::vector<DateAndTime> times_all;
381 times_all.assign(times_set.begin(), times_set.end());
390 if (roi !=
nullptr && roi->
size() > 0) {
399 const auto iter = std::find(values.cbegin(), values.cend(), ROI_USE);
400 if (iter == values.cend())
401 throw std::runtime_error(
"TimeROI cannot be created. All values are ignore.");
402 std::size_t start = std::size_t(std::distance(values.cbegin(), iter));
407 m_roi.push_back(times[start]);
411 const auto NUM_VALUES = values.size();
412 for (std::size_t i = start; i < NUM_VALUES; ++i) {
413 if (values[i - 1] == values[i])
416 m_roi.push_back(times[i]);
422 throw std::runtime_error(
423 "Cannot guess ending value from a TimeSeriesProperty that contains only a single time");
437 m_roi.assign(other.m_roi.cbegin(), other.m_roi.cend());
444 m_roi.assign(roi.cbegin(), roi.cend());
448template <
typename TYPE>
454 else if (
left.empty())
458 if (
left.size() % 2 != 0)
459 throw std::runtime_error(
"Cannot calculate_intersection with odd left dimension");
460 if (
right.size() % 2 != 0)
461 throw std::runtime_error(
"Cannot calculate_intersection with odd right dimension");
464 std::vector<TYPE> result;
467 auto it1 =
left.cbegin();
468 auto it2 =
right.cbegin();
470 while (it1 !=
left.cend() && it2 !=
right.cend()) {
472 const TYPE &leftBound = std::max(*it1, *it2);
475 const auto it1_next = std::next(it1);
476 const auto it2_next = std::next(it2);
477 const TYPE &rightBound = std::min(*it1_next, *it2_next);
480 if (leftBound < rightBound) {
481 result.emplace_back(leftBound);
482 result.emplace_back(rightBound);
486 if (*it1_next < *it2_next)
487 std::advance(it1, 2);
489 std::advance(it2, 2);
508 if (other.useAll() || this->useAll()) {
520 m_roi = std::move(output);
535 for (
const auto &interval : other.toTimeIntervals()) {
536 this->
addROI(interval.start(), interval.stop());
551 }
else if (!other.useAll()) {
558 const auto NUM_VAL =
m_roi.size();
559 std::vector<TimeInterval> output;
561 for (std::size_t i = 0; i < NUM_VAL; i += 2) {
575 const auto NUM_VAL =
m_roi.size();
576 std::vector<TimeInterval> output;
578 for (std::size_t i = 0; i < NUM_VAL; i += 2) {
579 if (
m_roi[i + 1] > after) {
580 if (
m_roi[i] > after) {
583 output.emplace_back(after,
m_roi[i + 1]);
603 std::stringstream ss;
605 const auto NUM_VALUES{
m_roi.size()};
606 for (std::size_t i = 0; i < NUM_VALUES; i += 2) {
607 ss << (i / 2) <<
": " <<
m_roi[i] <<
" to " <<
m_roi[i + 1] <<
"\n";
609 }
else if (type == 1) {
610 for (
const auto &val :
m_roi)
614 throw std::runtime_error(
"Invalid type parameter");
632 for (std::size_t i = 0; i < ROI_SIZE - 1; i += 2) {
633 total += DateAndTime::secondsFromDuration(
m_roi[i + 1] -
m_roi[i]);
644 const Types::Core::DateAndTime &stopTime)
const {
645 assert_increasing(startTime, stopTime);
649 return DateAndTime::secondsFromDuration(stopTime - startTime);
652 if (stopTime <=
m_roi.front()) {
654 }
else if (startTime >=
m_roi.back()) {
656 }
else if ((startTime <=
m_roi.front()) && (stopTime >=
m_roi.back())) {
660 TimeROI temp{startTime, stopTime};
662 return temp.durationInSeconds();
668 if (
m_roi.size() % 2 != 0) {
669 std::stringstream msg;
670 msg <<
"Something went wrong in " << label <<
" and the object is now invalid. "
671 <<
"There are " <<
m_roi.size() <<
" regions and it must be an even number";
672 throw std::runtime_error(msg.str());
675 if (!std::is_sorted(
m_roi.cbegin(),
m_roi.cend())) {
676 throw std::runtime_error(
"Values are not in increasing order");
679 const std::size_t NUM_UNIQUE = std::size_t(std::distance(
m_roi.begin(), std::unique(
m_roi.begin(),
m_roi.end())));
680 if (NUM_UNIQUE !=
m_roi.size()) {
681 std::stringstream msg;
682 msg <<
"In " << label <<
": Values are not unique";
683 throw std::runtime_error(msg.str());
705 tsp.
addValue(interval.start(), ROI_USE);
706 tsp.
addValue(interval.stop(), ROI_IGNORE);
716 const std::vector<std::size_t> &
right);
717template MANTID_KERNEL_DLL std::vector<Types::Core::DateAndTime>
719 const std::vector<Types::Core::DateAndTime> &
right);
std::map< DeltaEMode::Type, std::string > index
The Logger class is in charge of the publishing messages from the framework through various channels.
void debug(const std::string &msg)
Logs at debug level.
Represents a time interval.
TimeInterval intersection(const TimeInterval &ti) const
Returns an intersection of two intervals.
TimeROI : Object that holds information about when the time measurement was active.
void replaceROI(const TimeSeriesProperty< bool > *roi)
double durationInSeconds() const
Duration of the whole TimeROI.
Types::Core::DateAndTime getEffectiveTime(const Types::Core::DateAndTime &time) const
Returns the time supplied if it is in a "use" region, or the minimum of the next higher use region.
void addMask(const std::string &startTime, const std::string &stopTime)
const std::vector< Kernel::TimeInterval > toTimeIntervals() const
This method is to lend itself to helping with transition.
const std::vector< Types::Core::DateAndTime > & getAllTimes() const
std::vector< std::pair< size_t, size_t > > calculate_indices(const std::vector< Types::Core::DateAndTime > ×) const
bool operator==(const TimeROI &other) const
std::size_t numBoundaries() const
Types::Core::DateAndTime firstTime() const
std::vector< Types::Core::DateAndTime > m_roi
void clear()
Removes all ROI's, leaving an empty object.
bool isCompletelyInROI(const Types::Core::DateAndTime &startTime, const Types::Core::DateAndTime &stopTime) const
This method returns true if the entire region between startTime and stopTime is inside an existing us...
std::size_t numberOfRegions() const
void update_union(const TimeROI &other)
Updates the TimeROI values with the union with another TimeROI.
void saveNexus(Nexus::File *file) const
bool operator!=(const TimeROI &other) const
size_t getMemorySize() const
void addROI(const std::string &startTime, const std::string &stopTime)
bool isCompletelyInMask(const Types::Core::DateAndTime &startTime, const Types::Core::DateAndTime &stopTime) const
This method returns true if the entire region between startTime and stopTime is inside an existing ig...
bool useNone() const
TimeROI selects no time to be used as all is invalid.
static const std::string NAME
the underlying property needs a name
std::string debugStrPrint(const std::size_t type=0) const
print the ROI boundaries to a string
bool useAll() const
TimeROI selects all time to be used.
Types::Core::DateAndTime timeAtIndex(unsigned long index) const
void update_or_replace_intersection(const TimeROI &other)
If this is empty, replace it with the supplied TimeROI, otherwise calculate the intersection.
void update_intersection(const TimeROI &other)
Updates the TimeROI values with the intersection with another TimeROI.
void appendROIFast(const Types::Core::DateAndTime &startTime, const Types::Core::DateAndTime &stopTime)
Append a new region to TimeROI fast.
Types::Core::DateAndTime lastTime() const
bool valueAtTime(const Types::Core::DateAndTime &time) const
This returns whether the time should be "used" (rather than ignored).
static const TimeROI USE_ALL
Constant for TimeROI where any time is used.
static const TimeROI USE_NONE
Constant for TimeROI where no time is used.
void validateValues(const std::string &label)
A specialised Property class for holding a series of time-value pairs.
int size() const override
Returns the number of values at UNIQUE time intervals in the time series.
std::vector< TYPE > valuesAsVector() const
Return the time series's values (unfiltered) as a vector<TYPE>
Types::Core::DateAndTime firstTime() const
Returns the first time regardless of filter.
void eliminateDuplicates()
Detects whether there are duplicated entries (of time) in property & eliminates them.
void addValue(const Types::Core::DateAndTime &time, const TYPE &value)
Add a value to the map using a DateAndTime object.
Types::Core::DateAndTime lastTime() const
Returns the last time.
TYPE lastValue() const
Returns the last value.
std::vector< Types::Core::DateAndTime > timesAsVector() const override
Return the time series's times as a vector<DateAndTime>
void saveProperty(Nexus::File *file) override
bool MANTID_GEOMETRY_DLL intersection(const ConvexPolygon &P, const ConvexPolygon &Q, ConvexPolygon &out)
Compute the instersection of two convex polygons.
Logger g_log("DateAndTime")
std::vector< TYPE > calculate_intersection(const std::vector< TYPE > &left, const std::vector< TYPE > &right)
This calculates the intersection of two sorted vectors that represent regions of interest (ROI).
std::vector< DateAndTime >::iterator DateAndTimeIter
Helper class which provides the Collimation Length for SANS instruments.