Mantid
Loading...
Searching...
No Matches
EventList.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 +
14#include "MantidKernel/Logger.h"
15#include "MantidKernel/Unit.h"
16
17#ifdef _MSC_VER
18// qualifier applied to function type has no meaning; ignored
19#pragma warning(disable : 4180)
20#endif
21#include "tbb/parallel_sort.h"
22#ifdef _MSC_VER
23#pragma warning(default : 4180)
24#endif
25
26#include <algorithm>
27#include <cfloat>
28#include <cmath>
29#include <functional>
30#include <limits>
31#include <stdexcept>
32
33using std::ostream;
34using std::runtime_error;
35using std::size_t;
36using std::vector;
37
38namespace Mantid::DataObjects {
39using Types::Core::DateAndTime;
40using Types::Event::TofEvent;
41using namespace Mantid::API;
42
43namespace {
44
45const double SEC_TO_NANO = 1.e9;
46
54template <typename EventType>
55int64_t calculateCorrectedFullTime(const EventType &event, const double tofFactor, const double tofShift) {
56 return event.pulseTime().totalNanoseconds() +
57 static_cast<int64_t>(tofFactor * (event.tof() * 1.0E3) + (tofShift * 1.0E9));
58}
59
63template <typename EventType> class CompareTimeAtSample {
64private:
65 const double m_tofFactor;
66 const double m_tofShift;
67
68public:
69 CompareTimeAtSample(const double tofFactor, const double tofShift) : m_tofFactor(tofFactor), m_tofShift(tofShift) {}
70
80 bool operator()(const EventType &e1, const EventType &e2) const {
81 const auto tAtSample1 = calculateCorrectedFullTime(e1, m_tofFactor, m_tofShift);
82 const auto tAtSample2 = calculateCorrectedFullTime(e2, m_tofFactor, m_tofShift);
83 return (tAtSample1 < tAtSample2);
84 }
85};
86} // namespace
87//==========================================================================
90//==========================================================================
95bool compareEventPulseTime(const TofEvent &e1, const TofEvent &e2) { return (e1.pulseTime() < e2.pulseTime()); }
96
103bool compareEventPulseTimeTOF(const TofEvent &e1, const TofEvent &e2) {
104
105 if (e1.pulseTime() < e2.pulseTime()) {
106 return true;
107 } else if ((e1.pulseTime() == e2.pulseTime()) && (e1.tof() < e2.tof())) {
108 return true;
109 }
110
111 return false;
112}
113
114// comparator for pulse time with tolerance
116 explicit comparePulseTimeTOFDelta(const Types::Core::DateAndTime &start, const double seconds)
117 : startNano(start.totalNanoseconds()), deltaNano(static_cast<int64_t>(seconds * SEC_TO_NANO)) {}
118
119 bool operator()(const TofEvent &e1, const TofEvent &e2) {
120 // get the pulse times converted into bin number from start time
121 const int64_t e1Pulse = (e1.pulseTime().totalNanoseconds() - startNano) / deltaNano;
122 const int64_t e2Pulse = (e2.pulseTime().totalNanoseconds() - startNano) / deltaNano;
123
124 // compare with the calculated bin information
125 if (e1Pulse < e2Pulse) {
126 return true;
127 } else if ((e1Pulse == e2Pulse) && (e1.tof() < e2.tof())) {
128 return true;
129 }
130
131 return false;
132 }
133
134 int64_t startNano;
135 int64_t deltaNano;
136};
137
139// EventWorkspace is always histogram data and so is thus EventList
141 : m_histogram(HistogramData::Histogram::XMode::BinEdges, HistogramData::Histogram::YMode::Counts), eventType(TOF),
142 order(UNSORTED), mru(nullptr) {}
143
149 : IEventList(specNo),
150 m_histogram(HistogramData::Histogram::XMode::BinEdges, HistogramData::Histogram::YMode::Counts), eventType(TOF),
151 order(UNSORTED), mru(mru) {}
152
155EventList::EventList(const EventList &rhs) : IEventList(rhs), m_histogram(rhs.m_histogram), mru{nullptr} {
156 // Note that operator= also assigns m_histogram, but the above use of the copy
157 // constructor avoid a memory allocation and is thus faster.
158 this->operator=(rhs);
159}
160
163EventList::EventList(const std::vector<TofEvent> &events)
164 : m_histogram(HistogramData::Histogram::XMode::BinEdges, HistogramData::Histogram::YMode::Counts), eventType(TOF),
165 mru(nullptr) {
166 this->events.assign(events.begin(), events.end());
167 this->eventType = TOF;
168 this->order = UNSORTED;
169}
170
173EventList::EventList(const std::vector<WeightedEvent> &events)
174 : m_histogram(HistogramData::Histogram::XMode::BinEdges, HistogramData::Histogram::YMode::Counts), mru(nullptr) {
175 this->weightedEvents.assign(events.begin(), events.end());
176 this->eventType = WEIGHTED;
177 this->order = UNSORTED;
178}
179
182EventList::EventList(const std::vector<WeightedEventNoTime> &events)
183 : m_histogram(HistogramData::Histogram::XMode::BinEdges, HistogramData::Histogram::YMode::Counts), mru(nullptr) {
184 this->weightedEventsNoTime.assign(events.begin(), events.end());
186 this->order = UNSORTED;
187}
188
191 // Note: These two lines do not seem to have an effect on releasing memory
192 // at least on Linux. (Memory usage seems to increase event after deleting
193 // EventWorkspaces.
194 // Therefore, for performance, they are kept commented:
195 clear();
196
197 // this->events.clear();
198 // std::vector<TofEvent>().swap(events); //Trick to release the vector memory.
199}
200
202void EventList::copyDataFrom(const ISpectrum &source) { source.copyDataInto(*this); }
203
207 sink.events = events;
210 sink.eventType = eventType;
211 sink.order = order;
212}
213
216
217// --------------------------------------------------------------------------
229void EventList::createFromHistogram(const ISpectrum *inSpec, bool GenerateZeros, bool GenerateMultipleEvents,
230 int MaxEventsPerBin) {
231 // Fresh start
232 this->clear(true);
233
234 // Get the input histogram
235 const MantidVec &X = inSpec->readX();
236 const MantidVec &Y = inSpec->readY();
237 const MantidVec &E = inSpec->readE();
238 if (Y.size() + 1 != X.size())
239 throw std::runtime_error("Expected a histogram (X vector should be 1 longer than the Y vector)");
240
241 // Copy detector IDs and spectra
242 this->copyInfoFrom(*inSpec);
243 // We need weights but have no way to set the time. So use weighted, no time
245 if (GenerateZeros)
246 this->weightedEventsNoTime.reserve(Y.size());
247
248 for (size_t i = 0; i < X.size() - 1; i++) {
249 double weight = Y[i];
250 if ((weight != 0.0 || GenerateZeros) && std::isfinite(weight)) {
251 double error = E[i];
252 // Also check that the error is not a bad number
253 if (std::isfinite(error)) {
254 if (GenerateMultipleEvents) {
255 // --------- Multiple events per bin ----------
256 double errorSquared = error * error;
257 // Find how many events to fake
258 double val = weight / E[i];
259 val *= val;
260 // Convert to int with slight rounding up. This is to avoid rounding
261 // errors
262 auto numEvents = int(val + 0.2);
263 if (numEvents < 1)
264 numEvents = 1;
265 if (numEvents > MaxEventsPerBin)
266 numEvents = MaxEventsPerBin;
267 // Scale the weight and error for each
268 weight /= numEvents;
269 errorSquared /= numEvents;
270
271 // Spread the TOF. e.g. 2 events = 0.25, 0.75.
272 double tofStep = (X[i + 1] - X[i]) / (numEvents);
273 for (size_t j = 0; j < size_t(numEvents); j++) {
274 double tof = X[i] + tofStep * (0.5 + double(j));
275 // Create and add the event
276 // TODO: try emplace_back() here.
277 weightedEventsNoTime.emplace_back(tof, weight, errorSquared);
278 }
279 } else {
280 // --------- Single event per bin ----------
281 // TOF = midpoint of the bin
282 double tof = (X[i] + X[i + 1]) / 2.0;
283 // Error squared is carried in the event
284 double errorSquared = E[i];
285 errorSquared *= errorSquared;
286 // Create and add the event
287 weightedEventsNoTime.emplace_back(tof, weight, errorSquared);
288 }
289 } // error is nont NAN or infinite
290 } // weight is non-zero, not NAN, and non-infinite
291 } // (each bin)
292
293 // Set the X binning parameters
294 this->setX(inSpec->ptrX());
295
296 // Manually set that this is sorted by TOF, since it is. This will make it
297 // "threadSafe" in other algos.
298 this->setSortOrder(TOF_SORT);
299}
300
301// --------------------------------------------------------------------------
302// --- Operators
303// -------------------------------------------------------------------
304
310 // Note that we are NOT copying the MRU pointer
311 // the EventWorkspace that posseses the EventList has already configured the mru
312 IEventList::operator=(rhs);
313 m_histogram = rhs.m_histogram;
314 events = rhs.events;
315 weightedEvents = rhs.weightedEvents;
316 weightedEventsNoTime = rhs.weightedEventsNoTime;
317 eventType = rhs.eventType;
318 order = rhs.order;
319 return *this;
320}
321
322// --------------------------------------------------------------------------
327EventList &EventList::operator+=(const TofEvent &event) {
328
329 switch (this->eventType) {
330 case TOF:
331 // Simply push the events
332 this->events.emplace_back(event);
333 break;
334
335 case WEIGHTED:
336 this->weightedEvents.emplace_back(event);
337 break;
338
339 case WEIGHTED_NOTIME:
340 this->weightedEventsNoTime.emplace_back(event);
341 break;
342 }
343
344 this->order = UNSORTED;
345 return *this;
346}
347
348// --------------------------------------------------------------------------
355EventList &EventList::operator+=(const std::vector<TofEvent> &more_events) {
356 switch (this->eventType) {
357 case TOF:
358 // Simply push the events
359 this->events.insert(this->events.end(), more_events.begin(), more_events.end());
360 break;
361
362 case WEIGHTED:
363 // Add default weights to all the un-weighted incoming events from the list.
364 // and append to the list
365 this->weightedEvents.reserve(this->weightedEvents.size() + more_events.size());
366 for (const auto &event : more_events) {
367 this->weightedEvents.emplace_back(event);
368 }
369 break;
370
371 case WEIGHTED_NOTIME:
372 // Add default weights to all the un-weighted incoming events from the list.
373 // and append to the list
374 this->weightedEventsNoTime.reserve(this->weightedEventsNoTime.size() + more_events.size());
375 for (const auto &more_event : more_events)
376 this->weightedEventsNoTime.emplace_back(more_event);
377 break;
378 }
379
380 this->order = UNSORTED;
381 return *this;
382}
383
384// --------------------------------------------------------------------------
393 this->switchTo(WEIGHTED);
394 this->weightedEvents.emplace_back(event);
395 this->order = UNSORTED;
396 return *this;
397}
398
399// --------------------------------------------------------------------------
407EventList &EventList::operator+=(const std::vector<WeightedEvent> &more_events) {
408 switch (this->eventType) {
409 case TOF:
410 // Need to switch to weighted
411 this->switchTo(WEIGHTED);
412 // Fall through to the insertion!
413
414 case WEIGHTED:
415 // Append the two lists
416 this->weightedEvents.insert(weightedEvents.end(), more_events.begin(), more_events.end());
417 break;
418
419 case WEIGHTED_NOTIME:
420 // Add default weights to all the un-weighted incoming events from the list.
421 // and append to the list
422 this->weightedEventsNoTime.reserve(this->weightedEventsNoTime.size() + more_events.size());
423 for (const auto &event : more_events) {
424 this->weightedEventsNoTime.emplace_back(event);
425 }
426 break;
427 }
428
429 this->order = UNSORTED;
430 return *this;
431}
432
433// --------------------------------------------------------------------------
441EventList &EventList::operator+=(const std::vector<WeightedEventNoTime> &more_events) {
442 switch (this->eventType) {
443 case TOF:
444 case WEIGHTED:
445 // Need to switch to weighted with no time
447 // Fall through to the insertion!
448
449 case WEIGHTED_NOTIME:
450 // Simple appending of the two lists
451 this->weightedEventsNoTime.insert(weightedEventsNoTime.end(), more_events.begin(), more_events.end());
452 break;
453 }
454
455 this->order = UNSORTED;
456 return *this;
457}
458
459// --------------------------------------------------------------------------
469 // We'll let the += operator for the given vector of event lists handle it
470 switch (more_events.getEventType()) {
471 case TOF:
472 this->operator+=(more_events.events);
473 break;
474
475 case WEIGHTED:
476 this->operator+=(more_events.weightedEvents);
477 break;
478
479 case WEIGHTED_NOTIME:
480 this->operator+=(more_events.weightedEventsNoTime);
481 break;
482 }
483
484 // No guaranteed order
485 this->order = UNSORTED;
486 // Do a union between the detector IDs of both lists
487 addDetectorIDs(more_events.getDetectorIDs());
488
489 return *this;
490}
491
492// --------------------------------------------------------------------------
502template <class T1, class T2> void EventList::minusHelper(std::vector<T1> &events, const std::vector<T2> &more_events) {
503 // Make the end vector big enough in one go (avoids repeated re-allocations).
504 events.reserve(events.size() + more_events.size());
505 /* In the event of subtracting in place, calling the end() vector would make
506 * it point at the wrong place
507 * Using it caused a segault, Ticket #2306.
508 * So we cache the end (this speeds up too).
509 */
510 // We call the constructor for T1. In the case of WeightedEventNoTime, the
511 // pulse time will just be ignored.
512 std::transform(more_events.cbegin(), more_events.cend(), std::back_inserter(events),
513 [](const auto &ev) { return T1(ev.tof(), ev.pulseTime(), ev.weight() * (-1.0), ev.errorSquared()); });
514}
515
516// --------------------------------------------------------------------------
525 if (this == &more_events) {
526 // Special case, ticket #3844 part 2.
527 // When doing this = this - this,
528 // simply clear the input event list. Saves memory!
529 this->clearData();
530 return *this;
531 }
532
533 // We'll let the -= operator for the given vector of event lists handle it
534 switch (this->getEventType()) {
535 case TOF:
536 this->switchTo(WEIGHTED);
537 // Fall through
538
539 case WEIGHTED:
540 switch (more_events.getEventType()) {
541 case TOF:
542 minusHelper(this->weightedEvents, more_events.events);
543 break;
544 case WEIGHTED:
545 minusHelper(this->weightedEvents, more_events.weightedEvents);
546 break;
547 case WEIGHTED_NOTIME:
548 // TODO: Should this throw?
550 break;
551 }
552 break;
553
554 case WEIGHTED_NOTIME:
555 switch (more_events.getEventType()) {
556 case TOF:
557 minusHelper(this->weightedEventsNoTime, more_events.events);
558 break;
559 case WEIGHTED:
561 break;
562 case WEIGHTED_NOTIME:
564 break;
565 }
566 break;
567 }
568
569 // No guaranteed order
570 this->order = UNSORTED;
571
572 // NOTE: What to do about detector ID's?
573 return *this;
574}
575
576// --------------------------------------------------------------------------
582 if (this->getNumberEvents() != rhs.getNumberEvents())
583 return false;
584 if (this->eventType != rhs.eventType)
585 return false;
586 // Check all event lists; The empty ones will compare equal
587 if (events != rhs.events)
588 return false;
589 if (weightedEvents != rhs.weightedEvents)
590 return false;
591 if (weightedEventsNoTime != rhs.weightedEventsNoTime)
592 return false;
593 return true;
594}
595
600bool EventList::operator!=(const EventList &rhs) const { return (!this->operator==(rhs)); }
601
602bool EventList::equals(const EventList &rhs, const double tolTof, const double tolWeight,
603 const int64_t tolPulse) const {
604 // generic checks
605 if (this->getNumberEvents() != rhs.getNumberEvents())
606 return false;
607 if (this->eventType != rhs.eventType)
608 return false;
609
610 // loop over the events
611 size_t numEvents = this->getNumberEvents();
612 switch (this->eventType) {
613 case TOF:
614 for (size_t i = 0; i < numEvents; ++i) {
615 if (!this->events[i].equals(rhs.events[i], tolTof, tolPulse))
616 return false;
617 }
618 break;
619 case WEIGHTED:
620 for (size_t i = 0; i < numEvents; ++i) {
621 if (!this->weightedEvents[i].equals(rhs.weightedEvents[i], tolTof, tolWeight, tolPulse))
622 return false;
623 }
624 break;
625 case WEIGHTED_NOTIME:
626 for (size_t i = 0; i < numEvents; ++i) {
627 if (!this->weightedEventsNoTime[i].equals(rhs.weightedEventsNoTime[i], tolTof, tolWeight))
628 return false;
629 }
630 break;
631 default:
632 break;
633 }
634
635 // anything that gets this far is equal within tolerances
636 return true;
637}
638
639// -----------------------------------------------------------------------------------------------
644
645// -----------------------------------------------------------------------------------------------
650 switch (newType) {
651 case TOF:
652 if (eventType != TOF)
653 throw std::runtime_error("EventList::switchTo() called on an EventList "
654 "with weights to go down to TofEvent's. This "
655 "would remove weight information and therefore "
656 "is not possible.");
657 break;
658
659 case WEIGHTED:
661 break;
662
663 case WEIGHTED_NOTIME:
665 break;
666 }
667 // Make sure to free memory
668 this->clearUnused();
669}
670
671// -----------------------------------------------------------------------------------------------
676 switch (eventType) {
677 case WEIGHTED:
678 // Do nothing; it already is weighted
679 return;
680
681 case WEIGHTED_NOTIME:
682 throw std::runtime_error("EventList::switchToWeightedEvents() called on an "
683 "EventList with WeightedEventNoTime's. It has "
684 "lost the pulse time information and can't go "
685 "back to WeightedEvent's.");
686 break;
687
688 case TOF:
689 weightedEventsNoTime.clear();
690 // Convert and copy all TofEvents to the weightedEvents list.
691 this->weightedEvents.assign(events.cbegin(), events.cend());
692 // Get rid of the old events
693 events.clear();
695 break;
696 }
697}
698
699// -----------------------------------------------------------------------------------------------
704 switch (eventType) {
705 case WEIGHTED_NOTIME:
706 // Do nothing if already there
707 return;
708
709 case TOF: {
710 // Convert and copy all TofEvents to the weightedEvents list.
711 this->weightedEventsNoTime.assign(events.cbegin(), events.cend());
712 // Get rid of the old events
713 events.clear();
714 weightedEvents.clear();
716 } break;
717
718 case WEIGHTED: {
719 // Convert and copy all TofEvents to the weightedEvents list.
720 this->weightedEventsNoTime.assign(weightedEvents.cbegin(), weightedEvents.cend());
721 // Get rid of the old events
722 events.clear();
723 weightedEvents.clear();
725 } break;
726 }
727}
728
729// ==============================================================================================
730// --- Testing functions (mostly)
731// ---------------------------------------------------------------
732// ==============================================================================================
733
740WeightedEvent EventList::getEvent(size_t event_number) {
741 switch (eventType) {
742 case TOF:
743 return WeightedEvent(events[event_number]);
744 case WEIGHTED:
745 return weightedEvents[event_number];
746 case WEIGHTED_NOTIME:
747 return WeightedEvent(weightedEventsNoTime[event_number].tof(), 0, weightedEventsNoTime[event_number].weight(),
748 weightedEventsNoTime[event_number].errorSquared());
749 }
750 throw std::runtime_error("EventList: invalid event type value was found.");
751}
752
753// ==============================================================================================
754// --- Handling the event list
755// -------------------------------------------------------------------
756// ==============================================================================================
757
765const std::vector<TofEvent> &EventList::getEvents() const {
766 if (eventType != TOF)
767 throw std::runtime_error("EventList::getEvents() called for an EventList "
768 "that has weights. Use getWeightedEvents() or "
769 "getWeightedEventsNoTime().");
770 return this->events;
771}
772
780std::vector<TofEvent> &EventList::getEvents() {
781 if (eventType != TOF)
782 throw std::runtime_error("EventList::getEvents() called for an EventList "
783 "that has weights. Use getWeightedEvents() or "
784 "getWeightedEventsNoTime().");
785 return this->events;
786}
787
795std::vector<WeightedEvent> &EventList::getWeightedEvents() {
796 if (eventType != WEIGHTED)
797 throw std::runtime_error("EventList::getWeightedEvents() called for an "
798 "EventList not of type WeightedEvent. Use "
799 "getEvents() or getWeightedEventsNoTime().");
800 return this->weightedEvents;
801}
802
810const std::vector<WeightedEvent> &EventList::getWeightedEvents() const {
811 if (eventType != WEIGHTED)
812 throw std::runtime_error("EventList::getWeightedEvents() called for an "
813 "EventList not of type WeightedEvent. Use "
814 "getEvents() or getWeightedEventsNoTime().");
815 return this->weightedEvents;
816}
817
823std::vector<WeightedEventNoTime> &EventList::getWeightedEventsNoTime() {
825 throw std::runtime_error("EventList::getWeightedEvents() called for an "
826 "EventList not of type WeightedEventNoTime. Use "
827 "getEvents() or getWeightedEvents().");
828 return this->weightedEventsNoTime;
829}
830
836const std::vector<WeightedEventNoTime> &EventList::getWeightedEventsNoTime() const {
838 throw std::runtime_error("EventList::getWeightedEventsNoTime() called for "
839 "an EventList not of type WeightedEventNoTime. "
840 "Use getEvents() or getWeightedEvents().");
841 return this->weightedEventsNoTime;
842}
843
847void EventList::clear(const bool removeDetIDs) {
848 if (mru)
849 mru->deleteIndex(this);
850 this->events.clear();
851 std::vector<TofEvent>().swap(this->events); // STL Trick to release memory
852 this->weightedEvents.clear();
853 std::vector<WeightedEvent>().swap(this->weightedEvents); // STL Trick to release memory
854 this->weightedEventsNoTime.clear();
855 std::vector<WeightedEventNoTime>().swap(this->weightedEventsNoTime); // STL Trick to release memory
856 if (removeDetIDs)
857 this->clearDetectorIDs();
858}
859
865 if (eventType != TOF) {
866 this->events.clear();
867 std::vector<TofEvent>().swap(this->events); // STL Trick to release memory
868 }
869 if (eventType != WEIGHTED) {
870 this->weightedEvents.clear();
871 std::vector<WeightedEvent>().swap(this->weightedEvents); // STL Trick to release memory
872 }
873 if (eventType != WEIGHTED_NOTIME) {
874 this->weightedEventsNoTime.clear();
875 std::vector<WeightedEventNoTime>().swap(this->weightedEventsNoTime); // STL Trick to release memory
876 }
877}
878
880void EventList::clearData() { this->clear(false); }
881
886void EventList::setMRU(EventWorkspaceMRU *newMRU) { mru = newMRU; }
887
895void EventList::reserve(size_t num) {
896 switch (this->eventType) {
897 case TOF:
898 this->events.reserve(num);
899 break;
900 case WEIGHTED:
901 this->weightedEvents.reserve(num);
902 break;
903 case WEIGHTED_NOTIME:
904 this->weightedEventsNoTime.reserve(num);
905 break;
906 }
907}
908
909// ==============================================================================================
910// --- Sorting functions -----------------------------------------------------
911// ==============================================================================================
912
913// --------------------------------------------------------------------------
917void EventList::sort(const EventSortType order) const {
918 if (order == UNSORTED) {
919 return; // don't bother doing anything. Why did you ask to unsort?
920 } else if (order == TOF_SORT) {
921 this->sortTof();
922 } else if (order == PULSETIME_SORT) {
923 this->sortPulseTime();
924 } else if (order == PULSETIMETOF_SORT) {
925 this->sortPulseTimeTOF();
926 } else if (order == PULSETIMETOF_DELTA_SORT) {
927 throw std::invalid_argument("sorting by pulse time with delta requires "
928 "extra parameters. Use sortPulseTimeTOFDelta "
929 "instead.");
930 } else if (order == TIMEATSAMPLE_SORT) {
931 throw std::invalid_argument("sorting by time at sample requires extra "
932 "parameters. Use sortTimeAtSample instead.");
933 } else {
934 throw runtime_error("Invalid sort type in EventList::sort(EventSortType)");
935 }
936}
937
938// --------------------------------------------------------------------------
943void EventList::setSortOrder(const EventSortType order) const { this->order = order; }
944
945// --------------------------------------------------------------------------
947void EventList::sortTof() const {
948 // nothing to do
949 if (this->order == TOF_SORT)
950 return;
951
952 // Avoid sorting from multiple threads
953 std::lock_guard<std::mutex> _lock(m_sortMutex);
954 // If the list was sorted while waiting for the lock, return.
955 if (this->order == TOF_SORT)
956 return;
957
958 switch (eventType) {
959 case TOF:
960 tbb::parallel_sort(events.begin(), events.end());
961 break;
962 case WEIGHTED:
963 tbb::parallel_sort(weightedEvents.begin(), weightedEvents.end());
964 break;
965 case WEIGHTED_NOTIME:
966 tbb::parallel_sort(weightedEventsNoTime.begin(), weightedEventsNoTime.end());
967 break;
968 }
969 // Save the order to avoid unnecessary re-sorting.
970 this->order = TOF_SORT;
971}
972
973// --------------------------------------------------------------------------
982void EventList::sortTimeAtSample(const double &tofFactor, const double &tofShift, bool forceResort) const {
983 // Check pre-cached sort flag.
984 if (this->order == TIMEATSAMPLE_SORT && !forceResort)
985 return;
986
987 // Avoid sorting from multiple threads
988 std::lock_guard<std::mutex> _lock(m_sortMutex);
989 // If the list was sorted while waiting for the lock, return.
990 if (this->order == TIMEATSAMPLE_SORT && !forceResort)
991 return;
992
993 // Perform sort.
994 switch (eventType) {
995 case TOF: {
996 CompareTimeAtSample<TofEvent> comparitor(tofFactor, tofShift);
997 tbb::parallel_sort(events.begin(), events.end(), comparitor);
998 } break;
999 case WEIGHTED: {
1000 CompareTimeAtSample<WeightedEvent> comparitor(tofFactor, tofShift);
1001 tbb::parallel_sort(weightedEvents.begin(), weightedEvents.end(), comparitor);
1002 } break;
1003 case WEIGHTED_NOTIME: {
1004 CompareTimeAtSample<WeightedEventNoTime> comparitor(tofFactor, tofShift);
1005 tbb::parallel_sort(weightedEventsNoTime.begin(), weightedEventsNoTime.end(), comparitor);
1006 } break;
1007 }
1008 // Save the order to avoid unnecessary re-sorting.
1009 this->order = TIMEATSAMPLE_SORT;
1010}
1011
1012// --------------------------------------------------------------------------
1015 if (this->order == PULSETIME_SORT)
1016 return; // nothing to do
1017
1018 // Avoid sorting from multiple threads
1019 std::lock_guard<std::mutex> _lock(m_sortMutex);
1020 // If the list was sorted while waiting for the lock, return.
1021 if (this->order == PULSETIME_SORT)
1022 return;
1023
1024 // Perform sort.
1025 switch (eventType) {
1026 case TOF:
1027 tbb::parallel_sort(events.begin(), events.end(), compareEventPulseTime);
1028 break;
1029 case WEIGHTED:
1030 tbb::parallel_sort(weightedEvents.begin(), weightedEvents.end(), compareEventPulseTime);
1031 break;
1032 case WEIGHTED_NOTIME:
1033 // Do nothing; there is no time to sort
1034 break;
1035 }
1036 // Save the order to avoid unnecessary re-sorting.
1037 this->order = PULSETIME_SORT;
1038}
1039
1040/*
1041 * Sort events by pulse time + TOF
1042 * (the absolute time)
1043 */
1045 if (this->order == PULSETIMETOF_SORT)
1046 return; // already ordered
1047
1048 // Avoid sorting from multiple threads
1049 std::lock_guard<std::mutex> _lock(m_sortMutex);
1050 // If the list was sorted while waiting for the lock, return.
1051 if (this->order == PULSETIMETOF_SORT)
1052 return;
1053
1054 switch (eventType) {
1055 case TOF:
1056 tbb::parallel_sort(events.begin(), events.end(), compareEventPulseTimeTOF);
1057 break;
1058 case WEIGHTED:
1059 tbb::parallel_sort(weightedEvents.begin(), weightedEvents.end(), compareEventPulseTimeTOF);
1060 break;
1061 case WEIGHTED_NOTIME:
1062 // Do nothing; there is no time to sort
1063 break;
1064 }
1065
1066 // Save
1067 this->order = PULSETIMETOF_SORT;
1068}
1069
1077void EventList::sortPulseTimeTOFDelta(const Types::Core::DateAndTime &start, const double seconds) const {
1078 // Avoid sorting from multiple threads
1079 std::lock_guard<std::mutex> _lock(m_sortMutex);
1080
1081 std::function<bool(const TofEvent &, const TofEvent &)> comparator = comparePulseTimeTOFDelta(start, seconds);
1082
1083 switch (eventType) {
1084 case TOF:
1085 tbb::parallel_sort(events.begin(), events.end(), comparator);
1086 break;
1087 case WEIGHTED:
1088 tbb::parallel_sort(weightedEvents.begin(), weightedEvents.end(), comparator);
1089 break;
1090 case WEIGHTED_NOTIME:
1091 // Do nothing; there is no time to sort
1092 break;
1093 }
1094
1095 this->order = UNSORTED; // so the function always re-runs
1096}
1097
1098// --------------------------------------------------------------------------
1100bool EventList::isSortedByTof() const { return (this->order == TOF_SORT); }
1101
1102// --------------------------------------------------------------------------
1105
1106// --------------------------------------------------------------------------
1113 // reverse the histogram bin parameters
1114 MantidVec &x = dataX();
1115 std::reverse(x.begin(), x.end());
1116
1117 // flip the events if they are tof sorted
1118 if (this->isSortedByTof()) {
1119 switch (eventType) {
1120 case TOF:
1121 std::reverse(this->events.begin(), this->events.end());
1122 break;
1123 case WEIGHTED:
1124 std::reverse(this->weightedEvents.begin(), this->weightedEvents.end());
1125 break;
1126 case WEIGHTED_NOTIME:
1127 std::reverse(this->weightedEventsNoTime.begin(), this->weightedEventsNoTime.end());
1128 break;
1129 }
1130 // And we are still sorted! :)
1131 }
1132 // Otherwise, do nothing. If it was sorted by pulse time, then it still is
1133}
1134
1135// --------------------------------------------------------------------------
1144 switch (eventType) {
1145 case TOF:
1146 return this->events.size();
1147 case WEIGHTED:
1148 return this->weightedEvents.size();
1149 case WEIGHTED_NOTIME:
1150 return this->weightedEventsNoTime.size();
1151 }
1152 throw std::runtime_error("EventList: invalid event type value was found.");
1153}
1154
1158bool EventList::empty() const {
1159 switch (eventType) {
1160 case TOF:
1161 return this->events.empty();
1162 case WEIGHTED:
1163 return this->weightedEvents.empty();
1164 case WEIGHTED_NOTIME:
1165 return this->weightedEventsNoTime.empty();
1166 }
1167 throw std::runtime_error("EventList: invalid event type value was found.");
1168}
1169
1170// --------------------------------------------------------------------------
1178 switch (eventType) {
1179 case TOF:
1180 return this->events.capacity() * sizeof(TofEvent) + sizeof(EventList);
1181 case WEIGHTED:
1182 return this->weightedEvents.capacity() * sizeof(WeightedEvent) + sizeof(EventList);
1183 case WEIGHTED_NOTIME:
1184 return this->weightedEventsNoTime.capacity() * sizeof(WeightedEventNoTime) + sizeof(EventList);
1185 }
1186 throw std::runtime_error("EventList: invalid event type value was found.");
1187}
1188
1189// --------------------------------------------------------------------------
1193 size_t x_size = readX().size();
1194 if (x_size > 1)
1195 return x_size - 1;
1196 else
1197 return 0;
1198}
1199
1200// ==============================================================================================
1201// --- Setting the Histogram X axis, without recalculating the histogram
1202// -----------------------
1203// ==============================================================================================
1204
1210 m_histogram.setX(X);
1211 if (mru)
1212 mru->deleteIndex(this);
1213}
1214
1219 if (mru)
1220 mru->deleteIndex(this);
1221 return m_histogram.dataX();
1222}
1223
1226const MantidVec &EventList::dataX() const { return m_histogram.dataX(); }
1227
1229const MantidVec &EventList::readX() const { return m_histogram.readX(); }
1230
1233
1237const MantidVec &EventList::dataDx() const { return m_histogram.dataDx(); }
1239const MantidVec &EventList::readDx() const { return m_histogram.readDx(); }
1240
1241// ==============================================================================================
1242// --- Return Data Vectors --------------------------------------------------
1243// ==============================================================================================
1244
1251 auto Y = new MantidVec();
1252 MantidVec E;
1253 // Generate the Y histogram while skipping the E if possible.
1254 generateHistogram(readX(), *Y, E, true);
1255 return Y;
1256}
1257
1264 MantidVec Y;
1265 auto E = new MantidVec();
1266 generateHistogram(readX(), Y, *E);
1267 // Y is unused.
1268 return E;
1269}
1270
1271HistogramData::Histogram EventList::histogram() const {
1272 HistogramData::Histogram ret(m_histogram);
1273 ret.setSharedY(sharedY());
1274 ret.setSharedE(sharedE());
1275 return ret;
1276}
1277
1278HistogramData::Counts EventList::counts() const { return histogram().counts(); }
1279
1280HistogramData::CountVariances EventList::countVariances() const { return histogram().countVariances(); }
1281
1282HistogramData::CountStandardDeviations EventList::countStandardDeviations() const {
1283 return histogram().countStandardDeviations();
1284}
1285
1286HistogramData::Frequencies EventList::frequencies() const { return histogram().frequencies(); }
1287
1288HistogramData::FrequencyVariances EventList::frequencyVariances() const { return histogram().frequencyVariances(); }
1289
1290HistogramData::FrequencyStandardDeviations EventList::frequencyStandardDeviations() const {
1291 return histogram().frequencyStandardDeviations();
1292}
1293
1294const HistogramData::HistogramY &EventList::y() const {
1295 if (!mru)
1296 throw std::runtime_error("'EventList::y()' called with no MRU set. This is not allowed.");
1297
1298 return *sharedY();
1299}
1300const HistogramData::HistogramE &EventList::e() const {
1301 if (!mru)
1302 throw std::runtime_error("'EventList::e()' called with no MRU set. This is not allowed.");
1303
1304 return *sharedE();
1305}
1307 // This is the thread number from which this function was called.
1308 int thread = PARALLEL_THREAD_NUMBER;
1309
1311
1312 // Is the data in the mrulist?
1313 if (mru) {
1314 mru->ensureEnoughBuffersY(thread);
1315 yData = mru->findY(thread, this);
1316 }
1317
1318 if (!yData) {
1319 MantidVec Y;
1320 MantidVec E;
1321 this->generateHistogram(readX(), Y, E);
1322
1323 // Create the MRU object
1324 yData = Kernel::make_cow<HistogramData::HistogramY>(std::move(Y));
1325
1326 // Lets save it in the MRU
1327 if (mru) {
1328 mru->insertY(thread, yData, this);
1329 auto eData = Kernel::make_cow<HistogramData::HistogramE>(std::move(E));
1330 mru->ensureEnoughBuffersE(thread);
1331 mru->insertE(thread, eData, this);
1332 }
1333 }
1334 return yData;
1335}
1337 // This is the thread number from which this function was called.
1338 int thread = PARALLEL_THREAD_NUMBER;
1339
1341
1342 // Is the data in the mrulist?
1343 if (mru) {
1344 mru->ensureEnoughBuffersE(thread);
1345 eData = mru->findE(thread, this);
1346 }
1347
1348 if (!eData) {
1349 // Now use that to get E -- Y values are generated from another function
1350 MantidVec Y_ignored;
1351 MantidVec E;
1352 this->generateHistogram(readX(), Y_ignored, E);
1353 eData = Kernel::make_cow<HistogramData::HistogramE>(std::move(E));
1354
1355 // Lets save it in the MRU
1356 if (mru)
1357 mru->insertE(thread, eData, this);
1358 }
1359 return eData;
1360}
1367 if (!mru)
1368 throw std::runtime_error("'EventList::dataY()' called with no MRU set. This is not allowed.");
1369
1370 // WARNING: The Y data of sharedY() is stored in MRU, returning reference fine
1371 // as long as it stays there.
1372 return sharedY()->rawData();
1373}
1374
1381 if (!mru)
1382 throw std::runtime_error("'EventList::dataE()' called with no MRU set. This is not allowed.");
1383
1384 // WARNING: The E data of sharedE() is stored in MRU, returning reference fine
1385 // as long as it stays there.
1386 return sharedE()->rawData();
1387}
1388
1389namespace {
1390inline double calcNorm(const double errorSquared) {
1391 if (errorSquared == 0.)
1392 return 0;
1393 else if (errorSquared == 1.)
1394 return 1.;
1395 else
1396 return 1. / std::sqrt(errorSquared);
1397}
1398} // namespace
1399
1400// --------------------------------------------------------------------------
1409template <class T>
1410inline void EventList::compressEventsHelper(const std::vector<T> &events, std::vector<WeightedEventNoTime> &out,
1411 double tolerance) {
1412 // Clear the output. We can't know ahead of time how much space to reserve :(
1413 out.clear();
1414 // We will make a starting guess of 1/20th of the number of input events.
1415 out.reserve(events.size() / 20);
1416
1417 // The last TOF to which we are comparing.
1418 double lastTof = std::numeric_limits<double>::lowest();
1419 // For getting an accurate average TOF
1420 double totalTof = 0;
1421 int num = 0;
1422 // Carrying weight, error, and normalization
1423 double weight = 0;
1424 double errorSquared = 0;
1425 double normalization = 0.;
1426
1427 for (auto it = events.cbegin(); it != events.cend(); it++) {
1428 if ((it->m_tof - lastTof) <= tolerance) {
1429 // Carry the error and weight
1430 weight += it->weight();
1431 errorSquared += it->errorSquared();
1432 // Track the average tof
1433 num++;
1434 const double norm = calcNorm(it->errorSquared());
1435 normalization += norm;
1436 totalTof += it->m_tof * norm;
1437 } else {
1438 // We exceeded the tolerance
1439 // Create a new event with the average TOF and summed weights and
1440 // squared errors.
1441 if (num == 1) {
1442 // last time-of-flight is the only one contributing
1443 out.emplace_back(lastTof, weight, errorSquared);
1444 } else if (num > 1) {
1445 out.emplace_back(totalTof / normalization, weight, errorSquared);
1446 }
1447 // Start a new combined object
1448 num = 1;
1449 const double norm = calcNorm(it->errorSquared());
1450 normalization = norm;
1451 totalTof = it->m_tof * norm;
1452 weight = it->weight();
1453 errorSquared = it->errorSquared();
1454 lastTof = it->m_tof;
1455 }
1456 }
1457
1458 // Put the last event in there too with the average TOF and summed weights and
1459 // squared errors.
1460 if (num == 1) {
1461 // last time-of-flight is the only one contributing
1462 out.emplace_back(lastTof, weight, errorSquared);
1463 } else if (num > 1) {
1464 out.emplace_back(totalTof / normalization, weight, errorSquared);
1465 }
1466
1467 // If you have over-allocated by more than 5%, reduce the size.
1468 size_t excess_limit = out.size() / 20;
1469 if ((out.capacity() - out.size()) > excess_limit) {
1470 out.shrink_to_fit();
1471 }
1472}
1473
1474// --------------------------------------------------------------------------
1484template <class T>
1485void EventList::compressEventsParallelHelper(const std::vector<T> &events, std::vector<WeightedEventNoTime> &out,
1486 double tolerance) {
1487 // Create a local output vector for each thread
1488 int numThreads = PARALLEL_GET_MAX_THREADS;
1489 std::vector<std::vector<WeightedEventNoTime>> outputs(numThreads);
1490 // This is how many events to process in each thread.
1491 size_t numPerBlock = events.size() / numThreads;
1492
1493 // Do each block in parallel
1495 for (int thread = 0; thread < numThreads; thread++) {
1496 // The local output vector
1497 std::vector<WeightedEventNoTime> &localOut = outputs[thread];
1498 // Reserve a bit of space to avoid excess copying
1499 localOut.clear();
1500 localOut.reserve(numPerBlock / 20);
1501
1502 // The last TOF to which we are comparing.
1503 double lastTof = std::numeric_limits<double>::lowest();
1504 // For getting an accurate average TOF
1505 double totalTof = 0;
1506 int num = 0;
1507 // Carrying weight, error, and normalization
1508 double weight = 0;
1509 double errorSquared = 0;
1510 double normalization = 0.;
1511
1512 // Separate the
1513 typename std::vector<T>::const_iterator it = events.begin() + thread * numPerBlock;
1514 typename std::vector<T>::const_iterator it_end = events.begin() + (thread + 1) * numPerBlock; // cache for speed
1515 if (thread == numThreads - 1)
1516 it_end = events.end();
1517 for (; it != it_end; ++it) {
1518 if ((it->m_tof - lastTof) <= tolerance) {
1519 // Carry the error and weight
1520 weight += it->weight();
1521 errorSquared += it->errorSquared();
1522 // Track the average tof
1523 num++;
1524 const double norm = calcNorm(it->errorSquared());
1525 normalization += norm;
1526 totalTof += it->m_tof * norm;
1527 } else {
1528 // We exceeded the tolerance
1529 if (num > 0) {
1530 // Create a new event with the average TOF and summed weights and
1531 // squared errors.
1532 localOut.emplace_back(totalTof / normalization, weight, errorSquared);
1533 }
1534 // Start a new combined object
1535 num = 1;
1536 const double norm = calcNorm(it->errorSquared());
1537 normalization = norm;
1538 totalTof = it->m_tof * norm;
1539 weight = it->weight();
1540 errorSquared = it->errorSquared();
1541 lastTof = it->m_tof;
1542 }
1543 }
1544
1545 // Put the last event in there too.
1546 if (num > 0) {
1547 // Create a new event with the average TOF and summed weights and squared
1548 // errors.
1549 localOut.emplace_back(totalTof / normalization, weight, errorSquared);
1550 }
1551 }
1552
1553 // Clear the output. Reserve the required size
1554 out.clear();
1555 size_t numEvents = 0;
1556 for (int thread = 0; thread < numThreads; thread++)
1557 numEvents += outputs[thread].size();
1558 out.reserve(numEvents);
1559
1560 // Re-join all the outputs
1561 for (int thread = 0; thread < numThreads; thread++)
1562 out.insert(out.end(), outputs[thread].begin(), outputs[thread].end());
1563}
1564
1565template <class T>
1566inline void EventList::compressFatEventsHelper(const std::vector<T> &events, std::vector<WeightedEvent> &out,
1567 const double tolerance, const Types::Core::DateAndTime &timeStart,
1568 const double seconds) {
1569 // Clear the output. We can't know ahead of time how much space to reserve :(
1570 out.clear();
1571 // We will make a starting guess of 1/20th of the number of input events.
1572 out.reserve(events.size() / 20);
1573
1574 // The last TOF to which we are comparing.
1575 double lastTof = std::numeric_limits<double>::lowest();
1576 // For getting an accurate average TOF
1577 double totalTof = 0;
1578
1579 // pulsetime bin information - stored as int nanoseconds because it
1580 // is the implementation type for DateAndTime object
1581 const int64_t pulsetimeStart = timeStart.totalNanoseconds();
1582 const auto pulsetimeDelta = static_cast<int64_t>(seconds * SEC_TO_NANO);
1583
1584 // pulsetime information
1585 std::vector<DateAndTime> pulsetimes; // all the times for new event
1586 std::vector<double> pulsetimeWeights;
1587
1588 // Carrying weight and error
1589 double weight = 0.;
1590 double errorSquared = 0.;
1591 double tofNormalization = 0.;
1592
1593 // Move up to first event that has a large enough pulsetime. This is just in
1594 // case someone starts from after the starttime of the run. It is expected
1595 // that users will normally use the default which means this will only check
1596 // the first event.
1597 auto it = events.cbegin();
1598 for (; it != events.cend(); ++it) {
1599 if (it->m_pulsetime >= timeStart)
1600 break;
1601 }
1602
1603 // bin if the pulses are histogrammed
1604 int64_t lastPulseBin = (it->m_pulsetime.totalNanoseconds() - pulsetimeStart) / pulsetimeDelta;
1605 // loop through events and accumulate weight
1606 for (; it != events.cend(); ++it) {
1607 const int64_t eventPulseBin = (it->m_pulsetime.totalNanoseconds() - pulsetimeStart) / pulsetimeDelta;
1608 if ((eventPulseBin <= lastPulseBin) && (std::fabs(it->m_tof - lastTof) <= tolerance)) {
1609 // Carry the error and weight
1610 weight += it->weight();
1611 errorSquared += it->errorSquared();
1612 double norm = calcNorm(it->errorSquared());
1613 tofNormalization += norm;
1614 // Track the average tof
1615 totalTof += it->m_tof * norm;
1616 // Accumulate the pulse times
1617 pulsetimes.emplace_back(it->m_pulsetime);
1618 pulsetimeWeights.emplace_back(norm);
1619 } else {
1620 // We exceeded the tolerance
1621 if (!pulsetimes.empty()) {
1622 // Create a new event with the average TOF and summed weights and
1623 // squared errors. 1 event used doesn't need to average
1624 if (pulsetimes.size() == 1) {
1625 out.emplace_back(lastTof, pulsetimes.front(), weight, errorSquared);
1626 } else {
1627 out.emplace_back(totalTof / tofNormalization,
1628 Kernel::DateAndTimeHelpers::averageSorted(pulsetimes, pulsetimeWeights), weight,
1629 errorSquared);
1630 }
1631 }
1632 // Start a new combined object
1633 double norm = calcNorm(it->errorSquared());
1634 totalTof = it->m_tof * norm;
1635 weight = it->weight();
1636 errorSquared = it->errorSquared();
1637 tofNormalization = norm;
1638 lastTof = it->m_tof;
1639 lastPulseBin = eventPulseBin;
1640 pulsetimes.clear();
1641 pulsetimes.emplace_back(it->m_pulsetime);
1642 pulsetimeWeights.clear();
1643 pulsetimeWeights.emplace_back(norm);
1644 }
1645 }
1646
1647 // Put the last event in there too.
1648 if (!pulsetimes.empty()) {
1649 // Create a new event with the average TOF and summed weights and
1650 // squared errors. 1 event used doesn't need to average
1651 if (pulsetimes.size() == 1) {
1652 out.emplace_back(lastTof, pulsetimes.front(), weight, errorSquared);
1653 } else {
1654 out.emplace_back(totalTof / tofNormalization,
1655 Kernel::DateAndTimeHelpers::averageSorted(pulsetimes, pulsetimeWeights), weight, errorSquared);
1656 }
1657 }
1658
1659 // If you have over-allocated by more than 5%, reduce the size.
1660 size_t excess_limit = out.size() / 20;
1661 if ((out.capacity() - out.size()) > excess_limit) {
1662 out.shrink_to_fit();
1663 }
1664}
1665
1666// --------------------------------------------------------------------------
1677 if (!this->empty()) {
1678 this->sortTof();
1679 switch (eventType) {
1680 case TOF:
1681 // if (parallel)
1682 // compressEventsParallelHelper(this->events,
1683 // destination->weightedEventsNoTime, tolerance);
1684 // else
1685 compressEventsHelper(this->events, destination->weightedEventsNoTime, tolerance);
1686 break;
1687
1688 case WEIGHTED:
1689 // if (parallel)
1690 // compressEventsParallelHelper(this->weightedEvents,
1691 // destination->weightedEventsNoTime, tolerance);
1692 // else
1694
1695 break;
1696
1697 case WEIGHTED_NOTIME:
1698 if (destination == this) {
1699 // Put results in a temp output
1700 std::vector<WeightedEventNoTime> out;
1701 // if (parallel)
1702 // compressEventsParallelHelper(this->weightedEventsNoTime,
1703 // out,
1704 // tolerance);
1705 // else
1707 // Put it back
1708 this->weightedEventsNoTime.swap(out);
1709 } else {
1710 // if (parallel)
1711 // compressEventsParallelHelper(this->weightedEventsNoTime,
1712 // destination->weightedEventsNoTime, tolerance);
1713 // else
1715 }
1716 break;
1717 }
1718 }
1719 // In all cases, you end up WEIGHTED_NOTIME.
1720 destination->eventType = WEIGHTED_NOTIME;
1721 // The sort is still valid!
1722 destination->order = TOF_SORT;
1723 // Empty out storage for vectors that are now unused.
1724 destination->clearUnused();
1725}
1726
1727void EventList::compressFatEvents(const double tolerance, const Mantid::Types::Core::DateAndTime &timeStart,
1728 const double seconds, EventList *destination) {
1729
1730 // only worry about non-empty EventLists
1731 if (!this->empty()) {
1732 switch (eventType) {
1733 case WEIGHTED_NOTIME:
1734 throw std::invalid_argument("Cannot compress events that do not have pulsetime");
1735 case TOF:
1736 this->sortPulseTimeTOFDelta(timeStart, seconds);
1737 compressFatEventsHelper(this->events, destination->weightedEvents, tolerance, timeStart, seconds);
1738 break;
1739 case WEIGHTED:
1740 this->sortPulseTimeTOFDelta(timeStart, seconds);
1741 if (destination == this) {
1742 // Put results in a temp output
1743 std::vector<WeightedEvent> out;
1744 compressFatEventsHelper(this->weightedEvents, out, tolerance, timeStart, seconds);
1745 // Put it back
1746 this->weightedEvents.swap(out);
1747 } else {
1748 compressFatEventsHelper(this->weightedEvents, destination->weightedEvents, tolerance, timeStart, seconds);
1749 }
1750 break;
1751 }
1752 }
1753 // In all cases, you end up WEIGHTED_NOTIME.
1754 destination->eventType = WEIGHTED;
1755 // The sort order is pulsetimetof as we've compressed out the tolerance
1756 destination->order = PULSETIMETOF_SORT;
1757 // Empty out storage for vectors that are now unused.
1758 destination->clearUnused();
1759}
1760
1761// --------------------------------------------------------------------------
1771template <class T>
1772typename std::vector<T>::const_iterator static findFirstEvent(const std::vector<T> &events, T seek_tof) {
1773 return std::find_if_not(events.cbegin(), events.cend(), [seek_tof](const T &x) { return x < seek_tof; });
1774}
1775
1776// --------------------------------------------------------------------------
1786template <class T>
1787typename std::vector<T>::const_iterator EventList::findFirstPulseEvent(const std::vector<T> &events,
1788 const double seek_pulsetime) {
1789 auto itev = events.begin();
1790 auto itev_end = events.end(); // cache for speed
1791
1792 // if tof < X[0], that means that you need to skip some events
1793 while ((itev != itev_end) && (static_cast<double>(itev->pulseTime().totalNanoseconds()) < seek_pulsetime))
1794 itev++;
1795 // Better fix would be to use a binary search instead of the linear one used
1796 // here.
1797 return itev;
1798}
1799
1800// --------------------------------------------------------------------------
1813template <class T>
1814typename std::vector<T>::const_iterator
1815EventList::findFirstTimeAtSampleEvent(const std::vector<T> &events, const double seek_time, const double &tofFactor,
1816 const double &tofOffset) const {
1817 auto itev = events.cbegin();
1818 auto itev_end = events.cend(); // cache for speed
1819
1820 // if tof < X[0], that means that you need to skip some events
1821 while ((itev != itev_end) &&
1822 (static_cast<double>(calculateCorrectedFullTime(*itev, tofFactor, tofOffset)) < seek_time))
1823 itev++;
1824 // Better fix would be to use a binary search instead of the linear one used
1825 // here.
1826 return itev;
1827}
1828
1829// --------------------------------------------------------------------------
1839template <class T> typename std::vector<T>::iterator static findFirstEvent(std::vector<T> &events, T seek_tof) {
1840 return std::find_if_not(events.begin(), events.end(), [seek_tof](const T &x) { return x < seek_tof; });
1841}
1842
1843// --------------------------------------------------------------------------
1853template <class T>
1854void EventList::histogramForWeightsHelper(const std::vector<T> &events, const MantidVec &X, MantidVec &Y,
1855 MantidVec &E) {
1856 // For slight speed=up.
1857 size_t x_size = X.size();
1858
1859 if (x_size <= 1) {
1860 // X was not set. Return an empty array.
1861 Y.resize(0, 0);
1862 return;
1863 }
1864
1865 // If the sizes are the same, then the "resize" command will NOT clear the
1866 // original values.
1867 bool mustFill = (Y.size() == x_size - 1);
1868 // Clear the Y data, assign all to 0.
1869 Y.resize(x_size - 1, 0.0);
1870 // Clear the Error data, assign all to 0.
1871 // Note: Errors will be squared until the last step.
1872 E.resize(x_size - 1, 0.0);
1873
1874 if (mustFill) {
1875 // We must make sure the starting point is 0.0
1876 std::fill(Y.begin(), Y.end(), 0.0);
1877 std::fill(E.begin(), E.end(), 0.0);
1878 }
1879
1880 //---------------------- Histogram without weights
1881 //---------------------------------
1882
1883 // Do we even have any events to do?
1884 if (!events.empty()) {
1885 // Iterate through all events (sorted by tof)
1886 auto itev = findFirstEvent(events, T(X[0]));
1887 auto itev_end = events.cend();
1888 // The above can still take you to end() if no events above X[0], so check
1889 // again.
1890 if (itev == itev_end)
1891 return;
1892
1893 // Find the first bin
1894 size_t bin = 0;
1895 // The tof is greater the first bin boundary, so we need to find the first
1896 // bin
1897 double tof = itev->tof();
1898 while (bin < x_size - 1) {
1899 // Within range?
1900 if ((tof >= X[bin]) && (tof < X[bin + 1])) {
1901 // Add up the weight (convert to double before adding, to preserve
1902 // precision)
1903 Y[bin] += double(itev->m_weight);
1904 E[bin] += double(itev->m_errorSquared); // square of error
1905 break;
1906 }
1907 ++bin;
1908 }
1909 // Go to the next event, we've already binned this first one.
1910 ++itev;
1911
1912 // Keep going through all the events
1913 while ((itev != itev_end) && (bin < x_size - 1)) {
1914 tof = itev->tof();
1915 while (bin < x_size - 1) {
1916 // Within range? Since both events and X are sorted, they are going to
1917 // have
1918 // tof >= X[bin] because the previous event was.
1919 if (tof < X[bin + 1]) {
1920 // Add up the weight (convert to double before adding, to preserve
1921 // precision)
1922 Y[bin] += double(itev->m_weight);
1923 E[bin] += double(itev->m_errorSquared); // square of error
1924 break;
1925 }
1926 ++bin;
1927 }
1928 ++itev;
1929 }
1930 } // end if (there are any events to histogram)
1931
1932 // Now do the sqrt of all errors
1933 std::transform(E.begin(), E.end(), E.begin(), static_cast<double (*)(double)>(sqrt));
1934}
1935
1936// --------------------------------------------------------------------------
1946void EventList::generateHistogramPulseTime(const MantidVec &X, MantidVec &Y, MantidVec &E, bool skipError) const {
1947 // All types of weights need to be sorted by Pulse Time
1948 this->sortPulseTime();
1949
1950 switch (eventType) {
1951 case TOF:
1952 // Make the single ones
1954 if (!skipError)
1955 this->generateErrorsHistogram(Y, E);
1956 break;
1957
1958 case WEIGHTED:
1959 throw std::runtime_error("Cannot histogram by pulse time on Weighted "
1960 "Events currently"); // This could be supported.
1961
1962 case WEIGHTED_NOTIME:
1963 throw std::runtime_error("Cannot histogram by pulse time on Weighted Events NoTime");
1964 }
1965}
1966
1979 const double &tofOffset, bool skipError) const {
1980 // All types of weights need to be sorted by time at sample
1981 this->sortTimeAtSample(tofFactor, tofOffset);
1982
1983 switch (eventType) {
1984 case TOF:
1985 // Make the single ones
1986 this->generateCountsHistogramTimeAtSample(X, Y, tofFactor, tofOffset);
1987 if (!skipError)
1988 this->generateErrorsHistogram(Y, E);
1989 break;
1990
1991 case WEIGHTED:
1992 throw std::runtime_error("Cannot histogram by time at sample on Weighted "
1993 "Events currently"); // This could be supported.
1994
1995 case WEIGHTED_NOTIME:
1996 throw std::runtime_error("Cannot histogram by time at sample on Weighted Events NoTime");
1997 }
1998}
1999
2000// --------------------------------------------------------------------------
2010void EventList::generateHistogram(const MantidVec &X, MantidVec &Y, MantidVec &E, bool skipError) const {
2011 // All types of weights need to be sorted by TOF
2012
2013 this->sortTof();
2014
2015 switch (eventType) {
2016 case TOF:
2017 // Make the single ones
2018 this->generateCountsHistogram(X, Y);
2019 if (!skipError)
2020 this->generateErrorsHistogram(Y, E);
2021 break;
2022
2023 case WEIGHTED:
2025 break;
2026
2027 case WEIGHTED_NOTIME:
2029 break;
2030 }
2031}
2032
2033// --------------------------------------------------------------------------
2041 // For slight speed=up.
2042 size_t x_size = X.size();
2043
2044 if (x_size <= 1) {
2045 // X was not set. Return an empty array.
2046 Y.resize(0, 0);
2047 return;
2048 }
2049
2050 // Sort the events by pulsetime
2051 this->sortPulseTime();
2052 // Clear the Y data, assign all to 0.
2053 Y.resize(x_size - 1, 0);
2054
2055 //---------------------- Histogram without weights
2056 //---------------------------------
2057
2058 if (!this->events.empty()) {
2059 // Iterate through all events (sorted by pulse time)
2060 auto itev = findFirstPulseEvent(this->events, X[0]);
2061 auto itev_end = events.cend(); // cache for speed
2062 // The above can still take you to end() if no events above X[0], so check
2063 // again.
2064 if (itev == itev_end)
2065 return;
2066
2067 // Find the first bin
2068 size_t bin = 0;
2069
2070 // The tof is greater the first bin boundary, so we need to find the first
2071 // bin
2072 double pulsetime = static_cast<double>(itev->pulseTime().totalNanoseconds());
2073 while (bin < x_size - 1) {
2074 // Within range?
2075 if ((pulsetime >= X[bin]) && (pulsetime < X[bin + 1])) {
2076 Y[bin]++;
2077 break;
2078 }
2079 ++bin;
2080 }
2081 // Go to the next event, we've already binned this first one.
2082 ++itev;
2083
2084 // Keep going through all the events
2085 while ((itev != itev_end) && (bin < x_size - 1)) {
2086 pulsetime = static_cast<double>(itev->pulseTime().totalNanoseconds());
2087 while (bin < x_size - 1) {
2088 // Within range?
2089 if ((pulsetime >= X[bin]) && (pulsetime < X[bin + 1])) {
2090 Y[bin]++;
2091 break;
2092 }
2093 ++bin;
2094 }
2095 ++itev;
2096 }
2097 } // end if (there are any events to histogram)
2098}
2099
2114void EventList::generateCountsHistogramPulseTime(const double &xMin, const double &xMax, MantidVec &Y,
2115 const double TOF_min, const double TOF_max) const {
2116
2117 if (this->events.empty())
2118 return;
2119
2120 size_t nBins = Y.size();
2121
2122 if (nBins == 0)
2123 return;
2124
2125 double step = (xMax - xMin) / static_cast<double>(nBins);
2126
2127 for (const TofEvent &ev : this->events) {
2128 double pulsetime = static_cast<double>(ev.pulseTime().totalNanoseconds());
2129 if (pulsetime < xMin || pulsetime >= xMax)
2130 continue;
2131 if (ev.tof() < TOF_min || ev.tof() >= TOF_max)
2132 continue;
2133
2134 auto n_bin = static_cast<size_t>((pulsetime - xMin) / step);
2135 Y[n_bin]++;
2136 }
2137}
2138
2139// --------------------------------------------------------------------------
2149 const double &tofOffset) const {
2150 // For slight speed=up.
2151 const size_t x_size = X.size();
2152
2153 if (x_size <= 1) {
2154 // X was not set. Return an empty array.
2155 Y.resize(0, 0);
2156 return;
2157 }
2158
2159 // Sort the events by pulsetime
2160 this->sortTimeAtSample(tofFactor, tofOffset);
2161 // Clear the Y data, assign all to 0.
2162 Y.resize(x_size - 1, 0);
2163
2164 //---------------------- Histogram without weights
2165 //---------------------------------
2166
2167 if (!this->events.empty()) {
2168 // Iterate through all events (sorted by pulse time)
2169 auto itev = findFirstTimeAtSampleEvent(this->events, X[0], tofFactor, tofOffset);
2170 std::vector<TofEvent>::const_iterator itev_end = events.end(); // cache for speed
2171 // The above can still take you to end() if no events above X[0], so check
2172 // again.
2173 if (itev == itev_end)
2174 return;
2175
2176 // Find the first bin
2177 size_t bin = 0;
2178
2179 auto tAtSample = static_cast<double>(calculateCorrectedFullTime(*itev, tofFactor, tofOffset));
2180 while (bin < x_size - 1) {
2181 // Within range?
2182 if ((tAtSample >= X[bin]) && (tAtSample < X[bin + 1])) {
2183 Y[bin]++;
2184 break;
2185 }
2186 ++bin;
2187 }
2188 // Go to the next event, we've already binned this first one.
2189 ++itev;
2190
2191 // Keep going through all the events
2192 while ((itev != itev_end) && (bin < x_size - 1)) {
2193 tAtSample = static_cast<double>(calculateCorrectedFullTime(*itev, tofFactor, tofOffset));
2194 while (bin < x_size - 1) {
2195 // Within range?
2196 if ((tAtSample >= X[bin]) && (tAtSample < X[bin + 1])) {
2197 Y[bin]++;
2198 break;
2199 }
2200 ++bin;
2201 }
2202 ++itev;
2203 }
2204 } // end if (there are any events to histogram)
2205}
2206
2207// --------------------------------------------------------------------------
2214 // For slight speed=up.
2215 size_t x_size = X.size();
2216
2217 if (x_size <= 1) {
2218 // X was not set. Return an empty array.
2219 Y.resize(0, 0);
2220 return;
2221 }
2222
2223 // Sort the events by tof
2224 this->sortTof();
2225 // Clear the Y data, assign all to 0.
2226 Y.resize(x_size - 1, 0);
2227
2228 //---------------------- Histogram without weights
2229 //---------------------------------
2230
2231 // Do we even have any events to do?
2232 if (!this->events.empty()) {
2233 // Iterate through all events (sorted by tof) placing them in the correct
2234 // bin.
2235 auto itev = findFirstEvent(this->events, TofEvent(X[0]));
2236 // Go through all the events,
2237 for (auto itx = X.cbegin(); itev != events.end(); ++itev) {
2238 double tof = itev->tof();
2239 itx = std::find_if(itx, X.cend(), [tof](const double x) { return tof < x; });
2240 if (itx == X.cend()) {
2241 break;
2242 }
2243 auto bin = std::max(std::distance(X.cbegin(), itx) - 1, std::ptrdiff_t{0});
2244 ++Y[bin];
2245 }
2246 } // end if (there are any events to histogram)
2247}
2248
2249// --------------------------------------------------------------------------
2258 // Fill the vector for the errors, containing sqrt(count)
2259 E.resize(Y.size(), 0);
2260
2261 // windows can get confused about std::sqrt
2262 std::transform(Y.begin(), Y.end(), E.begin(), static_cast<double (*)(double)>(sqrt));
2263
2264} //----------------------------------------------------------------------------------
2274template <class T>
2275double EventList::integrateHelper(std::vector<T> &events, const double minX, const double maxX,
2276 const bool entireRange) {
2277 double sum(0), error(0);
2278 integrateHelper(events, minX, maxX, entireRange, sum, error);
2279 return sum;
2280}
2281
2292template <class T>
2293void EventList::integrateHelper(std::vector<T> &events, const double minX, const double maxX, const bool entireRange,
2294 double &sum, double &error) {
2295 sum = 0;
2296 error = 0;
2297 // Nothing in the list?
2298 if (events.empty())
2299 return;
2300
2301 // Iterators for limits - whole range by default
2302 typename std::vector<T>::iterator lowit, highit;
2303 lowit = events.begin();
2304 highit = events.end();
2305
2306 // But maybe we don't want the entire range?
2307 if (!entireRange) {
2308 // If a silly range was given, return 0.
2309 if (maxX < minX)
2310 return;
2311
2312 // If the first element is lower that the xmin then search for new lowit
2313 if (lowit->tof() < minX)
2314 lowit = std::lower_bound(events.begin(), events.end(), minX);
2315 // If the last element is higher that the xmax then search for new lowit
2316 if ((highit - 1)->tof() > maxX) {
2317 highit = std::upper_bound(lowit, events.end(), T(maxX));
2318 }
2319 }
2320
2321 // Sum up all the weights
2322 for (auto it = lowit; it != highit; ++it) {
2323 sum += it->weight();
2324 error += it->errorSquared();
2325 }
2326 error = std::sqrt(error);
2327}
2328
2329// --------------------------------------------------------------------------
2338double EventList::integrate(const double minX, const double maxX, const bool entireRange) const {
2339 double sum(0), error(0);
2340 integrate(minX, maxX, entireRange, sum, error);
2341 return sum;
2342}
2343
2354void EventList::integrate(const double minX, const double maxX, const bool entireRange, double &sum,
2355 double &error) const {
2356 sum = 0;
2357 error = 0;
2358 if (!entireRange) {
2359 // The event list must be sorted by TOF!
2360 this->sortTof();
2361 }
2362
2363 // Convert the list
2364 switch (eventType) {
2365 case TOF:
2366 integrateHelper(this->events, minX, maxX, entireRange, sum, error);
2367 break;
2368 case WEIGHTED:
2369 integrateHelper(this->weightedEvents, minX, maxX, entireRange, sum, error);
2370 break;
2371 case WEIGHTED_NOTIME:
2372 integrateHelper(this->weightedEventsNoTime, minX, maxX, entireRange, sum, error);
2373 break;
2374 default:
2375 throw std::runtime_error("EventList: invalid event type value was found.");
2376 }
2377}
2378
2379// ==============================================================================================
2380// ----------- Conversion Functions (changing tof values)
2381// ---------------------------------------
2382// ==============================================================================================
2383
2390void EventList::convertTof(std::function<double(double)> func, const int sorting) {
2391 // fix the histogram parameter
2392 MantidVec &x = dataX();
2393 transform(x.begin(), x.end(), x.begin(), func);
2394
2395 // do nothing if sorting > 0
2396 if (sorting == 0) {
2397 this->setSortOrder(UNSORTED);
2398 } else if ((sorting < 0) && (this->getSortType() == TOF_SORT)) {
2399 this->reverse();
2400 }
2401
2402 if (this->getNumberEvents() == 0)
2403 return;
2404
2405 // Convert the list
2406 switch (eventType) {
2407 case TOF:
2408 this->convertTofHelper(this->events, func);
2409 break;
2410 case WEIGHTED:
2411 this->convertTofHelper(this->weightedEvents, func);
2412 break;
2413 case WEIGHTED_NOTIME:
2414 this->convertTofHelper(this->weightedEventsNoTime, func);
2415 break;
2416 }
2417}
2418
2423template <class T> void EventList::convertTofHelper(std::vector<T> &events, const std::function<double(double)> &func) {
2424 // iterate through all events
2425 for (auto &ev : events)
2426 ev.m_tof = func(ev.m_tof);
2427}
2428
2429// --------------------------------------------------------------------------
2435void EventList::convertTof(const double factor, const double offset) {
2436 // fix the histogram parameter
2437 auto &x = mutableX();
2438 x *= factor;
2439 x += offset;
2440
2441 if ((factor < 0.) && (this->getSortType() == TOF_SORT))
2442 this->reverse();
2443
2444 if (this->getNumberEvents() == 0)
2445 return;
2446
2447 // Convert the list
2448 switch (eventType) {
2449 case TOF:
2450 this->convertTofHelper(this->events, factor, offset);
2451 break;
2452 case WEIGHTED:
2453 this->convertTofHelper(this->weightedEvents, factor, offset);
2454 break;
2455 case WEIGHTED_NOTIME:
2456 this->convertTofHelper(this->weightedEventsNoTime, factor, offset);
2457 break;
2458 }
2459}
2460
2461// --------------------------------------------------------------------------
2470template <class T> void EventList::convertTofHelper(std::vector<T> &events, const double factor, const double offset) {
2471 // iterate through all events
2472 for (auto &event : events) {
2473 event.m_tof = event.m_tof * factor + offset;
2474 }
2475}
2476
2477// --------------------------------------------------------------------------
2484void EventList::scaleTof(const double factor) { this->convertTof(factor, 0.0); }
2485
2486// --------------------------------------------------------------------------
2491void EventList::addTof(const double offset) { this->convertTof(1.0, offset); }
2492
2493// --------------------------------------------------------------------------
2499template <class T> void EventList::addPulsetimeHelper(std::vector<T> &events, const double seconds) {
2500 // iterate through all events
2501 for (auto &event : events) {
2502 event.m_pulsetime += seconds;
2503 }
2504}
2505
2512template <class T> void EventList::addPulsetimesHelper(std::vector<T> &events, const std::vector<double> &seconds) {
2513 auto eventIterEnd{events.end()};
2514 auto secondsIter{seconds.cbegin()};
2515 for (auto eventIter = events.begin(); eventIter < eventIterEnd; ++eventIter, ++secondsIter) {
2516 eventIter->m_pulsetime += *secondsIter;
2517 }
2518}
2519
2520// --------------------------------------------------------------------------
2525void EventList::addPulsetime(const double seconds) {
2526 if (this->getNumberEvents() == 0)
2527 return;
2528
2529 // Convert the list
2530 switch (eventType) {
2531 case TOF:
2532 this->addPulsetimeHelper(this->events, seconds);
2533 break;
2534 case WEIGHTED:
2535 this->addPulsetimeHelper(this->weightedEvents, seconds);
2536 break;
2537 case WEIGHTED_NOTIME:
2538 throw std::runtime_error("EventList::addPulsetime() called on an event "
2539 "list with no pulse times. You must call this "
2540 "algorithm BEFORE CompressEvents.");
2541 break;
2542 }
2543}
2544
2545// --------------------------------------------------------------------------
2550void EventList::addPulsetimes(const std::vector<double> &seconds) {
2551 if (this->getNumberEvents() == 0)
2552 return;
2553 if (this->getNumberEvents() != seconds.size()) {
2554 throw std::runtime_error("");
2555 }
2556
2557 // Convert the list
2558 switch (eventType) {
2559 case TOF:
2560 this->addPulsetimesHelper(this->events, seconds);
2561 break;
2562 case WEIGHTED:
2563 this->addPulsetimesHelper(this->weightedEvents, seconds);
2564 break;
2565 case WEIGHTED_NOTIME:
2566 throw std::runtime_error("EventList::addPulsetime() called on an event "
2567 "list with no pulse times. You must call this "
2568 "algorithm BEFORE CompressEvents.");
2569 break;
2570 }
2571}
2572
2573// --------------------------------------------------------------------------
2581template <class T>
2582std::size_t EventList::maskTofHelper(std::vector<T> &events, const double tofMin, const double tofMax) {
2583 // quick checks to make sure that the masking range is even in the data
2584 if (tofMin > events.rbegin()->tof())
2585 return 0;
2586 if (tofMax < events.begin()->tof())
2587 return 0;
2588
2589 // Find the index of the first tofMin
2590 auto it_first = std::lower_bound(events.begin(), events.end(), tofMin);
2591 if ((it_first != events.end()) && (it_first->tof() < tofMax)) {
2592 // Something was found
2593 // Look for the first one > tofMax
2594 auto it_last = std::upper_bound(it_first, events.end(), T(tofMax));
2595
2596 if (it_first >= it_last) {
2597 throw std::runtime_error("Event filter is all messed up"); // TODO
2598 }
2599
2600 size_t tmp = (it_last - it_first);
2601 // it_last will either be at the end (if not found) or before it.
2602 // Erase this range from the vector
2603 events.erase(it_first, it_last);
2604
2605 // Done! Sorting is still valid, no need to redo.
2606 return tmp; //(it_last - it_first); the iterators get invalid after erase
2607 //(on my machine)
2608 }
2609 return 0;
2610}
2611
2612// --------------------------------------------------------------------------
2619void EventList::maskTof(const double tofMin, const double tofMax) {
2620 if (tofMax <= tofMin)
2621 throw std::runtime_error("EventList::maskTof: tofMax must be > tofMin");
2622
2623 // don't do anything with an emply list
2624 if (this->getNumberEvents() == 0)
2625 return;
2626
2627 // Start by sorting by tof
2628 this->sortTof();
2629
2630 // Convert the list
2631 size_t numOrig = 0;
2632 size_t numDel = 0;
2633 switch (eventType) {
2634 case TOF:
2635 numOrig = this->events.size();
2636 numDel = this->maskTofHelper(this->events, tofMin, tofMax);
2637 break;
2638 case WEIGHTED:
2639 numOrig = this->weightedEvents.size();
2640 numDel = this->maskTofHelper(this->weightedEvents, tofMin, tofMax);
2641 break;
2642 case WEIGHTED_NOTIME:
2643 numOrig = this->weightedEventsNoTime.size();
2644 numDel = this->maskTofHelper(this->weightedEventsNoTime, tofMin, tofMax);
2645 break;
2646 }
2647
2648 if (numDel >= numOrig)
2649 this->clear(false);
2650}
2651
2652// --------------------------------------------------------------------------
2659template <class T> std::size_t EventList::maskConditionHelper(std::vector<T> &events, const std::vector<bool> &mask) {
2660
2661 // runs through the two synchronized vectors and delete elements
2662 // for condition false
2663 auto itm = std::find(mask.begin(), mask.end(), false);
2664 auto first = events.begin() + (itm - mask.begin());
2665
2666 if (itm != mask.end()) {
2667 for (auto ite = first; ++ite != events.end() && ++itm != mask.end();) {
2668 if (*itm != false) {
2669 *first++ = std::move(*ite);
2670 }
2671 }
2672 }
2673
2674 auto n = events.end() - first;
2675 if (n != 0)
2676 events.erase(first, events.end());
2677
2678 return n;
2679}
2680
2681// --------------------------------------------------------------------------
2687void EventList::maskCondition(const std::vector<bool> &mask) {
2688
2689 // mask size must match the number of events
2690 if (this->getNumberEvents() != mask.size())
2691 throw std::runtime_error("EventList::maskTof: tofMax must be > tofMin");
2692
2693 // don't do anything with an emply list
2694 if (this->getNumberEvents() == 0)
2695 return;
2696
2697 // Convert the list
2698 size_t numOrig = 0;
2699 size_t numDel = 0;
2700 switch (eventType) {
2701 case TOF:
2702 numOrig = this->events.size();
2703 numDel = this->maskConditionHelper(this->events, mask);
2704 break;
2705 case WEIGHTED:
2706 numOrig = this->weightedEvents.size();
2707 numDel = this->maskConditionHelper(this->weightedEvents, mask);
2708 break;
2709 case WEIGHTED_NOTIME:
2710 numOrig = this->weightedEventsNoTime.size();
2711 numDel = this->maskConditionHelper(this->weightedEventsNoTime, mask);
2712 break;
2713 }
2714
2715 if (numDel >= numOrig)
2716 this->clear(false);
2717}
2718
2719// --------------------------------------------------------------------------
2725template <class T> void EventList::getTofsHelper(const std::vector<T> &events, std::vector<double> &tofs) {
2726 tofs.clear();
2727 for (auto itev = events.cbegin(); itev != events.cend(); ++itev)
2728 tofs.emplace_back(itev->m_tof);
2729}
2730
2734void EventList::getTofs(std::vector<double> &tofs) const {
2735 // Set the capacity of the vector to avoid multiple resizes
2736 tofs.reserve(this->getNumberEvents());
2737
2738 // Convert the list
2739 switch (eventType) {
2740 case TOF:
2741 this->getTofsHelper(this->events, tofs);
2742 break;
2743 case WEIGHTED:
2744 this->getTofsHelper(this->weightedEvents, tofs);
2745 break;
2746 case WEIGHTED_NOTIME:
2747 this->getTofsHelper(this->weightedEventsNoTime, tofs);
2748 break;
2749 }
2750}
2751
2756std::vector<double> EventList::getTofs() const {
2757 std::vector<double> tofs;
2758 this->getTofs(tofs);
2759 return tofs;
2760}
2761
2762// --------------------------------------------------------------------------
2768template <class T> void EventList::getWeightsHelper(const std::vector<T> &events, std::vector<double> &weights) {
2769 weights.clear();
2770 weights.reserve(events.size());
2771 std::transform(events.cbegin(), events.cend(), std::back_inserter(weights),
2772 [](const auto &event) { return event.weight(); });
2773}
2774
2778void EventList::getWeights(std::vector<double> &weights) const {
2779 // Set the capacity of the vector to avoid multiple resizes
2780 weights.reserve(this->getNumberEvents());
2781
2782 // Convert the list
2783 switch (eventType) {
2784 case WEIGHTED:
2785 this->getWeightsHelper(this->weightedEvents, weights);
2786 break;
2787 case WEIGHTED_NOTIME:
2788 this->getWeightsHelper(this->weightedEventsNoTime, weights);
2789 break;
2790 default:
2791 // not a weighted event type, return 1.0 for all.
2792 weights.assign(this->getNumberEvents(), 1.0);
2793 break;
2794 }
2795}
2796
2801std::vector<double> EventList::getWeights() const {
2802 std::vector<double> weights;
2803 this->getWeights(weights);
2804 return weights;
2805}
2806
2807// --------------------------------------------------------------------------
2813template <class T>
2814void EventList::getWeightErrorsHelper(const std::vector<T> &events, std::vector<double> &weightErrors) {
2815 weightErrors.clear();
2816 weightErrors.reserve(events.size());
2817 std::transform(events.cbegin(), events.cend(), std::back_inserter(weightErrors),
2818 [](const auto &event) { return event.error(); });
2819}
2820
2824void EventList::getWeightErrors(std::vector<double> &weightErrors) const {
2825 // Set the capacity of the vector to avoid multiple resizes
2826 weightErrors.reserve(this->getNumberEvents());
2827
2828 // Convert the list
2829 switch (eventType) {
2830 case WEIGHTED:
2831 this->getWeightErrorsHelper(this->weightedEvents, weightErrors);
2832 break;
2833 case WEIGHTED_NOTIME:
2834 this->getWeightErrorsHelper(this->weightedEventsNoTime, weightErrors);
2835 break;
2836 default:
2837 // not a weighted event type, return 1.0 for all.
2838 weightErrors.assign(this->getNumberEvents(), 1.0);
2839 break;
2840 }
2841}
2842
2847std::vector<double> EventList::getWeightErrors() const {
2848 std::vector<double> weightErrors;
2849 this->getWeightErrors(weightErrors);
2850 return weightErrors;
2851}
2852
2853// --------------------------------------------------------------------------
2859template <class T>
2860void EventList::getPulseTimesHelper(const std::vector<T> &events,
2861 std::vector<Mantid::Types::Core::DateAndTime> &times) {
2862 times.clear();
2863 times.reserve(events.size());
2864 std::transform(events.cbegin(), events.cend(), std::back_inserter(times),
2865 [](const auto &event) { return event.pulseTime(); });
2866}
2867
2872std::vector<Mantid::Types::Core::DateAndTime> EventList::getPulseTimes() const {
2873 std::vector<Mantid::Types::Core::DateAndTime> times;
2874 // Set the capacity of the vector to avoid multiple resizes
2875 times.reserve(this->getNumberEvents());
2876
2877 // Convert the list
2878 switch (eventType) {
2879 case TOF:
2880 this->getPulseTimesHelper(this->events, times);
2881 break;
2882 case WEIGHTED:
2883 this->getPulseTimesHelper(this->weightedEvents, times);
2884 break;
2885 case WEIGHTED_NOTIME:
2886 this->getPulseTimesHelper(this->weightedEventsNoTime, times);
2887 break;
2888 }
2889 return times;
2890}
2891
2892// --------------------------------------------------------------------------
2896double EventList::getTofMin() const {
2897 // set up as the maximum available double
2898 double tMin = std::numeric_limits<double>::max();
2899
2900 // no events is a soft error
2901 if (this->empty())
2902 return tMin;
2903
2904 // when events are ordered by tof just need the first value
2905 if (this->order == TOF_SORT) {
2906 switch (eventType) {
2907 case TOF:
2908 return this->events.begin()->tof();
2909 case WEIGHTED:
2910 return this->weightedEvents.begin()->tof();
2911 case WEIGHTED_NOTIME:
2912 return this->weightedEventsNoTime.begin()->tof();
2913 }
2914 }
2915
2916 // now we are stuck with a linear search
2917 double temp = tMin; // start with the largest possible value
2918 size_t numEvents = this->getNumberEvents();
2919 for (size_t i = 0; i < numEvents; i++) {
2920 switch (eventType) {
2921 case TOF:
2922 temp = this->events[i].tof();
2923 break;
2924 case WEIGHTED:
2925 temp = this->weightedEvents[i].tof();
2926 break;
2927 case WEIGHTED_NOTIME:
2928 temp = this->weightedEventsNoTime[i].tof();
2929 break;
2930 }
2931 if (temp < tMin)
2932 tMin = temp;
2933 }
2934 return tMin;
2935}
2936
2940double EventList::getTofMax() const {
2941 // set up as the minimum available double
2942 double tMax = std::numeric_limits<double>::lowest();
2943
2944 // no events is a soft error
2945 if (this->empty())
2946 return tMax;
2947
2948 // when events are ordered by tof just need the first value
2949 if (this->order == TOF_SORT) {
2950 switch (eventType) {
2951 case TOF:
2952 return this->events.rbegin()->tof();
2953 case WEIGHTED:
2954 return this->weightedEvents.rbegin()->tof();
2955 case WEIGHTED_NOTIME:
2956 return this->weightedEventsNoTime.rbegin()->tof();
2957 }
2958 }
2959
2960 // now we are stuck with a linear search
2961 size_t numEvents = this->getNumberEvents();
2962 double temp = tMax; // start with the smallest possible value
2963 for (size_t i = 0; i < numEvents; i++) {
2964 switch (eventType) {
2965 case TOF:
2966 temp = this->events[i].tof();
2967 break;
2968 case WEIGHTED:
2969 temp = this->weightedEvents[i].tof();
2970 break;
2971 case WEIGHTED_NOTIME:
2972 temp = this->weightedEventsNoTime[i].tof();
2973 break;
2974 }
2975 if (temp > tMax)
2976 tMax = temp;
2977 }
2978 return tMax;
2979}
2980
2981// --------------------------------------------------------------------------
2985DateAndTime EventList::getPulseTimeMin() const {
2986 // set up as the maximum available date time.
2987 DateAndTime tMin = DateAndTime::maximum();
2988
2989 // no events is a soft error
2990 if (this->empty())
2991 return tMin;
2992
2993 // when events are ordered by pulse time just need the first value
2994 if (this->order == PULSETIME_SORT) {
2995 switch (eventType) {
2996 case TOF:
2997 return this->events.begin()->pulseTime();
2998 case WEIGHTED:
2999 return this->weightedEvents.begin()->pulseTime();
3000 case WEIGHTED_NOTIME:
3001 return this->weightedEventsNoTime.begin()->pulseTime();
3002 }
3003 }
3004
3005 // now we are stuck with a linear search
3006 DateAndTime temp = tMin; // start with the largest possible value
3007 size_t numEvents = this->getNumberEvents();
3008 for (size_t i = 0; i < numEvents; i++) {
3009 switch (eventType) {
3010 case TOF:
3011 temp = this->events[i].pulseTime();
3012 break;
3013 case WEIGHTED:
3014 temp = this->weightedEvents[i].pulseTime();
3015 break;
3016 case WEIGHTED_NOTIME:
3017 temp = this->weightedEventsNoTime[i].pulseTime();
3018 break;
3019 }
3020 if (temp < tMin)
3021 tMin = temp;
3022 }
3023 return tMin;
3024}
3025
3029DateAndTime EventList::getPulseTimeMax() const {
3030 // set up as the minimum available date time.
3031 DateAndTime tMax = DateAndTime::minimum();
3032
3033 // no events is a soft error
3034 if (this->empty())
3035 return tMax;
3036
3037 // when events are ordered by pulse time just need the first value
3038 if (this->order == PULSETIME_SORT) {
3039 switch (eventType) {
3040 case TOF:
3041 return this->events.rbegin()->pulseTime();
3042 case WEIGHTED:
3043 return this->weightedEvents.rbegin()->pulseTime();
3044 case WEIGHTED_NOTIME:
3045 return this->weightedEventsNoTime.rbegin()->pulseTime();
3046 }
3047 }
3048
3049 // now we are stuck with a linear search
3050 size_t numEvents = this->getNumberEvents();
3051 DateAndTime temp = tMax; // start with the smallest possible value
3052 for (size_t i = 0; i < numEvents; i++) {
3053 switch (eventType) {
3054 case TOF:
3055 temp = this->events[i].pulseTime();
3056 break;
3057 case WEIGHTED:
3058 temp = this->weightedEvents[i].pulseTime();
3059 break;
3060 case WEIGHTED_NOTIME:
3061 temp = this->weightedEventsNoTime[i].pulseTime();
3062 break;
3063 }
3064 if (temp > tMax)
3065 tMax = temp;
3066 }
3067 return tMax;
3068}
3069
3070void EventList::getPulseTimeMinMax(Mantid::Types::Core::DateAndTime &tMin,
3071 Mantid::Types::Core::DateAndTime &tMax) const {
3072 // set up as the minimum available date time.
3073 tMax = DateAndTime::minimum();
3074 tMin = DateAndTime::maximum();
3075
3076 // no events is a soft error
3077 if (this->empty())
3078 return;
3079
3080 // when events are ordered by pulse time just need the first/last values
3081 if (this->order == PULSETIME_SORT) {
3082 switch (eventType) {
3083 case TOF:
3084 tMin = this->events.begin()->pulseTime();
3085 tMax = this->events.rbegin()->pulseTime();
3086 return;
3087 case WEIGHTED:
3088 tMin = this->weightedEvents.begin()->pulseTime();
3089 tMax = this->weightedEvents.rbegin()->pulseTime();
3090 return;
3091 case WEIGHTED_NOTIME:
3092 tMin = this->weightedEventsNoTime.begin()->pulseTime();
3093 tMax = this->weightedEventsNoTime.rbegin()->pulseTime();
3094 return;
3095 }
3096 }
3097
3098 // now we are stuck with a linear search
3099 size_t numEvents = this->getNumberEvents();
3100 DateAndTime temp = tMax; // start with the smallest possible value
3101 for (size_t i = 0; i < numEvents; i++) {
3102 switch (eventType) {
3103 case TOF:
3104 temp = this->events[i].pulseTime();
3105 break;
3106 case WEIGHTED:
3107 temp = this->weightedEvents[i].pulseTime();
3108 break;
3109 case WEIGHTED_NOTIME:
3110 temp = this->weightedEventsNoTime[i].pulseTime();
3111 break;
3112 }
3113 if (temp > tMax)
3114 tMax = temp;
3115 if (temp < tMin)
3116 tMin = temp;
3117 }
3118}
3119
3120DateAndTime EventList::getTimeAtSampleMax(const double &tofFactor, const double &tofOffset) const {
3121 // set up as the minimum available date time.
3122 DateAndTime tMax = DateAndTime::minimum();
3123
3124 // no events is a soft error
3125 if (this->empty())
3126 return tMax;
3127
3128 // when events are ordered by time at sample just need the first value
3129 if (this->order == TIMEATSAMPLE_SORT) {
3130 switch (eventType) {
3131 case TOF:
3132 return calculateCorrectedFullTime(*(this->events.rbegin()), tofFactor, tofOffset);
3133 case WEIGHTED:
3134 return calculateCorrectedFullTime(*(this->weightedEvents.rbegin()), tofFactor, tofOffset);
3135 case WEIGHTED_NOTIME:
3136 return calculateCorrectedFullTime(*(this->weightedEventsNoTime.rbegin()), tofFactor, tofOffset);
3137 }
3138 }
3139
3140 // now we are stuck with a linear search
3141 size_t numEvents = this->getNumberEvents();
3142 DateAndTime temp = tMax; // start with the smallest possible value
3143 for (size_t i = 0; i < numEvents; i++) {
3144 switch (eventType) {
3145 case TOF:
3146 temp = calculateCorrectedFullTime(this->events[i], tofFactor, tofOffset);
3147 break;
3148 case WEIGHTED:
3149 temp = calculateCorrectedFullTime(this->weightedEvents[i], tofFactor, tofOffset);
3150 break;
3151 case WEIGHTED_NOTIME:
3152 temp = calculateCorrectedFullTime(this->weightedEventsNoTime[i], tofFactor, tofOffset);
3153 break;
3154 }
3155 if (temp > tMax)
3156 tMax = temp;
3157 }
3158 return tMax;
3159}
3160
3161DateAndTime EventList::getTimeAtSampleMin(const double &tofFactor, const double &tofOffset) const {
3162 // set up as the minimum available date time.
3163 DateAndTime tMin = DateAndTime::maximum();
3164
3165 // no events is a soft error
3166 if (this->empty())
3167 return tMin;
3168
3169 // when events are ordered by time at sample just need the first value
3170 if (this->order == TIMEATSAMPLE_SORT) {
3171 switch (eventType) {
3172 case TOF:
3173 return calculateCorrectedFullTime(*(this->events.begin()), tofFactor, tofOffset);
3174 case WEIGHTED:
3175 return calculateCorrectedFullTime(*(this->weightedEvents.begin()), tofFactor, tofOffset);
3176 case WEIGHTED_NOTIME:
3177 return calculateCorrectedFullTime(*(this->weightedEventsNoTime.begin()), tofFactor, tofOffset);
3178 }
3179 }
3180
3181 // now we are stuck with a linear search
3182 size_t numEvents = this->getNumberEvents();
3183 DateAndTime temp = tMin; // start with the smallest possible value
3184 for (size_t i = 0; i < numEvents; i++) {
3185 switch (eventType) {
3186 case TOF:
3187 temp = calculateCorrectedFullTime(this->events[i], tofFactor, tofOffset);
3188 break;
3189 case WEIGHTED:
3190 temp = calculateCorrectedFullTime(this->weightedEvents[i], tofFactor, tofOffset);
3191 break;
3192 case WEIGHTED_NOTIME:
3193 temp = calculateCorrectedFullTime(this->weightedEventsNoTime[i], tofFactor, tofOffset);
3194 break;
3195 }
3196 if (temp < tMin)
3197 tMin = temp;
3198 }
3199 return tMin;
3200}
3201
3202// --------------------------------------------------------------------------
3208template <class T> void EventList::setTofsHelper(std::vector<T> &events, const std::vector<double> &tofs) {
3209 if (tofs.empty())
3210 return;
3211
3212 size_t x_size = tofs.size();
3213 if (events.size() != x_size)
3214 return; // should this throw an exception?
3215
3216 for (size_t i = 0; i < x_size; ++i)
3217 events[i].m_tof = tofs[i];
3218}
3219
3220// --------------------------------------------------------------------------
3227 this->order = UNSORTED;
3228
3229 // Convert the list
3230 switch (eventType) {
3231 case TOF:
3232 this->setTofsHelper(this->events, tofs);
3233 break;
3234 case WEIGHTED:
3235 this->setTofsHelper(this->weightedEvents, tofs);
3236 break;
3237 case WEIGHTED_NOTIME:
3238 this->setTofsHelper(this->weightedEventsNoTime, tofs);
3239 break;
3240 }
3241}
3242
3243// ==============================================================================================
3244// ----------- MULTIPLY AND DIVIDE ---------------------------------------
3245// ==============================================================================================
3246
3247//------------------------------------------------------------------------------------------------
3255template <class T> void EventList::multiplyHelper(std::vector<T> &events, const double value, const double error) {
3256 // Square of the value's error
3257 double errorSquared = error * error;
3258 double valueSquared = value * value;
3259
3260 auto itev_end = events.end();
3261
3262 if (error == 0) {
3263 // Error-less calculation
3264 for (auto itev = events.begin(); itev != itev_end; itev++) {
3265 itev->m_errorSquared = static_cast<float>(itev->m_errorSquared * valueSquared);
3266 itev->m_weight *= static_cast<float>(value);
3267 }
3268 } else {
3269 // Carry the scalar error
3270 for (auto itev = events.begin(); itev != itev_end; itev++) {
3271 itev->m_errorSquared =
3272 static_cast<float>(itev->m_errorSquared * valueSquared + errorSquared * itev->m_weight * itev->m_weight);
3273 itev->m_weight *= static_cast<float>(value);
3274 }
3275 }
3276}
3277
3278//------------------------------------------------------------------------------------------------
3291 this->multiply(value);
3292 return *this;
3293}
3294
3295//------------------------------------------------------------------------------------------------
3324void EventList::multiply(const double value, const double error) {
3325 // Do nothing if multiplying by exactly one and there is no error
3326 if ((value == 1.0) && (error == 0.0))
3327 return;
3328
3329 switch (eventType) {
3330 case TOF:
3331 // Switch to weights if needed.
3332 this->switchTo(WEIGHTED);
3333 // Fall through
3334
3335 case WEIGHTED:
3336 multiplyHelper(this->weightedEvents, value, error);
3337 break;
3338
3339 case WEIGHTED_NOTIME:
3341 break;
3342 }
3343}
3344
3345//------------------------------------------------------------------------------------------------
3354template <class T>
3355void EventList::multiplyHistogramHelper(std::vector<T> &events, const MantidVec &X, const MantidVec &Y,
3356 const MantidVec &E) {
3357 // Validate inputs
3358 if ((X.size() < 2) || (Y.size() != E.size()) || (X.size() != 1 + Y.size())) {
3359 std::stringstream msg;
3360 msg << "EventList::multiply() was given invalid size or "
3361 "inconsistent histogram arrays: X["
3362 << X.size() << "] "
3363 << "Y[" << Y.size() << " E[" << E.size() << "]";
3364 throw std::invalid_argument(msg.str());
3365 }
3366
3367 size_t x_size = X.size();
3368
3369 // Iterate through all events (sorted by tof)
3370 auto itev = findFirstEvent(events, T(X[0]));
3371 auto itev_end = events.end();
3372 // The above can still take you to end() if no events above X[0], so check
3373 // again.
3374 if (itev == itev_end)
3375 return;
3376
3377 // Find the first bin
3378 size_t bin = 0;
3379
3380 // Multiplier values
3381 double value;
3382 double error;
3383 double valueSquared;
3384 double errorSquared;
3385
3386 // If the tof is greater the first bin boundary, so we need to find the first
3387 // bin
3388 double tof = itev->tof();
3389 while (bin < x_size - 1) {
3390 // Within range?
3391 if ((tof >= X[bin]) && (tof < X[bin + 1]))
3392 break; // Stop increasing bin
3393 ++bin;
3394 }
3395
3396 // New bin! Find what you are multiplying!
3397 value = Y[bin];
3398 error = E[bin];
3399 valueSquared = value * value;
3400 errorSquared = error * error;
3401
3402 // Keep going through all the events
3403 while ((itev != itev_end) && (bin < x_size - 1)) {
3404 tof = itev->tof();
3405 while (bin < x_size - 1) {
3406 // Event is Within range?
3407 if ((tof >= X[bin]) && (tof < X[bin + 1])) {
3408 // Process this event. Multiply and calculate error.
3409 itev->m_errorSquared =
3410 static_cast<float>(itev->m_errorSquared * valueSquared + errorSquared * itev->m_weight * itev->m_weight);
3411 itev->m_weight *= static_cast<float>(value);
3412 break; // out of the bin-searching-while-loop
3413 }
3414 ++bin;
3415 if (bin >= x_size - 1)
3416 break;
3417
3418 // New bin! Find what you are multiplying!
3419 value = Y[bin];
3420 error = E[bin];
3421 valueSquared = value * value;
3422 errorSquared = error * error;
3423 }
3424 ++itev;
3425 }
3426}
3427
3428//------------------------------------------------------------------------------------------------
3449void EventList::multiply(const MantidVec &X, const MantidVec &Y, const MantidVec &E) {
3450 switch (eventType) {
3451 case TOF:
3452 // Switch to weights if needed.
3453 this->switchTo(WEIGHTED);
3454 // Fall through
3455
3456 case WEIGHTED:
3457 // Sorting by tof is necessary for the algorithm
3458 this->sortTof();
3460 break;
3461
3462 case WEIGHTED_NOTIME:
3463 // Sorting by tof is necessary for the algorithm
3464 this->sortTof();
3466 break;
3467 }
3468}
3469
3470//------------------------------------------------------------------------------------------------
3479template <class T>
3480void EventList::divideHistogramHelper(std::vector<T> &events, const MantidVec &X, const MantidVec &Y,
3481 const MantidVec &E) {
3482 // Validate inputs
3483 if ((X.size() < 2) || (Y.size() != E.size()) || (X.size() != 1 + Y.size())) {
3484 std::stringstream msg;
3485 msg << "EventList::divide() was given invalid size or "
3486 "inconsistent histogram arrays: X["
3487 << X.size() << "] "
3488 << "Y[" << Y.size() << " E[" << E.size() << "]";
3489 throw std::invalid_argument(msg.str());
3490 }
3491
3492 size_t x_size = X.size();
3493
3494 // Iterate through all events (sorted by tof)
3495 auto itev = findFirstEvent(events, T(X[0]));
3496 auto itev_end = events.end();
3497 // The above can still take you to end() if no events above X[0], so check
3498 // again.
3499 if (itev == itev_end)
3500 return;
3501
3502 // Find the first bin
3503 size_t bin = 0;
3504
3505 // Multiplier values
3506 double value;
3507 double error;
3508 double valError_over_value_squared;
3509
3510 // If the tof is greater the first bin boundary, so we need to find the first
3511 // bin
3512 double tof = itev->tof();
3513 while (bin < x_size - 1) {
3514 // Within range?
3515 if ((tof >= X[bin]) && (tof < X[bin + 1]))
3516 break; // Stop increasing bin
3517 ++bin;
3518 }
3519
3520 // New bin! Find what you are multiplying!
3521 value = Y[bin];
3522 error = E[bin];
3523
3524 // --- Division case ---
3525 if (value == 0) {
3526 value = std::numeric_limits<float>::quiet_NaN(); // Avoid divide by zero
3527 valError_over_value_squared = 0;
3528 } else
3529 valError_over_value_squared = error * error / (value * value);
3530
3531 // Keep going through all the events
3532 while ((itev != events.end()) && (bin < x_size - 1)) {
3533 tof = itev->tof();
3534 while (bin < x_size - 1) {
3535 // Event is Within range?
3536 if ((tof >= X[bin]) && (tof < X[bin + 1])) {
3537 // Process this event. Divide and calculate error.
3538 double newWeight = itev->m_weight / value;
3539 itev->m_errorSquared = static_cast<float>(
3540 newWeight * newWeight *
3541 ((itev->m_errorSquared / (itev->m_weight * itev->m_weight)) + valError_over_value_squared));
3542 itev->m_weight = static_cast<float>(newWeight);
3543 break; // out of the bin-searching-while-loop
3544 }
3545 ++bin;
3546 if (bin >= x_size - 1)
3547 break;
3548
3549 // New bin! Find what you are multiplying!
3550 value = Y[bin];
3551 error = E[bin];
3552
3553 // --- Division case ---
3554 if (value == 0) {
3555 value = std::numeric_limits<float>::quiet_NaN(); // Avoid divide by zero
3556 valError_over_value_squared = 0;
3557 } else
3558 valError_over_value_squared = error * error / (value * value);
3559 }
3560 ++itev;
3561 }
3562}
3563
3564//------------------------------------------------------------------------------------------------
3586void EventList::divide(const MantidVec &X, const MantidVec &Y, const MantidVec &E) {
3587 switch (eventType) {
3588 case TOF:
3589 // Switch to weights if needed.
3590 this->switchTo(WEIGHTED);
3591 // Fall through
3592
3593 case WEIGHTED:
3594 // Sorting by tof is necessary for the algorithm
3595 this->sortTof();
3597 break;
3598
3599 case WEIGHTED_NOTIME:
3600 // Sorting by tof is necessary for the algorithm
3601 this->sortTof();
3603 break;
3604 }
3605}
3606
3607//------------------------------------------------------------------------------------------------
3617 if (value == 0.0)
3618 throw std::invalid_argument("EventList::divide() called with value of 0.0. Cannot divide by zero.");
3619 this->multiply(1.0 / value, 0.0);
3620 return *this;
3621}
3622
3623//------------------------------------------------------------------------------------------------
3633void EventList::divide(const double value, const double error) {
3634 if (value == 0.0)
3635 throw std::invalid_argument("EventList::divide() called with value of 0.0. Cannot divide by zero.");
3636 // Do nothing if dividing by exactly 1.0, no error
3637 else if (value == 1.0 && error == 0.0)
3638 return;
3639
3640 // We'll multiply by 1/value
3641 double invValue = 1.0 / value;
3642 // Relative error remains the same
3643 double invError = (error / value) * invValue;
3644
3645 this->multiply(invValue, invError);
3646}
3647
3648// ==============================================================================================
3649// ----------- SPLITTING AND FILTERING ---------------------------------------
3650// ==============================================================================================
3658template <class T>
3659void EventList::filterByPulseTimeHelper(std::vector<T> &events, DateAndTime start, DateAndTime stop,
3660 std::vector<T> &output) {
3661 auto itev = events.begin();
3662 auto itev_end = events.end();
3663 // Find the first event with m_pulsetime >= start
3664 while ((itev != itev_end) && (itev->m_pulsetime < start))
3665 itev++;
3666
3667 while ((itev != itev_end) && (itev->m_pulsetime < stop)) {
3668 // Add the copy to the output
3669 output.emplace_back(*itev);
3670 ++itev;
3671 }
3672}
3673
3683template <class T>
3684void EventList::filterByTimeAtSampleHelper(std::vector<T> &events, DateAndTime start, DateAndTime stop,
3685 double tofFactor, double tofOffset, std::vector<T> &output) {
3686 auto itev = events.begin();
3687 auto itev_end = events.end();
3688 // Find the first event with m_pulsetime >= start
3689 while ((itev != itev_end) && (calculateCorrectedFullTime(*itev, tofFactor, tofOffset) < start.totalNanoseconds()))
3690 itev++;
3691
3692 while ((itev != itev_end) && (calculateCorrectedFullTime(*itev, tofFactor, tofOffset) < stop.totalNanoseconds())) {
3693 // Add the copy to the output
3694 output.emplace_back(*itev);
3695 ++itev;
3696 }
3697}
3698
3699//------------------------------------------------------------------------------------------------
3709void EventList::filterByPulseTime(DateAndTime start, DateAndTime stop, EventList &output) const {
3710 if (this == &output) {
3711 throw std::invalid_argument("In-place filtering is not allowed");
3712 }
3713
3714 // Start by sorting the event list by pulse time.
3715 this->sortPulseTime();
3716 // Clear the output
3717 output.clear();
3718 // Has to match the given type
3719 output.switchTo(eventType);
3720 output.setDetectorIDs(this->getDetectorIDs());
3721 output.setHistogram(m_histogram);
3722 output.setSortOrder(this->order);
3723
3724 // Iterate through all events (sorted by pulse time)
3725 switch (eventType) {
3726 case TOF:
3727 filterByPulseTimeHelper(this->events, start, stop, output.events);
3728 break;
3729 case WEIGHTED:
3730 filterByPulseTimeHelper(this->weightedEvents, start, stop, output.weightedEvents);
3731 break;
3732 case WEIGHTED_NOTIME:
3733 throw std::runtime_error("EventList::filterByPulseTime() called on an "
3734 "EventList that no longer has time information.");
3735 break;
3736 }
3737}
3738
3739void EventList::filterByTimeAtSample(Types::Core::DateAndTime start, Types::Core::DateAndTime stop, double tofFactor,
3740 double tofOffset, EventList &output) const {
3741 if (this == &output) {
3742 throw std::invalid_argument("In-place filtering is not allowed");
3743 }
3744
3745 // Start by sorting
3746 this->sortTimeAtSample(tofFactor, tofOffset);
3747 // Clear the output
3748 output.clear();
3749 // Has to match the given type
3750 output.switchTo(eventType);
3751 output.setDetectorIDs(this->getDetectorIDs());
3752 output.setHistogram(m_histogram);
3753 output.setSortOrder(this->order);
3754
3755 // Iterate through all events (sorted by pulse time)
3756 switch (eventType) {
3757 case TOF:
3758 filterByTimeAtSampleHelper(this->events, start, stop, tofFactor, tofOffset, output.events);
3759 break;
3760 case WEIGHTED:
3761 filterByTimeAtSampleHelper(this->weightedEvents, start, stop, tofFactor, tofOffset, output.weightedEvents);
3762 break;
3763 case WEIGHTED_NOTIME:
3764 throw std::runtime_error("EventList::filterByTimeAtSample() called on an "
3765 "EventList that no longer has full time "
3766 "information.");
3767 break;
3768 }
3769}
3770
3771//------------------------------------------------------------------------------------------------
3780template <class T>
3781void EventList::filterInPlaceHelper(Kernel::TimeSplitterType &splitter, typename std::vector<T> &events) {
3782 // Iterate through the splitter at the same time
3783 auto itspl = splitter.begin();
3784 auto itspl_end = splitter.end();
3785 DateAndTime start, stop;
3786
3787 // Iterate for the input
3788 auto itev = events.begin();
3789 auto itev_end = events.end();
3790
3791 // Iterator for the outputted list; will follow the input except when events
3792 // are dropped.
3793 auto itOut = events.begin();
3794
3795 // This is the time of the first section. Anything before is thrown out.
3796 while (itspl != itspl_end) {
3797 // Get the splitting interval times and destination
3798 start = itspl->start();
3799 stop = itspl->stop();
3800 const int index = itspl->index();
3801
3802 // Skip the events before the start of the time
3803 while ((itev != itev_end) && (itev->m_pulsetime < start))
3804 itev++;
3805
3806 // Are we aligned in the input vs output?
3807 bool copyingInPlace = (itOut == itev);
3808 if (copyingInPlace) {
3809 while ((itev != itev_end) && (itev->m_pulsetime < stop))
3810 ++itev;
3811 // Make sure the iterators still match
3812 itOut = itev;
3813 } else {
3814 // Go through all the events that are in the interval (if any)
3815 while ((itev != itev_end) && (itev->m_pulsetime < stop)) {
3816 if (index >= 0) {
3817 // Copy the input Event to the output iterator position.
3818 // Strictly speaking, this is not necessary if itOut == itev; but the
3819 // extra check would likely
3820 // slow down the filtering in the 99% of cases where itOut != itev.
3821 *itOut = *itev;
3822 // And go up a spot in the output iterator.
3823 ++itOut;
3824 }
3825 ++itev;
3826 }
3827 }
3828
3829 // Go to the next interval
3830 ++itspl;
3831 // But if we reached the end, then we are done.
3832 if (itspl == itspl_end)
3833 break;
3834
3835 // No need to keep looping through the filter if we are out of events
3836 if (itev == itev_end)
3837 break;
3838
3839 } // Looping through entries in the splitter vector
3840
3841 // Ok, now resize the event list to reflect the fact that it (probably) shrank
3842 events.resize((itOut - events.begin()));
3843}
3844
3845//------------------------------------------------------------------------------------------------
3853 // Start by sorting the event list by pulse time.
3854 this->sortPulseTime();
3855
3856 // Iterate through all events (sorted by pulse time)
3857 switch (eventType) {
3858 case TOF:
3859 filterInPlaceHelper(splitter, this->events);
3860 break;
3861 case WEIGHTED:
3862 filterInPlaceHelper(splitter, this->weightedEvents);
3863 break;
3864 case WEIGHTED_NOTIME:
3865 throw std::runtime_error("EventList::filterInPlace() called on an "
3866 "EventList that no longer has time information.");
3867 break;
3868 }
3869}
3870
3871//------------------------------------------------------------------------------------------------
3883template <class T>
3884void EventList::splitByTimeHelper(Kernel::TimeSplitterType &splitter, std::vector<EventList *> outputs,
3885 typename std::vector<T> &events) const {
3886 size_t numOutputs = outputs.size();
3887
3888 // Iterate through the splitter at the same time
3889 auto itspl = splitter.begin();
3890 auto itspl_end = splitter.end();
3891 DateAndTime start, stop;
3892
3893 // Iterate through all events (sorted by tof)
3894 auto itev = events.begin();
3895 auto itev_end = events.end();
3896
3897 // This is the time of the first section. Anything before is thrown out.
3898 while (itspl != itspl_end) {
3899 // Get the splitting interval times and destination
3900 start = itspl->start();
3901 stop = itspl->stop();
3902 const size_t index = itspl->index();
3903
3904 // Skip the events before the start of the time
3905 while ((itev != itev_end) && (itev->m_pulsetime < start))
3906 itev++;
3907
3908 // Go through all the events that are in the interval (if any)
3909 while ((itev != itev_end) && (itev->m_pulsetime < stop)) {
3910 // Copy the event into another
3911 const T eventCopy(*itev);
3912 if (index < numOutputs) {
3913 EventList *myOutput = outputs[index];
3914 // Add the copy to the output
3915 myOutput->addEventQuickly(eventCopy);
3916 }
3917 ++itev;
3918 }
3919
3920 // Go to the next interval
3921 ++itspl;
3922 // But if we reached the end, then we are done.
3923 if (itspl == itspl_end)
3924 break;
3925
3926 // No need to keep looping through the filter if we are out of events
3927 if (itev == itev_end)
3928 break;
3929 }
3930 // Done!
3931}
3932
3933//------------------------------------------------------------------------------------------------
3941void EventList::splitByTime(Kernel::TimeSplitterType &splitter, std::vector<EventList *> outputs) const {
3943 throw std::runtime_error("EventList::splitByTime() called on an EventList "
3944 "that no longer has time information.");
3945
3946 // Start by sorting the event list by pulse time.
3947 this->sortPulseTime();
3948
3949 // Initialize all the outputs
3950 size_t numOutputs = outputs.size();
3951 for (size_t i = 0; i < numOutputs; i++) {
3952 outputs[i]->clear();
3953 outputs[i]->setDetectorIDs(this->getDetectorIDs());
3954 outputs[i]->setHistogram(m_histogram);
3955 // Match the output event type.
3956 outputs[i]->switchTo(eventType);
3957 }
3958
3959 // Do nothing if there are no entries
3960 if (splitter.empty())
3961 return;
3962
3963 switch (eventType) {
3964 case TOF:
3965 splitByTimeHelper(splitter, outputs, this->events);
3966 break;
3967 case WEIGHTED:
3968 splitByTimeHelper(splitter, outputs, this->weightedEvents);
3969 break;
3970 case WEIGHTED_NOTIME:
3971 break;
3972 }
3973}
3974
3975//------------------------------------------------------------------------------------------------
3991template <class T>
3992void EventList::splitByFullTimeHelper(Kernel::TimeSplitterType &splitter, std::map<int, EventList *> outputs,
3993 typename std::vector<T> &events, bool docorrection, double toffactor,
3994 double tofshift) const {
3995 // 1. Prepare to Iterate through the splitter at the same time
3996 auto itspl = splitter.begin();
3997 auto itspl_end = splitter.end();
3998
3999 // 2. Prepare to Iterate through all events (sorted by tof)
4000 auto itev = events.begin();
4001 auto itev_end = events.end();
4002
4003 // 3. This is the time of the first section. Anything before is thrown out.
4004 while (itspl != itspl_end) {
4005 // Get the splitting interval times and destination
4006 int64_t start = itspl->start().totalNanoseconds();
4007 int64_t stop = itspl->stop().totalNanoseconds();
4008 const int index = itspl->index();
4009
4010 // a) Skip the events before the start of the time
4011 // TODO This step can be
4012 EventList *myOutput = outputs[-1];
4013 while (itev != itev_end) {
4014 int64_t fulltime;
4015 if (docorrection)
4016 fulltime = calculateCorrectedFullTime(*itev, toffactor, tofshift);
4017 else
4018 fulltime = itev->m_pulsetime.totalNanoseconds() + static_cast<int64_t>(itev->m_tof * 1000);
4019 if (fulltime < start) {
4020 // a1) Record to index = -1 space
4021 const T eventCopy(*itev);
4022 myOutput->addEventQuickly(eventCopy);
4023 itev++;
4024 } else {
4025 break;
4026 }
4027 }
4028
4029 // b) Go through all the events that are in the interval (if any)
4030 while (itev != itev_end) {
4031 int64_t fulltime;
4032 if (docorrection)
4033 fulltime = itev->m_pulsetime.totalNanoseconds() +
4034 static_cast<int64_t>(toffactor * itev->m_tof * 1000 + tofshift * 1.0E9);
4035 else
4036 fulltime = itev->m_pulsetime.totalNanoseconds() + static_cast<int64_t>(itev->m_tof * 1000);
4037 if (fulltime < stop) {
4038 // b1) Add a copy to the output
4039 outputs[index]->addEventQuickly(*itev);
4040 ++itev;
4041 } else {
4042 break;
4043 }
4044 }
4045
4046 // Go to the next interval
4047 ++itspl;
4048 // But if we reached the end, then we are done.
4049 if (itspl == itspl_end)
4050 break;
4051
4052 // No need to keep looping through the filter if we are out of events
4053 if (itev == itev_end)
4054 break;
4055 } // END-WHILE Splitter
4056}
4057
4058//------------------------------------------------------------------------------------------------
4070void EventList::splitByFullTime(Kernel::TimeSplitterType &splitter, std::map<int, EventList *> outputs,
4071 bool docorrection, double toffactor, double tofshift) const {
4073 throw std::runtime_error("EventList::splitByTime() called on an EventList "
4074 "that no longer has time information.");
4075
4076 // 1. Start by sorting the event list by pulse time.
4077 this->sortPulseTimeTOF();
4078
4079 // 2. Initialize all the outputs
4080 std::map<int, EventList *>::iterator outiter;
4081 for (outiter = outputs.begin(); outiter != outputs.end(); ++outiter) {
4082 EventList *opeventlist = outiter->second;
4083 opeventlist->clear();
4084 opeventlist->setDetectorIDs(this->getDetectorIDs());
4085 opeventlist->setHistogram(m_histogram);
4086 // Match the output event type.
4087 opeventlist->switchTo(eventType);
4088 }
4089
4090 // Do nothing if there are no entries
4091 if (splitter.empty()) {
4092 // 3A. Copy all events to group workspace = -1
4093 (*outputs[-1]) = (*this);
4094 // this->duplicate(outputs[-1]);
4095 } else {
4096 // 3B. Split
4097 switch (eventType) {
4098 case TOF:
4099 splitByFullTimeHelper(splitter, outputs, this->events, docorrection, toffactor, tofshift);
4100 break;
4101 case WEIGHTED:
4102 splitByFullTimeHelper(splitter, outputs, this->weightedEvents, docorrection, toffactor, tofshift);
4103 break;
4104 case WEIGHTED_NOTIME:
4105 break;
4106 }
4107 }
4108}
4109
4110//------------------------------------------------------------------------------------------------
4130template <class T>
4131std::string
4132EventList::splitByFullTimeVectorSplitterHelper(const std::vector<int64_t> &vectimes, const std::vector<int> &vecgroups,
4133 std::map<int, EventList *> outputs, typename std::vector<T> &vecEvents,
4134 bool docorrection, double toffactor, double tofshift) const {
4135 // Define variables for events
4136 // size_t numevents = events.size();
4137 typename std::vector<T>::iterator eviter;
4138 std::stringstream msgss;
4139
4140 // Loop through events
4141 for (eviter = vecEvents.begin(); eviter != vecEvents.end(); ++eviter) {
4142 // Obtain time of event
4143 int64_t evabstimens;
4144 if (docorrection)
4145 evabstimens = eviter->m_pulsetime.totalNanoseconds() +
4146 static_cast<int64_t>(toffactor * eviter->m_tof * 1000 + tofshift * 1.0E9);
4147 else
4148 evabstimens = eviter->m_pulsetime.totalNanoseconds() + static_cast<int64_t>(eviter->m_tof * 1000);
4149
4150 // Search in vector
4151 int index = static_cast<int>(lower_bound(vectimes.begin(), vectimes.end(), evabstimens) - vectimes.begin());
4152 int group;
4153 // FIXME - whether lower_bound() equal to vectimes.size()-1 should be
4154 // filtered out?
4155 if (index == 0 || index > static_cast<int>(vectimes.size() - 1)) {
4156 // Event is before first splitter or after last splitter. Put to -1
4157 group = -1;
4158 } else {
4159 group = vecgroups[index - 1];
4160 }
4161
4162 // Copy event to the proper group
4163 EventList *myOutput = outputs[group];
4164 if (!myOutput) {
4165 std::stringstream errss;
4166 errss << "Group " << group << " has a NULL output EventList. "
4167 << "\n";
4168 msgss << errss.str();
4169 } else {
4170 const T eventCopy(*eviter);
4171 myOutput->addEventQuickly(eventCopy);
4172 }
4173 }
4174
4175 return (msgss.str());
4176}
4177
4178//------------------------------------------------------------------------------------------------
4198template <class T>
4199std::string EventList::splitByFullTimeSparseVectorSplitterHelper(const std::vector<int64_t> &vectimes,
4200 const std::vector<int> &vecgroups,
4201 std::map<int, EventList *> outputs,
4202 typename std::vector<T> &vecEvents, bool docorrection,
4203 double toffactor, double tofshift) const {
4204 // Define variables for events
4205 // size_t numevents = events.size();
4206 // typename std::vector<T>::iterator eviter;
4207 std::stringstream msgss;
4208
4209 size_t num_splitters = vecgroups.size();
4210 // prepare to Iterate through all events (sorted by tof)
4211 auto iter_events = vecEvents.begin();
4212 auto iter_events_end = vecEvents.end();
4213
4214 // std::stringstream debug_ss;
4215 // debug_ss << "\nFilter events...:\n";
4216
4217 for (size_t i = 0; i < num_splitters; ++i) {
4218 // get one splitter
4219 int64_t start_i64 = vectimes[i];
4220 int64_t stop_i64 = vectimes[i + 1];
4221 int group = vecgroups[i];
4222 // debug_ss << "working on splitter: " << i << " from " << start_i64 << " to
4223 // " << stop_i64 << "\n";
4224
4225 // go over events
4226 while (iter_events != iter_events_end) {
4227 int64_t absolute_time;
4228 if (docorrection)
4229 absolute_time = iter_events->m_pulsetime.totalNanoseconds() +
4230 static_cast<int64_t>(toffactor * iter_events->m_tof * 1000 + tofshift * 1.0E9);
4231 else
4232 absolute_time = iter_events->m_pulsetime.totalNanoseconds() + static_cast<int64_t>(iter_events->m_tof * 1000);
4233
4234 // debug_ss << " event " << iter_events - vecEvents.begin() << " abs.time
4235 // = " << absolute_time << "\n";
4236
4237 if (absolute_time < start_i64) {
4238 // event occurs before the splitter. only can happen with first
4239 // splitter. Then ignore and move to next
4240 ++iter_events;
4241 continue;
4242 }
4243
4244 if (absolute_time < stop_i64) {
4245 // in the splitter, then copy the event into another
4246 const T eventCopy(*iter_events);
4247 // Copy event to the proper group
4248 EventList *myOutput = outputs[group];
4249 if (!myOutput) {
4250 // there is no such group defined. quit for this group
4251 std::stringstream errss;
4252 errss << "Group " << group << " has a NULL output EventList. "
4253 << "\n";
4254 msgss << errss.str();
4255 throw std::runtime_error(errss.str());
4256 }
4257 // Add the copy to the output
4258 myOutput->addEventQuickly(eventCopy);
4259 ++iter_events;
4260 } else {
4261 // event occurs after the stop time, it should belonged to the next
4262 // splitter
4263 break;
4264 }
4265 } // while
4266
4267 // quit the loop if there is no more event left
4268 if (iter_events == iter_events_end)
4269 break;
4270 } // for splitter
4271
4272 // std::cout << debug_ss.str();
4273
4274 return (msgss.str());
4275}
4276
4277//----------------------------------------------------------------------------------------------
4288// TODO/FIXME/NOW - Consider to use vector to replace vec_outputEventList and
4289// have an option to ignore the un-filtered events!
4290std::string EventList::splitByFullTimeMatrixSplitter(const std::vector<int64_t> &vec_splitters_time,
4291 const std::vector<int> &vecgroups,
4292 std::map<int, EventList *> vec_outputEventList, bool docorrection,
4293 double toffactor, double tofshift) const {
4294 // Check validity
4296 throw std::runtime_error("EventList::splitByTime() called on an EventList "
4297 "that no longer has time information.");
4298
4299 // Start by sorting the event list by pulse time, if its flag is not set up
4300 // right
4302
4303 // Initialize all the output event list
4304 std::map<int, EventList *>::iterator outiter;
4305 for (outiter = vec_outputEventList.begin(); outiter != vec_outputEventList.end(); ++outiter) {
4306 EventList *opeventlist = outiter->second;
4307 opeventlist->clear();
4308 opeventlist->setDetectorIDs(this->getDetectorIDs());
4309 opeventlist->setHistogram(m_histogram);
4310 // Match the output event type.
4311 opeventlist->switchTo(eventType);
4312 }
4313
4314 std::string debugmessage;
4315
4316 // Do nothing if there are no entries
4317 if (vecgroups.empty()) {
4318 // Copy all events to group workspace = -1
4319 (*vec_outputEventList[-1]) = (*this);
4320 // this->duplicate(outputs[-1]);
4321 } else {
4322 // Split
4323
4324 // Try to find out which filtering algorithm to use by comparing number of
4325 // splitters and number of events
4326 bool sparse_splitter = vec_splitters_time.size() < this->getNumberEvents();
4327
4328 switch (eventType) {
4329 case TOF:
4330 if (sparse_splitter)
4331 debugmessage = splitByFullTimeSparseVectorSplitterHelper(vec_splitters_time, vecgroups, vec_outputEventList,
4332 this->events, docorrection, toffactor, tofshift);
4333 else
4334 debugmessage = splitByFullTimeVectorSplitterHelper(vec_splitters_time, vecgroups, vec_outputEventList,
4335 this->events, docorrection, toffactor, tofshift);
4336 break;
4337 case WEIGHTED:
4338 if (sparse_splitter)
4339 debugmessage =
4340 splitByFullTimeSparseVectorSplitterHelper(vec_splitters_time, vecgroups, vec_outputEventList,
4341 this->weightedEvents, docorrection, toffactor, tofshift);
4342 else
4343 debugmessage = splitByFullTimeVectorSplitterHelper(vec_splitters_time, vecgroups, vec_outputEventList,
4344 this->weightedEvents, docorrection, toffactor, tofshift);
4345 break;
4346 case WEIGHTED_NOTIME:
4347 debugmessage = "TOF type is weighted no time. Impossible to split. ";
4348 break;
4349 }
4350 }
4351
4352 return debugmessage;
4353}
4354
4355//-------------------------------------------
4356//--------------------------------------------------
4359template <class T>
4360void EventList::splitByPulseTimeHelper(Kernel::TimeSplitterType &splitter, std::map<int, EventList *> outputs,
4361 typename std::vector<T> &events) const {
4362 // Prepare to TimeSplitter Iterate through the splitter at the same time
4363 auto itspl = splitter.begin();
4364 auto itspl_end = splitter.end();
4365 Types::Core::DateAndTime start, stop;
4366
4367 // Prepare to Events Iterate through all events (sorted by tof)
4368 auto itev = events.begin();
4369 auto itev_end = events.end();
4370
4371 // Iterate (loop) on all splitters
4372 while (itspl != itspl_end) {
4373 // Get the splitting interval times and destination group
4374 start = itspl->start().totalNanoseconds();
4375 stop = itspl->stop().totalNanoseconds();
4376 const int index = itspl->index();
4377
4378 // Skip the events before the start of the time and put to 'unfiltered'
4379 // EventList
4380 EventList *myOutput = outputs[-1];
4381 while (itev != itev_end) {
4382 if (itev->m_pulsetime < start) {
4383 // Record to index = -1 space
4384 const T eventCopy(*itev);
4385 myOutput->addEventQuickly(eventCopy);
4386 ++itev;
4387 } else {
4388 // Event within a splitter interval
4389 break;
4390 }
4391 }
4392
4393 // Go through all the events that are in the interval (if any)
4394 while (itev != itev_end) {
4395
4396 if (itev->m_pulsetime < stop) {
4397 outputs[index]->addEventQuickly(*itev);
4398 ++itev;
4399 } else {
4400 // Out of interval
4401 break;
4402 }
4403 }
4404
4405 // Go to the next interval
4406 ++itspl;
4407 // But if we reached the end, then we are done.
4408 if (itspl == itspl_end)
4409 break;
4410
4411 // No need to keep looping through the filter if we are out of events
4412 if (itev == itev_end)
4413 break;
4414 } // END-WHILE Splitter
4415}
4416
4417//----------------------------------------------------------------------------------------------
4420void EventList::splitByPulseTime(Kernel::TimeSplitterType &splitter, std::map<int, EventList *> outputs) const {
4421 // Check for supported event type
4423 throw std::runtime_error("EventList::splitByTime() called on an EventList "
4424 "that no longer has time information.");
4425
4426 // Start by sorting the event list by pulse time.
4427 this->sortPulseTimeTOF();
4428
4429 // Initialize all the output event lists
4430 std::map<int, EventList *>::iterator outiter;
4431 for (outiter = outputs.begin(); outiter != outputs.end(); ++outiter) {
4432 EventList *opeventlist = outiter->second;
4433 opeventlist->clear();
4434 opeventlist->setDetectorIDs(this->getDetectorIDs());
4435 opeventlist->setHistogram(m_histogram);
4436 // Match the output event type.
4437 opeventlist->switchTo(eventType);
4438 }
4439
4440 // Split
4441 if (splitter.empty()) {
4442 // No splitter: copy all events to group workspace = -1
4443 (*outputs[-1]) = (*this);
4444 } else {
4445 // Split
4446 switch (eventType) {
4447 case TOF:
4448 splitByPulseTimeHelper(splitter, outputs, this->events);
4449 break;
4450 case WEIGHTED:
4451 splitByPulseTimeHelper(splitter, outputs, this->weightedEvents);
4452 break;
4453 case WEIGHTED_NOTIME:
4454 break;
4455 }
4456 }
4457}
4458
4459//----------------------------------------------------------------------------------------------
4462// TODO/NOW - TEST
4463void EventList::splitByPulseTimeWithMatrix(const std::vector<int64_t> &vec_times, const std::vector<int> &vec_target,
4464 std::map<int, EventList *> outputs) const {
4465 // Check for supported event type
4467 throw std::runtime_error("EventList::splitByTime() called on an EventList "
4468 "that no longer has time information.");
4469
4470 // Start by sorting the event list by pulse time.
4471 this->sortPulseTimeTOF();
4472
4473 // Initialize all the output event lists
4474 std::map<int, EventList *>::iterator outiter;
4475 for (outiter = outputs.begin(); outiter != outputs.end(); ++outiter) {
4476 EventList *opeventlist = outiter->second;
4477 opeventlist->clear();
4478 opeventlist->setDetectorIDs(this->getDetectorIDs());
4479 opeventlist->setHistogram(m_histogram);
4480 // Match the output event type.
4481 opeventlist->switchTo(eventType);
4482 }
4483
4484 // Split
4485 if (vec_target.empty()) {
4486 // No splitter: copy all events to group workspace = -1
4487 (*outputs[-1]) = (*this);
4488 } else {
4489 // Split
4490 switch (eventType) {
4491 case TOF:
4492 splitByPulseTimeWithMatrixHelper(vec_times, vec_target, outputs, this->events);
4493 break;
4494 case WEIGHTED:
4495 splitByPulseTimeWithMatrixHelper(vec_times, vec_target, outputs, this->weightedEvents);
4496 break;
4497 case WEIGHTED_NOTIME:
4498 break;
4499 }
4500 }
4501}
4502
4503template <class T>
4504void EventList::splitByPulseTimeWithMatrixHelper(const std::vector<int64_t> &vec_split_times,
4505 const std::vector<int> &vec_split_target,
4506 std::map<int, EventList *> outputs,
4507 typename std::vector<T> &events) const {
4508 // Prepare to TimeSplitter Iterate through the splitter at the same time
4509 if (vec_split_times.size() != vec_split_target.size() + 1)
4510 throw std::runtime_error("Splitter time vector size and splitter target "
4511 "vector size are not correct.");
4512
4513 // Prepare to Events Iterate through all events (sorted by tof)
4514 auto itev = events.begin();
4515 auto itev_end = events.end();
4516
4517 // Iterate (loop) on all splitters
4518 for (size_t i_target = 0; i_target < vec_split_target.size(); ++i_target) {
4519 // Get the splitting interval times and destination group
4520 int64_t start = vec_split_times[i_target];
4521 int64_t stop = vec_split_times[i_target + 1];
4522 const int index = vec_split_target[i_target];
4523
4524 // Skip the events before the start of the time and put to 'unfiltered'
4525 // EventList
4526 EventList *myOutput = outputs[-1];
4527 while (itev != itev_end) {
4528 if (itev->m_pulsetime < start) {
4529 // Record to index = -1 space
4530 const T eventCopy(*itev);
4531 myOutput->addEventQuickly(eventCopy);
4532 ++itev;
4533 } else {
4534 // Event within a splitter interval
4535 break;
4536 }
4537 }
4538
4539 // Go through all the events that are in the interval (if any)
4540 while (itev != itev_end) {
4541
4542 if (itev->m_pulsetime < stop) {
4543 outputs[index]->addEventQuickly(*itev);
4544 ++itev;
4545 } else {
4546 // Out of interval
4547 break;
4548 }
4549 }
4550
4551 // No need to keep looping through the filter if we are out of events
4552 if (itev == itev_end)
4553 break;
4554 } // END-WHILE Splitter
4555}
4556
4557//--------------------------------------------------------------------------
4567void getEventsFrom(EventList &el, std::vector<TofEvent> *&events) { events = &el.getEvents(); }
4568void getEventsFrom(const EventList &el, std::vector<TofEvent> const *&events) { events = &el.getEvents(); }
4569
4570//--------------------------------------------------------------------------
4580void getEventsFrom(EventList &el, std::vector<WeightedEvent> *&events) { events = &el.getWeightedEvents(); }
4581void getEventsFrom(const EventList &el, std::vector<WeightedEvent> const *&events) { events = &el.getWeightedEvents(); }
4582
4583//--------------------------------------------------------------------------
4593void getEventsFrom(EventList &el, std::vector<WeightedEventNoTime> *&events) { events = &el.getWeightedEventsNoTime(); }
4594void getEventsFrom(const EventList &el, std::vector<WeightedEventNoTime> const *&events) {
4595 events = &el.getWeightedEventsNoTime();
4596}
4597
4598//--------------------------------------------------------------------------
4606template <class T>
4607void EventList::convertUnitsViaTofHelper(typename std::vector<T> &events, Mantid::Kernel::Unit *fromUnit,
4608 Mantid::Kernel::Unit *toUnit) {
4609 auto itev = events.begin();
4610 auto itev_end = events.end();
4611 for (; itev != itev_end; itev++) {
4612 // Conver to TOF
4613 double tof = fromUnit->singleToTOF(itev->m_tof);
4614 // And back from TOF to whatever
4615 itev->m_tof = toUnit->singleFromTOF(tof);
4616 }
4617}
4618
4619//--------------------------------------------------------------------------
4628 // Check for initialized
4629 if (!fromUnit || !toUnit)
4630 throw std::runtime_error("EventList::convertUnitsViaTof(): one of the units is NULL!");
4631 if (!fromUnit->isInitialized())
4632 throw std::runtime_error("EventList::convertUnitsViaTof(): fromUnit is not initialized!");
4633 if (!toUnit->isInitialized())
4634 throw std::runtime_error("EventList::convertUnitsViaTof(): toUnit is not initialized!");
4635
4636 switch (eventType) {
4637 case TOF:
4638 convertUnitsViaTofHelper(this->events, fromUnit, toUnit);
4639 break;
4640 case WEIGHTED:
4641 convertUnitsViaTofHelper(this->weightedEvents, fromUnit, toUnit);
4642 break;
4643 case WEIGHTED_NOTIME:
4644 convertUnitsViaTofHelper(this->weightedEventsNoTime, fromUnit, toUnit);
4645 break;
4646 }
4647}
4648
4649//--------------------------------------------------------------------------
4656template <class T>
4657void EventList::convertUnitsQuicklyHelper(typename std::vector<T> &events, const double &factor, const double &power) {
4658 for (auto &event : events) {
4659 // Output unit = factor * (input) ^ power
4660 event.m_tof = factor * std::pow(event.m_tof, power);
4661 }
4662}
4663
4664//--------------------------------------------------------------------------
4670void EventList::convertUnitsQuickly(const double &factor, const double &power) {
4671 switch (eventType) {
4672 case TOF:
4673 convertUnitsQuicklyHelper(this->events, factor, power);
4674 break;
4675 case WEIGHTED:
4676 convertUnitsQuicklyHelper(this->weightedEvents, factor, power);
4677 break;
4678 case WEIGHTED_NOTIME:
4679 convertUnitsQuicklyHelper(this->weightedEventsNoTime, factor, power);
4680 break;
4681 }
4682}
4683
4684HistogramData::Histogram &EventList::mutableHistogramRef() {
4685 if (mru)
4686 mru->deleteIndex(this);
4687 return m_histogram;
4688}
4689
4690void EventList::checkAndSanitizeHistogram(HistogramData::Histogram &histogram) {
4691 if (histogram.xMode() != HistogramData::Histogram::XMode::BinEdges)
4692 throw std::runtime_error("EventList: setting histogram with storage mode "
4693 "other than BinEdges is not possible");
4694 if (histogram.sharedY() || histogram.sharedE())
4695 throw std::runtime_error("EventList: setting histogram data with non-null "
4696 "Y or E data is not possible");
4697 // Avoid flushing of YMode: we only change X but YMode depends on events.
4698 if (histogram.yMode() == HistogramData::Histogram::YMode::Uninitialized)
4699 histogram.setYMode(m_histogram.yMode());
4700 if (histogram.yMode() != m_histogram.yMode())
4701 throw std::runtime_error("EventList: setting histogram data with different "
4702 "YMode is not possible");
4703}
4704
4706 throw std::runtime_error("EventList: setting Points as X data is not "
4707 "possible, only BinEdges are supported");
4708}
4709
4711 throw std::runtime_error("EventList: Cannot set Y or E data, these data are "
4712 "generated automatically based on the events");
4713}
4714
4715} // namespace Mantid::DataObjects
gsl_vector * tmp
const std::vector< double > & rhs
const double m_tofFactor
Definition: EventList.cpp:65
const double m_tofShift
Definition: EventList.cpp:66
double value
The value of the point.
Definition: FitMW.cpp:51
double error
Definition: IndexPeaks.cpp:133
std::map< DeltaEMode::Type, std::string > index
Definition: DeltaEMode.cpp:19
#define PARALLEL_THREAD_NUMBER
#define PARALLEL_FOR_NO_WSP_CHECK()
#define PARALLEL_GET_MAX_THREADS
double tolerance
IEventList : Interface to Mantid::DataObjects::EventList class, used to expose to PythonAPI.
Definition: IEventList.h:26
A "spectrum" is an object that holds the data for a particular spectrum, in particular:
Definition: ISpectrum.h:39
void setHistogram(T &&...data)
Sets the Histogram associated with this spectrum.
Definition: ISpectrum.h:97
void addDetectorIDs(const std::set< detid_t > &detIDs)
Add a set of detector IDs to the set of detector IDs.
Definition: ISpectrum.cpp:62
virtual const MantidVec & readX() const =0
void setDetectorIDs(const std::set< detid_t > &detIDs)
Set the detector IDs to be the set given.
Definition: ISpectrum.cpp:94
virtual const MantidVec & readE() const
Deprecated, use e() instead. Returns the y error data const.
Definition: ISpectrum.cpp:45
void clearDetectorIDs()
Clear the detector IDs set.
Definition: ISpectrum.cpp:117
void copyInfoFrom(const ISpectrum &other)
Copy spectrum number and detector IDs, but not X vector, from another ISpectrum.
Definition: ISpectrum.cpp:24
virtual const MantidVec & readY() const
Deprecated, use y() instead. Returns the y data const.
Definition: ISpectrum.cpp:42
const std::set< detid_t > & getDetectorIDs() const
Get a const reference to the detector IDs set.
Definition: ISpectrum.cpp:113
virtual void copyDataInto(DataObjects::EventList &) const
Override in child classes for polymorphic copying of data.
Definition: ISpectrum.cpp:201
virtual Kernel::cow_ptr< HistogramData::HistogramX > ptrX() const =0
HistogramData::HistogramX & mutableX() &
Definition: ISpectrum.h:176
A class for holding :
Definition: EventList.h:56
void sortTimeAtSample(const double &tofFactor, const double &tofShift, bool forceResort=false) const
Sort events by time at sample.
Definition: EventList.cpp:982
size_t getMemorySize() const override
Memory used by this event list.
Definition: EventList.cpp:1177
static void getWeightErrorsHelper(const std::vector< T > &events, std::vector< double > &weightErrors)
Get the weight error member of all events in a list.
Definition: EventList.cpp:2814
void addPulsetimes(const std::vector< double > &seconds) override
Add an offset to the pulsetime (wall-clock time) of each event in the list.
Definition: EventList.cpp:2550
void convertUnitsViaTof(Mantid::Kernel::Unit *fromUnit, Mantid::Kernel::Unit *toUnit)
Converts the X units in each event by going through TOF.
Definition: EventList.cpp:4627
Mantid::Types::Core::DateAndTime getTimeAtSampleMax(const double &tofFactor, const double &tofOffset) const override
Get the maximum time at sample.
Definition: EventList.cpp:3120
std::vector< Mantid::Types::Core::DateAndTime > getPulseTimes() const override
Get the pulse times of each event in this EventList.
Definition: EventList.cpp:2872
void setTofs(const MantidVec &tofs) override
Set a list of TOFs to the current event list.
Definition: EventList.cpp:3226
void compressEventsParallelHelper(const std::vector< T > &events, std::vector< WeightedEventNoTime > &out, double tolerance)
Compress the event list by grouping events with the same TOF.
Definition: EventList.cpp:1485
void maskTof(const double tofMin, const double tofMax) override
Mask out events that have a tof between tofMin and tofMax (inclusively).
Definition: EventList.cpp:2619
void multiply(const double value, const double error=0.0) override
Multiply the weights in this event list by a scalar variable with an error; though the error can be 0...
Definition: EventList.cpp:3324
void checkWorksWithPoints() const override
Definition: EventList.cpp:4705
HistogramData::CountStandardDeviations countStandardDeviations() const override
Definition: EventList.cpp:1282
void switchToWeightedEvents()
Switch the EventList to use WeightedEvents instead of TofEvent.
Definition: EventList.cpp:675
EventList & operator=(const EventList &)
Copy into this event list from another.
Definition: EventList.cpp:309
void compressFatEvents(const double tolerance, const Types::Core::DateAndTime &timeStart, const double seconds, EventList *destination)
Definition: EventList.cpp:1727
HistogramData::Histogram & mutableHistogramRef() override
Definition: EventList.cpp:4684
HistogramData::Counts counts() const override
Definition: EventList.cpp:1278
std::vector< double > getWeights() const override
Return the list of event weight values.
Definition: EventList.cpp:2801
void convertUnitsViaTofHelper(typename std::vector< T > &events, Mantid::Kernel::Unit *fromUnit, Mantid::Kernel::Unit *toUnit)
Helper function for the conversion to TOF.
Definition: EventList.cpp:4607
void convertUnitsQuickly(const double &factor, const double &power)
Convert the event's TOF (x) value according to a simple output = a * (input^b) relationship.
Definition: EventList.cpp:4670
EventList()
Constructor (empty)
Definition: EventList.cpp:140
void compressEvents(double tolerance, EventList *destination)
Compress the event list by grouping events with the same TOF (within a given tolerance).
Definition: EventList.cpp:1676
double getTofMax() const override
Definition: EventList.cpp:2940
virtual size_t histogram_size() const
Return the size of the histogram data.
Definition: EventList.cpp:1192
HistogramData::Histogram histogram() const override
Returns the Histogram associated with this spectrum.
Definition: EventList.cpp:1271
void generateHistogram(const MantidVec &X, MantidVec &Y, MantidVec &E, bool skipError=false) const override
Generates both the Y and E (error) histograms w.r.t TOF for an EventList with or without WeightedEven...
Definition: EventList.cpp:2010
static void filterByTimeAtSampleHelper(std::vector< T > &events, Types::Core::DateAndTime start, Types::Core::DateAndTime stop, double tofFactor, double tofOffset, std::vector< T > &output)
~EventList() override
Destructor.
Definition: EventList.cpp:190
std::vector< Types::Event::TofEvent > & getEvents()
Return the list of TofEvents contained.
Definition: EventList.cpp:780
std::vector< WeightedEventNoTime > weightedEventsNoTime
List of WeightedEvent's.
Definition: EventList.h:339
void splitByTimeHelper(Kernel::TimeSplitterType &splitter, std::vector< EventList * > outputs, typename std::vector< T > &events) const
Split the event list into n outputs, operating on a vector of either TofEvent's or WeightedEvent's On...
Definition: EventList.cpp:3884
HistogramData::FrequencyStandardDeviations frequencyStandardDeviations() const override
Definition: EventList.cpp:1290
void setSortOrder(const EventSortType order) const
Manually set the event list sort order value.
Definition: EventList.cpp:943
HistogramData::Histogram m_histogram
Histogram object holding the histogram data. Currently only X.
Definition: EventList.h:330
void generateCountsHistogramPulseTime(const double &xMin, const double &xMax, MantidVec &Y, const double TofMin=std::numeric_limits< double >::lowest(), const double TofMax=std::numeric_limits< double >::max()) const
With respect to PulseTime fill a histogram given equal histogram bins.
Definition: EventList.cpp:2114
void generateErrorsHistogram(const MantidVec &Y, MantidVec &E) const
Generate the Error histogram for the provided counts histogram.
Definition: EventList.cpp:2257
double getTofMin() const override
Definition: EventList.cpp:2896
static void compressEventsHelper(const std::vector< T > &events, std::vector< WeightedEventNoTime > &out, double tolerance)
Compress the event list by grouping events with the same TOF.
Definition: EventList.cpp:1410
static void getPulseTimesHelper(const std::vector< T > &events, std::vector< Mantid::Types::Core::DateAndTime > &times)
Get the pulsetimes of all events in a list.
Definition: EventList.cpp:2860
Mantid::API::EventType eventType
What type of event is in our list.
Definition: EventList.h:342
EventSortType getSortType() const
Return the type of sorting used in this event list.
Definition: EventList.cpp:1104
void filterByTimeAtSample(Types::Core::DateAndTime start, Types::Core::DateAndTime stop, double tofFactor, double tofOffset, EventList &output) const
Definition: EventList.cpp:3739
void switchToWeightedEventsNoTime()
Switch the EventList to use WeightedEventNoTime's instead of TofEvent.
Definition: EventList.cpp:703
static void setTofsHelper(std::vector< T > &events, const std::vector< double > &tofs)
Set a list of TOFs to the current event list.
Definition: EventList.cpp:3208
void addTof(const double offset) override
Add an offset to the TOF of each event in the list.
Definition: EventList.cpp:2491
bool equals(const EventList &rhs, const double tolTof, const double tolWeight, const int64_t tolPulse) const
Definition: EventList.cpp:602
Kernel::cow_ptr< HistogramData::HistogramE > sharedE() const override
Definition: EventList.cpp:1336
static std::size_t maskConditionHelper(std::vector< T > &events, const std::vector< bool > &mask)
Mask out events by the condition vector.
Definition: EventList.cpp:2659
EventList & operator/=(const double value)
Operator to divide the weights in this EventList by an error-less scalar.
Definition: EventList.cpp:3616
void checkAndSanitizeHistogram(HistogramData::Histogram &histogram) override
Definition: EventList.cpp:4690
void copyDataInto(EventList &sink) const override
Used by copyDataFrom for dynamic dispatch for its source.
Definition: EventList.cpp:205
const HistogramData::HistogramY & y() const override
Definition: EventList.cpp:1294
HistogramData::Frequencies frequencies() const override
Definition: EventList.cpp:1286
std::vector< Types::Event::TofEvent > events
List of TofEvent (no weights).
Definition: EventList.h:333
std::size_t getNumberEvents() const override
Return the number of events in the list.
Definition: EventList.cpp:1143
void splitByFullTime(Kernel::TimeSplitterType &splitter, std::map< int, EventList * > outputs, bool docorrection, double toffactor, double tofshift) const
Split the event list into n outputs by event's full time (tof + pulse time)
Definition: EventList.cpp:4070
void generateCountsHistogram(const MantidVec &X, MantidVec &Y) const
Fill a histogram given specified histogram bounds.
Definition: EventList.cpp:2213
Mantid::API::EventType getEventType() const override
Return the type of Event vector contained within.
Definition: EventList.cpp:643
const MantidVec & readDx() const override
Deprecated, use dx() instead.
Definition: EventList.cpp:1239
void scaleTof(const double factor) override
Convert the units in the TofEvent's m_tof field to some other value, by scaling by a multiplier.
Definition: EventList.cpp:2484
void getPulseTimeMinMax(Mantid::Types::Core::DateAndTime &tMin, Mantid::Types::Core::DateAndTime &tM) const
Definition: EventList.cpp:3070
static void multiplyHelper(std::vector< T > &events, const double value, const double error=0.0)
Helper method for multiplying an event list by a scalar value with/without error.
Definition: EventList.cpp:3255
HistogramData::FrequencyVariances frequencyVariances() const override
Definition: EventList.cpp:1288
std::vector< WeightedEventNoTime > & getWeightedEventsNoTime()
Return the list of WeightedEvent contained.
Definition: EventList.cpp:823
void setMRU(EventWorkspaceMRU *newMRU)
Sets the MRU list for this event list.
Definition: EventList.cpp:886
EventWorkspaceMRU * mru
MRU lists of the parent EventWorkspace.
Definition: EventList.h:348
static void integrateHelper(std::vector< T > &events, const double minX, const double maxX, const bool entireRange, double &sum, double &error)
Integrate the events between a range of X values, or all events.
Definition: EventList.cpp:2293
void filterInPlace(Kernel::TimeSplitterType &splitter)
Use a TimeSplitterType to filter the event list in place.
Definition: EventList.cpp:3852
static void multiplyHistogramHelper(std::vector< T > &events, const MantidVec &X, const MantidVec &Y, const MantidVec &E)
Helper method for multiplying an event list by a histogram with error.
Definition: EventList.cpp:3355
Mantid::Types::Core::DateAndTime getPulseTimeMax() const override
Definition: EventList.cpp:3029
Kernel::cow_ptr< HistogramData::HistogramX > ptrX() const override
Deprecated, use sharedX() instead. Returns a pointer to the x data.
Definition: EventList.cpp:1232
MantidVec & dataX() override
Deprecated, use mutableX() instead.
Definition: EventList.cpp:1218
void clearUnused()
Clear any unused event lists (the ones that do not match the currently used type).
Definition: EventList.cpp:864
MantidVec & dataDx() override
Deprecated, use mutableDx() instead.
Definition: EventList.cpp:1235
bool operator==(const EventList &rhs) const
Equality operator between EventList's.
Definition: EventList.cpp:581
EventSortType order
Last sorting order.
Definition: EventList.h:345
void convertTofHelper(std::vector< T > &events, const std::function< double(double)> &func)
Definition: EventList.cpp:2423
void clearData() override
Mask the spectrum to this value. Removes all events.
Definition: EventList.cpp:880
EventList & operator+=(const Types::Event::TofEvent &event)
std::string splitByFullTimeVectorSplitterHelper(const std::vector< int64_t > &vectimes, const std::vector< int > &vecgroups, std::map< int, EventList * > outputs, typename std::vector< T > &vecEvents, bool docorrection, double toffactor, double tofshift) const
Split the event list into n outputs, operating on a vector of either TofEvent's or WeightedEvent's Th...
Definition: EventList.cpp:4132
static void minusHelper(std::vector< T1 > &events, const std::vector< T2 > &more_events)
SUBTRACT another EventList from this event list.
Definition: EventList.cpp:502
void splitByPulseTimeHelper(Kernel::TimeSplitterType &splitter, std::map< int, EventList * > outputs, typename std::vector< T > &events) const
Split events by pulse time.
Definition: EventList.cpp:4360
void addPulsetimesHelper(std::vector< T > &events, const std::vector< double > &seconds)
Add an offset per event to the pulsetime (wall-clock time) of each event in the list.
Definition: EventList.cpp:2512
void filterInPlaceHelper(Kernel::TimeSplitterType &splitter, typename std::vector< T > &events)
Perform an in-place filtering on a vector of either TofEvent's or WeightedEvent's.
Definition: EventList.cpp:3781
void addPulsetime(const double seconds) override
Add an offset to the pulsetime (wall-clock time) of each event in the list.
Definition: EventList.cpp:2525
void reserve(size_t num) override
Reserve a certain number of entries in event list of the specified eventType.
Definition: EventList.cpp:895
void setX(const Kernel::cow_ptr< HistogramData::HistogramX > &X) override
Deprecated, use setSharedX() instead.
Definition: EventList.cpp:1209
std::vector< double > getWeightErrors() const override
Return the list of event weight error values.
Definition: EventList.cpp:2847
void sortTof() const
Sort events by TOF in one thread.
Definition: EventList.cpp:947
HistogramData::CountVariances countVariances() const override
Definition: EventList.cpp:1280
std::string splitByFullTimeSparseVectorSplitterHelper(const std::vector< int64_t > &vectimes, const std::vector< int > &vecgroups, std::map< int, EventList * > outputs, typename std::vector< T > &vecEvents, bool docorrection, double toffactor, double tofshift) const
Split the event list into n outputs, operating on a vector of either TofEvent's or WeightedEvent's Th...
Definition: EventList.cpp:4199
MantidVec & dataE() override
Deprecated, use mutableE() instead.
Definition: EventList.h:183
void splitByPulseTime(Kernel::TimeSplitterType &splitter, std::map< int, EventList * > outputs) const
Split events by pulse time.
Definition: EventList.cpp:4420
static void compressFatEventsHelper(const std::vector< T > &events, std::vector< WeightedEvent > &out, const double tolerance, const Mantid::Types::Core::DateAndTime &timeStart, const double seconds)
MantidVec & dataY() override
Deprecated, use mutableY() instead.
Definition: EventList.h:180
Mantid::Types::Core::DateAndTime getTimeAtSampleMin(const double &tofFactor, const double &tofOffset) const override
Get the minimum time at sample.
Definition: EventList.cpp:3161
const HistogramData::HistogramE & e() const override
Definition: EventList.cpp:1300
bool isSortedByTof() const override
Return true if the event list is sorted by TOF.
Definition: EventList.cpp:1100
bool operator!=(const EventList &rhs) const
Inequality comparator.
Definition: EventList.cpp:600
std::mutex m_sortMutex
Mutex that is locked while sorting an event list.
Definition: EventList.h:351
static void filterByPulseTimeHelper(std::vector< T > &events, Types::Core::DateAndTime start, Types::Core::DateAndTime stop, std::vector< T > &output)
void generateCountsHistogramTimeAtSample(const MantidVec &X, MantidVec &Y, const double &tofFactor, const double &tofOffset) const
With respect to Time at Sample, fill a histogram given specified histogram bounds.
Definition: EventList.cpp:2148
void reverse()
Reverse the histogram boundaries and the associated events if they are sorted by time-of-flight.
Definition: EventList.cpp:1112
void switchTo(Mantid::API::EventType newType) override
Switch the EventList to use the given EventType (TOF, WEIGHTED, or WEIGHTED_NOTIME)
Definition: EventList.cpp:649
void splitByPulseTimeWithMatrix(const std::vector< int64_t > &vec_times, const std::vector< int > &vec_target, std::map< int, EventList * > outputs) const
Split events by pulse time with Matrix splitters.
Definition: EventList.cpp:4463
static void divideHistogramHelper(std::vector< T > &events, const MantidVec &X, const MantidVec &Y, const MantidVec &E)
Helper method for dividing an event list by a histogram with error.
Definition: EventList.cpp:3480
static void histogramForWeightsHelper(const std::vector< T > &events, const MantidVec &X, MantidVec &Y, MantidVec &E)
Generates both the Y and E (error) histograms for an EventList with WeightedEvents.
Definition: EventList.cpp:1854
bool empty() const
Much like stl containers, returns true if there is nothing in the event list.
Definition: EventList.cpp:1158
std::vector< WeightedEvent > weightedEvents
List of WeightedEvent's.
Definition: EventList.h:336
const MantidVec & readX() const override
Deprecated, use x() instead. Returns the x data const.
Definition: EventList.cpp:1229
WeightedEvent getEvent(size_t event_number)
Return the given event in the list.
Definition: EventList.cpp:740
void integrate(const double minX, const double maxX, const bool entireRange, double &sum, double &error) const
Integrate the events between a range of X values, or all events.
Definition: EventList.cpp:2354
Kernel::cow_ptr< HistogramData::HistogramY > sharedY() const override
Definition: EventList.cpp:1306
void generateHistogramTimeAtSample(const MantidVec &X, MantidVec &Y, MantidVec &E, const double &tofFactor, const double &tofOffset, bool skipError=false) const override
Generates both the Y and E (error) histograms w.r.t Time at sample position.
Definition: EventList.cpp:1978
void createFromHistogram(const ISpectrum *inSpec, bool GenerateZeros, bool GenerateMultipleEvents, int MaxEventsPerBin)
Create an EventList from a histogram.
Definition: EventList.cpp:229
void convertUnitsQuicklyHelper(typename std::vector< T > &events, const double &factor, const double &power)
Convert the event's TOF (x) value according to a simple output = a * (input^b) relationship.
Definition: EventList.cpp:4657
void splitByFullTimeHelper(Kernel::TimeSplitterType &splitter, std::map< int, EventList * > outputs, typename std::vector< T > &events, bool docorrection, double toffactor, double tofshift) const
Split the event list into n outputs, operating on a vector of either TofEvent's or WeightedEvent's Th...
Definition: EventList.cpp:3992
MantidVec * makeDataE() const
Calculates and returns a pointer to the E histogrammed data.
Definition: EventList.cpp:1263
std::string splitByFullTimeMatrixSplitter(const std::vector< int64_t > &vec_splitters_time, const std::vector< int > &vecgroups, std::map< int, EventList * > vec_outputEventList, bool docorrection, double toffactor, double tofshift) const
Split ...
Definition: EventList.cpp:4290
void checkIsYAndEWritable() const override
Definition: EventList.cpp:4710
void generateHistogramPulseTime(const MantidVec &X, MantidVec &Y, MantidVec &E, bool skipError=false) const override
Generates both the Y and E (error) histograms w.r.t Pulse Time for an EventList with or without Weigh...
Definition: EventList.cpp:1946
void copyDataFrom(const ISpectrum &source) override
Copy data from another EventList, via ISpectrum reference.
Definition: EventList.cpp:202
void splitByTime(Kernel::TimeSplitterType &splitter, std::vector< EventList * > outputs) const
Split the event list into n outputs.
Definition: EventList.cpp:3941
void filterByPulseTime(Types::Core::DateAndTime start, Types::Core::DateAndTime stop, EventList &output) const
Filter this EventList into an output EventList, using keeping only events within the >= start and < e...
Definition: EventList.cpp:3709
void addPulsetimeHelper(std::vector< T > &events, const double seconds)
Add an offset to the pulsetime (wall-clock time) of each event in the list.
Definition: EventList.cpp:2499
std::vector< double > getTofs() const override
Get the times-of-flight of each event in this EventList.
Definition: EventList.cpp:2756
EventList & operator*=(const double value)
Operator to multiply the weights in this EventList by an error-less scalar.
Definition: EventList.cpp:3290
void convertTof(std::function< double(double)> func, const int sorting=0) override
Definition: EventList.cpp:2390
Mantid::Types::Core::DateAndTime getPulseTimeMin() const override
Definition: EventList.cpp:2985
static void getWeightsHelper(const std::vector< T > &events, std::vector< double > &weights)
Get the weight member of all events in a list.
Definition: EventList.cpp:2768
void maskCondition(const std::vector< bool > &mask) override
Mask out events by the condition vector.
Definition: EventList.cpp:2687
void sortPulseTime() const
Sort events by Frame.
Definition: EventList.cpp:1014
std::vector< T >::const_iterator findFirstTimeAtSampleEvent(const std::vector< T > &events, const double seek_time, const double &tofFactor, const double &tofOffset) const
Utility function: Returns the iterator into events of the first TofEvent with time at sample > seek_t...
Definition: EventList.cpp:1815
void sortPulseTimeTOFDelta(const Types::Core::DateAndTime &start, const double seconds) const
Sort by the pulse time with a tolerance.
Definition: EventList.cpp:1077
void splitByPulseTimeWithMatrixHelper(const std::vector< int64_t > &vec_split_times, const std::vector< int > &vec_split_target, std::map< int, EventList * > outputs, typename std::vector< T > &events) const
Split events (template) by pulse time with matrix splitters.
Definition: EventList.cpp:4504
static std::size_t maskTofHelper(std::vector< T > &events, const double tofMin, const double tofMax)
Mask out events that have a tof between tofMin and tofMax (inclusively).
Definition: EventList.cpp:2582
void addEventQuickly(const Types::Event::TofEvent &event)
Append an event to the histogram, without clearing the cache, to make it faster.
Definition: EventList.h:104
static std::vector< T >::const_iterator findFirstPulseEvent(const std::vector< T > &events, const double seek_pulsetime)
Utility function: Returns the iterator into events of the first TofEvent with pulsetime() > seek_puls...
Definition: EventList.cpp:1787
EventList & operator-=(const EventList &more_events)
SUBTRACT another EventList from this event list.
Definition: EventList.cpp:524
void sort(const EventSortType order) const
Sort events by TOF or Frame.
Definition: EventList.cpp:917
MantidVec * makeDataY() const
Calculates and returns a pointer to the Y histogrammed data.
Definition: EventList.cpp:1250
static void getTofsHelper(const std::vector< T > &events, std::vector< double > &tofs)
Get the m_tof member of all events in a list.
Definition: EventList.cpp:2725
void clear(const bool removeDetIDs=true) override
Clear the list of events and any associated detector ID's.
Definition: EventList.cpp:847
std::vector< WeightedEvent > & getWeightedEvents()
Return the list of WeightedEvent contained.
Definition: EventList.cpp:795
void divide(const double value, const double error=0.0) override
Divide the weights in this event list by a scalar with an (optional) error.
Definition: EventList.cpp:3633
This is a container for the MRU (most-recently-used) list of generated histograms.
void insertY(size_t thread_num, YType data, const EventList *index)
Insert a new histogram into the MRU.
EType findE(size_t thread_num, const EventList *index)
Find a Y histogram in the MRU.
void insertE(size_t thread_num, EType data, const EventList *index)
Insert a new histogram into the MRU.
void ensureEnoughBuffersE(size_t thread_num) const
This function makes sure that there are enough data buffers (MRU's) for E for the number of threads r...
YType findY(size_t thread_num, const EventList *index)
Find a Y histogram in the MRU.
void deleteIndex(const EventList *index)
Delete any entries in the MRU at the given index.
void ensureEnoughBuffersY(size_t thread_num) const
This function makes sure that there are enough data buffers (MRU's) for Y for the number of threads r...
1D histogram implementation.
Definition: Histogram1D.h:18
Info about a single neutron detection event, including a weight and error value, but excluding the pu...
Definition: Events.h:91
Info about a single neutron detection event, including a weight and error value:
Definition: Events.h:39
The base units (abstract) class.
Definition: Unit.h:41
virtual double singleToTOF(const double x) const =0
Convert a single X value to TOF.
virtual double singleFromTOF(const double tof) const =0
Convert a single tof value to this unit.
bool isInitialized() const
Definition: Unit.h:176
Implements a copy on write data template.
Definition: cow_ptr.h:41
EventType
What kind of event list is being stored.
Definition: IEventList.h:18
@ WEIGHTED_NOTIME
Definition: IEventList.h:18
std::size_t numEvents(::NeXus::File &file, bool &hasTotalCounts, bool &oldNeXusFileNames, const std::string &prefix, const NexusHDF5Descriptor &descriptor)
Get the number of events in the currently opened group.
DLLExport void getEventsFrom(EventList &el, std::vector< Types::Event::TofEvent > *&events)
bool compareEventPulseTime(const TofEvent &e1, const TofEvent &e2)
Compare two events' FRAME id, return true if e1 should be before e2.
Definition: EventList.cpp:95
static std::vector< T >::const_iterator findFirstEvent(const std::vector< T > &events, T seek_tof)
Utility function: Returns the iterator into events of the first TofEvent with tof() > seek_tof Will r...
Definition: EventList.cpp:1772
EventSortType
How the event list is sorted.
Definition: EventList.h:31
bool compareEventPulseTimeTOF(const TofEvent &e1, const TofEvent &e2)
Compare two events' FRAME id, return true if e1 should be before e2.
Definition: EventList.cpp:103
MANTID_KERNEL_DLL Types::Core::DateAndTime averageSorted(const std::vector< Types::Core::DateAndTime > &times)
averageSorted Assuming that the vector is sorted, find the average time
std::vector< SplittingInterval > TimeSplitterType
A typedef for splitting events according their pulse time.
Definition: LogManager.h:31
std::vector< double > MantidVec
typedef for the data storage used in Mantid matrix workspaces
Definition: cow_ptr.h:172
int32_t specnum_t
Typedef for a spectrum Number.
Definition: IDTypes.h:16
bool operator()(const TofEvent &e1, const TofEvent &e2)
Definition: EventList.cpp:119
comparePulseTimeTOFDelta(const Types::Core::DateAndTime &start, const double seconds)
Definition: EventList.cpp:116