15#include "MantidHistogramData/Histogram.h"
20#include <boost/math/special_functions/round.hpp>
28using Types::Core::DateAndTime;
29using Types::Core::time_duration;
39 :
API::
Algorithm(), m_dataWS(), m_splitWS(), m_filterWS(), m_filterInfoWS(), m_startTime(), m_stopTime(),
40 m_runEndTime(), m_timeUnitConvertFactorToNS(0.), m_dblLog(
nullptr), m_intLog(
nullptr), m_logAtCentre(false),
41 m_logTimeTolerance(0.), m_forFastLog(false), m_splitters(), m_vecSplitterTime(), m_vecSplitterGroup(),
42 m_useParallel(false), m_vecSplitterTimeSet(), m_vecGroupIndexSet() {}
50 "An input Matrix workspace.");
53 "The name to use for the output SplittersWorkspace object, ie the filter.");
57 "Optional output for the information of each splitter workspace index");
59 declareProperty(
"FastLog",
false,
"Fast log will make output workspace to be a matrix workspace. ");
63 "The start time, such that all events before this time are filtered out: it could be \n"
64 "(1) relative time to run start time in unit as specified property 'UnitOfTime'\n"
66 "Absolute time takes a string in format as 1990-01-01T00:00:00, while the relative time takes "
67 "a string representing an integer or a floating-point number.");
70 "The stop time, such that all events after this time are filtered out: it could be \n"
71 "(1) relative time to run start time in unit as specified property 'UnitOfTime'\n"
73 "Absolute time takes a string in format as 1990-01-01T00:00:00, while the relative time takes "
74 "a string representing an integer or a floating-point number.");
79 "Array for lengths of time intervals for splitters: \n"
80 "if the array is empty, then there will be one splitter created from StartTime and StopTime; \n"
81 "if the array has one value, then if this value is positive, all splitters will have same time intervals, else "
82 "the time intervals will be exponentially increasing;\n"
83 "if the size of the array is larger than one, then the splitters can have various time interval values.");
86 std::vector<std::string> timeoptions{
"Seconds",
"Nanoseconds",
"Percent"};
87 declareProperty(
"UnitOfTime",
"Seconds", std::make_shared<Kernel::StringListValidator>(timeoptions),
88 "This option determines the units of options 'StartTime', 'StopTime' and 'DeltaTime'. "
89 "Allowed units are 'Seconds' or 'Nanoseconds', counting from the run start time, "
90 "or a 'Percentage' of the total run time.");
95 "Name of the sample log to use to filter - for example, the pulse charge is recorded in 'ProtonCharge'.");
105 "Delta of log value to be sliced into from min log value and max log value; if not given, then only value ");
108 std::vector<std::string> filteroptions{
"Both",
"Increase",
"Decrease"};
110 std::make_shared<Kernel::StringListValidator>(filteroptions),
111 "d(log value)/dt can be positive and negative, they can be put to different splitters\n"
112 "there are 3 options, 'Both', 'Increase' and 'Decrease' corresponding to d(log value)/dt being any "
113 "value, positive only and negative only respectively.");
115 std::make_unique<VisibleWhenProperty>(
"LogName",
IS_NOT_EQUAL_TO,
""));
118 "Tolerance, in seconds, for the event times to keep. It is used in the case to filter by single "
119 "value. How TimeTolerance is applied is highly correlated to LogBoundary and PulseFilter. Check the "
120 "help or algorithm documents for details.");
123 vector<string> logboundoptions{
"Centre",
"Left",
"Other"};
124 auto logvalidator = std::make_shared<StringListValidator>(logboundoptions);
126 "How to treat log values as being measured in the centre of time. "
127 "There are three options, 'Centre', 'Left' and 'Other'. "
128 "This value must be set to Left if the sample log is recorded upon changing,"
129 "which applies to most of the sample environment devices in SNS.");
134 "Tolerance of the log value to be included in filter, used in the case to filter by multiple values.");
138 declareProperty(
"TitleOfSplitters",
"",
"Title of output splitters workspace and information workspace.");
141 vector<string> processoptions{
"Serial",
"Parallel"};
142 auto procvalidator = std::make_shared<StringListValidator>(processoptions);
144 "Use multiple cores to generate events filter by log values: \n"
145 "Serial: Use a single core, good for slow log; \n"
146 "Parallel: Use multiple cores, appropriate for fast log. ");
149 declareProperty(
"UseReverseLogarithmic",
false,
"Use reverse logarithm for the time filtering.");
165 std::string logname = this->
getProperty(
"LogName");
166 if (logname.empty()) {
197 std::string title =
getProperty(
"TitleOfSplitters");
216 if (algtype ==
"Serial")
218 else if (algtype ==
"Parallel")
221 throw std::runtime_error(
"Impossible to have 3rd type other than Serial and Parallel. ");
225 g_log.
warning(
"Parallelization is for fast log only. Automatically turn "
238 std::string s_inpt0 = this->
getProperty(
"StartTime");
239 std::string s_inptf = this->
getProperty(
"StopTime");
242 bool defaultstart = s_inpt0.empty();
243 bool defaultstop = s_inptf.empty();
246 bool instringformat =
true;
247 if (!defaultstart && s_inpt0.find(
':') == std::string::npos) {
249 instringformat =
false;
250 }
else if (!defaultstop && s_inptf.find(
':') == std::string::npos) {
252 instringformat =
false;
256 DateAndTime runstarttime =
m_dataWS->run().startTime();
261 std::string timeunit = this->
getProperty(
"UnitOfTime");
263 if (timeunit ==
"Seconds") {
266 }
else if (timeunit ==
"Nanoseconds") {
269 }
else if (timeunit ==
"Percent") {
271 int64_t runtime_ns =
m_runEndTime.totalNanoseconds() - runstarttime.totalNanoseconds();
272 auto runtimed_ns =
static_cast<double>(runtime_ns);
277 errss <<
"TimeType " << timeunit <<
" is not supported.";
278 throw std::runtime_error(errss.str());
285 }
else if (instringformat) {
290 double inpt0 = std::stod(s_inpt0.c_str());
293 errss <<
"Input relative StartTime " << inpt0 <<
" cannot be negative. ";
294 throw std::invalid_argument(errss.str());
304 }
else if (instringformat) {
309 double inptf = std::stod(s_inptf.c_str());
318 errss <<
"Input StartTime " <<
m_startTime.toISO8601String() <<
" is equal or later than "
319 <<
"input StopTime " <<
m_stopTime.toFormattedString();
320 throw runtime_error(errss.str());
324 <<
"; Run start = " << runstarttime.toISO8601String()
325 <<
", Run stop = " <<
m_runEndTime.toISO8601String() <<
"\n";
332 vector<double> vec_timeintervals = this->
getProperty(
"TimeInterval");
334 bool singleslot =
false;
335 if (vec_timeintervals.empty()) {
339 if (std::all_of(vec_timeintervals.begin(), vec_timeintervals.end(), [](
double i) { return i == 0; }))
340 throw std::invalid_argument(
"If TimeInterval has one or more values, at "
341 "least one of those values must be non-zero.");
348 <<
"stop @ " <<
m_stopTime.totalNanoseconds() <<
"\n";
354 std::stringstream ss;
357 }
else if (vec_timeintervals.size() == 1) {
358 double timeinterval = vec_timeintervals[0];
359 int64_t timeslot = 0;
361 int64_t runStartTime =
m_dataWS->run().startTime().totalNanoseconds();
362 bool isLogarithmic = (timeinterval < 0);
366 g_log.
warning(
"UseReverseLogarithmic checked but linear time interval provided. Using linear time interval.");
370 if (isLogarithmic &&
m_startTime.totalNanoseconds() == runStartTime)
371 throw runtime_error(
"Cannot do logarithmic time interval if the start time is the same as the start of the run.");
374 double factor = std::fabs(timeinterval);
376 int64_t startTime_ns =
m_startTime.totalNanoseconds();
377 int64_t endTime_ns =
m_stopTime.totalNanoseconds();
379 double relativeStartTime_ns =
static_cast<double>(startTime_ns - runStartTime);
380 double relativeEndTime_ns =
static_cast<double>(endTime_ns - runStartTime);
384 int64_t initialReverseLogStep = startTime_ns - runStartTime;
386 int totalNumberOfSlices;
392 double logSize = std::log(relativeEndTime_ns / relativeStartTime_ns) / std::log1p(factor);
394 totalNumberOfSlices =
static_cast<int>(std::ceil(logSize));
397 totalNumberOfSlices = 1;
399 double previousBin = std::pow(1 + factor, std::floor(logSize) - 1);
402 if (relativeEndTime_ns - relativeStartTime_ns * previousBin * (1 + factor) >
403 relativeStartTime_ns * previousBin * factor) {
405 totalNumberOfSlices =
static_cast<int>(std::ceil(logSize));
408 totalNumberOfSlices =
static_cast<int>(std::floor(logSize));
414 totalNumberOfSlices =
415 static_cast<int>((relativeEndTime_ns - relativeStartTime_ns) /
static_cast<double>(deltatime_ns));
427 int64_t step = initialReverseLogStep + endTime_ns - runStartTime - curtime_ns;
428 nexttime_ns = curtime_ns -
static_cast<int64_t
>(
static_cast<double>(step) * factor);
430 nexttime_ns =
static_cast<int64_t
>(
static_cast<double>(curtime_ns) * (1 + factor));
433 nexttime_ns = curtime_ns + deltatime_ns;
435 if (nexttime_ns + runStartTime >
m_stopTime.totalNanoseconds())
436 nexttime_ns =
m_stopTime.totalNanoseconds() - runStartTime;
439 if (runStartTime + nexttime_ns - (curtime_ns - nexttime_ns) <
m_startTime.totalNanoseconds())
440 nexttime_ns =
m_startTime.totalNanoseconds() - runStartTime;
443 Types::Core::DateAndTime t0(std::min(curtime_ns, nexttime_ns) + runStartTime);
444 Types::Core::DateAndTime tf(std::max(curtime_ns, nexttime_ns) + runStartTime);
445 std::stringstream ss;
446 ss <<
"Time.Interval.From." << t0 <<
".to." << tf;
451 curtime_ns = nexttime_ns;
456 newtimeslot = (endTime_ns - (curtime_ns + runStartTime)) * 90 / totaltime;
459 newtimeslot = (curtime_ns + runStartTime - startTime_ns) * 90 / totaltime;
462 if (newtimeslot > timeslot) {
464 timeslot = newtimeslot;
465 double prog = 0.1 + double(timeslot) / 100.0;
475 size_t numtimeintervals = vec_timeintervals.size();
476 std::vector<int64_t> vec_dtimens(numtimeintervals);
477 for (
size_t id = 0;
id < numtimeintervals; ++id) {
479 vec_dtimens[id] = deltatime_ns;
483 int64_t timeslot = 0;
485 int64_t curtime_ns =
m_startTime.totalNanoseconds();
487 while (curtime_ns <
m_stopTime.totalNanoseconds()) {
488 for (
size_t id = 0;
id < numtimeintervals; ++id) {
490 int64_t deltatime_ns = vec_dtimens[id];
492 int64_t nexttime_ns = curtime_ns + deltatime_ns;
493 bool breaklater =
false;
494 if (nexttime_ns >
m_stopTime.totalNanoseconds()) {
500 Types::Core::DateAndTime t0(curtime_ns);
501 Types::Core::DateAndTime tf(nexttime_ns);
502 std::stringstream ss;
503 ss <<
"Time.Interval.From." << t0 <<
".to." << tf;
508 curtime_ns = nexttime_ns;
512 int64_t newtimeslot = (curtime_ns -
m_startTime.totalNanoseconds()) * 90 / totaltime;
513 if (newtimeslot > timeslot) {
515 timeslot = newtimeslot;
516 double prog = 0.1 + double(timeslot) / 100.0;
537 errmsg <<
"Log " << logname <<
" does not exist or is not TimeSeriesProperty in double or integer.";
538 throw runtime_error(errmsg.str());
543 g_log.
debug(
"Attempting to remove duplicates in double series log.");
548 g_log.
debug(
"Attempting to remove duplicates in integer series log.");
554 double minvalue = this->
getProperty(
"MinimumLogValue");
555 double maxvalue = this->
getProperty(
"MaximumLogValue");
556 double deltaValue = this->
getProperty(
"LogValueInterval");
559 std::string filterdirection =
getProperty(
"FilterLogValueByChangingDirection");
562 if (filterdirection ==
"Both") {
563 filterIncrease =
true;
564 filterDecrease =
true;
565 }
else if (filterdirection ==
"Increase") {
567 filterIncrease =
true;
568 filterDecrease =
false;
570 filterIncrease =
false;
571 filterDecrease =
true;
574 bool toProcessSingleValueFilter =
false;
576 toProcessSingleValueFilter =
true;
577 }
else if (deltaValue < 0) {
578 throw runtime_error(
"Delta value cannot be negative.");
598 if (minvalue > maxvalue) {
600 errmsg <<
"Fatal Error: Input minimum log value " << minvalue <<
" is larger than maximum log value " << maxvalue;
601 throw runtime_error(errmsg.str());
603 g_log.
debug() <<
"Filter by log value: min = " << minvalue <<
", max = " << maxvalue
604 <<
", process single value? = " << toProcessSingleValueFilter <<
", delta value = " << deltaValue
609 if (toProcessSingleValueFilter) {
619 int minvaluei, maxvaluei;
622 minvalue =
static_cast<double>(minvaluei);
624 minvaluei = boost::math::iround(minvalue);
628 maxvalue =
static_cast<double>(maxvaluei);
630 maxvaluei = boost::math::iround(maxvalue);
632 if (minvalue > maxvalue) {
634 errmsg <<
"Fatal Error: Input minimum log value " << minvalue <<
" is larger than maximum log value " << maxvalue;
635 throw runtime_error(errmsg.str());
637 g_log.
information() <<
"Generate event-filter for integer log: min = " << minvaluei <<
", "
638 <<
"max = " << maxvaluei <<
"\n";
642 DateAndTime runendtime =
m_dataWS->run().endTime();
648 <<
"maximum value = " << maxvalue <<
".\n";
661 bool filterdecrease) {
663 double timetolerance = this->
getProperty(
"TimeTolerance");
666 std::string logboundary = this->
getProperty(
"LogBoundary");
667 transform(logboundary.begin(), logboundary.end(), logboundary.begin(), ::tolower);
672 makeFilterBySingleValue(minvalue, maxvalue,
static_cast<double>(timetolerance_ns) * 1.0E-9, logboundary ==
"centre",
677 throw runtime_error(
"m_filterInfoWS has not been initialized.");
680 std::stringstream ss;
681 ss <<
"Log." <<
m_dblLog->
name() <<
".From." << minvalue <<
".To." << maxvalue <<
".Value-change-direction:";
682 if (filterincrease && filterdecrease) {
684 }
else if (filterincrease) {
689 row << 0 << ss.str();
703 bool filterincrease,
bool filterdecrease) {
705 if (valueinterval <= 0)
706 throw std::invalid_argument(
"Multiple values filter must have LogValueInterval larger than ZERO.");
707 double valuetolerance = this->
getProperty(
"LogValueTolerance");
710 valuetolerance = 0.5 * valueinterval;
711 else if (valuetolerance < 0.0)
712 throw std::runtime_error(
"LogValueTolerance cannot be less than zero.");
716 std::map<size_t, int> indexwsindexmap;
717 std::vector<double> logvalueranges;
721 double curvalue = minvalue;
722 while (curvalue - valuetolerance < maxvalue) {
723 indexwsindexmap.emplace(
index, wsindex);
726 double lowbound = curvalue - valuetolerance;
727 double upbound = curvalue + valueinterval - valuetolerance;
728 logvalueranges.emplace_back(lowbound);
729 logvalueranges.emplace_back(upbound);
732 std::stringstream ss;
733 ss <<
"Log." <<
m_dblLog->
name() <<
".From." << lowbound <<
".To." << upbound <<
".Value-change-direction:";
734 if (filterincrease && filterdecrease) {
736 }
else if (filterincrease) {
742 newrow << wsindex << ss.str();
744 curvalue += valueinterval;
750 stringstream dbsplitss;
751 dbsplitss <<
"Index map size = " << indexwsindexmap.
size() <<
"\n";
752 for (
auto const &mit : indexwsindexmap) {
753 dbsplitss <<
"Index " << mit.first <<
": WS-group = " << mit.second <<
". Log value range: ["
754 << logvalueranges[mit.first * 2] <<
", " << logvalueranges[mit.first * 2 + 1] <<
").\n";
759 if (logvalueranges.size() < 2) {
760 g_log.
warning(
"There is no log value interval existing.");
766 double upperboundinterval0 = logvalueranges[1];
767 double lowerboundlastinterval = logvalueranges[logvalueranges.size() - 2];
770 if (minlogvalue > upperboundinterval0 || maxlogvalue < lowerboundlastinterval) {
771 g_log.
warning() <<
"User specifies log interval from " << minvalue - valuetolerance <<
" to "
772 << maxvalue - valuetolerance <<
" with interval size = " << valueinterval <<
"; Log "
773 <<
m_dblLog->
name() <<
" has range " << minlogvalue <<
" to " << maxlogvalue
774 <<
". Therefore some workgroup index may not have any splitter.\n";
779 std::string logboundary = this->
getProperty(
"LogBoundary");
780 transform(logboundary.begin(), logboundary.end(), logboundary.begin(), ::tolower);
814 bool filterIncrease,
bool filterDecrease, DateAndTime startTime,
815 Types::Core::DateAndTime stopTime,
int wsindex) {
818 g_log.
warning() <<
"There is no entry in this property " << this->
name() <<
"\n";
827 bool lastGood =
false;
828 time_duration tol = DateAndTime::durationFromSeconds(TimeTolerance);
830 DateAndTime currT, start, stop;
838 bool isGood =
identifyLogEntry(i, currT, lastGood, min, max, startTime, stopTime, filterIncrease, filterDecrease);
843 if (isGood != lastGood) {
859 std::string empty(
"");
870 if (tmpslot > progslot) {
872 double prog = double(progslot) / 100.0 + 0.1;
886 std::string empty(
"");
903 const bool &lastgood,
const double &minvalue,
const double &maxvalue,
904 const Types::Core::DateAndTime &startT,
905 const Types::Core::DateAndTime &stopT,
const bool &filterIncrease,
906 const bool &filterDecrease) {
910 bool isgood = (val >= minvalue && val < maxvalue) && (currT >= startT && currT < stopT);
913 if (isgood && (!filterIncrease || !filterDecrease)) {
916 if (
index < numlogentries - 1) {
924 if (diff > 0 && filterIncrease)
926 else if (diff < 0 && filterDecrease)
954 const vector<double> &logvalueranges,
bool centre,
955 bool filterIncrease,
bool filterDecrease, DateAndTime startTime,
956 DateAndTime stopTime) {
957 g_log.
notice(
"Starting method 'makeMultipleFiltersByValues'. ");
967 double timetolerance = 0.0;
969 timetolerance = this->
getProperty(
"TimeTolerance");
971 time_duration tol = DateAndTime::durationFromSeconds(timetolerance);
975 vector<DateAndTime> tempvectimes;
977 vector<int> tempvecgroup;
982 auto iend =
static_cast<int>(logsize - 1);
985 logvalueranges, tol, filterIncrease, filterDecrease, startTime, stopTime);
1008 const vector<double> &logvalueranges,
bool centre,
1009 bool filterIncrease,
bool filterDecrease,
1010 DateAndTime startTime, DateAndTime stopTime) {
1019 double timetolerance = 0.0;
1021 timetolerance = this->
getProperty(
"TimeTolerance");
1023 time_duration tol = DateAndTime::durationFromSeconds(timetolerance);
1031 numThreads = std::min(numThreads, logsize / 8);
1036 std::vector<int> vecStart, vecEnd;
1037 int partloglength = (logsize - 1) / numThreads;
1038 int extra = (logsize - 1) % numThreads;
1039 for (
int i = 0; i < numThreads; ++i) {
1040 int istart = i * partloglength;
1046 int iend = istart + partloglength;
1050 vecStart.emplace_back(istart);
1051 vecEnd.emplace_back(iend);
1056 dbss <<
"Number of thread = " << numThreads <<
", Log Size = " << logsize <<
"\n";
1057 for (
size_t i = 0; i < vecStart.size(); ++i) {
1058 dbss <<
"Thread " << i <<
": Log range: [" << vecStart[i] <<
", " << vecEnd[i] <<
") "
1059 <<
"Size = " << vecEnd[i] - vecStart[i] <<
"\n";
1067 for (
int i = 0; i < numThreads; ++i) {
1068 vector<DateAndTime> tempvectimes;
1070 vector<int> tempvecgroup;
1078 PRAGMA_OMP(parallel
for schedule(dynamic, 1) )
1079 for (
int i = 0; i < numThreads; ++i) {
1082 int istart = vecStart[i];
1083 int iend = vecEnd[i];
1086 indexwsindexmap, logvalueranges, tol, filterIncrease, filterDecrease,
1087 startTime, stopTime);
1093 for (
int i = 1; i < numThreads; ++i) {
1102 errss <<
"Previous vector of group index set (" << (i - 1) <<
") is equal to -1. "
1103 <<
"It is not likely to happen! Size of previous vector of "
1106 throw runtime_error(errss.str());
1115 g_log.
debug() <<
"Splitter at the end of thread " << i <<
" is extended from " << origtime <<
" to " << newt0
1127 if (lastindex != -1 && firstindex != -1) {
1135 g_log.
debug() <<
"Thread = " << i <<
", change ending time of " << i - 1 <<
" to "
1142 throw runtime_error(
"It is not possible to have start or end of "
1143 "filter to be minus-one index. ");
1155 int istart,
int iend, std::vector<Types::Core::DateAndTime> &vecSplitTime, std::vector<int> &vecSplitGroup,
1156 map<size_t, int> indexwsindexmap,
const vector<double> &logvalueranges,
const time_duration &tol,
1157 bool filterIncrease,
bool filterDecrease, DateAndTime startTime, DateAndTime stopTime) {
1160 if (istart < 0 || iend >= logsize)
1161 throw runtime_error(
"Input index of makeMultipleFiltersByValuesPartialLog "
1162 "is out of boundary. ");
1164 int64_t tol_ns = tol.total_nanoseconds();
1167 const Types::Core::DateAndTime ZeroTime(0);
1170 DateAndTime currTime, start, stop;
1173 g_log.
information() <<
"Log time coverage (index: " << istart <<
", " << iend <<
") from "
1176 DateAndTime laststoptime(0);
1181 for (
int i = istart; i <= iend; i++) {
1183 bool breakloop =
false;
1184 bool createsplitter =
false;
1192 if (currTime < startTime) {
1194 createsplitter =
false;
1195 }
else if (currTime > stopTime) {
1200 if (start.totalNanoseconds() > 0) {
1201 createsplitter =
true;
1206 bool newsplitter =
false;
1210 if (i < lastlogindex) {
1218 direction = prevDirection;
1221 direction = prevDirection;
1223 prevDirection = direction;
1227 bool correctdir =
true;
1228 if (filterIncrease && filterDecrease) {
1233 if (filterIncrease && direction > 0)
1235 else if (filterDecrease && direction < 0)
1237 else if (direction == 0)
1238 throw runtime_error(
"Direction is not determined.");
1248 bool valueWithinMinMax =
true;
1249 if (
index > logvalueranges.size()) {
1251 valueWithinMinMax =
false;
1254 if (
g_log.
is(Logger::Priority::PRIO_DEBUG)) {
1256 dbss <<
"[DBx257] Examine Log Index " << i <<
", Value = " << currValue <<
", Data Range Index = " <<
index
1258 <<
"Group Index = " << indexwsindexmap[
index / 2]
1259 <<
" (log value range vector size = " << logvalueranges.size() <<
"): ";
1261 dbss << logvalueranges[
index] <<
", " << logvalueranges[
index + 1];
1262 else if (
index == logvalueranges.size())
1263 dbss << logvalueranges[
index - 1] <<
", " << logvalueranges[
index];
1264 else if (valueWithinMinMax)
1265 dbss << logvalueranges[
index - 1] <<
", " << logvalueranges[
index] <<
", " << logvalueranges[
index + 1];
1269 if (valueWithinMinMax) {
1270 if (
index % 2 == 0) {
1272 currindex = indexwsindexmap[
index / 2];
1274 if (currindex != lastindex && start.totalNanoseconds() == 0) {
1278 }
else if (currindex != lastindex && start.totalNanoseconds() > 0) {
1282 createsplitter =
true;
1284 }
else if (currindex == lastindex && start.totalNanoseconds() > 0) {
1290 createsplitter =
true;
1291 newsplitter =
false;
1298 std::stringstream errmsg;
1300 errmsg <<
"Impossible to have currindex == lastindex == " << currindex
1301 <<
", while start is not init. Log Index = " << i <<
"\t value = " << currValue
1302 <<
"\t, Index = " <<
index <<
" in range " << logvalueranges[
index] <<
", "
1303 << logvalueranges[
index + 1] <<
"; Last value = " << lastvalue;
1304 throw std::runtime_error(errmsg.str());
1310 g_log.
warning() <<
"Not likely to happen! Current value = " << currValue
1311 <<
" is within value range but its index = " <<
index <<
" has no map to group index. "
1313 if (start.totalNanoseconds() > 0) {
1316 createsplitter =
true;
1322 if (start.totalNanoseconds() > 0) {
1325 createsplitter =
true;
1335 if (start.totalNanoseconds() > 0) {
1337 createsplitter =
true;
1342 if (createsplitter) {
1344 makeSplitterInVector(vecSplitTime, vecSplitGroup, start, stop, lastindex, tol_ns, laststoptime);
1360 lastindex = currindex;
1367 if (vecSplitTime.empty()) {
1371 makeSplitterInVector(vecSplitTime, vecSplitGroup, start, stop, lastindex, tol_ns, laststoptime);
1384 bool filterDecrease, DateAndTime runend) {
1387 bool singlevaluemode;
1388 if (minvalue == maxvalue) {
1389 singlevaluemode =
true;
1391 singlevaluemode =
false;
1393 double deltadbl =
getProperty(
"LogValueInterval");
1395 delta = maxvalue - minvalue + 1;
1397 delta = boost::math::iround(deltadbl);
1401 errss <<
"In a non-single value mode, LogValueInterval cannot be 0 or "
1402 "negative for integer. "
1403 <<
"Current input is " << deltadbl <<
".";
1404 throw runtime_error(errss.str());
1415 int64_t timetolns = timetol.total_nanoseconds();
1417 DateAndTime splitstarttime(0);
1419 DateAndTime laststoptime(0);
1421 g_log.
debug() <<
"Number of integer log entries = " << numlogentries <<
".\n";
1423 for (
size_t i = 0; i < numlogentries; ++i) {
1424 int currvalue = vecValue[i];
1429 if (currvalue >= minvalue && currvalue <= maxvalue) {
1431 if ((i == 0) || (filterIncrease && vecValue[i] >= vecValue[i - 1]) ||
1432 (filterDecrease && vecValue[i] <= vecValue[i - 1])) {
1435 if (singlevaluemode) {
1438 currgroup = (currvalue - minvalue) /
delta;
1445 if (pregroup >= 0 && currgroup < 0) {
1448 if (splitstarttime.totalNanoseconds() == 0)
1449 throw runtime_error(
"Programming logic error.");
1453 laststoptime = vecTimes[i];
1455 splitstarttime = DateAndTime(0);
1456 statuschanged =
true;
1457 }
else if (pregroup < 0 && currgroup >= 0) {
1460 splitstarttime = vecTimes[i];
1461 statuschanged =
true;
1462 }
else if (currgroup >= 0 && pregroup != currgroup) {
1464 if (splitstarttime.totalNanoseconds() == 0)
1465 throw runtime_error(
"Programming logic error (1).");
1468 laststoptime = vecTimes[i];
1470 splitstarttime = vecTimes[i];
1471 statuschanged =
true;
1474 statuschanged =
false;
1479 pregroup = currgroup;
1483 if (pregroup >= 0) {
1485 if (splitstarttime.totalNanoseconds() == 0)
1486 throw runtime_error(
"Programming logic error (1).");
1493 if (singlevaluemode) {
1495 stringstream message;
1497 newrow << 0 << message.str();
1499 int logvalue = minvalue;
1501 while (logvalue <= maxvalue) {
1502 stringstream message;
1503 if (logvalue +
delta - 1 > logvalue)
1504 message <<
m_intLog->
name() <<
"=[" << logvalue <<
"," << logvalue +
delta - 1 <<
"]";
1508 message <<
".Value change direction:";
1509 if (filterIncrease && filterDecrease)
1511 else if (filterIncrease)
1512 message <<
"Increasing";
1513 else if (filterDecrease)
1514 message <<
"Decreasing";
1517 newrow << wsindex << message.str();
1525 <<
", Number of split info = " <<
m_filterInfoWS->rowCount() <<
".\n";
1540 size_t numdata = sorteddata.size();
1541 size_t outrange = numdata + 1;
1544 else if (
value < sorteddata.front() ||
value > sorteddata.back())
1549 static_cast<size_t>(std::lower_bound(sorteddata.begin(), sorteddata.end(),
value) - sorteddata.begin());
1560 if (
index == sorteddata.size())
1574 int index = startindex;
1575 while (direction == 0 &&
index > 0) {
1591 while (direction == 0 &&
index < maxindex) {
1602 throw runtime_error(
"Sample log is flat. Use option 'Both' instead! ");
1611 Types::Core::DateAndTime stoptime,
int wsindex,
1612 const string &info) {
1628 throw runtime_error(
"Logic error. Trying to insert a splitter, whose "
1629 "start time is earlier than last splitter.");
1642 if (!info.empty()) {
1645 row << wsindex << info;
1649 row << wsindex << info;
1659 std::vector<int> &vecGroupIndex, Types::Core::DateAndTime start,
1660 Types::Core::DateAndTime stop,
int group, int64_t tol_ns,
1661 DateAndTime lasttime) {
1662 DateAndTime starttime(start.totalNanoseconds() - tol_ns);
1663 DateAndTime stoptime(stop.totalNanoseconds() - tol_ns);
1667 size_t timevecsize = vecSplitTime.size();
1668 if (timevecsize > 0)
1669 lasttime = vecSplitTime.back();
1672 if (timevecsize == 0) {
1674 vecSplitTime.emplace_back(starttime);
1675 }
else if (lasttime < starttime) {
1678 vecSplitTime.emplace_back(starttime);
1679 vecGroupIndex.emplace_back(-1);
1680 }
else if (lasttime > starttime) {
1682 throw runtime_error(
"Impossible situation.");
1691 vecSplitTime.emplace_back(stoptime);
1693 vecGroupIndex.emplace_back(
group);
1708 if (sizex - sizey != 1) {
1709 throw runtime_error(
"Logic error on splitter vectors' size. ");
1712 m_filterWS = create<Workspace2D>(1, BinEdges(sizex));
1714 for (
size_t i = 0; i < sizex; ++i) {
1716 dataX[i] =
static_cast<double>(
m_vecSplitterTime[i].totalNanoseconds()) * 1.E-9;
1720 for (
size_t i = 0; i < sizey; ++i) {
1732 size_t numtimes = 0;
1734 for (
size_t i = 0; i < numThreads; ++i) {
1741 size_t sizex = numtimes;
1743 m_filterWS = create<Workspace2D>(1, BinEdges(sizex));
1748 for (
size_t i = 0; i < numThreads; ++i) {
1766 if (groupindex >= 0) {
1785 DateAndTime runendtime(0);
1786 bool norunendset =
false;
1788 runendtime =
m_dataWS->run().endTime();
1789 }
catch (
const std::runtime_error &) {
1795 if (!eventWS || eventWS->getNumberEvents() == 0) {
1796 throw std::runtime_error(
"Run end time cannot be determined.");
1798 runendtime = eventWS->getPulseTimeMax();
1802 auto extended_ns =
static_cast<int64_t
>(1.0E8);
1803 if (
m_dataWS->run().hasProperty(
"proton_charge")) {
1806 if (protonchargelog->
size() > 1) {
1807 extended_ns = protonchargelog->
nthTime(1).totalNanoseconds() - protonchargelog->
nthTime(0).totalNanoseconds();
1812 runendtime = DateAndTime(runendtime.totalNanoseconds() + extended_ns);
#define DECLARE_ALGORITHM(classname)
double value
The value of the point.
std::map< DeltaEMode::Type, std::string > index
#define PARALLEL_START_INTERRUPT_REGION
Begins a block to skip processing is the algorithm has been interupted Note the end of the block if n...
#define PARALLEL_END_INTERRUPT_REGION
Ends a block to skip processing is the algorithm has been interupted Note the start of the block if n...
#define PRAGMA_OMP(expression)
#define PARALLEL_GET_MAX_THREADS
#define PARALLEL_CHECK_INTERRUPT_REGION
Adds a check after a Parallel region to see if it was interupted.
Base class from which all concrete algorithm classes should be derived.
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
static bool isEmpty(const NumT toCheck)
checks that the value was not set by users, uses the value in empty double/int.
TableRow represents a row in a TableWorkspace.
size_t size() const
Returns the number of rows in the TableWorkspace.
A property class for workspaces.
GenerateEventsFilter : Generate an events-filter, i.e., a SplittersWorkspace according to user's requ...
bool m_forFastLog
Flag to output matrix workspace for fast log.
double m_timeUnitConvertFactorToNS
std::vector< Types::Core::DateAndTime > m_vecSplitterTime
Vector as date and time.
void processInOutWorkspaces()
Process properties.
Types::Core::DateAndTime m_startTime
Types::Core::DateAndTime m_runEndTime
Run end time.
void exec() override
Implement abstract Algorithm methods.
int determineChangingDirection(int startindex)
Determine the chaning direction of log value.
std::vector< std::vector< Types::Core::DateAndTime > > m_vecSplitterTimeSet
void processSingleValueFilter(double minvalue, double maxvalue, bool filterincrease, bool filterdecrease)
Generate filters by single log value.
void makeMultipleFiltersByValues(std::map< size_t, int > indexwsindexmap, const std::vector< double > &logvalueranges, bool centre, bool filterIncrease, bool filterDecrease, Types::Core::DateAndTime startTime, Types::Core::DateAndTime stopTime)
Make multiple-log-value filters in serial.
void addNewTimeFilterSplitter(Types::Core::DateAndTime starttime, Types::Core::DateAndTime stoptime, int wsindex, const std::string &info)
Add a splitter.
const std::string name() const override
Algorithm's name for identification overriding a virtual method.
API::ITableWorkspace_sptr m_filterInfoWS
void init() override
Implement abstract Algorithm methods.
size_t searchValue(const std::vector< double > &sorteddata, double value)
Search a value in a sorted vector.
void setFilterByTimeOnly()
Set splitters by time value / interval only.
void generateSplittersInMatrixWorkspaceParallel()
Generate a matrix workspace from the parallel version.
bool identifyLogEntry(const int &index, const Types::Core::DateAndTime &currT, const bool &lastgood, const double &minvalue, const double &maxvalue, const Types::Core::DateAndTime &startT, const Types::Core::DateAndTime &stopT, const bool &filterIncrease, const bool &filterDecrease)
Identify the a sample log entry is within intended value and time region.
void setFilterByLogValue(const std::string &logname)
Generate filters by log values.
bool m_isReverseLogarithmic
Flag if is reverse logarithmic time binning.
API::MatrixWorkspace_const_sptr m_dataWS
API::MatrixWorkspace_sptr m_filterWS
Matrix workspace containing splitters.
void generateSplittersInMatrixWorkspace()
Generate a matrix workspace containing splitters.
Kernel::TimeSeriesProperty< int > * m_intLog
void processIntegerValueFilter(int minvalue, int maxvalue, bool filterIncrease, bool filterDecrease, Types::Core::DateAndTime runend)
Generate event filters for integer sample log.
void makeFilterBySingleValue(double min, double max, double TimeTolerance, bool centre, bool filterIncrease, bool filterDecrease, Types::Core::DateAndTime startTime, Types::Core::DateAndTime stopTime, int wsindex)
Fill a SplittingIntervalVec that will filter the events by matching SINGLE log values >= min and < ma...
void processInputTime()
Process the input for time.
Types::Core::DateAndTime m_stopTime
void processMultipleValueFilters(double minvalue, double valueinterval, double maxvalue, bool filterincrease, bool filterdecrease)
Generate filters from multiple values.
void makeMultipleFiltersByValuesParallel(const std::map< size_t, int > &indexwsindexmap, const std::vector< double > &logvalueranges, bool centre, bool filterIncrease, bool filterDecrease, Types::Core::DateAndTime startTime, Types::Core::DateAndTime stopTime)
Make multiple-log-value filters in serial in parallel.
Kernel::TimeSeriesProperty< double > * m_dblLog
DataObjects::SplittersWorkspace_sptr m_splitWS
SplitterWorkspace.
Types::Core::DateAndTime findRunEnd()
Find the end of the run.
Types::Core::DateAndTime makeSplitterInVector(std::vector< Types::Core::DateAndTime > &vecSplitTime, std::vector< int > &vecGroupIndex, Types::Core::DateAndTime start, Types::Core::DateAndTime stop, int group, int64_t tol_ns, Types::Core::DateAndTime lasttime)
Create a splitter and add to the vector of time splitters.
double m_logTimeTolerance
std::vector< std::vector< int > > m_vecGroupIndexSet
bool m_useParallel
Processing algorithm type.
void makeMultipleFiltersByValuesPartialLog(int istart, int iend, std::vector< Types::Core::DateAndTime > &vecSplitTime, std::vector< int > &vecSplitGroup, std::map< size_t, int > indexwsindexmap, const std::vector< double > &logvalueranges, const Types::Core::time_duration &tol, bool filterIncrease, bool filterDecrease, Types::Core::DateAndTime startTime, Types::Core::DateAndTime stopTime)
Generate event splitters for partial sample log (serial)
std::vector< int > m_vecSplitterGroup
void generateSplittersInSplitterWS()
Generate a SplittersWorkspace for filtering by log values.
SplittersWorkspace : A TableWorkspace to contain TimeSplitters.
Support for a property that holds an array of values.
IPropertyManager * setProperty(const std::string &name, const T &value)
Templated method to set the value of a PropertyWithValue.
void setPropertySettings(const std::string &name, std::unique_ptr< IPropertySettings > settings)
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.
bool is(int level) const
Returns true if at least the given log level is set.
void information(const std::string &msg)
Logs at information level.
const std::string & name() const
Get the property's name.
Class holding a start/end time and a destination for splitting event lists and logs.
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.
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>
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.
virtual TYPE nthValue(int n) const
Returns n-th value of n-th interval in an incredibly inefficient way.
std::vector< Types::Core::DateAndTime > timesAsVector() const override
Return the time series's times as a vector<DateAndTime>
virtual Types::Core::DateAndTime nthTime(int n) const
Returns n-th time. NOTE: Complexity is order(n)! regardless of filter.
std::shared_ptr< const EventWorkspace > EventWorkspace_const_sptr
shared pointer to a const Workspace2D
Helper class which provides the Collimation Length for SANS instruments.
constexpr int EMPTY_INT() noexcept
Returns what we consider an "empty" integer within a property.
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
@ Input
An input workspace.
@ Output
An output workspace.