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");
36 : m_roi_map(other.m_roi_map), m_name_index_map(other.m_name_index_map), m_index_name_map(other.m_index_name_map) {}
57 if (ws->getNumberHistograms() != 1) {
58 throw std::runtime_error(
"MatrixWorkspace can only have 1 histogram when constructing TimeSplitter.");
61 const auto X = ws->binEdges(0);
62 const auto &
Y = ws->y(0);
63 if (std::any_of(
X.begin(),
X.end(), [](
double i) { return static_cast<int>(i) < 0; })) {
64 throw std::runtime_error(
"All X values in MatrixWorkspace must be >= 0 to construct TimeSplitter.");
66 if (
X.size() !=
Y.size() + 1) {
67 throw std::runtime_error(
68 "Size of x values must be one more than size of y values to construct TimeSplitter from MatrixWorkspace.");
71 int64_t offset_ns{offset.totalNanoseconds()};
72 for (
size_t i = 1; i <
X.size(); i++) {
73 auto timeStart = Types::Core::DateAndTime(
X[i - 1], 0.0) + offset_ns;
74 auto timeEnd = Types::Core::DateAndTime(
X[i], 0.0) + offset_ns;
75 auto target_index =
static_cast<int>(
Y[i - 1]);
77 g_log.
warning() <<
"Values between " << timeStart.second() <<
"(s) and " << timeEnd.second()
78 <<
"(s) may be overwritten in conversion to TimeSplitter" <<
'\n';
80 this->
addROI(timeStart, timeEnd, target_index);
88 if (tws->columnCount() != 3) {
89 throw std::runtime_error(
"Table workspace used for event filtering must have 3 columns.");
93 const std::size_t COL_START{0};
94 const std::size_t COL_STOP{1};
95 const std::size_t COL_TARGET{2};
99 int max_target_index{0};
101 g_log.
information() <<
"Creating a time splitter from a table workspace. Total number of rows: " << tws->rowCount()
105 bool has_target_name_numeric =
false;
106 bool has_target_name_nonnumeric =
false;
108 for (
size_t row = 0; row < tws->rowCount(); row++) {
110 const double timeStart_s{tws->cell_cast<
double>(row, COL_START)};
111 const double timeStop_s{tws->cell_cast<
double>(row, COL_STOP)};
113 if (timeStart_s < 0 || timeStop_s < 0) {
114 throw std::runtime_error(
"All times in TableWorkspace must be >= 0 to construct TimeSplitter.");
118 const Types::Core::DateAndTime timeStart = offset + timeStart_s;
119 const Types::Core::DateAndTime timeStop = offset + timeStop_s;
122 std::string target_name = col_target->cell<std::string>(row);
130 target_index = std::stoi(target_name);
134 has_target_name_numeric =
true;
135 }
catch (std::invalid_argument &) {
136 has_target_name_nonnumeric =
true;
139 target_index = max_target_index;
149 target_index = targetIter->second;
154 g_log.
warning() <<
"Workspace row " << row <<
" may be overwritten in conversion to TimeSplitter" <<
'\n';
157 addROI(timeStart, timeStop, target_index);
162 if (has_target_name_numeric && has_target_name_nonnumeric)
163 throw std::runtime_error(
"Valid splitter targets cannot be a mix of numeric and non-numeric names.");
167 for (
size_t ii = 0; ii < sws->rowCount(); ii++) {
173 g_log.
warning() <<
"Workspace row " << ii <<
" may be overwritten in conversion to TimeSplitter" <<
'\n';
176 int target_index = interval.
index();
186 std::stringstream msg;
188 msg << iter.second <<
"|" << iter.first <<
"\n";
197 std::stringstream msg;
198 msg <<
"Invalid target index " << workspaceIndex <<
" when calling TimeSplitter::getWorkspaceIndexName";
199 throw std::runtime_error(msg.str());
206 if (numericalShift != 0) {
211 target_index = std::stoi(target_name);
212 }
catch (std::invalid_argument &)
214 throw std::runtime_error(
215 "FilterEvents property \"OutputWorkspaceIndexedFrom1\" is not compatible with non-numeric targets.");
220 s << target_index + numericalShift;
233 assertIncreasing(start, stop);
239 const DateAndTime &firstTime =
m_roi_map.begin()->first;
240 const DateAndTime &lastTime =
m_roi_map.rbegin()->first;
241 if ((start <= firstTime) && (stop >= lastTime)) {
244 }
else if ((stop < firstTime) || (start > lastTime)) {
250 }
else if (start == lastTime) {
255 }
else if (stop == firstTime) {
261 g_log.
debug() <<
"addROI(" << start <<
", " << stop <<
", " <<
value <<
")\n";
269 auto startIterator =
m_roi_map.lower_bound(start);
270 if ((startIterator->first != start) && (startIterator !=
m_roi_map.begin()))
274 auto stopIterator =
m_roi_map.upper_bound(stop);
278 const bool atStart = (startIterator ==
m_roi_map.begin());
281 m_roi_map.erase(startIterator, stopIterator);
291 stopIterator =
m_roi_map.lower_bound(stop);
292 if ((stopIterator !=
m_roi_map.end()) && (
value == stopIterator->second)) {
295 if (
value != stopValue) {
301 throw std::runtime_error(
"Something went wrong in TimeSplitter::addROI");
352 for (; it != std::prev(
m_roi_map.cend()); it++) {
353 DateAndTime intervalStart = it->first;
354 DateAndTime intervalStop = std::next(it)->first;
355 int target = it->second;
366 std::ostringstream err;
367 err <<
"Open-ended time interval is invalid in event filtering: " << it->first <<
" - ?,"
368 <<
" target index: " << it->second << std::endl;
369 throw std::runtime_error(err.str());
385 while (std::next(it) != itEnd) {
387 if (includeNoTarget || it->second !=
NO_TARGET)
393 std::ostringstream err;
394 err <<
"Open-ended time interval is invalid in event filtering: " << it->first <<
" - ?,"
395 <<
" target index: " << it->second << std::endl;
396 throw std::runtime_error(err.str());
424 auto location =
m_roi_map.lower_bound(time);
425 if (location->first == time) {
427 return location->second;
428 }
else if (location ==
m_roi_map.begin()) {
435 return location->second;
444 std::set<int> outputSet;
449 outputSet.insert(iter.second);
466 std::lock_guard<std::mutex> lock(
m_mutex);
472 const int effectiveIndex = std::max<int>(workspaceIndex,
NO_TARGET);
488 std::lock_guard<std::mutex> lock(
m_mutex);
520 const bool tofCorrect,
const double factor,
const double shift)
const {
522 if (events.
getEventType() == EventType::WEIGHTED_NOTIME)
523 throw std::invalid_argument(
"EventList::splitEventList() called on an EventList "
524 "that no longer has time information.");
544 case EventType::WEIGHTED:
548 throw std::runtime_error(
"Unhandled event type");
552 for (
auto &partial : partials) {
553 if (!partial.second->empty())
554 partial.second->setSortOrder(sortOrder);
574template <
typename EventType>
577 const bool pulseTof,
const bool tofCorrect,
const double factor,
578 const double shift)
const {
580 std::function<
const DateAndTime(
const EventType &)> timeCalc;
583 timeCalc = [factor, shift](
const EventType &event) {
return event.pulseTOFTimeAtSample(factor, shift); };
585 timeCalc = [](
const EventType &event) {
return event.pulseTOFTime(); };
588 timeCalc = [](
const EventType &event) {
return event.pulseTime(); };
595template <
typename EventType>
597 const std::vector<EventType> &events, std::map<int, EventList *> &partials)
const {
602 auto itSplitter = splittersVec.cbegin();
603 const auto itSplitterEnd = splittersVec.cend();
606 auto itEvent = events.cbegin();
607 const auto itEventEnd = events.cend();
612 const auto stop = itSplitter->start();
613 const bool shouldAppend = (partial != partials.end());
614 while (itEvent != itEventEnd && timeCalc(*itEvent) < stop) {
616 partial->second->addEventQuickly(*itEvent);
624 while (itEvent != itEventEnd && itSplitter != itSplitterEnd) {
626 const auto eventTime = timeCalc(*itEvent);
628 if (eventTime > itSplitter->stop()) {
631 if (itSplitter == itSplitterEnd)
635 if (itSplitter->stop() < eventTime) {
637 std::lower_bound(itSplitter, itSplitterEnd, eventTime,
638 [](
const auto &splitter,
const auto &eventTime) {
return splitter.start() < eventTime; });
640 if ((std::prev(itSplitterEnd))->stop() > eventTime)
641 itSplitter = std::prev(itSplitter);
644 if (itSplitter == itSplitterEnd)
648 const int destination = itSplitter->index();
649 const auto stop = itSplitter->stop();
652 partial = partials.find(destination);
655 const bool shouldAppend = (partial != partials.end());
656 while (itEvent != itEventEnd && timeCalc(*itEvent) < stop) {
658 partial->second->addEventQuickly(*itEvent);
668 if (itEvent != itEventEnd) {
670 if (partial != partials.end()) {
671 for (; itEvent != itEventEnd; ++itEvent) {
672 partial->second->addEventQuickly(*itEvent);
687std::vector<std::pair<int, std::pair<size_t, size_t>>>
691 std::vector<std::pair<int, std::pair<size_t, size_t>>> indices;
692 indices.reserve(splittingIntervals.size());
694 for (
const auto &it : splittingIntervals) {
695 const auto startIdx = std::lower_bound(times.cbegin(), times.cend(), it.start());
696 if (startIdx != times.cend()) {
697 const auto stopIdx = std::lower_bound(times.cbegin(), times.cend(), it.stop());
698 if (stopIdx != times.cend()) {
699 if (startIdx != stopIdx) {
700 indices.emplace_back(it.index(), std::make_pair(std::distance(times.cbegin(), startIdx),
701 std::distance(times.cbegin(), stopIdx)));
704 indices.emplace_back(
705 it.index(), std::make_pair(std::distance(times.cbegin(), startIdx), std::numeric_limits<size_t>::max()));
725 for (; it != std::prev(
m_roi_map.cend()); it++) {
728 DateAndTime intervalStart = it->first - start_offset;
729 DateAndTime intervalStop = std::next(it)->first;
730 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)