Mantid
Loading...
Searching...
No Matches
GenerateEventsFilter.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 +
9#include "MantidAPI/Run.h"
10#include "MantidAPI/TableRow.h"
15#include "MantidHistogramData/Histogram.h"
19
20#include <boost/math/special_functions/round.hpp>
21#include <utility>
22
23using namespace Mantid;
24using namespace Mantid::Kernel;
25using namespace Mantid::API;
26using namespace Mantid::DataObjects;
27using namespace Mantid::HistogramData;
28using Types::Core::DateAndTime;
29using Types::Core::time_duration;
30
31using namespace std;
32
33namespace Mantid::Algorithms {
34DECLARE_ALGORITHM(GenerateEventsFilter)
35
36
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() {}
43
47 // Input/Output Workspaces
49 std::make_unique<API::WorkspaceProperty<API::MatrixWorkspace>>("InputWorkspace", "", Direction::Input),
50 "An input Matrix workspace.");
51
52 declareProperty(std::make_unique<API::WorkspaceProperty<API::Workspace>>("OutputWorkspace", "", Direction::Output),
53 "The name to use for the output SplittersWorkspace object, ie the filter.");
54
56 std::make_unique<API::WorkspaceProperty<API::ITableWorkspace>>("InformationWorkspace", "", Direction::Output),
57 "Optional output for the information of each splitter workspace index");
58
59 declareProperty("FastLog", false, "Fast log will make output workspace to be a matrix workspace. ");
60
61 // Time (general) range
62 declareProperty("StartTime", "",
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"
65 "(2) absolute time\n"
66 "Absolute time takes a string in format as 1990-01-01T00:00:00, while the relative time takes "
67 "integer or float.");
68
69 declareProperty("StopTime", "",
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"
72 "(2) absolute time\n"
73 "Absolute time takes a string in format as 1990-01-01T00:00:00, while the relative time takes "
74 "integer or float.");
75
76 // Split by time (only) in steps
78 std::make_unique<ArrayProperty<double>>("TimeInterval"),
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.");
84 setPropertySettings("TimeInterval", std::make_unique<VisibleWhenProperty>("LogName", IS_EQUAL_TO, ""));
85
86 std::vector<std::string> timeoptions{"Seconds", "Nanoseconds", "Percent"};
87 declareProperty("UnitOfTime", "Seconds", std::make_shared<Kernel::StringListValidator>(timeoptions),
88 "StartTime, StopTime and DeltaTime can be given in various unit; the unit can be 'Seconds' or "
89 "'Nanoseconds' from run start time or can also be defined as 'Percentage' of total run time.");
90
91 // Split by log value (only) in steps
93 "LogName", "",
94 "Name of the sample log to use to filter - for example, the pulse charge is recorded in 'ProtonCharge'.");
95
96 declareProperty("MinimumLogValue", EMPTY_DBL(), "Minimum log value for which to keep events.");
97 setPropertySettings("MinimumLogValue", std::make_unique<VisibleWhenProperty>("LogName", IS_NOT_EQUAL_TO, ""));
98
99 declareProperty("MaximumLogValue", EMPTY_DBL(), "Maximum log value for which to keep events.");
100 setPropertySettings("MaximumLogValue", std::make_unique<VisibleWhenProperty>("LogName", IS_NOT_EQUAL_TO, ""));
101
103 "LogValueInterval", EMPTY_DBL(),
104 "Delta of log value to be sliced into from min log value and max log value; if not given, then only value ");
105 setPropertySettings("LogValueInterval", std::make_unique<VisibleWhenProperty>("LogName", IS_NOT_EQUAL_TO, ""));
106
107 std::vector<std::string> filteroptions{"Both", "Increase", "Decrease"};
108 declareProperty("FilterLogValueByChangingDirection", "Both",
109 std::make_shared<Kernel::StringListValidator>(filteroptions),
110 "d(log value)/dt can be positive and negative, they can be put to different splitters\n"
111 "there are 3 options, 'Both', 'Increase' and 'Decrease' corresponding to d(log value)/dt being any "
112 "value, positive only and negative only respectively.");
113 setPropertySettings("FilterLogValueByChangingDirection",
114 std::make_unique<VisibleWhenProperty>("LogName", IS_NOT_EQUAL_TO, ""));
115
116 declareProperty("TimeTolerance", 0.0,
117 "Tolerance, in seconds, for the event times to keep. It is used in the case to filter by single "
118 "value. How TimeTolerance is applied is highly correlated to LogBoundary and PulseFilter. Check the "
119 "help or algorithm documents for details.");
120 setPropertySettings("TimeTolerance", std::make_unique<VisibleWhenProperty>("LogName", IS_NOT_EQUAL_TO, ""));
121
122 vector<string> logboundoptions{"Centre", "Left", "Other"};
123 auto logvalidator = std::make_shared<StringListValidator>(logboundoptions);
124 declareProperty("LogBoundary", "Centre", logvalidator,
125 "How to treat log values as being measured in the centre of time. "
126 "There are three options, 'Centre', 'Left' and 'Other'. "
127 "This value must be set to Left if the sample log is recorded upon changing,"
128 "which applies to most of the sample environment devices in SNS.");
129 setPropertySettings("LogBoundary", std::make_unique<VisibleWhenProperty>("LogName", IS_NOT_EQUAL_TO, ""));
130
132 "LogValueTolerance", EMPTY_DBL(),
133 "Tolerance of the log value to be included in filter, used in the case to filter by multiple values.");
134 setPropertySettings("LogValueTolerance", std::make_unique<VisibleWhenProperty>("LogName", IS_NOT_EQUAL_TO, ""));
135
136 // Output workspaces' title and name
137 declareProperty("TitleOfSplitters", "", "Title of output splitters workspace and information workspace.");
138
139 // Linear or parallel
140 vector<string> processoptions{"Serial", "Parallel"};
141 auto procvalidator = std::make_shared<StringListValidator>(processoptions);
142 declareProperty("UseParallelProcessing", "Serial", procvalidator,
143 "Use multiple cores to generate events filter by log values: \n"
144 "Serial: Use a single core, good for slow log; \n"
145 "Parallel: Use multiple cores, appropriate for fast log. ");
146
147 declareProperty("NumberOfThreads", EMPTY_INT(), "Number of threads forced to use in the parallel mode. ");
148 declareProperty("UseReverseLogarithmic", false, "Use reverse logarithm for the time filtering.");
149}
150
154 // Process input properties
156
157 // Get Time
159
160 double prog = 0.1;
161 progress(prog);
162
163 // Get Log
164 std::string logname = this->getProperty("LogName");
165 if (logname.empty()) {
166 // Set up filters by time only
168 } else {
169 // Set up filters by log value in time range
170 setFilterByLogValue(logname);
171 }
172
173 // Set output workspaces
174 if (m_forFastLog) {
175 if (m_useParallel) {
177 } else {
179 }
180 setProperty("OutputWorkspace", m_filterWS);
181 } else {
183 setProperty("OutputWorkspace", m_splitWS);
184 }
185 setProperty("InformationWorkspace", m_filterInfoWS);
186}
187
188//----------------------------------------------------------------------------------------------
192 // Input data workspace
193 m_dataWS = this->getProperty("InputWorkspace");
194
195 // Output splitter information workspace
196 std::string title = getProperty("TitleOfSplitters");
197 if (title.empty()) {
198 // Using default
199 title = "Splitters";
200 }
201 m_filterInfoWS = std::make_shared<TableWorkspace>();
202 m_filterInfoWS->setTitle(title);
203 m_filterInfoWS->addColumn("int", "workspacegroup");
204 m_filterInfoWS->addColumn("str", "title");
205
206 // Output Splitters workspace: MatrixWorkspace (optioned) will be generated in
207 // last step
208 m_forFastLog = getProperty("FastLog");
209 if (!m_forFastLog) {
210 m_splitWS = std::shared_ptr<DataObjects::SplittersWorkspace>(new DataObjects::SplittersWorkspace());
211 m_splitWS->setTitle(title);
212 }
213
214 string algtype = getPropertyValue("UseParallelProcessing");
215 if (algtype == "Serial")
216 m_useParallel = false;
217 else if (algtype == "Parallel")
218 m_useParallel = true;
219 else
220 throw std::runtime_error("Impossible to have 3rd type other than Serial and Parallel. ");
221
222 // Conflict
223 if (m_useParallel && !m_forFastLog) {
224 g_log.warning("Parallelization is for fast log only. Automatically turn "
225 "FastLog on. ");
226 m_forFastLog = true;
227 }
228}
229
230//----------------------------------------------------------------------------------------------
236 // Get input
237 std::string s_inpt0 = this->getProperty("StartTime");
238 std::string s_inptf = this->getProperty("StopTime");
239
240 // Default
241 bool defaultstart = s_inpt0.empty();
242 bool defaultstop = s_inptf.empty();
243
244 // Determine format
245 bool instringformat = true;
246 if (!defaultstart && s_inpt0.find(':') == std::string::npos) {
247 // StartTime is not empty and does not contain ":": not ISO
248 instringformat = false;
249 } else if (!defaultstop && s_inptf.find(':') == std::string::npos) {
250 // StopTime is not empty and does not contain ":": not ISO format
251 instringformat = false;
252 }
253
254 // Obtain run time range
255 DateAndTime runstarttime = m_dataWS->run().startTime();
256
258
259 // Obtain time unit converter
260 std::string timeunit = this->getProperty("UnitOfTime");
262 if (timeunit == "Seconds") {
263 // (second)
265 } else if (timeunit == "Nanoseconds") {
266 // (nano-seconds)
268 } else if (timeunit == "Percent") {
269 // (percent of total run time)
270 int64_t runtime_ns = m_runEndTime.totalNanoseconds() - runstarttime.totalNanoseconds();
271 auto runtimed_ns = static_cast<double>(runtime_ns);
272 m_timeUnitConvertFactorToNS = 0.01 * runtimed_ns;
273 } else {
274 // (Not defined/supported)
275 stringstream errss;
276 errss << "TimeType " << timeunit << " is not supported.";
277 throw std::runtime_error(errss.str());
278 }
279
280 // Set up start time
281 if (defaultstart) {
282 // Default
283 m_startTime = runstarttime;
284 } else if (instringformat) {
285 // Time is absolute time in ISO format
286 m_startTime = DateAndTime(s_inpt0);
287 } else {
288 // Relative time in double.
289 double inpt0 = std::stod(s_inpt0.c_str());
290 if (inpt0 < 0) {
291 stringstream errss;
292 errss << "Input relative StartTime " << inpt0 << " cannot be negative. ";
293 throw std::invalid_argument(errss.str());
294 }
295 int64_t t0_ns = runstarttime.totalNanoseconds() + static_cast<int64_t>(inpt0 * m_timeUnitConvertFactorToNS);
296 m_startTime = Types::Core::DateAndTime(t0_ns);
297 }
298
299 // Set up run stop time
300 if (defaultstop) {
301 // Default
303 } else if (instringformat) {
304 // Absolute time in ISO format
305 m_stopTime = DateAndTime(s_inptf);
306 } else {
307 // Relative time in double
308 double inptf = std::stod(s_inptf.c_str());
309 int64_t tf_ns = runstarttime.totalNanoseconds() + static_cast<int64_t>(inptf * m_timeUnitConvertFactorToNS);
310 m_stopTime = Types::Core::DateAndTime(tf_ns);
311 }
312
313 // Check start/stop time
314 // if (m_startTime.totalNanoseconds() >= m_stopTime.totalNanoseconds()) {
315 if (m_startTime >= m_stopTime) {
316 stringstream errss;
317 errss << "Input StartTime " << m_startTime.toISO8601String() << " is equal or later than "
318 << "input StopTime " << m_stopTime.toFormattedString();
319 throw runtime_error(errss.str());
320 }
321
322 g_log.information() << "Filter: StartTime = " << m_startTime << ", StopTime = " << m_stopTime
323 << "; Run start = " << runstarttime.toISO8601String()
324 << ", Run stop = " << m_runEndTime.toISO8601String() << "\n";
325}
326
327//----------------------------------------------------------------------------------------------
331 vector<double> vec_timeintervals = this->getProperty("TimeInterval");
332
333 bool singleslot = false;
334 if (vec_timeintervals.empty()) {
335 singleslot = true;
336 } else {
337 // Check that there is at least one non-zero time value/interval
338 if (std::all_of(vec_timeintervals.begin(), vec_timeintervals.end(), [](double i) { return i == 0; }))
339 throw std::invalid_argument("If TimeInterval has one or more values, at "
340 "least one of those values must be non-zero.");
341 }
342
343 // Progress
344 int64_t totaltime = m_stopTime.totalNanoseconds() - m_startTime.totalNanoseconds();
345
346 g_log.information() << "Filter by time: start @ " << m_startTime.totalNanoseconds() << "; "
347 << "stop @ " << m_stopTime.totalNanoseconds() << "\n";
348
349 if (singleslot) {
350 int wsindex = 0;
351
352 // Default and thus just one interval
353 std::stringstream ss;
354 ss << "Time.Interval.From." << m_startTime << ".To." << m_stopTime;
356 } else if (vec_timeintervals.size() == 1) {
357 double timeinterval = vec_timeintervals[0];
358 int64_t timeslot = 0;
359
360 int64_t runStartTime = m_dataWS->run().startTime().totalNanoseconds();
361 bool isLogarithmic = (timeinterval < 0);
362 m_isReverseLogarithmic = this->getProperty("UseReverseLogarithmic");
363
364 if (m_isReverseLogarithmic && !isLogarithmic) {
365 g_log.warning("UseReverseLogarithmic checked but linear time interval provided. Using linear time interval.");
367 }
368
369 if (isLogarithmic && m_startTime.totalNanoseconds() == runStartTime)
370 throw runtime_error("Cannot do logarithmic time interval if the start time is the same as the start of the run.");
371
372 auto deltatime_ns = static_cast<int64_t>(timeinterval * m_timeUnitConvertFactorToNS);
373 double factor = std::fabs(timeinterval);
374
375 int64_t startTime_ns = m_startTime.totalNanoseconds();
376 int64_t endTime_ns = m_stopTime.totalNanoseconds();
377
378 double relativeStartTime_ns = static_cast<double>(startTime_ns - runStartTime);
379 double relativeEndTime_ns = static_cast<double>(endTime_ns - runStartTime);
380
381 int64_t curtime_ns = !m_isReverseLogarithmic ? startTime_ns - runStartTime : endTime_ns - runStartTime;
382
383 int64_t initialReverseLogStep = startTime_ns - runStartTime;
384
385 int totalNumberOfSlices;
386
387 // we compute the total expected number of slices
388 if (isLogarithmic) {
389 // if logarithmic, first an approximation of the value, then the final value depends if reverseLogarithmic is
390 // used, because of the way the last bin is managed
391 double logSize = std::log(relativeEndTime_ns / relativeStartTime_ns) / std::log1p(factor);
393 totalNumberOfSlices = static_cast<int>(std::ceil(logSize));
394 } else {
395 if (logSize < 1) {
396 totalNumberOfSlices = 1;
397 } else {
398 double previousBin = std::pow(1 + factor, std::floor(logSize) - 1);
399
400 // we check if the last bin can fit without being smaller than the previous one
401 if (relativeEndTime_ns - relativeStartTime_ns * previousBin * (1 + factor) >
402 relativeStartTime_ns * previousBin * factor) {
403 // case where it can
404 totalNumberOfSlices = static_cast<int>(std::ceil(logSize));
405 } else {
406 // case where it cannot and is merged with the previous one
407 totalNumberOfSlices = static_cast<int>(std::floor(logSize));
408 }
409 }
410 }
411 } else {
412 // nice linear case
413 totalNumberOfSlices =
414 static_cast<int>((relativeEndTime_ns - relativeStartTime_ns) / static_cast<double>(deltatime_ns));
415 }
416
417 int wsindex = !m_isReverseLogarithmic ? 0 : totalNumberOfSlices - 1;
418
419 while ((!m_isReverseLogarithmic && curtime_ns + runStartTime < endTime_ns) ||
420 (m_isReverseLogarithmic && curtime_ns + runStartTime > startTime_ns)) {
421 // Calculate next time
422 int64_t nexttime_ns; // note that this is the time since the start of the run
423
424 if (isLogarithmic) {
426 int64_t step = initialReverseLogStep + endTime_ns - runStartTime - curtime_ns;
427 nexttime_ns = curtime_ns - static_cast<int64_t>(static_cast<double>(step) * factor);
428 } else
429 nexttime_ns = static_cast<int64_t>(static_cast<double>(curtime_ns) * (1 + factor));
430
431 } else
432 nexttime_ns = curtime_ns + deltatime_ns;
433
434 if (nexttime_ns + runStartTime > m_stopTime.totalNanoseconds())
435 nexttime_ns = m_stopTime.totalNanoseconds() - runStartTime;
436
437 // in the reverseLog case, we make sure that the "last" bin cannot be smaller than the previous one.
438 if (runStartTime + nexttime_ns - (curtime_ns - nexttime_ns) < m_startTime.totalNanoseconds())
439 nexttime_ns = m_startTime.totalNanoseconds() - runStartTime;
440
441 // Create splitter and information
442 Types::Core::DateAndTime t0(std::min(curtime_ns, nexttime_ns) + runStartTime);
443 Types::Core::DateAndTime tf(std::max(curtime_ns, nexttime_ns) + runStartTime);
444 std::stringstream ss;
445 ss << "Time.Interval.From." << t0 << ".to." << tf;
446
447 addNewTimeFilterSplitter(t0, tf, wsindex, ss.str());
448
449 // Update loop variable and progress
450 curtime_ns = nexttime_ns;
451
452 int64_t newtimeslot;
454 wsindex++;
455 newtimeslot = (endTime_ns - (curtime_ns + runStartTime)) * 90 / totaltime;
456 } else {
457 wsindex--;
458 newtimeslot = (curtime_ns + runStartTime - startTime_ns) * 90 / totaltime;
459 }
460
461 if (newtimeslot > timeslot) {
462 // There is change and update progress
463 timeslot = newtimeslot;
464 double prog = 0.1 + double(timeslot) / 100.0;
465 progress(prog);
466 }
467 } // END-WHILE
468
469 } // END-IF-ELSE
470 else {
471 // Explicitly N time intervals with various interval
472
473 // Construct a vector for time intervals in nanosecond
474 size_t numtimeintervals = vec_timeintervals.size();
475 std::vector<int64_t> vec_dtimens(numtimeintervals);
476 for (size_t id = 0; id < numtimeintervals; ++id) {
477 auto deltatime_ns = static_cast<int64_t>(vec_timeintervals[id] * m_timeUnitConvertFactorToNS);
478 vec_dtimens[id] = deltatime_ns;
479 }
480
481 // Build the splitters
482 int64_t timeslot = 0;
483
484 int64_t curtime_ns = m_startTime.totalNanoseconds();
485 int wsindex = 0;
486 while (curtime_ns < m_stopTime.totalNanoseconds()) {
487 for (size_t id = 0; id < numtimeintervals; ++id) {
488 // get next time interval value
489 int64_t deltatime_ns = vec_dtimens[id];
490 // Calculate next.time
491 int64_t nexttime_ns = curtime_ns + deltatime_ns;
492 bool breaklater = false;
493 if (nexttime_ns > m_stopTime.totalNanoseconds()) {
494 nexttime_ns = m_stopTime.totalNanoseconds();
495 breaklater = true;
496 }
497
498 // Create splitter and information
499 Types::Core::DateAndTime t0(curtime_ns);
500 Types::Core::DateAndTime tf(nexttime_ns);
501 std::stringstream ss;
502 ss << "Time.Interval.From." << t0 << ".to." << tf;
503
504 addNewTimeFilterSplitter(t0, tf, wsindex, ss.str());
505
506 // Update loop variable
507 curtime_ns = nexttime_ns;
508 ++wsindex;
509
510 // Update progress
511 int64_t newtimeslot = (curtime_ns - m_startTime.totalNanoseconds()) * 90 / totaltime;
512 if (newtimeslot > timeslot) {
513 // There is change and update progress
514 timeslot = newtimeslot;
515 double prog = 0.1 + double(timeslot) / 100.0;
516 progress(prog);
517 }
518
519 if (breaklater)
520 break;
521 } // END-FOR
522 } // END-WHILE
523 }
524} // namespace Algorithms
525
526//----------------------------------------------------------------------------------------------
530void GenerateEventsFilter::setFilterByLogValue(const std::string &logname) {
531 // Obtain reference of sample log to filter with
532 m_dblLog = dynamic_cast<TimeSeriesProperty<double> *>(m_dataWS->run().getProperty(logname));
533 m_intLog = dynamic_cast<TimeSeriesProperty<int> *>(m_dataWS->run().getProperty(logname));
534 if (!m_dblLog && !m_intLog) {
535 stringstream errmsg;
536 errmsg << "Log " << logname << " does not exist or is not TimeSeriesProperty in double or integer.";
537 throw runtime_error(errmsg.str());
538 }
539
540 // Clear duplicate value and extend to run end
541 if (m_dblLog) {
542 g_log.debug("Attempting to remove duplicates in double series log.");
546 } else {
547 g_log.debug("Attempting to remove duplicates in integer series log.");
550 }
551
552 // Process input properties related to filter with log value
553 double minvalue = this->getProperty("MinimumLogValue");
554 double maxvalue = this->getProperty("MaximumLogValue");
555 double deltaValue = this->getProperty("LogValueInterval");
556
557 // Log value change direction
558 std::string filterdirection = getProperty("FilterLogValueByChangingDirection");
559 bool filterIncrease;
560 bool filterDecrease;
561 if (filterdirection == "Both") {
562 filterIncrease = true;
563 filterDecrease = true;
564 } else if (filterdirection == "Increase") {
565
566 filterIncrease = true;
567 filterDecrease = false;
568 } else {
569 filterIncrease = false;
570 filterDecrease = true;
571 }
572
573 bool toProcessSingleValueFilter = false;
574 if (isEmpty(deltaValue)) {
575 toProcessSingleValueFilter = true;
576 } else if (deltaValue < 0) {
577 throw runtime_error("Delta value cannot be negative.");
578 }
579
580 // Log boundary
581 string logboundary = getProperty("LogBoundary");
582 m_logAtCentre = bool(logboundary == "Centre");
583
584 m_logTimeTolerance = getProperty("TimeTolerance");
585
586 // Generate filters
587 if (m_dblLog) {
588 // Double TimeSeriesProperty log
589 // Process min/max
590 if (minvalue == EMPTY_DBL()) {
591 minvalue = m_dblLog->minValue();
592 }
593 if (maxvalue == EMPTY_DBL()) {
594 maxvalue = m_dblLog->maxValue();
595 }
596
597 if (minvalue > maxvalue) {
598 stringstream errmsg;
599 errmsg << "Fatal Error: Input minimum log value " << minvalue << " is larger than maximum log value " << maxvalue;
600 throw runtime_error(errmsg.str());
601 } else {
602 g_log.debug() << "Filter by log value: min = " << minvalue << ", max = " << maxvalue
603 << ", process single value? = " << toProcessSingleValueFilter << ", delta value = " << deltaValue
604 << "\n";
605 }
606
607 // Filter double value log
608 if (toProcessSingleValueFilter) {
609 // Generate a filter for a single log value
610 processSingleValueFilter(minvalue, maxvalue, filterIncrease, filterDecrease);
611 } else {
612 // Generate filters for a series of log value
613 processMultipleValueFilters(minvalue, deltaValue, maxvalue, filterIncrease, filterDecrease);
614 }
615 } else {
616 // Integer TimeSeriesProperty log
617 // Process min/max allowed value
618 int minvaluei, maxvaluei;
619 if (minvalue == EMPTY_DBL()) {
620 minvaluei = m_intLog->minValue();
621 minvalue = static_cast<double>(minvaluei);
622 } else
623 minvaluei = boost::math::iround(minvalue);
624
625 if (maxvalue == EMPTY_DBL()) {
626 maxvaluei = m_intLog->maxValue();
627 maxvalue = static_cast<double>(maxvaluei);
628 } else
629 maxvaluei = boost::math::iround(maxvalue);
630
631 if (minvalue > maxvalue) {
632 stringstream errmsg;
633 errmsg << "Fatal Error: Input minimum log value " << minvalue << " is larger than maximum log value " << maxvalue;
634 throw runtime_error(errmsg.str());
635 } else {
636 g_log.information() << "Generate event-filter for integer log: min = " << minvaluei << ", "
637 << "max = " << maxvaluei << "\n";
638 }
639
640 // Split along log
641 DateAndTime runendtime = m_dataWS->run().endTime();
642 processIntegerValueFilter(minvaluei, maxvaluei, filterIncrease, filterDecrease, runendtime);
643
644 } // ENDIFELSE: Double/Integer Log
645
646 g_log.information() << "Minimum value = " << minvalue << ", "
647 << "maximum value = " << maxvalue << ".\n";
648}
649
650//----------------------------------------------------------------------------------------------
659void GenerateEventsFilter::processSingleValueFilter(double minvalue, double maxvalue, bool filterincrease,
660 bool filterdecrease) {
661 // Get parameters time-tolerance and log-boundary
662 double timetolerance = this->getProperty("TimeTolerance");
663 auto timetolerance_ns = static_cast<int64_t>(timetolerance * m_timeUnitConvertFactorToNS);
664
665 std::string logboundary = this->getProperty("LogBoundary");
666 transform(logboundary.begin(), logboundary.end(), logboundary.begin(), ::tolower);
667
668 // Generate filter
669 // std::vector<Kernel::SplittingInterval> splitters;
670 int wsindex = 0;
671 makeFilterBySingleValue(minvalue, maxvalue, static_cast<double>(timetolerance_ns) * 1.0E-9, logboundary == "centre",
672 filterincrease, filterdecrease, m_startTime, m_stopTime, wsindex);
673
674 // Create information table workspace
675 if (!m_filterInfoWS)
676 throw runtime_error("m_filterInfoWS has not been initialized.");
677
678 API::TableRow row = m_filterInfoWS->appendRow();
679 std::stringstream ss;
680 ss << "Log." << m_dblLog->name() << ".From." << minvalue << ".To." << maxvalue << ".Value-change-direction:";
681 if (filterincrease && filterdecrease) {
682 ss << "both";
683 } else if (filterincrease) {
684 ss << "increase";
685 } else {
686 ss << "decrease";
687 }
688 row << 0 << ss.str();
689}
690
691//----------------------------------------------------------------------------------------------
701void GenerateEventsFilter::processMultipleValueFilters(double minvalue, double valueinterval, double maxvalue,
702 bool filterincrease, bool filterdecrease) {
703 // Read more input
704 if (valueinterval <= 0)
705 throw std::invalid_argument("Multiple values filter must have LogValueInterval larger than ZERO.");
706 double valuetolerance = this->getProperty("LogValueTolerance");
707
708 if (valuetolerance == EMPTY_DBL())
709 valuetolerance = 0.5 * valueinterval;
710 else if (valuetolerance < 0.0)
711 throw std::runtime_error("LogValueTolerance cannot be less than zero.");
712
713 // Create log value interval (low/up boundary) list and split information
714 // workspace
715 std::map<size_t, int> indexwsindexmap;
716 std::vector<double> logvalueranges;
717 int wsindex = 0;
718 size_t index = 0;
719
720 double curvalue = minvalue;
721 while (curvalue - valuetolerance < maxvalue) {
722 indexwsindexmap.emplace(index, wsindex);
723
724 // Log interval/value boundary
725 double lowbound = curvalue - valuetolerance;
726 double upbound = curvalue + valueinterval - valuetolerance;
727 logvalueranges.emplace_back(lowbound);
728 logvalueranges.emplace_back(upbound);
729
730 // Workgroup information
731 std::stringstream ss;
732 ss << "Log." << m_dblLog->name() << ".From." << lowbound << ".To." << upbound << ".Value-change-direction:";
733 if (filterincrease && filterdecrease) {
734 ss << "both";
735 } else if (filterincrease) {
736 ss << "increase";
737 } else {
738 ss << "decrease";
739 };
740 API::TableRow newrow = m_filterInfoWS->appendRow();
741 newrow << wsindex << ss.str();
742
743 curvalue += valueinterval;
744 wsindex++;
745 ++index;
746 } // ENDWHILE
747
748 // Debug print
749 stringstream dbsplitss;
750 dbsplitss << "Index map size = " << indexwsindexmap.size() << "\n";
751 for (auto &mit : indexwsindexmap) {
752 dbsplitss << "Index " << mit.first << ": WS-group = " << mit.second << ". Log value range: ["
753 << logvalueranges[mit.first * 2] << ", " << logvalueranges[mit.first * 2 + 1] << ").\n";
754 }
755 g_log.information(dbsplitss.str());
756
757 // Check split interval obtained wehther is with valid size
758 if (logvalueranges.size() < 2) {
759 g_log.warning("There is no log value interval existing.");
760 return;
761 }
762
763 {
764 // Warning information
765 double upperboundinterval0 = logvalueranges[1];
766 double lowerboundlastinterval = logvalueranges[logvalueranges.size() - 2];
767 double minlogvalue = m_dblLog->minValue();
768 double maxlogvalue = m_dblLog->maxValue();
769 if (minlogvalue > upperboundinterval0 || maxlogvalue < lowerboundlastinterval) {
770 g_log.warning() << "User specifies log interval from " << minvalue - valuetolerance << " to "
771 << maxvalue - valuetolerance << " with interval size = " << valueinterval << "; Log "
772 << m_dblLog->name() << " has range " << minlogvalue << " to " << maxlogvalue
773 << ". Therefore some workgroup index may not have any splitter.\n";
774 }
775 }
776
777 // Generate event filters by log value
778 std::string logboundary = this->getProperty("LogBoundary");
779 transform(logboundary.begin(), logboundary.end(), logboundary.begin(), ::tolower);
780
781 if (m_useParallel) {
782 // Make filters in parallel
783 makeMultipleFiltersByValuesParallel(indexwsindexmap, logvalueranges, logboundary == "centre", filterincrease,
784 filterdecrease, m_startTime, m_stopTime);
785 } else {
786 // Make filters in serial
787 makeMultipleFiltersByValues(indexwsindexmap, logvalueranges, logboundary == "centre", filterincrease,
788 filterdecrease, m_startTime, m_stopTime);
789 }
790}
791
792//-----------------------------------------------------------------------------------------------
812void GenerateEventsFilter::makeFilterBySingleValue(double min, double max, double TimeTolerance, bool centre,
813 bool filterIncrease, bool filterDecrease, DateAndTime startTime,
814 Types::Core::DateAndTime stopTime, int wsindex) {
815 // Do nothing if the log is empty.
816 if (m_dblLog->size() == 0) {
817 g_log.warning() << "There is no entry in this property " << this->name() << "\n";
818 return;
819 }
820
821 // Clear splitters in vector format
822 m_vecSplitterGroup.clear();
823 m_vecSplitterTime.clear();
824
825 // Initialize control parameters
826 bool lastGood = false;
827 time_duration tol = DateAndTime::durationFromSeconds(TimeTolerance);
828 int numgood = 0;
829 DateAndTime currT, start, stop;
830
831 size_t progslot = 0;
832 for (int i = 0; i < m_dblLog->size(); i++) {
833 // The new entry
834 currT = m_dblLog->nthTime(i);
835
836 // A good value?
837 bool isGood = identifyLogEntry(i, currT, lastGood, min, max, startTime, stopTime, filterIncrease, filterDecrease);
838 if (isGood)
839 numgood++;
840
841 // Log status (time/value/value changing direciton) is changed
842 if (isGood != lastGood) {
843 // We switched from bad to good or good to bad
844 if (isGood) {
845 // Start of a good section
846 if (centre)
847 start = currT - tol;
848 else
849 start = currT;
850 } else {
851 // End of the good section
852 if (centre) {
853 stop = currT - tol;
854 } else {
855 stop = currT;
856 }
857
858 std::string empty("");
859 addNewTimeFilterSplitter(start, stop, wsindex, empty);
860
861 // Reset the number of good ones, for next time
862 numgood = 0;
863 }
864 lastGood = isGood;
865 }
866
867 // Progress bar..
868 size_t tmpslot = i * 90 / m_dblLog->size();
869 if (tmpslot > progslot) {
870 progslot = tmpslot;
871 double prog = double(progslot) / 100.0 + 0.1;
872 progress(prog);
873 }
874
875 } // ENDFOR
876
877 if (numgood > 0) {
878 // The log ended on "good" so we need to close it using the last time we
879 // found
880 if (centre)
881 stop = currT - tol;
882 else
883 stop = currT;
884
885 std::string empty("");
886 addNewTimeFilterSplitter(start, stop, wsindex, empty);
887 }
888
889 return;
890}
891
892//----------------------------------------------------------------------------------------------
901bool GenerateEventsFilter::identifyLogEntry(const int &index, const Types::Core::DateAndTime &currT,
902 const bool &lastgood, const double &minvalue, const double &maxvalue,
903 const Types::Core::DateAndTime &startT,
904 const Types::Core::DateAndTime &stopT, const bool &filterIncrease,
905 const bool &filterDecrease) {
906 double val = m_dblLog->nthValue(index);
907
908 // Identify by time and value
909 bool isgood = (val >= minvalue && val < maxvalue) && (currT >= startT && currT < stopT);
910
911 // Consider direction: not both (i.e., not increase or not decrease)
912 if (isgood && (!filterIncrease || !filterDecrease)) {
913 int numlogentries = m_dblLog->size();
914 double diff;
915 if (index < numlogentries - 1) {
916 // For a non-last log entry
917 diff = m_dblLog->nthValue(index + 1) - val;
918 } else {
919 // Last log entry: follow the last direction
920 diff = val - m_dblLog->nthValue(index - 1);
921 }
922
923 if (diff > 0 && filterIncrease)
924 isgood = true;
925 else if (diff < 0 && filterDecrease)
926 isgood = true;
927 else if (diff == 0)
928 isgood = lastgood;
929 else
930 isgood = false;
931 }
932
933 return isgood;
934}
935
936//-----------------------------------------------------------------------------------------------
952void GenerateEventsFilter::makeMultipleFiltersByValues(map<size_t, int> indexwsindexmap,
953 const vector<double> &logvalueranges, bool centre,
954 bool filterIncrease, bool filterDecrease, DateAndTime startTime,
955 DateAndTime stopTime) {
956 g_log.notice("Starting method 'makeMultipleFiltersByValues'. ");
957
958 // Return if the log is empty.
959 int logsize = m_dblLog->size();
960 if (logsize == 0) {
961 g_log.warning() << "There is no entry in this property " << m_dblLog->name() << '\n';
962 return;
963 }
964
965 // Set up
966 double timetolerance = 0.0;
967 if (centre) {
968 timetolerance = this->getProperty("TimeTolerance");
969 }
970 time_duration tol = DateAndTime::durationFromSeconds(timetolerance);
971
972 // Determine the number of threads to use
973 // int numThreads = 1;
974 vector<DateAndTime> tempvectimes;
975 // tempvectimes.reserve(m_dblLog->size());
976 vector<int> tempvecgroup;
977 // tempvecgroup.reserve(m_dblLog->size());
978 m_vecSplitterTimeSet.emplace_back(tempvectimes);
979 m_vecGroupIndexSet.emplace_back(tempvecgroup);
980 int istart = 0;
981 auto iend = static_cast<int>(logsize - 1);
982
983 makeMultipleFiltersByValuesPartialLog(istart, iend, m_vecSplitterTime, m_vecSplitterGroup, std::move(indexwsindexmap),
984 logvalueranges, tol, filterIncrease, filterDecrease, startTime, stopTime);
985
986 progress(1.0);
987}
988
989//-----------------------------------------------------------------------------------------------
1006void GenerateEventsFilter::makeMultipleFiltersByValuesParallel(const map<size_t, int> &indexwsindexmap,
1007 const vector<double> &logvalueranges, bool centre,
1008 bool filterIncrease, bool filterDecrease,
1009 DateAndTime startTime, DateAndTime stopTime) {
1010 // Return if the log is empty.
1011 int logsize = m_dblLog->size();
1012 if (logsize == 0) {
1013 g_log.warning() << "There is no entry in this property " << m_dblLog->name() << '\n';
1014 return;
1015 }
1016
1017 // Set up
1018 double timetolerance = 0.0;
1019 if (centre) {
1020 timetolerance = this->getProperty("TimeTolerance");
1021 }
1022 time_duration tol = DateAndTime::durationFromSeconds(timetolerance);
1023
1024 // Determine the number of threads to use
1025 int numThreads = getProperty("NumberOfThreads");
1026 if (isEmpty(numThreads))
1027 numThreads = static_cast<int>(PARALLEL_GET_MAX_THREADS);
1028
1029 // Limit the number of threads.
1030 numThreads = std::min(numThreads, logsize / 8);
1031
1032 // Determine the istart and iend
1033 // For split, log should be [0, n], [n, 2n], [2n, 3n], ... as to look into n
1034 // log values
1035 std::vector<int> vecStart, vecEnd;
1036 int partloglength = (logsize - 1) / numThreads;
1037 int extra = (logsize - 1) % numThreads;
1038 for (int i = 0; i < numThreads; ++i) {
1039 int istart = i * partloglength;
1040 if (i < extra)
1041 istart += i;
1042 else
1043 istart += extra;
1044
1045 int iend = istart + partloglength;
1046 if (i < extra)
1047 ++iend;
1048
1049 vecStart.emplace_back(istart);
1050 vecEnd.emplace_back(iend);
1051 }
1052
1053 {
1054 stringstream dbss;
1055 dbss << "Number of thread = " << numThreads << ", Log Size = " << logsize << "\n";
1056 for (size_t i = 0; i < vecStart.size(); ++i) {
1057 dbss << "Thread " << i << ": Log range: [" << vecStart[i] << ", " << vecEnd[i] << ") "
1058 << "Size = " << vecEnd[i] - vecStart[i] << "\n";
1059 }
1060 g_log.information(dbss.str());
1061 }
1062
1063 // Create partial vectors
1064 m_vecSplitterTimeSet.clear();
1065 m_vecGroupIndexSet.clear();
1066 for (int i = 0; i < numThreads; ++i) {
1067 vector<DateAndTime> tempvectimes;
1068 tempvectimes.reserve(m_dblLog->size());
1069 vector<int> tempvecgroup;
1070 tempvecgroup.reserve(m_dblLog->size());
1071 m_vecSplitterTimeSet.emplace_back(tempvectimes);
1072 m_vecGroupIndexSet.emplace_back(tempvecgroup);
1073 }
1074
1075 // Create event filters/splitters in parallel
1076
1077 PRAGMA_OMP(parallel for schedule(dynamic, 1) )
1078 for (int i = 0; i < numThreads; ++i) {
1080
1081 int istart = vecStart[i];
1082 int iend = vecEnd[i];
1083
1085 indexwsindexmap, logvalueranges, tol, filterIncrease, filterDecrease,
1086 startTime, stopTime);
1088 }
1090
1091 // Concatenate splitters on different threads together
1092 for (int i = 1; i < numThreads; ++i) {
1093 if (m_vecSplitterTimeSet[i - 1].back() == m_vecSplitterTimeSet[i].front()) {
1094 // T_(i).back() = T_(i+1).front()
1095 if (m_vecGroupIndexSet[i - 1].back() == m_vecGroupIndexSet[i].front()) {
1096 // G_(i).back() = G_(i+1).front(), combine these adjacent 2 splitters
1097 // Rule out impossible situation
1098 if (m_vecGroupIndexSet[i - 1].back() == -1) {
1099 // Throw with detailed error message
1100 stringstream errss;
1101 errss << "Previous vector of group index set (" << (i - 1) << ") is equal to -1. "
1102 << "It is not likely to happen! Size of previous vector of "
1103 "group is "
1104 << m_vecGroupIndexSet[i - 1].size() << ". \nSuggest to use sequential mode. ";
1105 throw runtime_error(errss.str());
1106 }
1107
1108 // Pop back last element
1109 m_vecGroupIndexSet[i - 1].pop_back();
1110 DateAndTime newt0 = m_vecSplitterTimeSet[i - 1].front();
1111 m_vecSplitterTimeSet[i - 1].pop_back();
1112 DateAndTime origtime = m_vecSplitterTimeSet[i][0];
1113 m_vecSplitterTimeSet[i][0] = newt0;
1114 g_log.debug() << "Splitter at the end of thread " << i << " is extended from " << origtime << " to " << newt0
1115 << "\n";
1116 } else {
1117 // 2 different and continous spliiter: ideal case without any
1118 // operation
1119 ;
1120 }
1121 } else {
1122 // T_(i).back() != T_(i+1).front(): need to fill the gap in time
1123 int lastindex = m_vecGroupIndexSet[i - 1].back();
1124 int firstindex = m_vecGroupIndexSet[i].front();
1125
1126 if (lastindex != -1 && firstindex != -1) {
1127 // T_stop < T_start, I_stop != -1, I_start != 1. : Insert a minus-one
1128 // entry to make it complete
1129 m_vecGroupIndexSet[i - 1].emplace_back(-1);
1130 m_vecSplitterTimeSet[i - 1].emplace_back(m_vecSplitterTimeSet[i].front());
1131 } else if (lastindex == -1 && m_vecGroupIndexSet[i - 1].size() == 1) {
1132 // Empty splitter of the thread. Extend this to next
1133 m_vecSplitterTimeSet[i - 1].back() = m_vecSplitterTimeSet[i].front();
1134 g_log.debug() << "Thread = " << i << ", change ending time of " << i - 1 << " to "
1135 << m_vecSplitterTimeSet[i].front() << "\n";
1136 } else if (firstindex == -1 && m_vecGroupIndexSet[i].size() == 1) {
1137 // Empty splitter of the thread. Extend last one to this
1138 m_vecSplitterTimeSet[i].front() = m_vecSplitterTimeSet[i - 1].back();
1139 g_log.debug() << "Thread = " << i << ", change starting time to " << m_vecSplitterTimeSet[i].front() << "\n";
1140 } else {
1141 throw runtime_error("It is not possible to have start or end of "
1142 "filter to be minus-one index. ");
1143 }
1144 }
1145 }
1146
1147 progress(1.0);
1148}
1149
1150//----------------------------------------------------------------------------------------------
1154 int istart, int iend, std::vector<Types::Core::DateAndTime> &vecSplitTime, std::vector<int> &vecSplitGroup,
1155 map<size_t, int> indexwsindexmap, const vector<double> &logvalueranges, const time_duration &tol,
1156 bool filterIncrease, bool filterDecrease, DateAndTime startTime, DateAndTime stopTime) {
1157 // Check
1158 int logsize = m_dblLog->size();
1159 if (istart < 0 || iend >= logsize)
1160 throw runtime_error("Input index of makeMultipleFiltersByValuesPartialLog "
1161 "is out of boundary. ");
1162
1163 int64_t tol_ns = tol.total_nanoseconds();
1164
1165 // Define loop control parameters
1166 const Types::Core::DateAndTime ZeroTime(0);
1167 int lastindex = -1;
1168 int currindex;
1169 DateAndTime currTime, start, stop;
1170 // size_t progslot = 0;
1171
1172 g_log.information() << "Log time coverage (index: " << istart << ", " << iend << ") from "
1173 << m_dblLog->nthTime(istart) << ", " << m_dblLog->nthTime(iend) << "\n";
1174
1175 DateAndTime laststoptime(0);
1176 int lastlogindex = m_dblLog->size() - 1;
1177
1178 int prevDirection = determineChangingDirection(istart);
1179
1180 for (int i = istart; i <= iend; i++) {
1181 // Initialize status flags and new entry
1182 bool breakloop = false;
1183 bool createsplitter = false;
1184
1185 currTime = m_dblLog->nthTime(i);
1186 double currValue = m_dblLog->nthValue(i);
1187
1188 // Filter out by time and direction (optional)
1189 if (currTime < startTime) {
1190 // case i. Too early, do nothing
1191 createsplitter = false;
1192 } else if (currTime > stopTime) {
1193 // case ii. Too late. Put to splitter if half of splitter is done. But
1194 // still within range
1195 breakloop = true;
1196 stop = currTime;
1197 if (start.totalNanoseconds() > 0) {
1198 createsplitter = true;
1199 }
1200 }
1201
1202 // Check log within given time range
1203 bool newsplitter = false; // Flag to start a new split in this loop
1204
1205 // Determine direction
1206 int direction = 0;
1207 if (i < lastlogindex) {
1208 // Not the last log entry
1209 double diff = m_dblLog->nthValue(i + 1) - m_dblLog->nthValue(i);
1210 if (diff > 0)
1211 direction = 1;
1212 else if (diff < 0)
1213 direction = -1;
1214 else
1215 direction = prevDirection;
1216 } else {
1217 // Last log entry: use the previous direction
1218 direction = prevDirection;
1219 }
1220 prevDirection = direction;
1221
1222 // Examine log value for filter
1223 // Determine whether direction is fine
1224 bool correctdir = true;
1225 if (filterIncrease && filterDecrease) {
1226 // Both direction is fine
1227 correctdir = true;
1228 } else {
1229 // Filter out one direction
1230 if (filterIncrease && direction > 0)
1231 correctdir = true;
1232 else if (filterDecrease && direction < 0)
1233 correctdir = true;
1234 else if (direction == 0)
1235 throw runtime_error("Direction is not determined.");
1236 else
1237 correctdir = false;
1238 } // END-IF-ELSE: Direction
1239
1240 // Treat the log entry based on: changing direction (+ time range)
1241 if (correctdir) {
1242 // Check this value whether it falls into any range
1243 size_t index = searchValue(logvalueranges, currValue);
1244
1245 bool valueWithinMinMax = true;
1246 if (index > logvalueranges.size()) {
1247 // Out of range
1248 valueWithinMinMax = false;
1249 }
1250
1251 if (g_log.is(Logger::Priority::PRIO_DEBUG)) {
1252 stringstream dbss;
1253 dbss << "[DBx257] Examine Log Index " << i << ", Value = " << currValue << ", Data Range Index = " << index
1254 << "; "
1255 << "Group Index = " << indexwsindexmap[index / 2]
1256 << " (log value range vector size = " << logvalueranges.size() << "): ";
1257 if (index == 0)
1258 dbss << logvalueranges[index] << ", " << logvalueranges[index + 1];
1259 else if (index == logvalueranges.size())
1260 dbss << logvalueranges[index - 1] << ", " << logvalueranges[index];
1261 else if (valueWithinMinMax)
1262 dbss << logvalueranges[index - 1] << ", " << logvalueranges[index] << ", " << logvalueranges[index + 1];
1263 g_log.debug(dbss.str());
1264 }
1265
1266 if (valueWithinMinMax) {
1267 if (index % 2 == 0) {
1268 // [Situation] Falls in the interval
1269 currindex = indexwsindexmap[index / 2];
1270
1271 if (currindex != lastindex && start.totalNanoseconds() == 0) {
1272 // Group index is different from last and start is not set up: new
1273 // a region!
1274 newsplitter = true;
1275 } else if (currindex != lastindex && start.totalNanoseconds() > 0) {
1276 // Group index is different from last and start is set up: close
1277 // a region and new a region
1278 stop = currTime;
1279 createsplitter = true;
1280 newsplitter = true;
1281 } else if (currindex == lastindex && start.totalNanoseconds() > 0) {
1282 // Still of the group index
1283 if (i == iend) {
1284 // Last entry in this section of log. Need to flag to close the
1285 // pair
1286 stop = currTime;
1287 createsplitter = true;
1288 newsplitter = false;
1289 } else {
1290 // Do nothing
1291 ;
1292 }
1293 } else {
1294 // An impossible situation
1295 std::stringstream errmsg;
1296 double lastvalue = m_dblLog->nthValue(i - 1);
1297 errmsg << "Impossible to have currindex == lastindex == " << currindex
1298 << ", while start is not init. Log Index = " << i << "\t value = " << currValue
1299 << "\t, Index = " << index << " in range " << logvalueranges[index] << ", "
1300 << logvalueranges[index + 1] << "; Last value = " << lastvalue;
1301 throw std::runtime_error(errmsg.str());
1302 }
1303 } // [In-bound: Inside interval]
1304 else {
1305 // [Situation] Fall between interval (which is not likley happen)
1306 currindex = -1;
1307 g_log.warning() << "Not likely to happen! Current value = " << currValue
1308 << " is within value range but its index = " << index << " has no map to group index. "
1309 << "\n";
1310 if (start.totalNanoseconds() > 0) {
1311 // Close the interval pair if it has been started.
1312 stop = currTime;
1313 createsplitter = true;
1314 }
1315 } // [In-bound: Between interval]
1316 } else {
1317 // Out of a range: check whether there is a splitter started
1318 currindex = -1;
1319 if (start.totalNanoseconds() > 0) {
1320 // End situation
1321 stop = currTime;
1322 createsplitter = true;
1323 }
1324 } // [Out-bound]
1325
1326 } // [CORRECT DIRECTION]
1327 else {
1328 // Log Index i falls out b/c out of wrong direction
1329 currindex = -1;
1330
1331 // Condition to generate a Splitter (close parenthesis)
1332 if (start.totalNanoseconds() > 0) {
1333 stop = currTime;
1334 createsplitter = true;
1335 }
1336 }
1337
1338 // d) Create Splitter
1339 if (createsplitter) {
1340 // make_splitter(start, stop, lastindex, tol);
1341 makeSplitterInVector(vecSplitTime, vecSplitGroup, start, stop, lastindex, tol_ns, laststoptime);
1342
1343 // reset
1344 start = ZeroTime;
1345 }
1346
1347 // e) Start new splitter: have to be here due to start cannot be updated
1348 // before a possible splitter generated
1349 if (newsplitter)
1350 start = currTime;
1351
1352 // f) Break
1353 if (breakloop)
1354 break;
1355
1356 // e) Update loop variable
1357 lastindex = currindex;
1358
1359 } // For each log value
1360
1361 // To fill the blanks at the end of log to make last entry of splitter is stop
1362 // time
1363 // To make it non-empty
1364 if (vecSplitTime.empty()) {
1365 start = m_dblLog->nthTime(istart);
1366 stop = m_dblLog->nthTime(iend);
1367 lastindex = -1;
1368 makeSplitterInVector(vecSplitTime, vecSplitGroup, start, stop, lastindex, tol_ns, laststoptime);
1369 }
1370}
1371
1372//-----------------------------------------------------------------------------------------------
1380void GenerateEventsFilter::processIntegerValueFilter(int minvalue, int maxvalue, bool filterIncrease,
1381 bool filterDecrease, DateAndTime runend) {
1382 // Determine the filter mode and delta
1383 int delta = 0;
1384 bool singlevaluemode;
1385 if (minvalue == maxvalue) {
1386 singlevaluemode = true;
1387 } else {
1388 singlevaluemode = false;
1389
1390 double deltadbl = getProperty("LogValueInterval");
1391 if (isEmpty(deltadbl))
1392 delta = maxvalue - minvalue + 1;
1393 else
1394 delta = boost::math::iround(deltadbl);
1395
1396 if (delta <= 0) {
1397 stringstream errss;
1398 errss << "In a non-single value mode, LogValueInterval cannot be 0 or "
1399 "negative for integer. "
1400 << "Current input is " << deltadbl << ".";
1401 throw runtime_error(errss.str());
1402 } else
1403 g_log.information() << "Generate event-filter by integer log: step = " << delta << "\n";
1404 }
1405
1406 // Search along log to generate splitters
1407 size_t numlogentries = m_intLog->size();
1408 vector<DateAndTime> vecTimes = m_intLog->timesAsVector();
1409 vector<int> vecValue = m_intLog->valuesAsVector();
1410
1411 time_duration timetol = DateAndTime::durationFromSeconds(m_logTimeTolerance * m_timeUnitConvertFactorToNS * 1.0E-9);
1412 int64_t timetolns = timetol.total_nanoseconds();
1413
1414 DateAndTime splitstarttime(0);
1415 int pregroup = -1;
1416 DateAndTime laststoptime(0);
1417
1418 g_log.debug() << "Number of integer log entries = " << numlogentries << ".\n";
1419
1420 for (size_t i = 0; i < numlogentries; ++i) {
1421 int currvalue = vecValue[i];
1422 int currgroup = -1;
1423
1424 // Determine whether this log value is allowed and then the ws group it
1425 // belonged to.
1426 if (currvalue >= minvalue && currvalue <= maxvalue) {
1427 // Log value is in specified range
1428 if ((i == 0) || (filterIncrease && vecValue[i] >= vecValue[i - 1]) ||
1429 (filterDecrease && vecValue[i] <= vecValue[i - 1])) {
1430 // First entry (regardless direction) and other entries considering
1431 // change of value
1432 if (singlevaluemode) {
1433 currgroup = 0;
1434 } else {
1435 currgroup = (currvalue - minvalue) / delta;
1436 }
1437 }
1438 }
1439
1440 // Make a new splitter if condition is met
1441 bool statuschanged;
1442 if (pregroup >= 0 && currgroup < 0) {
1443 // previous log is in allowed region. but this one is not. create a
1444 // splitter
1445 if (splitstarttime.totalNanoseconds() == 0)
1446 throw runtime_error("Programming logic error.");
1447
1448 makeSplitterInVector(m_vecSplitterTime, m_vecSplitterGroup, splitstarttime, vecTimes[i], pregroup, timetolns,
1449 laststoptime);
1450 laststoptime = vecTimes[i];
1451
1452 splitstarttime = DateAndTime(0);
1453 statuschanged = true;
1454 } else if (pregroup < 0 && currgroup >= 0) {
1455 // previous log is not allowed, but this one is. this is the start of a
1456 // new splitter
1457 splitstarttime = vecTimes[i];
1458 statuschanged = true;
1459 } else if (currgroup >= 0 && pregroup != currgroup) {
1460 // migrated to a new region
1461 if (splitstarttime.totalNanoseconds() == 0)
1462 throw runtime_error("Programming logic error (1).");
1463 makeSplitterInVector(m_vecSplitterTime, m_vecSplitterGroup, splitstarttime, vecTimes[i], pregroup, timetolns,
1464 laststoptime);
1465 laststoptime = vecTimes[i];
1466
1467 splitstarttime = vecTimes[i];
1468 statuschanged = true;
1469 } else {
1470 // no need to do anything: status is not changed
1471 statuschanged = false;
1472 }
1473
1474 // Update group/pregroup
1475 if (statuschanged)
1476 pregroup = currgroup;
1477 } // ENDOFLOOP on time series
1478
1479 // Create the last splitter if existing
1480 if (pregroup >= 0) {
1481 // Last entry is in an allowed region.
1482 if (splitstarttime.totalNanoseconds() == 0)
1483 throw runtime_error("Programming logic error (1).");
1484 makeSplitterInVector(m_vecSplitterTime, m_vecSplitterGroup, splitstarttime, runend, pregroup, timetolns,
1485 laststoptime);
1486 }
1487
1488 // Write to the information workspace
1489 // FIXME - Consider to refactor this part with all other methods
1490 if (singlevaluemode) {
1491 TableRow newrow = m_filterInfoWS->appendRow();
1492 stringstream message;
1493 message << m_intLog->name() << " = " << minvalue;
1494 newrow << 0 << message.str();
1495 } else {
1496 int logvalue = minvalue;
1497 int wsindex = 0;
1498 while (logvalue <= maxvalue) {
1499 stringstream message;
1500 if (logvalue + delta - 1 > logvalue)
1501 message << m_intLog->name() << "=[" << logvalue << "," << logvalue + delta - 1 << "]";
1502 else
1503 message << m_intLog->name() << "=" << logvalue;
1504
1505 message << ".Value change direction:";
1506 if (filterIncrease && filterDecrease)
1507 message << "Both";
1508 else if (filterIncrease)
1509 message << "Increasing";
1510 else if (filterDecrease)
1511 message << "Decreasing";
1512
1513 TableRow newrow = m_filterInfoWS->appendRow();
1514 newrow << wsindex << message.str();
1515
1516 ++wsindex;
1517 logvalue += delta;
1518 }
1519 }
1520
1521 g_log.information() << "Integer log " << m_intLog->name() << ": Number of splitters = " << m_vecSplitterGroup.size()
1522 << ", Number of split info = " << m_filterInfoWS->rowCount() << ".\n";
1523}
1524
1525//----------------------------------------------------------------------------------------------
1535size_t GenerateEventsFilter::searchValue(const std::vector<double> &sorteddata, double value) {
1536 // Case of out-of-boundary
1537 size_t numdata = sorteddata.size();
1538 size_t outrange = numdata + 1;
1539 if (numdata == 0)
1540 return outrange;
1541 else if (value < sorteddata.front() || value > sorteddata.back())
1542 return outrange;
1543
1544 // Binary search
1545 size_t index =
1546 static_cast<size_t>(std::lower_bound(sorteddata.begin(), sorteddata.end(), value) - sorteddata.begin());
1547
1548 if (value < sorteddata[index] && index % 2 == 1) {
1549 // value to search is less than the boundary: use the index of the one just
1550 // smaller to the value to search
1551 --index;
1552 } else if (value == sorteddata[index] && index % 2 == 1) {
1553 // value to search is on the boudary, i..e, a,b,b,c,c,....,x,x,y
1554 ++index;
1555
1556 // return if out of range
1557 if (index == sorteddata.size())
1558 return outrange;
1559 }
1560
1561 return index;
1562}
1563
1564//----------------------------------------------------------------------------------------------
1568 int direction = 0;
1569
1570 // Search to earlier entries
1571 int index = startindex;
1572 while (direction == 0 && index > 0) {
1573 double diff = m_dblLog->nthValue(index) - m_dblLog->nthValue(index - 1);
1574 if (diff > 0)
1575 direction = 1;
1576 else if (diff < 0)
1577 direction = -1;
1578
1579 --index;
1580 }
1581
1582 if (direction != 0)
1583 return direction;
1584
1585 // Search to later entries
1586 index = startindex;
1587 int maxindex = m_dblLog->size() - 1;
1588 while (direction == 0 && index < maxindex) {
1589 double diff = m_dblLog->nthValue(index + 1) - m_dblLog->nthValue(index);
1590 if (diff > 0)
1591 direction = 1;
1592 else if (diff < 0)
1593 direction = -1;
1594
1595 ++index;
1596 }
1597
1598 if (direction == 0)
1599 throw runtime_error("Sample log is flat. Use option 'Both' instead! ");
1600
1601 return direction;
1602}
1603
1604//----------------------------------------------------------------------------------------------
1607void GenerateEventsFilter::addNewTimeFilterSplitter(Types::Core::DateAndTime starttime,
1608 Types::Core::DateAndTime stoptime, int wsindex,
1609 const string &info) {
1610 if (m_forFastLog) {
1611 // For MatrixWorkspace splitter
1612 // Start of splitter
1613 if (m_vecSplitterTime.empty()) {
1614 // First splitter
1615 m_vecSplitterTime.emplace_back(starttime);
1616 } else if (m_vecSplitterTime.back() < starttime) {
1617 // Splitter to insert has a gap to previous splitter
1618 m_vecSplitterTime.emplace_back(starttime);
1619 m_vecSplitterGroup.emplace_back(-1);
1620
1621 } else if (m_vecSplitterTime.back() == starttime) {
1622 // Splitter to insert is just behind previous one (no gap): nothing
1623 } else {
1624 // Impossible situation
1625 throw runtime_error("Logic error. Trying to insert a splitter, whose "
1626 "start time is earlier than last splitter.");
1627 }
1628 // Stop of splitter
1629 m_vecSplitterTime.emplace_back(stoptime);
1630 // Group
1631 m_vecSplitterGroup.emplace_back(wsindex);
1632 } else {
1633 // For regular Splitter
1634 Kernel::SplittingInterval spiv(starttime, stoptime, wsindex);
1635 m_splitWS->addSplitter(spiv);
1636 }
1637
1638 // Information
1639 if (!info.empty()) {
1641 API::TableRow row = m_filterInfoWS->appendRow();
1642 row << wsindex << info;
1643 } else {
1644 m_filterInfoWS->insertRow(0);
1645 API::TableRow row = m_filterInfoWS->getRow(0);
1646 row << wsindex << info;
1647 }
1648 }
1649}
1650
1651//----------------------------------------------------------------------------------------------
1655DateAndTime GenerateEventsFilter::makeSplitterInVector(std::vector<Types::Core::DateAndTime> &vecSplitTime,
1656 std::vector<int> &vecGroupIndex, Types::Core::DateAndTime start,
1657 Types::Core::DateAndTime stop, int group, int64_t tol_ns,
1658 DateAndTime lasttime) {
1659 DateAndTime starttime(start.totalNanoseconds() - tol_ns);
1660 DateAndTime stoptime(stop.totalNanoseconds() - tol_ns);
1661 // DateAndTime starttime = start-tolerance;
1662 // DateAndTime stoptime = stop-tolerance;
1663
1664 size_t timevecsize = vecSplitTime.size();
1665 if (timevecsize > 0)
1666 lasttime = vecSplitTime.back();
1667
1668 // Start time of splitter
1669 if (timevecsize == 0) {
1670 // First value
1671 vecSplitTime.emplace_back(starttime);
1672 } else if (lasttime < starttime) {
1673 // Stop time of previous splitter is earlier than start time of this
1674 // splitter (gap)
1675 vecSplitTime.emplace_back(starttime);
1676 vecGroupIndex.emplace_back(-1);
1677 } else if (lasttime > starttime) {
1678 // Impossible situation
1679 throw runtime_error("Impossible situation.");
1680 }
1681
1682 // The last situation is "Stop time of previous splitter is the start time of
1683 // this splitter".
1684 // No action is required to take
1685
1686 // Complete this splitter, i.e., stoptime and group
1687 // Stop time of splitter
1688 vecSplitTime.emplace_back(stoptime);
1689 // Group index
1690 vecGroupIndex.emplace_back(group);
1691
1692 return stoptime;
1693}
1694
1695//----------------------------------------------------------------------------------------------
1699 g_log.information() << "Size of splitter vector: " << m_vecSplitterTime.size() << ", " << m_vecSplitterGroup.size()
1700 << "\n";
1701
1702 size_t sizex = m_vecSplitterTime.size();
1703 size_t sizey = m_vecSplitterGroup.size();
1704
1705 if (sizex - sizey != 1) {
1706 throw runtime_error("Logic error on splitter vectors' size. ");
1707 }
1708
1709 m_filterWS = create<Workspace2D>(1, BinEdges(sizex));
1710 auto &dataX = m_filterWS->mutableX(0);
1711 for (size_t i = 0; i < sizex; ++i) {
1712 // x is in the unit as second
1713 dataX[i] = static_cast<double>(m_vecSplitterTime[i].totalNanoseconds()) * 1.E-9;
1714 }
1715
1716 auto &dataY = m_filterWS->mutableY(0);
1717 for (size_t i = 0; i < sizey; ++i) {
1718 dataY[i] = static_cast<double>(m_vecSplitterGroup[i]);
1719 }
1720}
1721
1722//----------------------------------------------------------------------------------------------
1728 // Determine size of output matrix workspace
1729 size_t numtimes = 0;
1730 size_t numThreads = m_vecSplitterTimeSet.size();
1731 for (size_t i = 0; i < numThreads; ++i) {
1732 numtimes += m_vecGroupIndexSet[i].size();
1733 g_log.debug() << "[DB] Thread " << i << " have " << m_vecGroupIndexSet[i].size() << " splitter "
1734 << "\n";
1735 }
1736 ++numtimes;
1737
1738 size_t sizex = numtimes;
1739
1740 m_filterWS = create<Workspace2D>(1, BinEdges(sizex));
1741 auto &dataX = m_filterWS->mutableX(0);
1742 auto &dataY = m_filterWS->mutableY(0);
1743
1744 size_t index = 0;
1745 for (size_t i = 0; i < numThreads; ++i) {
1746 for (size_t j = 0; j < m_vecGroupIndexSet[i].size(); ++j) {
1747 // x is in the unit as second
1748 dataX[index] = static_cast<double>(m_vecSplitterTimeSet[i][j].totalNanoseconds()) * 1.E-9;
1749 dataY[index] = static_cast<double>(m_vecGroupIndexSet[i][j]);
1750 ++index;
1751 }
1752 }
1753 // x is in the unit as second
1754 dataX[index] = static_cast<double>(m_vecSplitterTimeSet.back().back().totalNanoseconds()) * 1.E-9;
1755}
1756
1757//----------------------------------------------------------------------------------------------
1761 for (size_t i = 0; i < m_vecSplitterGroup.size(); ++i) {
1762 int groupindex = m_vecSplitterGroup[i];
1763 if (groupindex >= 0) {
1764 DateAndTime start = m_vecSplitterTime[i];
1765 DateAndTime stop = m_vecSplitterTime[i + 1];
1766 Kernel::SplittingInterval newsplit(start, stop, groupindex);
1767 m_splitWS->addSplitter(newsplit);
1768 }
1769 }
1770}
1771
1772//----------------------------------------------------------------------------------------------
1785 // Try to get the run end from Run object
1786 DateAndTime runendtime(0);
1787 bool norunendset = false;
1788 try {
1789 runendtime = m_dataWS->run().endTime();
1790 } catch (const std::runtime_error &) {
1791 norunendset = true;
1792 }
1793
1794 g_log.debug() << "Check point 1 "
1795 << "Run end time = " << runendtime << "/" << runendtime.totalNanoseconds()
1796 << ", no run end set = " << norunendset << "\n";
1797
1798 auto extended_ns = static_cast<int64_t>(1.0E8);
1799 if (m_dataWS->run().hasProperty("proton_charge")) {
1800 // Get last proton charge time and compare with run end time
1801 // this does nothing but make sure that run().endTime() is same as proton
1802 // charge end time
1803 Kernel::TimeSeriesProperty<double> *protonchargelog =
1804 dynamic_cast<Kernel::TimeSeriesProperty<double> *>(m_dataWS->run().getProperty("proton_charge"));
1805 if (!protonchargelog) {
1806 throw std::runtime_error("proton_charge log not found");
1807 }
1808
1809 if (protonchargelog->size() > 1) {
1810 Types::Core::DateAndTime tmpendtime = protonchargelog->lastTime();
1811 extended_ns = protonchargelog->nthTime(1).totalNanoseconds() - protonchargelog->nthTime(0).totalNanoseconds();
1812 if (tmpendtime > runendtime) {
1813 // Use the last proton charge time
1814 runendtime = tmpendtime;
1815 g_log.debug() << "Check point 1B: "
1816 << "Use last proton charge time = " << tmpendtime.totalNanoseconds() << " as run end. "
1817 << "\n";
1818 }
1819 norunendset = false;
1820 }
1821
1822 g_log.debug() << "Check point 2A "
1823 << " run end time = " << runendtime << "\n";
1824 } else if (norunendset) {
1825 // No proton_charge or run_end: sort events and find the last event
1826 norunendset = false;
1827
1828 runendtime = 0;
1829
1830 DataObjects::EventWorkspace_const_sptr eventWS = std::dynamic_pointer_cast<const EventWorkspace>(m_dataWS);
1831 if (!eventWS) {
1832 stringstream errss;
1833 errss << "Input workspace " << m_dataWS->getName()
1834 << " is not an Eventworkspace and does not have sample log "
1835 "'proton_charge'."
1836 "Therefore it fails to find run end time.";
1837 g_log.error(errss.str());
1838
1839 throw std::runtime_error(errss.str());
1840 } else if (eventWS->getNumberEvents() == 0) {
1841 stringstream errss;
1842 errss << "Input EventWorkspace " << m_dataWS->getName()
1843 << " has zero event and does not have sample log 'proton_charge'. "
1844 "Therefore, unable to "
1845 "determine run end time";
1846
1847 g_log.error(errss.str());
1848 throw std::runtime_error(errss.str());
1849 }
1850
1851 for (size_t i = 0; i < eventWS->getNumberHistograms(); ++i) {
1852 const DataObjects::EventList &evlist = eventWS->getSpectrum(i);
1853 if (evlist.getNumberEvents() > 0) {
1854 // If event list is empty, the returned value may not make any sense
1855 DateAndTime lastpulse = evlist.getPulseTimeMax();
1856 if (lastpulse > runendtime)
1857 runendtime = lastpulse;
1858 }
1859 }
1860 g_log.debug() << "Check point 2B "
1861 << " from last event: run end time = " << runendtime << " / " << runendtime.totalNanoseconds()
1862 << "\n";
1863 }
1864
1865 // Check whether run end time is set
1866 if (norunendset)
1867 throw runtime_error("Run end time cannot be determined. ");
1868
1869 // Add 1 second to make sure that no event left behind either last pulse time
1870 // or last event time
1871 runendtime = DateAndTime(runendtime.totalNanoseconds() + extended_ns);
1872
1873 return runendtime;
1874}
1875
1876} // namespace Mantid::Algorithms
#define DECLARE_ALGORITHM(classname)
Definition: Algorithm.h:576
double value
The value of the point.
Definition: FitMW.cpp:51
std::map< DeltaEMode::Type, std::string > index
Definition: DeltaEMode.cpp:19
#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...
Definition: MultiThreaded.h:94
#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.
Definition: Algorithm.h:85
void declareProperty(std::unique_ptr< Kernel::Property > p, const std::string &doc="") override
Add a property to the list of managed properties.
Definition: Algorithm.cpp:1913
std::string getPropertyValue(const std::string &name) const override
Get the value of a property as a string.
Definition: Algorithm.cpp:2026
TypedValue getProperty(const std::string &name) const override
Get the value of a property.
Definition: Algorithm.cpp:2076
Kernel::Logger & g_log
Definition: Algorithm.h:451
void progress(double p, const std::string &msg="", double estimatedTime=0.0, int progressPrecision=0)
Sends ProgressNotification.
Definition: Algorithm.cpp:231
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.
Definition: TableRow.h:39
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.
std::vector< Types::Core::DateAndTime > m_vecSplitterTime
Vector as date and time.
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.
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 TimeSplitterType that will filter the events by matching SINGLE log values >= min and < max.
void processInputTime()
Process the input for time.
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.
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)
void generateSplittersInSplitterWS()
Generate a SplittersWorkspace for filtering by log values.
A class for holding :
Definition: EventList.h:56
std::size_t getNumberEvents() const override
Return the number of events in the list.
Definition: EventList.cpp:1143
Mantid::Types::Core::DateAndTime getPulseTimeMax() const override
Definition: EventList.cpp:3029
SplittersWorkspace : A TableWorkspace to contain TimeSplitters.
Support for a property that holds an array of values.
Definition: ArrayProperty.h:28
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.
Definition: Logger.cpp:114
void notice(const std::string &msg)
Logs at notice level.
Definition: Logger.cpp:95
void error(const std::string &msg)
Logs at error level.
Definition: Logger.cpp:77
void warning(const std::string &msg)
Logs at warning level.
Definition: Logger.cpp:86
bool is(int level) const
Returns true if at least the given log level is set.
Definition: Logger.cpp:146
void information(const std::string &msg)
Logs at information level.
Definition: Logger.cpp:105
const std::string & name() const
Get the property's name.
Definition: Property.cpp:60
Class holding a start/end time and a destination for splitting event lists and logs.
Definition: TimeSplitter.h:23
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.
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>
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.
Definition: EmptyValues.h:25
constexpr double EMPTY_DBL() noexcept
Returns what we consider an "empty" double within a property.
Definition: EmptyValues.h:43
STL namespace.
@ Input
An input workspace.
Definition: Property.h:53
@ Output
An output workspace.
Definition: Property.h:54