16using Kernel::SplittingInterval;
19using Types::Core::DateAndTime;
21namespace DataObjects {
25void assertIncreasing(
const DateAndTime &start,
const DateAndTime &stop) {
27 throw std::runtime_error(
"start time found at a later time than stop time");
31Kernel::Logger
g_log(
"TimeSplitter");
60 if (ws->getNumberHistograms() != 1) {
61 throw std::runtime_error(
"MatrixWorkspace can only have 1 histogram when constructing TimeSplitter.");
64 const auto X = ws->binEdges(0);
65 const auto &
Y = ws->y(0);
66 if (std::any_of(
X.begin(),
X.end(), [](
double i) { return static_cast<int>(i) < 0; })) {
67 throw std::runtime_error(
"All X values in MatrixWorkspace must be >= 0 to construct TimeSplitter.");
69 if (
X.size() !=
Y.size() + 1) {
70 throw std::runtime_error(
71 "Size of x values must be one more than size of y values to construct TimeSplitter from MatrixWorkspace.");
74 int64_t offset_ns{offset.totalNanoseconds()};
75 for (
size_t i = 1; i <
X.size(); i++) {
76 auto timeStart = Types::Core::DateAndTime(
X[i - 1], 0.0) + offset_ns;
77 auto timeEnd = Types::Core::DateAndTime(
X[i], 0.0) + offset_ns;
78 auto target_index =
static_cast<int>(
Y[i - 1]);
80 g_log.
warning() <<
"Values between " << timeStart.second() <<
"(s) and " << timeEnd.second()
81 <<
"(s) may be overwritten in conversion to TimeSplitter" <<
'\n';
83 this->
addROI(timeStart, timeEnd, target_index);
91 if (tws->columnCount() != 3) {
92 throw std::runtime_error(
"Table workspace used for event filtering must have 3 columns.");
96 const std::size_t COL_START{0};
97 const std::size_t COL_STOP{1};
98 const std::size_t COL_TARGET{2};
102 int max_target_index{0};
104 g_log.
information() <<
"Creating a time splitter from a table workspace. Total number of rows: " << tws->rowCount()
108 bool has_target_name_numeric =
false;
109 bool has_target_name_nonnumeric =
false;
111 for (
size_t row = 0; row < tws->rowCount(); row++) {
113 const double timeStart_s{tws->cell_cast<
double>(row, COL_START)};
114 const double timeStop_s{tws->cell_cast<
double>(row, COL_STOP)};
116 if (timeStart_s < 0 || timeStop_s < 0) {
117 throw std::runtime_error(
"All times in TableWorkspace must be >= 0 to construct TimeSplitter.");
121 const Types::Core::DateAndTime timeStart = offset + timeStart_s;
122 const Types::Core::DateAndTime timeStop = offset + timeStop_s;
125 std::string target_name = col_target->cell<std::string>(row);
133 target_index = std::stoi(target_name);
137 has_target_name_numeric =
true;
138 }
catch (std::invalid_argument &) {
139 has_target_name_nonnumeric =
true;
142 target_index = max_target_index;
152 target_index = targetIter->second;
157 g_log.
warning() <<
"Workspace row " << row <<
" may be overwritten in conversion to TimeSplitter" <<
'\n';
160 addROI(timeStart, timeStop, target_index);
165 if (has_target_name_numeric && has_target_name_nonnumeric)
166 throw std::runtime_error(
"Valid splitter targets cannot be a mix of numeric and non-numeric names.");
170 for (
size_t ii = 0; ii < sws->rowCount(); ii++) {
176 g_log.
warning() <<
"Workspace row " << ii <<
" may be overwritten in conversion to TimeSplitter" <<
'\n';
179 int target_index = interval.
index();
189 std::stringstream msg;
191 msg << iter.second <<
"|" << iter.first <<
"\n";
200 std::stringstream msg;
201 msg <<
"Invalid target index " << workspaceIndex <<
" when calling TimeSplitter::getWorkspaceIndexName";
202 throw std::runtime_error(msg.str());
209 if (numericalShift != 0) {
214 target_index = std::stoi(target_name);
215 }
catch (std::invalid_argument &)
217 throw std::runtime_error(
218 "FilterEvents property \"OutputWorkspaceIndexedFrom1\" is not compatible with non-numeric targets.");
223 s << target_index + numericalShift;
236 assertIncreasing(start, stop);
242 const DateAndTime &firstTime =
m_roi_map.begin()->first;
243 const DateAndTime &lastTime =
m_roi_map.rbegin()->first;
244 if ((start <= firstTime) && (stop >= lastTime)) {
247 }
else if ((stop < firstTime) || (start > lastTime)) {
253 }
else if (start == lastTime) {
258 }
else if (stop == firstTime) {
264 g_log.
debug() <<
"addROI(" << start <<
", " << stop <<
", " <<
value <<
")\n";
272 auto startIterator =
m_roi_map.lower_bound(start);
273 if ((startIterator->first != start) && (startIterator !=
m_roi_map.begin()))
277 auto stopIterator =
m_roi_map.upper_bound(stop);
281 const bool atStart = (startIterator ==
m_roi_map.begin());
284 m_roi_map.erase(startIterator, stopIterator);
294 stopIterator =
m_roi_map.lower_bound(stop);
295 if ((stopIterator !=
m_roi_map.end()) && (
value == stopIterator->second)) {
298 if (
value != stopValue) {
304 throw std::runtime_error(
"Something went wrong in TimeSplitter::addROI");
355 for (; it != std::prev(
m_roi_map.cend()); it++) {
356 DateAndTime intervalStart = it->first;
357 DateAndTime intervalStop = std::next(it)->first;
358 int target = it->second;
369 std::ostringstream err;
370 err <<
"Open-ended time interval is invalid in event filtering: " << it->first <<
" - ?,"
371 <<
" target index: " << it->second << std::endl;
372 throw std::runtime_error(err.str());
388 while (std::next(it) != itEnd) {
390 if (includeNoTarget || it->second !=
NO_TARGET)
396 std::ostringstream err;
397 err <<
"Open-ended time interval is invalid in event filtering: " << it->first <<
" - ?,"
398 <<
" target index: " << it->second << std::endl;
399 throw std::runtime_error(err.str());
427 auto location =
m_roi_map.lower_bound(time);
428 if (location->first == time) {
430 return location->second;
431 }
else if (location ==
m_roi_map.begin()) {
438 return location->second;
447 std::set<int> outputSet;
452 outputSet.insert(iter.second);
469 std::lock_guard<std::mutex> lock(
m_mutex);
475 const int effectiveIndex = std::max<int>(workspaceIndex,
NO_TARGET);
491 std::lock_guard<std::mutex> lock(
m_mutex);
523 const bool tofCorrect,
const double factor,
const double shift)
const {
525 if (events.
getEventType() == EventType::WEIGHTED_NOTIME)
526 throw std::invalid_argument(
"EventList::splitEventList() called on an EventList "
527 "that no longer has time information.");
547 case EventType::WEIGHTED:
551 throw std::runtime_error(
"Unhandled event type");
555 for (
auto &partial : partials) {
556 if (!partial.second->empty())
557 partial.second->setSortOrder(sortOrder);
577template <
typename EventType>
580 const bool pulseTof,
const bool tofCorrect,
const double factor,
581 const double shift)
const {
583 std::function<
const DateAndTime(
const EventType &)> timeCalc;
586 timeCalc = [factor, shift](
const EventType &event) {
return event.pulseTOFTimeAtSample(factor, shift); };
588 timeCalc = [](
const EventType &event) {
return event.pulseTOFTime(); };
591 timeCalc = [](
const EventType &event) {
return event.pulseTime(); };
598template <
typename EventType>
600 const std::vector<EventType> &events, std::map<int, EventList *> &partials)
const {
605 auto itSplitter = splittersVec.cbegin();
606 const auto itSplitterEnd = splittersVec.cend();
609 auto itEvent = events.cbegin();
610 const auto itEventEnd = events.cend();
615 const auto stop = itSplitter->start();
616 const bool shouldAppend = (partial != partials.end());
617 while (itEvent != itEventEnd && timeCalc(*itEvent) < stop) {
619 partial->second->addEventQuickly(*itEvent);
627 while (itEvent != itEventEnd && itSplitter != itSplitterEnd) {
629 const auto eventTime = timeCalc(*itEvent);
631 if (eventTime > itSplitter->stop()) {
634 if (itSplitter == itSplitterEnd)
638 if (itSplitter->stop() < eventTime) {
640 std::lower_bound(itSplitter, itSplitterEnd, eventTime,
641 [](
const auto &splitter,
const auto &eventTime) {
return splitter.start() < eventTime; });
643 if ((std::prev(itSplitterEnd))->stop() > eventTime)
644 itSplitter = std::prev(itSplitter);
647 if (itSplitter == itSplitterEnd)
651 const int destination = itSplitter->index();
652 const auto stop = itSplitter->stop();
655 partial = partials.find(destination);
658 const bool shouldAppend = (partial != partials.end());
659 while (itEvent != itEventEnd && timeCalc(*itEvent) < stop) {
661 partial->second->addEventQuickly(*itEvent);
671 if (itEvent != itEventEnd) {
673 if (partial != partials.end()) {
674 for (; itEvent != itEventEnd; ++itEvent) {
675 partial->second->addEventQuickly(*itEvent);
690std::vector<std::pair<int, std::pair<size_t, size_t>>>
694 std::vector<std::pair<int, std::pair<size_t, size_t>>> indices;
695 indices.reserve(splittingIntervals.size());
697 for (
const auto &it : splittingIntervals) {
698 const auto startIdx = std::lower_bound(times.cbegin(), times.cend(), it.start());
699 if (startIdx != times.cend()) {
700 const auto stopIdx = std::lower_bound(times.cbegin(), times.cend(), it.stop());
701 if (stopIdx != times.cend()) {
702 if (startIdx != stopIdx) {
703 indices.emplace_back(it.index(), std::make_pair(std::distance(times.cbegin(), startIdx),
704 std::distance(times.cbegin(), stopIdx)));
707 indices.emplace_back(
708 it.index(), std::make_pair(std::distance(times.cbegin(), startIdx), std::numeric_limits<size_t>::max()));
728 for (; it != std::prev(
m_roi_map.cend()); it++) {
731 DateAndTime intervalStart = it->first - start_offset;
732 DateAndTime intervalStop = std::next(it)->first;
733 combined.
addROI(intervalStart, intervalStop);
double value
The value of the point.
std::vector< Types::Event::TofEvent > & getEvents()
Return the list of TofEvents contained.
Mantid::API::EventType getEventType() const override
Return the type of Event vector contained within.
void sortPulseTimeTOF() const
void sortPulseTime() const
Sort events by Frame.
std::vector< WeightedEvent > & getWeightedEvents()
Return the list of WeightedEvent contained.
void rebuildCachedSplittingIntervals(const bool includeNoTarget=true) const
const Kernel::TimeROI & getTimeROI(const int workspaceIndex) const
Returns a TimeROI for the requested workspace index.
std::map< DateAndTime, int > m_roi_map
bool empty() const
Check if the TimeSplitter is empty.
int valueAtTime(const DateAndTime &time) const
Find the destination index for an event with a given time.
void resetCachedPartialTimeROIs() const
void rebuildCachedPartialTimeROIs() const
const Kernel::TimeROI combinedTimeROI(const int64_t start_offset=0) const
Returns a combined TimeROI covering all intervals.
std::string debugPrint() const
Print the (destination index | DateAndTime boundary) pairs of this splitter.
const std::map< std::string, int > & getNameTargetMap() const
void splitEventVec(const std::vector< EventType > &events, std::map< int, EventList * > &partials, const bool pulseTof, const bool tofCorrect, const double factor, const double shift) const
Distribute a list of events by comparing a vector of times against the splitter boundaries.
std::map< int, std::string > m_index_name_map
const Kernel::SplittingIntervalVec & getSplittingIntervals(const bool includeNoTarget=true) const
Returns a vector of splitting intervals corresponding to the m_roi_map.
bool m_validCachedSplittingIntervals_WithValidTargets
const std::map< DateAndTime, int > & getSplittersMap() const
const std::map< int, std::string > & getTargetNameMap() const
std::set< int > outputWorkspaceIndices() const
Return a set of the output workspace indices.
void addROI(const DateAndTime &start, const DateAndTime &stop, const int value)
std::vector< std::pair< int, std::pair< size_t, size_t > > > calculate_target_indices(const std::vector< DateAndTime > ×) const
Given a list of times, calculate the corresponding indices in the TimeSplitter.
bool m_validCachedPartialTimeROIs
bool m_validCachedSplittingIntervals_All
static constexpr int NO_TARGET
std::map< std::string, int > m_name_index_map
void resetCachedSplittingIntervals() const
std::string getWorkspaceIndexName(const int workspaceIndex, const int numericalShift=0) const
void clearAndReplace(const DateAndTime &start, const DateAndTime &stop, const int value)
std::size_t numRawValues() const
these methods are to aid in testing and not intended for use elsewhere
Kernel::SplittingIntervalVec m_cachedSplittingIntervals
std::map< int, Kernel::TimeROI > m_cachedPartialTimeROIs
void splitEventList(const EventList &events, std::map< int, EventList * > &partials, const bool pulseTof=false, const bool tofCorrect=false, const double factor=1.0, const double shift=0.0) const
Split a list of events according to Pulse time or Pulse + TOF time.
TimeSplitter & operator=(const TimeSplitter &other)
void debug(const std::string &msg)
Logs at debug level.
void warning(const std::string &msg)
Logs at warning level.
void information(const std::string &msg)
Logs at information level.
Class holding a start/end time and a destination for splitting event lists and logs.
int index() const
Return the index (destination of this split time block)
const Types::Core::DateAndTime & start() const
Beginning of the interval.
const Types::Core::DateAndTime & stop() const
End of the interval.
TimeROI : Object that holds information about when the time measurement was active.
void addROI(const std::string &startTime, const std::string &stopTime)
static const TimeROI USE_ALL
Constant for TimeROI where any time is used.
std::shared_ptr< Column > Column_sptr
Kernel::Logger g_log("ExperimentInfo")
static logger object
EventType
What kind of event list is being stored.
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< SplittersWorkspace > SplittersWorkspace_sptr
std::shared_ptr< TableWorkspace > TableWorkspace_sptr
shared pointer to Mantid::DataObjects::TableWorkspace
EventSortType
How the event list is sorted.
std::vector< SplittingInterval > SplittingIntervalVec
A typedef for splitting events according their pulse time.
Helper class which provides the Collimation Length for SANS instruments.
std::string to_string(const wide_integer< Bits, Signed > &n)