Mantid
Loading...
Searching...
No Matches
FilteredTimeSeriesProperty.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
8#include "MantidKernel/DllConfig.h"
10#include "MantidKernel/Logger.h"
13#include <string>
14
15using namespace Mantid::Kernel;
16using Mantid::Types::Core::DateAndTime;
17
18namespace Mantid::Kernel {
19
20namespace {
22Logger g_log("FilteredTimeSeriesProperty");
23} // namespace
24
29template <typename TYPE>
31 : TimeSeriesProperty<TYPE>(name), m_filter(std::make_unique<TimeROI>()), m_filterMap(), m_filterApplied(false) {}
38template <typename HeldType>
40 const TimeSeriesProperty<bool> &filterProp)
41 : TimeSeriesProperty<HeldType>(*seriesProp), m_filter(std::make_unique<TimeROI>()), m_filterMap(),
42 m_filterIntervals(), m_filterApplied(false) {
43 // Now filter us with the filter
44 this->filterWith(&filterProp);
45}
46
47template <typename HeldType>
49 const std::vector<Types::Core::DateAndTime> &times,
50 const std::vector<HeldType> &values)
51 : TimeSeriesProperty<HeldType>(name, times, values), m_filter(std::make_unique<TimeROI>()), m_filterMap(),
52 m_filterIntervals(), m_filterApplied(false) {}
53
54template <typename HeldType>
56 : TimeSeriesProperty<HeldType>(*seriesProp), m_filter(std::make_unique<TimeROI>()), m_filterMap(),
57 m_filterIntervals(), m_filterApplied(false) {}
58
65template <typename HeldType>
67 std::unique_ptr<const TimeSeriesProperty<HeldType>> seriesProp, const TimeSeriesProperty<bool> &filterProp)
68 : TimeSeriesProperty<HeldType>(*seriesProp.get()), m_filter(std::make_unique<TimeROI>()), m_filterMap(),
69 m_filterIntervals(), m_filterApplied(false) {
70 // Now filter us with the filter
71 this->filterWith(&filterProp);
72}
73
79}
80
81template <typename HeldType>
83 : TimeSeriesProperty<HeldType>(prop.name(), prop.timesAsVector(), prop.valuesAsVector()),
84 m_filter(std::make_unique<TimeROI>(*prop.m_filter.get())), m_filterMap(prop.m_filterMap),
85 m_filterIntervals(prop.m_filterIntervals), m_filterApplied(prop.m_filterApplied) {}
90template <typename HeldType> FilteredTimeSeriesProperty<HeldType>::~FilteredTimeSeriesProperty() = default;
98template <typename TYPE>
100 // if this is not filtered just return the parent version
101 if (this->m_filter->useAll()) {
102 return TimeSeriesProperty<TYPE>::filteredValuesAsVector(roi); // no filtering to do
103 }
104 // if the supplied roi is empty use just this one
105 const auto internalRoi = this->intersectFilterWithOther(roi); // allocates memory
106 const auto result = TimeSeriesProperty<TYPE>::filteredValuesAsVector(internalRoi);
107 delete internalRoi;
108 return result;
109}
110
111template <typename TYPE> std::vector<TYPE> FilteredTimeSeriesProperty<TYPE>::filteredValuesAsVector() const {
112 return TimeSeriesProperty<TYPE>::filteredValuesAsVector(this->m_filter.get());
113}
114
119template <typename TYPE>
121 if (m_filter->useAll()) {
122 return TimeSeriesProperty<TYPE>::filteredTimesAsVector(roi); // no filtering to do
123 }
124 const auto internalRoi = this->intersectFilterWithOther(roi);
126}
127
128template <typename TYPE> std::vector<DateAndTime> FilteredTimeSeriesProperty<TYPE>::filteredTimesAsVector() const {
129 return TimeSeriesProperty<TYPE>::filteredTimesAsVector(this->m_filter.get());
130}
131
143 // Throw exception when there are no values
144 if (this->m_values.empty()) {
145 const std::string error("nthInterval(): FilteredTimeSeriesProperty '" + this->name() + "' is empty");
146 g_log.debug(error);
147 throw std::runtime_error(error);
148 }
149
150 // Calculate time interval
152 if (m_filter->useAll()) {
153 // No filter uses the parent class implmentation
155 } else {
156 this->applyFilter();
157 // Throw exception if out of bounds
158 if (n < 0 || n >= static_cast<int>(this->m_filterIntervals.size())) {
159 const std::string error("nthInterval(): FilteredTimeSeriesProperty '" + this->name() + "' interval " +
160 std::to_string(n) + " does not exist");
162 throw std::runtime_error(error);
163 }
164 deltaT = this->m_filterIntervals[std::size_t(n)];
165 }
166
167 return deltaT;
168}
169
170template <typename TYPE> Types::Core::DateAndTime FilteredTimeSeriesProperty<TYPE>::nthTime(int n) const {
171 const auto interval = this->nthInterval(n);
172 return interval.start();
173}
174
175//-----------------------------------------------------------------------------------------------
181template <typename TYPE> TYPE FilteredTimeSeriesProperty<TYPE>::nthValue(int n) const {
182 // Throw error if property is empty
183 if (this->m_values.empty()) {
184 const std::string error("nthValue(): FilteredTimeSeriesProperty '" + this->name() + "' is empty");
185 g_log.debug(error);
186 throw std::runtime_error(error);
187 }
188
189 TYPE value;
190 if (m_filter->useAll()) {
191 // 3. Situation 1: No filter
193 } else {
194 // 4. Situation 2: There is filter
195 this->applyFilter();
196
197 if (m_filterMap.empty()) {
198 // this shouldn't happen
199 value = this->m_values.back().value();
200 } else {
201 // going past the end gets the last value
202 const size_t n_index = std::min<size_t>(static_cast<size_t>(n), m_filterMap.size() - 1);
203 value = this->m_values[m_filterMap[n_index]].value();
204 }
205 }
206
207 return value;
208}
209
210/* Divide the property into allowed and disallowed time intervals according to
211 \a filter.
212 * (Repeated time-value pairs (two same time and value entries) mark the start
213 of a gap in the values.)
214 * If any time-value pair is repeated, it means that this entry is in disallowed
215 region.
216 * The gap ends and an allowed time interval starts when a single time-value is
217 met.
218 The disallowed region will be hidden for countSize() and nthInterval()
219 Boundary condition
220 ?. If filter[0].time > log[0].time, then all log before filter[0] are
221 considered TRUE
222 2. If filter[-1].time < log[-1].time, then all log after filter[-1] will be
223 considered same as filter[-1]
224
225 @param filter :: The filter mask to apply
226 */
227template <typename TYPE> void FilteredTimeSeriesProperty<TYPE>::filterWith(const TimeSeriesProperty<bool> *filter) {
228 if ((!filter) || (filter->size() == 0)) {
229 // if filter is empty, clear the current
230 this->clearFilter();
231 } else {
232 this->clearFilterCache();
233 if (filter->lastValue() == true) {
234 // get the invented end time that has the same duration as the last known duration
235 DateAndTime endTime = this->getFakeEndTime();
236
237 // create temporary filter to add this end time to
238 TimeSeriesProperty<bool> *filterModified = filter->clone();
239 filterModified->addValue(endTime, false);
240
241 m_filter->replaceROI(filterModified);
242 } else {
243 m_filter->replaceROI(filter);
244 }
245
246 applyFilter();
247 }
248}
249
250template <typename TYPE> void FilteredTimeSeriesProperty<TYPE>::filterWith(const TimeROI &filter) {
251 if (filter.useAll()) {
252 // if filter is empty, clear the current
253 this->clearFilter();
254 } else {
255 this->clearFilterCache();
256 m_filter->replaceROI(filter);
257
258 applyFilter();
259 }
260}
261
263 // copy the values and ignore the filter
264 return std::move(new TimeSeriesProperty<TYPE>(this->name(), this->timesAsVector(), this->valuesAsVector()));
265}
266
270template <typename TYPE> void FilteredTimeSeriesProperty<TYPE>::clearFilter() const {
271 m_filter->clear();
272 this->clearFilterCache();
273}
274
275template <typename TYPE> void FilteredTimeSeriesProperty<TYPE>::clearFilterCache() const {
276 m_filterApplied = false;
277 m_filterMap.clear();
278 m_filterIntervals.clear();
279}
280
284template <typename TYPE> void FilteredTimeSeriesProperty<TYPE>::countSize() const {
285 if (m_filter->useAll()) {
286 // 1. Not filter
287 this->m_size = int(this->m_values.size());
288 } else {
289 // 2. With Filter
290 this->applyFilter();
291 this->m_size = int(m_filterMap.empty() ? this->m_values.size() : m_filterMap.size());
292 }
293}
294
295template <typename TYPE> int FilteredTimeSeriesProperty<TYPE>::size() const {
296 countSize();
297 return this->m_size;
298}
299
300/*
301 * Apply filter
302 * Requirement: There is no 2 consecutive 'second' values that are same in
303 *mFilter
304 *
305 * It only works with filter starting from TRUE AND having TRUE and FALSE
306 *altered
307 */
308template <typename TYPE> void FilteredTimeSeriesProperty<TYPE>::applyFilter() const {
309 // 1. Check and reset
310 if (m_filterApplied)
311 return;
312
313 // clear out the previous version
314 this->clearFilterCache();
315
316 if (m_filter->useAll())
317 return;
318
319 // 2. Apply filter
320 this->sortIfNecessary();
321
322 // the index into the m_values array of the time, or -1 (before) or m_values.size() (after)
323 std::size_t index_current_log{0};
324
325 for (const auto &splitter : m_filter->toTimeIntervals()) {
326 const auto endTime = splitter.stop();
327
328 // check if the splitter starts too early
329 if (endTime < this->m_values[index_current_log].time()) {
330 continue; // skip to the next splitter
331 }
332
333 // cache values to reduce number of method calls
334 const auto beginTime = splitter.start();
335
336 // find the first log that should be added
337 if (this->m_values.back().time() < beginTime) {
338 // skip directly to the end if the filter starts after the last log
339 index_current_log = this->m_values.size() - 1;
340 } else {
341 // search for the right starting point
342 while ((this->m_values[index_current_log].time() <= beginTime)) {
343 if (index_current_log + 1 > this->m_values.size())
344 break;
345 index_current_log++;
346 }
347 // need to back up by one
348 if (index_current_log > 0)
349 index_current_log--;
350 // go backwards more while times are equal to the one being started at
351 while (index_current_log > 0 &&
352 this->m_values[index_current_log].time() == this->m_values[index_current_log - 1].time()) {
353 index_current_log--;
354 }
355 }
356
357 // add everything up to the end time
358 for (; index_current_log < this->m_values.size(); ++index_current_log) {
359 if (this->m_values[index_current_log].time() >= endTime)
360 break;
361
362 // the current value goes into the filter
363 m_filterMap.emplace_back(index_current_log);
364
365 // end time is the end of the filter or when the next value starts
366 DateAndTime myEndTime(endTime);
367 if (index_current_log + 1 < this->m_values.size())
368 myEndTime = std::min(endTime, this->m_values[index_current_log + 1].time());
369 // start time is when this value was created or when the filter started
370 m_filterIntervals.emplace_back(
371 TimeInterval(std::max(beginTime, this->m_values[index_current_log].time()), myEndTime));
372 }
373 // go back one so the next splitter can add a value
374 if (index_current_log > 0)
375 index_current_log--;
376 }
377
378 // Change flag
379 m_filterApplied = true;
380
381 // Re-count size
382 countSize();
383}
384
392template <typename TYPE> std::string FilteredTimeSeriesProperty<TYPE>::setValueFromProperty(const Property &right) {
393 auto prop = dynamic_cast<const FilteredTimeSeriesProperty<TYPE> *>(&right);
394 if (!prop) {
395 return "Could not set value: properties have different type.";
396 }
397 this->m_values = prop->m_values;
398 this->m_size = prop->m_size;
399 this->m_propSortedFlag = prop->m_propSortedFlag;
400 m_filter = std::unique_ptr<TimeROI>(prop->m_filter.get());
401 m_filterMap = prop->m_filterMap;
402 m_filterApplied = prop->m_filterApplied;
403 return "";
404}
405
410template <typename TYPE>
412 auto roi = new TimeROI(*m_filter.get());
413 if (other && (!other->useAll()))
415 return roi;
416}
417
418template <typename TYPE> const Kernel::TimeROI &FilteredTimeSeriesProperty<TYPE>::getTimeROI() const {
419 return *(this->m_filter.get());
420}
421
427template <typename TYPE> std::vector<TimeInterval> FilteredTimeSeriesProperty<TYPE>::getTimeIntervals() const {
428 if (m_filter->useAll()) {
429 // Case where there is no filter just use the parent implementation
431 } else {
432 if (!m_filterApplied) {
433 applyFilter();
434 }
435
436 return m_filter->toTimeIntervals();
437 }
438}
439
440template <typename HeldType>
442 const TimeROI *roi = intersectFilterWithOther(timeRoi);
443
444 if (size() == 1)
445 return static_cast<double>(TimeSeriesProperty<HeldType>::firstValue(*roi));
446 else
448}
449
450template <> double FilteredTimeSeriesProperty<std::string>::timeAverageValue(const TimeROI * /*timeRoi*/) const {
451 throw Exception::NotImplementedError("TimeSeriesProperty::timeAverageValue is not implemented for string properties");
452}
453
454template <typename HeldType>
456 const bool time_and_value_compare = TimeSeriesProperty<HeldType>::operator==(right);
457 if (!time_and_value_compare) {
458 // unfiltered doesn't match
459 return false;
460 } else {
461 // only need to compare the filters
462 const auto rhs_ftsp = dynamic_cast<const FilteredTimeSeriesProperty<HeldType> *>(&right);
463 if (m_filter->useAll()) {
464 if (!rhs_ftsp) {
465 // simple compare is fine
466 return time_and_value_compare;
467 } else {
468 // can't compare filters
469 return false;
470 }
471 } else {
472 // only need to compare filters
473 return m_filter == rhs_ftsp->m_filter;
474 }
475 }
476}
477
478template <typename HeldType> bool FilteredTimeSeriesProperty<HeldType>::operator==(const Property &right) const {
479 auto rhs_tsp = dynamic_cast<const TimeSeriesProperty<HeldType> *>(&right);
480 if (!rhs_tsp)
481 return false;
482 return this->operator==(*rhs_tsp);
483}
484
486// -------------------------- Macro to instantiation concrete types
487// --------------------------------
488#define INSTANTIATE(TYPE) template class FilteredTimeSeriesProperty<TYPE>;
489
490// -------------------------- Concrete instantiation
491// -----------------------------------------------
492INSTANTIATE(int32_t)
493INSTANTIATE(int64_t)
494INSTANTIATE(uint32_t)
495INSTANTIATE(uint64_t)
496INSTANTIATE(float)
497INSTANTIATE(double)
498INSTANTIATE(std::string)
499INSTANTIATE(bool)
500
501
502
503} // namespace Mantid::Kernel
std::string name
Definition Run.cpp:60
size_t m_size
Maximum size of the store.
double value
The value of the point.
Definition FitMW.cpp:51
double error
#define INSTANTIATE(TYPE)
double right
Marks code as not implemented yet.
Definition Exception.h:138
Templated class that defines a filtered time series but still gives access to the original data.
std::string setValueFromProperty(const Property &right) override
Set a value from another property.
std::unique_ptr< TimeROI > m_filter
The filter.
std::vector< HeldType > filteredValuesAsVector() const override
TimeInterval nthInterval(int n) const override
Returns n-th valid time interval, in a very inefficient way.
HeldType nthValue(int n) const override
Returns n-th value of n-th interval in an incredibly inefficient way.
void filterWith(const TimeSeriesProperty< bool > *filter)
Divide the property into allowed and disallowed time intervals according to a filter.
double timeAverageValue(const TimeROI *timeRoi=nullptr) const override
Returns the calculated time weighted average value.
std::vector< Mantid::Kernel::TimeInterval > getTimeIntervals() const override
If filtering by log, get the time intervals for splitting.
TimeROI * intersectFilterWithOther(const TimeROI *other) const
Combines the currently held filter with the supplied one as an intersection.
std::vector< Types::Core::DateAndTime > filteredTimesAsVector() const override
FilteredTimeSeriesProperty< HeldType > * clone() const override
"Virtual" copy constructor
Types::Core::DateAndTime nthTime(int n) const override
Returns n-th time. NOTE: Complexity is order(n)! regardless of filter.
FilteredTimeSeriesProperty()=delete
Disable default constructor.
void clearFilter() const
Restores the property to the unsorted state.
int size() const override
Return the size of this property.
~FilteredTimeSeriesProperty() override
Destructor.
const TimeSeriesProperty< HeldType > * unfiltered() const
Access the unfiltered log.
bool operator==(const TimeSeriesProperty< HeldType > &right) const override
void clearFilterCache() const
Clear out the applied filter.
The Logger class is in charge of the publishing messages from the framework through various channels.
Definition Logger.h:51
void debug(const std::string &msg)
Logs at debug level.
Definition Logger.cpp:145
Base class for properties.
Definition Property.h:94
Represents a time interval.
Definition DateAndTime.h:25
TimeROI : Object that holds information about when the time measurement was active.
Definition TimeROI.h:18
bool useAll() const
TimeROI selects all time to be used.
Definition TimeROI.cpp:693
void update_or_replace_intersection(const TimeROI &other)
If this is empty, replace it with the supplied TimeROI, otherwise calculate the intersection.
Definition TimeROI.cpp:548
A specialised Property class for holding a series of time-value pairs.
TimeSeriesProperty< TYPE > * clone() const override
"Virtual" copy constructor
int size() const override
Returns the number of values at UNIQUE time intervals in the time series.
TYPE firstValue() const
Returns the first value regardless of filter.
double timeAverageValue(const TimeROI *timeRoi=nullptr) const override
Returns the calculated time weighted average value.
virtual std::vector< Types::Core::DateAndTime > filteredTimesAsVector() const
void addValue(const Types::Core::DateAndTime &time, const TYPE &value)
Add a value to the map using a DateAndTime object.
TYPE lastValue() const
Returns the last value.
std::vector< TimeValueUnit< TYPE > > m_values
Holds the time series data.
virtual bool operator==(const TimeSeriesProperty< TYPE > &right) const
Deep comparison.
virtual std::vector< Mantid::Kernel::TimeInterval > getTimeIntervals() const
If filtering by log, get the time intervals for splitting.
virtual TYPE nthValue(int n) const
Returns n-th value of n-th interval in an incredibly inefficient way.
virtual TimeInterval nthInterval(int n) const
Returns n-th valid time interval, in a very inefficient way.
virtual std::vector< TYPE > filteredValuesAsVector() const
MANTID_KERNEL_DLL bool operator==(const Mantid::Kernel::Property &lhs, const Mantid::Kernel::Property &rhs)
Compares this to another property for equality.
Definition Property.cpp:244
STL namespace.
std::string to_string(const wide_integer< Bits, Signed > &n)