13#include "MantidNexus/NexusFile.h"
15#include <json/value.h>
17#include <boost/regex.hpp>
21using namespace Types::Core;
25Logger
g_log(
"TimeSeriesProperty");
33template <
typename TYPE>
bool allValuesAreSame(
const std::vector<TimeValueUnit<TYPE>> &values) {
34 assert(values.size() > 1);
35 const auto &first_value = values.front().value();
36 return std::all_of(std::next(values.cbegin()), values.cend(),
37 [&first_value](
const auto &v) { return v.value() == first_value; });
45template <
typename TYPE>
55template <
typename TYPE>
57 const std::vector<Types::Core::DateAndTime> ×,
58 const std::vector<TYPE> &values)
77template <
typename TYPE>
91 createFilteredData(timeROI, filteredTS->m_values);
93 filteredTS->m_size =
static_cast<int>(filteredTS->m_values.size());
103 auto timeSeriesProperty = this->clone();
104 auto values = timeSeriesProperty->valuesAsVector();
105 auto times = timeSeriesProperty->timesAsVector();
107 for (
auto it = times.begin(); it != times.end(); ++it) {
113 timeSeriesProperty->clear();
114 timeSeriesProperty->addValues(times, values);
115 return timeSeriesProperty;
127 if (this->m_values.size() < 2) {
128 throw std::runtime_error(
"Derivative is not defined for a time-series "
129 "property with less then two values");
132 this->sortIfNecessary();
133 auto it = this->m_values.begin();
134 int64_t t0 = it->time().totalNanoseconds();
135 TYPE v0 = it->value();
138 auto timeSeriesDeriv = std::make_unique<TimeSeriesProperty<double>>(this->
name() +
"_derivative");
139 timeSeriesDeriv->reserve(this->m_values.size() - 1);
140 for (; it != m_values.end(); it++) {
142 int64_t t1 = it->time().totalNanoseconds();
144 double deriv = 1.e+9 * (double(v1 - v0) / double(t1 - t0));
145 auto tm =
static_cast<int64_t
>((t1 + t0) / 2);
146 timeSeriesDeriv->addValue(Types::Core::DateAndTime(tm), deriv);
151 return timeSeriesDeriv;
155 throw std::runtime_error(
"Time series property derivative is not defined for strings");
163 return m_values.size() * (
sizeof(
TYPE) +
sizeof(DateAndTime));
184 if (this->
operator!=(*
rhs)) {
185 m_values.insert(m_values.end(),
rhs->m_values.begin(),
rhs->m_values.end());
194 m_size =
static_cast<int>(m_values.size());
198 <<
" could not be added to another property of the same "
199 "name but incompatible type.\n";
221 if (this->realSize() !=
right.realSize()) {
225 const std::vector<DateAndTime> rhsTimes =
right.timesAsVector();
226 if (!std::equal(lhsTimes.begin(), lhsTimes.end(), rhsTimes.begin())) {
230 const std::vector<TYPE> lhsValues = this->valuesAsVector();
231 const std::vector<TYPE> rhsValues =
right.valuesAsVector();
232 if (!std::equal(lhsValues.begin(), lhsValues.end(), rhsValues.begin())) {
283template <
typename TYPE>
286 filteredData.clear();
291 if (m_values.empty()) {
296 if (m_values.size() == 1) {
297 filteredData.push_back(m_values.front());
304 if (allValuesAreSame(m_values) && this->
name() !=
"proton_charge") {
305 filteredData.push_back(m_values.front());
311 std::copy(m_values.cbegin(), m_values.cend(), std::back_inserter(filteredData));
317 filteredData.push_back(m_values.front());
324 const std::vector<Types::Core::DateAndTime> &roiTimes = timeROI.
getAllTimes();
325 auto itROI = roiTimes.cbegin();
326 const auto itROIEnd = roiTimes.cend();
328 auto itValue = m_values.cbegin();
329 const auto itValueEnd = m_values.cend();
330 auto itLastValueUsed = itValue;
332 while (itROI != itROIEnd && itValue != itValueEnd) {
335 while (std::distance(itROI, itROIEnd) > 2 && *(std::next(itROI, 2)) <= itValue->time())
336 std::advance(itROI, 2);
338 itValue = std::lower_bound(itValue, itValueEnd, *itROI,
339 [](
const auto &
value,
const auto &roi_time) {
return value.time() < roi_time; });
341 auto itBeginUseValue = itValue;
342 auto itEndUseValue = itValue;
344 if (itValue == itValueEnd) {
347 itEndUseValue = itValueEnd;
350 else if (itValue->time() <= *(std::next(itROI))) {
352 itBeginUseValue = itValue == m_values.begin() ? itValue : std::prev(itValue);
354 while (itValue != itValueEnd && itValue->time() <= *(std::next(itROI)))
357 itEndUseValue = itValue == itValueEnd ? itValue : std::next(itValue);
361 else if (std::distance(itROI, itROIEnd) == 2 ||
362 (std::distance(itROI, itROIEnd) > 2 && itValue->time() < *(std::next(itROI, 2)))) {
364 itBeginUseValue = itValue == m_values.begin() ? itValue : std::prev(itValue);
365 itEndUseValue = std::next(itValue);
368 if (!filteredData.empty()) {
369 itBeginUseValue = std::max(itBeginUseValue, std::next(itLastValueUsed));
373 if (itBeginUseValue < itEndUseValue) {
374 std::copy(itBeginUseValue, itEndUseValue, std::back_inserter(filteredData));
375 itLastValueUsed = std::prev(itEndUseValue);
379 std::advance(itROI, 2);
389 std::vector<TimeValueUnit<TYPE>> mp_copy;
390 createFilteredData(timeROI, mp_copy);
396 m_size =
static_cast<int>(m_values.size());
407#pragma warning(disable : 4244)
408#pragma warning(disable : 4804)
411#if defined(__GNUC__) && !(defined(__INTEL_COMPILER))
412#pragma GCC diagnostic ignored "-Wconversion"
428template <
typename TYPE>
430 double TimeTolerance,
bool centre)
const {
431 const bool emptyMin = (min ==
EMPTY_DBL());
432 const bool emptyMax = (max ==
EMPTY_DBL());
434 if (!emptyMin && !emptyMax && max < min) {
435 std::stringstream ss;
436 ss <<
"TimeSeriesProperty::makeFilterByValue: 'max' argument must be "
437 "greater than 'min' "
438 <<
"(got min=" << min <<
" max=" << max <<
")";
439 throw std::invalid_argument(ss.str());
445 min =
static_cast<double>(minValue());
447 max =
static_cast<double>(maxValue());
453 if (m_values.empty())
460 bool lastGood(
false);
461 time_duration tol = DateAndTime::durationFromSeconds(TimeTolerance);
464 DateAndTime start, stop;
466 for (
size_t i = 0; i < m_values.size(); ++i) {
467 const DateAndTime lastGoodTime = t;
469 t = m_values[i].time();
470 TYPE val = m_values[i].value();
473 const bool isGood = ((val >= min) && (val <= max));
477 if (isGood != lastGood) {
483 start = centre ? t - tol : t;
488 stop = centre ? lastGoodTime + tol : t;
489 split.emplace_back(start, stop, 0);
501 split.emplace_back(start, stop, 0);
513 "is not implemented for string "
533template <
typename TYPE>
535 const TimeInterval &expandRange,
double TimeTolerance,
bool centre,
536 const TimeROI *existingROI)
const {
537 const bool emptyMin = (min ==
EMPTY_DBL());
538 const bool emptyMax = (max ==
EMPTY_DBL());
540 if (!emptyMin && !emptyMax && max < min) {
541 std::stringstream ss;
542 ss <<
"TimeSeriesProperty::makeFilterByValue: 'max' argument must be "
543 "greater than 'min' "
544 <<
"(got min=" << min <<
" max=" << max <<
")";
545 throw std::invalid_argument(ss.str());
551 min =
static_cast<double>(minValue());
553 max =
static_cast<double>(maxValue());
558 if (m_values.empty())
565 const time_duration tol = DateAndTime::durationFromSeconds(TimeTolerance);
567 DateAndTime start, stop;
570 for (
size_t i = 0; i < m_values.size(); ++i) {
571 TYPE val = m_values[i].value();
573 if ((val >= min) && (val <= max)) {
575 stop_t = m_values[i].time();
578 stop_t = m_values[i].time();
579 start = centre ? m_values[i].time() - tol : m_values[i].time();
582 stop = centre ? stop_t + tol : m_values[i].time();
584 newROI.
addROI(start, stop);
589 stop = centre ? stop_t + tol : stop_t;
591 newROI.
addROI(start, stop);
595 if (expandRange.
start() < firstTime()) {
596 auto val =
static_cast<double>(firstValue());
597 if ((val >= min) && (val <= max)) {
601 if (expandRange.
stop() > lastTime()) {
602 auto val =
static_cast<double>(lastValue());
603 if ((val >= min) && (val <= max)) {
604 newROI.
addROI(lastTime(), expandRange.
stop());
615 if (existingROI !=
nullptr && !existingROI->
useAll()) {
630 "is not implemented for string "
644template <
typename TYPE>
647 const bool emptyMin = (min ==
EMPTY_DBL());
648 const bool emptyMax = (max ==
EMPTY_DBL());
650 if (!emptyMin && !emptyMax && max < min) {
651 std::stringstream ss;
652 ss <<
"TimeSeriesProperty::expandFilterToRange: 'max' argument must be "
653 "greater than 'min' "
654 <<
"(got min=" << min <<
" max=" << max <<
")";
655 throw std::invalid_argument(ss.str());
661 min =
static_cast<double>(minValue());
663 max =
static_cast<double>(maxValue());
665 if (range.
start() < firstTime()) {
667 double val =
static_cast<double>(firstValue());
668 if ((val >= min) && (val <= max)) {
670 extraFilter.emplace_back(range.
start(), firstTime(), 0);
677 if (lastTime() < range.
stop()) {
679 double val =
static_cast<double>(lastValue());
680 if ((val >= min) && (val <= max)) {
682 extraFilter.emplace_back(lastTime(), range.
stop(), 0);
697 "is not implemented for string "
708 if ((timeRoi ==
nullptr) || (timeRoi->
useAll())) {
710 retVal = this->averageValueInFilter(intervals);
711 }
else if (timeRoi->
useNone()) {
718 retVal = this->averageValueInFilter(filter);
719 g_log.
warning(
"Calls to TimeSeriesProperty::timeAverageValue should be replaced with "
720 "Run::getTimeAveragedValue");
722 }
catch (std::exception &) {
724 retVal = std::numeric_limits<double>::quiet_NaN();
739template <
typename TYPE>
745 return static_cast<double>(this->firstValue());
749 if (realSize() == 0 || filter.empty()) {
750 return std::numeric_limits<double>::quiet_NaN();
755 double numerator(0.0), totalTime(0.0);
757 for (
const auto &time : filter) {
759 totalTime += time.duration();
763 double currentValue =
static_cast<double>(getSingleValue(time.start(),
index));
764 DateAndTime startTime = time.start();
766 while (
index < realSize() - 1 && m_values[
index + 1].time() < time.stop()) {
768 numerator += DateAndTime::secondsFromDuration(m_values[
index].time() - startTime) * currentValue;
769 startTime = m_values[
index].time();
770 currentValue =
static_cast<double>(m_values[
index].value());
774 numerator += DateAndTime::secondsFromDuration(time.stop() - startTime) * currentValue;
779 return numerator / totalTime;
793 "averageValueInFilter is not "
794 "implemented for string properties");
797template <
typename TYPE>
798std::pair<double, double>
800 double mean_prev, mean_current(0.0), s(0.0), variance, duration, weighted_sum(0.0);
804 if (realSize() <= 1 || intervals.empty()) {
805 return std::pair<double, double>{this->averageValueInFilter(intervals), std::numeric_limits<double>::quiet_NaN()};
807 auto real_size = realSize();
808 for (
const auto &time : intervals) {
810 auto currentValue =
static_cast<double>(getSingleValue(time.start(),
index));
811 DateAndTime startTime = time.start();
812 while (
index < realSize() - 1 && m_values[
index + 1].time() < time.stop()) {
814 if (
index == real_size) {
815 duration = DateAndTime::secondsFromDuration(time.stop() - startTime);
817 duration = DateAndTime::secondsFromDuration(m_values[
index].time() - startTime);
818 startTime = m_values[
index].time();
820 mean_prev = mean_current;
822 weighted_sum += duration;
824 mean_current = mean_prev + (duration / weighted_sum) * (currentValue - mean_prev);
825 s += duration * (currentValue - mean_prev) * (currentValue - mean_current);
827 currentValue =
static_cast<double>(m_values[
index].value());
831 duration = DateAndTime::secondsFromDuration(time.stop() - startTime);
833 weighted_sum += duration;
834 mean_prev = mean_current;
836 mean_current = mean_prev + (duration / weighted_sum) * (currentValue - mean_prev);
837 s += duration * (currentValue - mean_prev) * (currentValue - mean_current);
840 variance = s / weighted_sum;
842 return std::pair<double, double>{mean_current, std::sqrt(variance)};
849std::pair<double, double>
852 "averageAndStdDevInFilter is not "
853 "implemented for string properties");
856template <
typename TYPE>
859 if (this->realSize() == 0)
860 return std::pair<double, double>{std::numeric_limits<double>::quiet_NaN(),
861 std::numeric_limits<double>::quiet_NaN()};
862 else if (this->realSize() == 1)
863 return std::pair<double, double>(
static_cast<double>(this->firstValue()), 0.0);
866 std::vector<TimeInterval> intervals;
867 if (timeRoi && !timeRoi->
useAll()) {
873 return this->averageAndStdDevInFilter(intervals);
880std::pair<double, double>
883 "TimeSeriesProperty::timeAverageValueAndStdDev is not implemented for string properties");
890#if defined(__GNUC__) && !(defined(__INTEL_COMPILER))
891#pragma GCC diagnostic warning "-Wconversion"
905 std::map<DateAndTime, TYPE> asMap;
907 if (!m_values.empty()) {
908 for (
size_t i = 0; i < m_values.size(); i++)
909 asMap[m_values[i].time()] = m_values[i].value();
922 std::vector<TYPE> out;
923 out.reserve(m_values.size());
925 for (
size_t i = 0; i < m_values.size(); i++)
926 out.emplace_back(m_values[i].value());
938 std::multimap<DateAndTime, TYPE> asMultiMap;
940 if (!m_values.empty()) {
941 for (
size_t i = 0; i < m_values.size(); i++)
942 asMultiMap.insert(std::make_pair(m_values[i].time(), m_values[i].value()));
955 std::vector<DateAndTime> out;
956 out.reserve(m_values.size());
958 for (
size_t i = 0; i < m_values.size(); i++) {
959 out.emplace_back(m_values[i].time());
974template <
typename TYPE>
976 if (roi && !roi->
useAll()) {
977 this->sortIfNecessary();
978 std::vector<DateAndTime> filteredTimes;
979 if (roi->
firstTime() > this->m_values.back().time()) {
981 filteredTimes.emplace_back(roi->
firstTime());
984 std::size_t index_current_log{0};
987 const auto endTime = splitter.stop();
990 if (endTime < this->m_values[index_current_log].time()) {
995 const auto beginTime = splitter.start();
998 if (this->m_values.back().time() < beginTime) {
1000 index_current_log = this->m_values.size() - 1;
1003 while ((this->m_values[index_current_log].time() <= beginTime)) {
1004 if (index_current_log + 1 > this->m_values.size())
1006 index_current_log++;
1009 if (index_current_log > 0)
1010 index_current_log--;
1012 while (index_current_log > 0 &&
1013 this->m_values[index_current_log].time() == this->m_values[index_current_log - 1].time()) {
1014 index_current_log--;
1019 for (; index_current_log < this->m_values.size(); ++index_current_log) {
1020 if (this->m_values[index_current_log].time() >= endTime)
1024 filteredTimes.emplace_back(std::max(beginTime, this->m_values[index_current_log].time()));
1027 if (index_current_log > 0)
1028 index_current_log--;
1032 return filteredTimes;
1034 return this->timesAsVector();
1039 return this->timesAsVector();
1051 std::vector<double> out;
1052 if (!m_values.empty()) {
1053 out.reserve(m_values.size());
1055 Types::Core::DateAndTime start = m_values[0].time();
1056 for (
size_t i = 0; i < m_values.size(); i++) {
1057 out.emplace_back(DateAndTime::secondsFromDuration(m_values[i].time() - start));
1069template <
typename TYPE>
1075 std::vector<double> out;
1076 if (!m_values.empty()) {
1077 out.reserve(m_values.size());
1078 for (
size_t i = 0; i < m_values.size(); i++) {
1079 out.emplace_back(DateAndTime::secondsFromDuration(m_values[i].time() - start));
1091template <
typename TYPE>
1095 m_values.emplace_back(newvalue);
1122 return addValue(Types::Core::DateAndTime(time),
value);
1131 Types::Core::DateAndTime dt;
1132 dt.set_from_time_t(time);
1133 return addValue(dt,
value);
1141template <
typename TYPE>
1143 const std::vector<TYPE> &values) {
1144 size_t length = std::min(times.size(), values.size());
1145 m_size +=
static_cast<int>(length);
1146 for (
size_t i = 0; i < length; ++i) {
1147 m_values.emplace_back(times[i], values[i]);
1150 if (!values.empty())
1159template <
typename TYPE>
1161 const std::vector<TYPE> &values) {
1163 addValues(times, values);
1171 if (m_values.empty()) {
1172 const std::string
error(
"lastTime(): TimeSeriesProperty '" +
name() +
"' is empty");
1174 throw std::runtime_error(
error);
1179 return m_values.rbegin()->time();
1186 if (m_values.empty()) {
1187 const std::string
error(
"firstValue(): TimeSeriesProperty '" +
name() +
"' is empty");
1189 throw std::runtime_error(
error);
1194 return m_values[0].value();
1199 if (startTime <= this->firstTime()) {
1200 return this->firstValue();
1201 }
else if (startTime >= this->lastTime()) {
1202 return this->lastValue();
1204 const auto times = this->timesAsVector();
1205 auto iter = std::lower_bound(times.cbegin(), times.cend(), startTime);
1206 if (*iter > startTime)
1208 const auto index = std::size_t(std::distance(times.cbegin(), iter));
1210 const auto values = this->valuesAsVector();
1220 if (m_values.empty()) {
1221 const std::string
error(
"firstTime(): TimeSeriesProperty '" +
name() +
"' is empty");
1223 throw std::runtime_error(
error);
1228 return m_values[0].time();
1236 if (m_values.empty()) {
1237 const std::string
error(
"lastValue(): TimeSeriesProperty '" +
name() +
"' is empty");
1239 throw std::runtime_error(
error);
1244 return m_values.rbegin()->value();
1248 const auto stopTime = roi.
lastTime();
1249 const auto times = this->timesAsVector();
1250 if (stopTime <= times.front()) {
1251 return this->firstValue();
1252 }
else if (stopTime >= times.back()) {
1253 return this->lastValue();
1255 auto iter = std::lower_bound(times.cbegin(), times.cend(), stopTime);
1256 if ((iter != times.cbegin()) && (*iter > stopTime))
1258 const auto index = std::size_t(std::distance(times.cbegin(), iter));
1260 const auto values = this->valuesAsVector();
1276 if (this->size() == 0)
1277 return std::numeric_limits<double>::quiet_NaN();
1278 if (roi && !roi->
useAll()) {
1280 const auto thisFirstTime = this->firstTime();
1282 if (thisFirstTime > DateAndTime::GPS_EPOCH) {
1283 seriesSpan.
addMask(DateAndTime::GPS_EPOCH, thisFirstTime);
1288 const double duration_sec =
1289 std::accumulate(intervals.cbegin(), intervals.cend(), 0.,
1290 [](
double sum,
const auto &interval) { return sum + interval.duration(); });
1291 return duration_sec;
1306 return raw_stats.
mean;
1326 std::stringstream ins;
1327 for (
size_t i = 0; i < m_values.size(); i++) {
1329 ins << m_values[i].time().toSimpleString();
1330 ins <<
" " << m_values[i].value() <<
"\n";
1334 ins <<
"Error Error"
1349 std::vector<std::string> values;
1350 values.reserve(m_values.size());
1352 for (
size_t i = 0; i < m_values.size(); i++) {
1353 std::stringstream line;
1354 line << m_values[i].time().toSimpleString() <<
" " << m_values[i].value();
1355 values.emplace_back(line.str());
1374 std::map<DateAndTime, TYPE> asMap;
1375 if (m_values.empty())
1378 TYPE d = m_values[0].value();
1379 asMap[m_values[0].time()] =
d;
1381 for (
size_t i = 1; i < m_values.size(); i++) {
1382 if (m_values[i].
value() !=
d) {
1384 asMap[m_values[i].time()] = m_values[i].value();
1385 d = m_values[i].value();
1398 "Cannot extract TimeSeries from a "
1409 "Cannot extract TimeSeries from a "
1417template <
typename TYPE>
1420 "Cannot extract TimeSeries from "
1442 if (realSize() > 1) {
1443 auto lastValueInVec = m_values.back();
1445 m_values.emplace_back(lastValueInVec);
1460template <
typename TYPE>
1462 const std::vector<TYPE> &new_values) {
1463 if (time_sec.size() != new_values.size()) {
1464 std::stringstream msg;
1465 msg <<
"TimeSeriesProperty \"" <<
name() <<
"\" create: mismatched size "
1466 <<
"for the time and values vectors.";
1467 throw std::invalid_argument(msg.str());
1471 const std::size_t num = new_values.size();
1472 m_values.reserve(num);
1475 if (std::is_sorted(time_sec.cbegin(), time_sec.cend()))
1480 constexpr double SEC_TO_NANO{1000000000.0};
1481 const int64_t start_time_ns = start_time.totalNanoseconds();
1482 for (std::size_t i = 0; i < num; i++) {
1483 m_values.emplace_back(start_time_ns +
static_cast<int64_t
>(time_sec[i] * SEC_TO_NANO), new_values[i]);
1487 m_size =
static_cast<int>(m_values.size());
1499template <
typename TYPE>
1501 const std::vector<TYPE> &new_values) {
1502 if (new_times.size() != new_values.size())
1503 throw std::invalid_argument(
"TimeSeriesProperty::create: mismatched size "
1504 "for the time and values vectors.");
1508 if (new_times.empty()) {
1513 const std::size_t num = new_values.size();
1514 m_values.reserve(num);
1517 if (std::is_sorted(new_times.cbegin(), new_times.cend()))
1522 for (std::size_t i = 0; i < num; i++) {
1523 m_values.emplace_back(new_times[i], new_values[i]);
1527 m_size =
static_cast<int>(m_values.size());
1535 if (m_values.empty()) {
1536 const std::string
error(
"getSingleValue(): TimeSeriesProperty '" +
name() +
"' is empty");
1538 throw std::runtime_error(
error);
1546 if (t < m_values[0].time()) {
1548 valueAtTime = m_values[0].value();
1549 }
else if (t >= m_values.back().time()) {
1551 valueAtTime = m_values.back().value();
1554 int index = this->findIndex(t);
1559 }
else if (
index ==
int(m_values.size())) {
1561 index =
static_cast<int>(m_values.size()) - 1;
1562 }
else if (
index >
int(m_values.size())) {
1563 std::stringstream errss;
1564 errss <<
"TimeSeriesProperty.findIndex() returns index (" <<
index <<
" ) > maximum defined value "
1566 throw std::logic_error(errss.str());
1569 valueAtTime = m_values[
static_cast<size_t>(
index)].
value();
1580template <
typename TYPE>
1582 if (m_values.empty()) {
1583 const std::string
error(
"getSingleValue(): TimeSeriesProperty '" +
name() +
"' is empty");
1585 throw std::runtime_error(
error);
1593 if (t < m_values[0].time()) {
1595 valueAtTime = m_values[0].value();
1597 }
else if (t >= m_values.back().time()) {
1599 valueAtTime = m_values.back().value();
1600 index = int(m_values.size()) - 1;
1603 index = this->findIndex(t);
1608 }
else if (
index ==
int(m_values.size())) {
1610 index =
static_cast<int>(m_values.size()) - 1;
1611 }
else if (
index >
int(m_values.size())) {
1612 std::stringstream errss;
1613 errss <<
"TimeSeriesProperty.findIndex() returns index (" <<
index <<
" ) > maximum defined value "
1615 throw std::logic_error(errss.str());
1618 valueAtTime = m_values[
static_cast<size_t>(
index)].
value();
1636 if (m_values.empty()) {
1637 const std::string
error(
"nthInterval(): TimeSeriesProperty '" +
name() +
"' is empty");
1639 throw std::runtime_error(
error);
1650 if (
n >=
static_cast<int>(m_values.size()) || (
n ==
static_cast<int>(m_values.size()) - 1 && m_values.size() == 1)) {
1653 }
else if (
n ==
static_cast<int>(m_values.size()) - 1) {
1655 DateAndTime endTime = getFakeEndTime();
1660 DateAndTime startT = m_values[
static_cast<std::size_t
>(
n)].time();
1661 DateAndTime endT = m_values[
static_cast<std::size_t
>(
n) + 1].time();
1673 const auto ultimate = m_values.rbegin()->time();
1677 while (DateAndTime::secondsFromDuration(ultimate - (m_values.rbegin() + counter)->time()) == 0.) {
1682 time_duration lastDuration = m_values.rbegin()->time() - (m_values.rbegin() + counter)->time();
1685 return m_values.rbegin()->time() + lastDuration;
1697 if (m_values.empty()) {
1698 const std::string
error(
"nthValue(): TimeSeriesProperty '" +
name() +
"' is empty");
1700 throw std::runtime_error(
error);
1709 if (
static_cast<size_t>(
n) < m_values.size()) {
1710 const auto entry = m_values[
static_cast<std::size_t
>(
n)];
1711 nthValue = entry.value();
1713 const auto entry = m_values[
static_cast<std::size_t
>(
m_size) - 1];
1714 nthValue = entry.value();
1728 if (m_values.empty()) {
1729 const std::string
error(
"nthTime(): TimeSeriesProperty '" +
name() +
"' is empty");
1731 throw std::runtime_error(
error);
1734 if (n < 0 || n >=
static_cast<int>(m_values.size()))
1735 n =
static_cast<int>(m_values.size()) - 1;
1737 return m_values[
static_cast<size_t>(
n)].time();
1745 m_size = int(m_values.size());
1753 static const boost::regex re(
"^[0-9]{4}.[0-9]{2}.[0-9]{2}.[0-9]{2}.[0-9]{2}.[0-9]{2}");
1754 return boost::regex_search(str.begin(), str.end(), re);
1783template <
typename TYPE>
1787 out.
duration = this->durationInSeconds(roi);
1794 auto avAndDev = this->timeAverageValueAndStdDev(roi);
1815template <
typename TYPE>
1817 using namespace Kernel::Math;
1818 double singleValue = 0;
1819 switch (selection) {
1821 if (roi && !roi->
useAll())
1822 singleValue = double(this->firstValue(*roi));
1824 singleValue = double(this->nthValue(0));
1827 if (roi && !roi->
useAll())
1828 singleValue = double(this->lastValue(*roi));
1830 singleValue = double(this->nthValue(this->size() - 1));
1844 case TimeAveragedMean:
1850 case TimeAverageStdDev:
1851 singleValue = this->
getStatistics(roi).time_standard_deviation;
1854 throw std::invalid_argument(
"extractStatistic - Unknown statistic type: " + boost::lexical_cast<std::string>(
this));
1867 "extractStatistic is not "
1868 "implemented for string properties");
1880 const auto origSize{
m_size};
1885 auto it = std::unique(m_values.rbegin(), m_values.rend(),
1886 [](
const auto &a,
const auto &b) { return a.time() == b.time(); });
1887 m_values.erase(m_values.begin(), it.base());
1893 const auto numremoved = origSize -
m_size;
1895 g_log.
notice() <<
"Log \"" << this->
name() <<
"\" has " << numremoved <<
" entries removed due to duplicated time. "
1903 std::stringstream ss;
1904 for (
size_t i = 0; i < m_values.size(); ++i)
1905 ss << m_values[i].time() <<
"\t\t" << m_values[i].value() <<
"\n";
1921 bool sorted = is_sorted(m_values.begin(), m_values.end());
1930 <<
"\" is not sorted. Sorting is operated on it. \n";
1931 std::stable_sort(m_values.begin(), m_values.end());
1944 if (m_values.empty())
1951 if (t <= m_values[0].time()) {
1953 }
else if (t >= m_values.back().time()) {
1954 return (
int(m_values.size()));
1958 typename std::vector<TimeValueUnit<TYPE>>::const_iterator fid;
1960 fid = std::lower_bound(m_values.begin(), m_values.end(), temp);
1962 int newindex = int(fid - m_values.begin());
1963 if (fid->time() > t)
1975template <
typename TYPE>
1979 throw std::invalid_argument(
"Start Index cannot be less than 0");
1981 if (iend >=
static_cast<int>(m_values.size())) {
1982 throw std::invalid_argument(
"End Index cannot exceed the boundary");
1984 if (istart > iend) {
1985 throw std::invalid_argument(
"Start index cannot be greater than end index");
1989 if (t < (m_values.begin() + istart)->time()) {
1992 if (t > (m_values.begin() + iend)->time()) {
1993 return static_cast<int>(m_values.size());
2001 const auto first = m_values.cbegin() + istart;
2002 const auto last = m_values.cbegin() + iend + 1;
2003 const auto iter = std::lower_bound(first, last, temppair);
2007 throw std::runtime_error(
"Cannot find data");
2008 return static_cast<int>(std::distance(m_values.cbegin(), iter));
2021 return "Could not set value: properties have different type.";
2025 m_propSortedFlag = prop->m_propSortedFlag;
2035 std::vector<DateAndTime> times = this->timesAsVector();
2036 const DateAndTime &start = times.front();
2037 std::vector<double> timeSec(times.size());
2038 for (
size_t i = 0; i < times.size(); i++)
2039 timeSec[i] =
static_cast<double>(times[i].totalNanoseconds() - start.totalNanoseconds()) * 1e-9;
2040 file->writeData(
"time", timeSec);
2041 file->openData(
"time");
2042 file->putAttr(
"start", start.toISO8601String());
2049 std::vector<std::string> values = this->valuesAsVector();
2052 file->makeGroup(this->
name(),
"NXlog",
true);
2055 auto max_it = std::max_element(values.begin(), values.end(),
2056 [](
const std::string &a,
const std::string &b) { return a.size() < b.size(); });
2058 size_t maxlen = max_it->size() + 1;
2060 std::vector<char> strs(values.size() * maxlen);
2062 for (
const auto &prop : values) {
2063 std::copy(prop.begin(), prop.end(), &strs[
index]);
2069 file->putData(strs.data());
2071 saveTimeVector(file);
2082 std::vector<bool>
value = this->valuesAsVector();
2085 std::vector<uint8_t> asUint(
value.begin(),
value.end());
2086 file->makeGroup(this->
name(),
"NXlog",
true);
2087 file->writeData(
"value", asUint);
2088 file->putAttr(
"boolean",
"1");
2089 saveTimeVector(file);
2094 auto values = this->valuesAsVector();
2097 file->makeGroup(this->
name(),
"NXlog", 1);
2098 file->writeData(
"value", values);
2099 file->openData(
"value");
2100 file->putAttr(
"units", this->units());
2102 saveTimeVector(file);
2122template <
typename TYPE>
2124 std::vector<double> &counts)
const {
2126 size_t nPoints = counts.size();
2130 auto t0 =
static_cast<double>(tMin.totalNanoseconds());
2131 auto t1 =
static_cast<double>(tMax.totalNanoseconds());
2133 throw std::invalid_argument(
"invalid arguments for histogramData; tMax<tMin");
2135 double dt = (t1 - t0) /
static_cast<double>(nPoints);
2137 for (
auto const &ev : m_values) {
2138 auto time =
static_cast<double>(ev.time().totalNanoseconds());
2139 if (time < t0 || time >= t1)
2141 auto ind =
static_cast<size_t>((time - t0) / dt);
2142 counts[ind] +=
static_cast<double>(ev.value());
2148 const Types::Core::DateAndTime &tMax,
2149 std::vector<double> &counts)
const {
2153 throw std::runtime_error(
"histogramData is not implememnted for time series "
2154 "properties containing strings");
2167 if (roi && !roi->
useAll()) {
2168 this->sortIfNecessary();
2169 std::vector<TYPE> filteredValues;
2170 if (roi->
firstTime() > this->m_values.back().time()) {
2172 filteredValues.emplace_back(this->m_values.back().value());
2175 std::size_t index_current_log{0};
2177 const auto endTime = splitter.stop();
2180 if (endTime < this->m_values[index_current_log].time()) {
2185 const auto beginTime = splitter.start();
2188 if (this->m_values.back().time() < beginTime) {
2190 index_current_log = this->m_values.size() - 1;
2193 while ((this->m_values[index_current_log].time() <= beginTime)) {
2194 if (index_current_log + 1 > this->m_values.size())
2196 index_current_log++;
2199 if (index_current_log > 0)
2200 index_current_log--;
2202 while (index_current_log > 0 &&
2203 this->m_values[index_current_log].time() == this->m_values[index_current_log - 1].time()) {
2204 index_current_log--;
2209 for (; index_current_log < this->m_values.size(); ++index_current_log) {
2210 if (this->m_values[index_current_log].time() >= endTime)
2214 filteredValues.emplace_back(this->m_values[index_current_log].
value());
2217 if (index_current_log > 0)
2218 index_current_log--;
2221 return filteredValues;
2223 return this->valuesAsVector();
2228 return this->valuesAsVector();
2240 std::vector<TimeInterval> intervals;
2241 auto lastInterval = this->nthInterval(this->size() - 1);
2242 intervals.emplace_back(firstTime(), lastInterval.stop());
2249#define INSTANTIATE(TYPE) template class TimeSeriesProperty<TYPE>;
const std::vector< double > & rhs
size_t m_size
Maximum size of the store.
double value
The value of the point.
std::map< DeltaEMode::Type, std::string > index
#define INSTANTIATE(TYPE)
boost::python::list getTimeIntervals(const TimeROI &self)
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
Marks code as not implemented yet.
void debug(const std::string &msg)
Logs at debug level.
void notice(const std::string &msg)
Logs at notice level.
void warning(const std::string &msg)
Logs at warning level.
void information(const std::string &msg)
Logs at information level.
Base class for properties.
const std::string & name() const
Get the property's name.
Represents a time interval.
const Types::Core::DateAndTime & start() const
Beginning of the interval.
const Types::Core::DateAndTime & stop() const
End of the interval.
TimeROI : Object that holds information about when the time measurement was active.
double durationInSeconds() const
Duration of the whole TimeROI.
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
Types::Core::DateAndTime firstTime() const
void addROI(const std::string &startTime, const std::string &stopTime)
bool useNone() const
TimeROI selects no time to be used as all is invalid.
bool useAll() const
TimeROI selects all time to be used.
void update_intersection(const TimeROI &other)
Updates the TimeROI values with the intersection with another TimeROI.
Types::Core::DateAndTime lastTime() const
static const TimeROI USE_NONE
Constant for TimeROI where no time is used.
A specialised Property class for holding a series of time-value pairs.
void replaceValues(const std::vector< Types::Core::DateAndTime > ×, const std::vector< TYPE > &values)
Replaces the time series with new values time series values.
TimeSeriesProperty< TYPE > * clone() const override
"Virtual" copy constructor
std::string getDefault() const override
Returns the default value.
std::map< Types::Core::DateAndTime, TYPE > valueAsMap() const
Return the time series as a C++ map<DateAndTime, TYPE>
size_t getMemorySize() const override
Return the memory used by the property, in bytes.
Json::Value valueAsJson() const override
std::string toString() const
Stringize the property.
int size() const override
Returns the number of values at UNIQUE time intervals in the time series.
TYPE minValue() const
Returns the minimum value found in the series.
TYPE maxValue() const
Returns the maximum value found in the 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.
double durationInSeconds(const Kernel::TimeROI *roi=nullptr) const
Returns the duration of the time series, possibly restricted by a TimeROI object.
std::pair< double, double > timeAverageValueAndStdDev(const Kernel::TimeROI *timeRoi=nullptr) const override
Returns the calculated time weighted mean and standard deviation values.
void eliminateDuplicates()
Detects whether there are duplicated entries (of time) in property & eliminates them.
std::vector< double > timesAsVectorSeconds() const
Return the series as list of times, where the time is the number of seconds since the start.
std::multimap< Types::Core::DateAndTime, TYPE > valueAsMultiMap() const
Return the time series as a correct C++ multimap<DateAndTime, TYPE>.
TimeSeriesProperty & operator+=(Property const *right) override
Add the value of another property.
TimeSeriesProperty< TYPE > & merge(Property *rhs) override
Merge the given property with this one.
std::string value() const override
Get the time series property as a string of 'time value'.
void createFilteredData(const TimeROI &timeROI, std::vector< TimeValueUnit< TYPE > > &filteredData) const
Fill in the supplied vector of time series data according to the input TimeROI.
Property * cloneInTimeROI(const TimeROI &timeROI) const override
Create a partial copy according to TimeROI.
void makeFilterByValue(std::vector< SplittingInterval > &split, double min, double max, double TimeTolerance=0.0, bool centre=false) const override
Fill a SplittingIntervalVec that will filter the events by matching.
bool isDefault() const override
Returns if the value is at the default.
void sortIfNecessary() const
Sort the property into increasing times, if not already sorted.
double mean() const
Returns the mean value found in the series.
TimeSeriesPropertyStatistics getStatistics(const Kernel::TimeROI *roi=nullptr) const override
Return a TimeSeriesPropertyStatistics object.
int findIndex(Types::Core::DateAndTime t) const
Find the index of the entry of time t in the mP vector (sorted)
TYPE firstValue() const
Returns the first value regardless of filter.
void saveTimeVector(Nexus::File *file)
Saves the time vector has time + start attribute.
virtual bool operator!=(const TimeSeriesProperty< TYPE > &right) const
Deep comparison (not equal).
void histogramData(const Types::Core::DateAndTime &tMin, const Types::Core::DateAndTime &tMax, std::vector< double > &counts) const
generate constant time-step histogram from the property values
void expandFilterToRange(std::vector< SplittingInterval > &split, double min, double max, const TimeInterval &range) const override
Make sure an existing filter covers the full time range given.
~TimeSeriesProperty() override
Virtual destructor.
double timeAverageValue(const TimeROI *timeRoi=nullptr) const override
Returns the calculated time weighted average value.
std::string setValue(const std::string &) override
Set a property from a string.
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.
int m_size
The number of values (or time intervals) in the time series.
TimeSeriesProperty(const std::string &name)
Constructor.
void removeDataOutsideTimeROI(const TimeROI &timeRoi) override
Remove time values outside of TimeROI regions each defined as [roi_begin,roi_end].
void countSize() const
Updates size()
void clear() override
Deletes the series of values in the property.
Types::Core::DateAndTime lastTime() const
Returns the last time.
void setName(const std::string &name)
Set name of property.
TYPE lastValue() const
Returns the last value.
double extractStatistic(Math::StatisticType selection, const TimeROI *roi=nullptr) const override
Calculate a particular statistical quantity from the values of the time series.
std::map< Types::Core::DateAndTime, TYPE > valueAsCorrectMap() const
Return the time series as a correct C++ map<DateAndTime, TYPE>.
std::string setValueFromJson(const Json::Value &) override
Set a property from a string.
std::unique_ptr< TimeSeriesProperty< double > > getDerivative() const
Return time series property, containing time derivative of current property.
std::vector< TimeValueUnit< TYPE > > m_values
Holds the time series data.
void create(const Types::Core::DateAndTime &start_time, const std::vector< double > &time_sec, const std::vector< TYPE > &new_values)
Clears and creates a TimeSeriesProperty from these parameters.
Types::Core::DateAndTime getFakeEndTime() const
Returns an end time that will have the same spacing to the right of the last value as the last non-ze...
virtual bool operator==(const TimeSeriesProperty< TYPE > &right) const
Deep comparison.
double averageValueInFilter(const std::vector< TimeInterval > &filter) const
Calculate the time-weighted average of a property in a filtered range.
virtual std::vector< Mantid::Kernel::TimeInterval > getTimeIntervals() const
If filtering by log, get the time intervals for splitting.
void clearOutdated() override
Deletes all but the 'last entry' in the property.
virtual TYPE nthValue(int n) const
Returns n-th value of n-th interval in an incredibly inefficient way.
std::string setDataItem(const std::shared_ptr< DataItem > &) override
Set a property from a DataItem.
std::string isValid() const override
This doesn't check anything -we assume these are always valid.
std::vector< std::string > time_tValue() const
New method to return time series value pairs as std::vector<std::string>
std::vector< Types::Core::DateAndTime > timesAsVector() const override
Return the time series's times as a vector<DateAndTime>
std::pair< double, double > averageAndStdDevInFilter(const std::vector< TimeInterval > &intervals) const
Calculate the time-weighted average and std-deviation of a property in a filtered range.
virtual Types::Core::DateAndTime nthTime(int n) const
Returns n-th time. NOTE: Complexity is order(n)! regardless of filter.
TYPE getSingleValue(const Types::Core::DateAndTime &t) const
Returns the value at a particular time.
int upperBound(Types::Core::DateAndTime t, int istart, int iend) const
Find the upper_bound of time t in container.
virtual TimeInterval nthInterval(int n) const
Returns n-th valid time interval, in a very inefficient way.
void addValues(const std::vector< Types::Core::DateAndTime > ×, const std::vector< TYPE > &values)
Adds vectors of values to the map.
int realSize() const override
Returns the real size of the time series property map:
static bool isTimeString(const std::string &str)
Check if str has the right time format.
Property * cloneWithTimeShift(const double timeShift) const override
"Virtual" copy constructor with a time shift in seconds
std::string setValueFromProperty(const Property &right) override
Set a value from another property.
virtual std::vector< TYPE > filteredValuesAsVector() const
void saveProperty(Nexus::File *file) override
Class to hold unit value (DateAndTime, T)
static unsigned short constexpr CHAR
MatrixWorkspace_sptr MANTID_API_DLL operator+=(const MatrixWorkspace_sptr &lhs, const MatrixWorkspace_sptr &rhs)
Adds two workspaces.
void split(const int A, int &S, int &V)
Split a number into the sign and positive value.
Logger g_log("DateAndTime")
StatisticType
Maps a "statistic" to a number.
Statistics getStatistics(const std::vector< TYPE > &data, const unsigned int flags=StatOptions::AllStats)
Return a statistics object for the given data set.
std::vector< SplittingInterval > SplittingIntervalVec
A typedef for splitting events according their pulse time.
MANTID_KERNEL_DLL bool operator==(const Mantid::Kernel::Property &lhs, const Mantid::Kernel::Property &rhs)
Compares this to another property for equality.
std::vector< dimsize_t > DimVector
Helper class which provides the Collimation Length for SANS instruments.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Simple struct to store statistics.
double median
Median value.
double minimum
Minimum value.
double maximum
Maximum value.
double standard_deviation
standard_deviation of the values
Struct holding some useful statistics for a TimeSeriesProperty.
double time_standard_deviation
time weighted standard deviation
double standard_deviation
standard_deviation of the values
double time_mean
time weighted average
double duration
Duration in seconds.