Newer
Older
#include <stdexcept>
Peterson, Peter
committed
#include "MantidDataObjects/EventList.h"
Peterson, Peter
committed
#include "MantidKernel/Exception.h"
Janik Zikovsky
committed
#include "MantidKernel/DateAndTime.h"
Janik Zikovsky
committed
#include <functional>
Peterson, Peter
committed
using std::runtime_error;
Peterson, Peter
committed
using std::size_t;
using std::vector;
namespace Mantid
{
namespace DataObjects
{
Janik Zikovsky
committed
using Kernel::Exception::NotImplementedError;
Janik Zikovsky
committed
using Kernel::DateAndTime;
Peterson, Peter
committed
Janik Zikovsky
committed
Janik Zikovsky
committed
//==========================================================================
/// --------------------- TofEvent Comparators ----------------------------------
Janik Zikovsky
committed
//==========================================================================
/** Compare two events' TOF, return true if e1 should be before e2.
* @param e1 first event
* @param e2 second event
* */
Janik Zikovsky
committed
bool compareEventTof(const TofEvent & e1, const TofEvent& e2)
{
return (e1.tof() < e2.tof());
}
Janik Zikovsky
committed
/** Compare two events' FRAME id, return true if e1 should be before e2.
* @param e1 first event
* @param e2 second event
* */
Janik Zikovsky
committed
bool compareEventPulseTime(const TofEvent& e1, const TofEvent& e2)
Janik Zikovsky
committed
return (e1.pulseTime() < e2.pulseTime());
Janik Zikovsky
committed
// /** Comparison operator by TOF for TofEvents) */
// bool operator<(const TofEvent & e1, const TofEvent& e2)
// {
// return (e1.tof() < e2.tof());
// }
//
// /** Comparison operator by TOF for TofEvents) */
// bool operator>(const TofEvent & e1, const TofEvent& e2)
// {
// return (e1.tof() > e2.tof());
// }
//
// /** Comparison operator by TOF for TofEvents) */
// bool operator<(const WeightedEvent & e1, const WeightedEvent& e2)
// {
// return (e1.tof() < e2.tof());
// }
Janik Zikovsky
committed
//==========================================================================
/** Unary function for searching the event list.
* Returns true if the event's TOF is >= a value
* @param event the event being checked.
*/
class tofGreaterOrEqual: std::unary_function<TofEvent, double>
{
Janik Zikovsky
committed
double m_value;
public:
/// Constructor: save the value
tofGreaterOrEqual(double value): m_value(value)
{ }
/// () operator: return true if event.tof >= value
bool operator()(TofEvent event)
{
Janik Zikovsky
committed
return event.m_tof >= m_value;
Janik Zikovsky
committed
}
};
//==========================================================================
/** Unary function for searching the event list.
* Returns true if the event's TOF is > a value
* @param event the event being checked.
*/
class tofGreater: std::unary_function<TofEvent, double>
{
Janik Zikovsky
committed
double m_value;
public:
/// Constructor: save the value
tofGreater(double value): m_value(value)
{ }
/// () operator: return true if event.tof > value
bool operator()(TofEvent event)
{
Janik Zikovsky
committed
return event.m_tof > m_value;
Janik Zikovsky
committed
}
};
Janik Zikovsky
committed
//==========================================================================
// ---------------------- EventList stuff ----------------------------------
//==========================================================================
// --- Constructors -------------------------------------------------------------------
Janik Zikovsky
committed
/// Constructor (empty)
Janik Zikovsky
committed
EventList::EventList() :
Janik Zikovsky
committed
has_weights(false), order(UNSORTED), detectorIDs()
Peterson, Peter
committed
{
}
Janik Zikovsky
committed
/** Constructor copying from an existing event list
* @param rhs EventList object to copy*/
Peterson, Peter
committed
EventList::EventList(const EventList& rhs)
Peterson, Peter
committed
{
//Call the copy operator to do the job,
this->operator=(rhs);
Peterson, Peter
committed
}
Janik Zikovsky
committed
/** Constructor, taking a vector of events.
* @param events Vector of TofEvent's */
EventList::EventList(const std::vector<TofEvent> &events)
Peterson, Peter
committed
{
this->events.assign(events.begin(), events.end());
Janik Zikovsky
committed
this->has_weights = false;
this->order = UNSORTED;
Peterson, Peter
committed
}
Janik Zikovsky
committed
/// Destructor
Peterson, Peter
committed
EventList::~EventList()
Peterson, Peter
committed
{
// Note: These two lines do not seem to have an effect on releasing memory
// at least on Linux. (Memory usage seems to increase event after deleting EventWorkspaces.
// Therefore, for performance, they are kept commented:
//this->events.clear();
//std::vector<TofEvent>().swap(events); //Trick to release the vector memory.
Peterson, Peter
committed
}
// --------------------------------------------------------------------------
// --- Operators -------------------------------------------------------------------
Janik Zikovsky
committed
/** Copy into this event list from another
* @param rhs We will copy all the events from that into this object.
* @return reference to this
* */
EventList& EventList::operator=(const EventList& rhs)
//Copy all data from the rhs.
this->events.assign(rhs.events.begin(), rhs.events.end());
Janik Zikovsky
committed
this->weightedEvents.assign(rhs.weightedEvents.begin(), rhs.weightedEvents.end());
this->has_weights = rhs.has_weights;
this->refX = rhs.refX;
this->order = rhs.order;
Janik Zikovsky
committed
//Copy the detector ID set
this->detectorIDs = rhs.detectorIDs;
Roman Tolchenov
committed
return *this;
Janik Zikovsky
committed
// --------------------------------------------------------------------------
Janik Zikovsky
committed
/** Append an event to the histogram.
* @param event TofEvent to add at the end of the list.
* @return reference to this
* */
Peterson, Peter
committed
EventList& EventList::operator+=(const TofEvent &event)
Peterson, Peter
committed
{
Janik Zikovsky
committed
if (has_weights)
this->weightedEvents.push_back(WeightedEvent(event));
else
this->events.push_back(event);
this->order = UNSORTED;
Peterson, Peter
committed
return *this;
}
Janik Zikovsky
committed
// --------------------------------------------------------------------------
Janik Zikovsky
committed
/** Append a list of events to the histogram.
* @param more_events A vector of events to append.
* @return reference to this
* */
EventList& EventList::operator+=(const std::vector<TofEvent> & more_events)
Peterson, Peter
committed
{
Janik Zikovsky
committed
if (has_weights)
{
//Add default weights to all the un-weighted incoming events from the list.
// and append to the list
std::vector<TofEvent>::const_iterator it;
for(it = more_events.begin(); it != more_events.end(); it++)
this->weightedEvents.push_back( WeightedEvent(*it) );
}
else
{
//Simply push the events
this->events.insert(this->events.end(), more_events.begin(), more_events.end());
}
this->order = UNSORTED;
Peterson, Peter
committed
return *this;
}
Janik Zikovsky
committed
// --------------------------------------------------------------------------
/** Append a WeightedEvent to the histogram.
* Note: The whole list will switch to weights (a possibly lengthy operation)
* if it did not have weights before.
*
* @param event WeightedEvent to add at the end of the list.
* @return reference to this
* */
Janik Zikovsky
committed
EventList& EventList::operator+=(const WeightedEvent &event)
{
if (!has_weights)
this->switchToWeightedEvents();
this->weightedEvents.push_back(event);
this->order = UNSORTED;
return *this;
}
// --------------------------------------------------------------------------
/** Append a list of events to the histogram.
* Note: The whole list will switch to weights (a possibly lengthy operation)
* if it did not have weights before.
*
* @param more_events A vector of events to append.
* @return reference to this
* */
Janik Zikovsky
committed
EventList& EventList::operator+=(const std::vector<WeightedEvent> & more_events)
{
if (!has_weights)
this->switchToWeightedEvents();
//Simply push the events
this->weightedEvents.insert(weightedEvents.end(), more_events.begin(), more_events.end());
this->order = UNSORTED;
return *this;
}
Janik Zikovsky
committed
// --------------------------------------------------------------------------
/** Append another EventList to this event list.
* The event lists are concatenated, and a union of the sets of detector ID's is done.
* @param more_events Another EventList.
* @return reference to this
* */
EventList& EventList::operator+=(const EventList& more_events)
Janik Zikovsky
committed
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
if (more_events.hasWeights())
{
//We're adding something with weights
//Make sure that THIS has weights too.
if (!has_weights)
this->switchToWeightedEvents();
//At this point, both have weights. Great!
const vector<WeightedEvent> & rel = more_events.getWeightedEvents();
this->weightedEvents.insert(this->weightedEvents.end(), rel.begin(), rel.end());
}
if (has_weights && !more_events.hasWeights())
{
//THIS has weights, but we're adding something that doesn't.
const vector<TofEvent> & rel = more_events.getEvents();
this->operator+=(rel);
}
else if (!has_weights && !more_events.hasWeights())
{
//Neither has weights. Keep the unweighted event lists.
const vector<TofEvent> & rel = more_events.getEvents();
this->events.insert(this->events.end(), rel.begin(), rel.end());
}
//No guaranteed order
Janik Zikovsky
committed
this->order = UNSORTED;
//Do a union between the detector IDs of both lists
std::set<int>::const_iterator it;
for (it = more_events.detectorIDs.begin(); it != more_events.detectorIDs.end(); it++ )
this->detectorIDs.insert( *it );
Janik Zikovsky
committed
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
// --------------------------------------------------------------------------
/** SUBTRACT another EventList from this event list.
* The event lists are concatenated, but the weights of the incoming
* list are multiplied by -1.0.
*
* @param more_events Another EventList.
* @return reference to this
* */
EventList& EventList::operator-=(const EventList& more_events)
{
if (more_events.hasWeights())
{
//We're adding something with weights
//Make sure that THIS has weights too.
this->switchToWeightedEvents();
//At this point, both have weights. Great!
const vector<WeightedEvent> & rel = more_events.getWeightedEvents();
std::vector<WeightedEvent>::const_iterator it;
for(it = rel.begin(); it != rel.end(); it++)
this->weightedEvents.push_back( WeightedEvent(it->m_tof, it->m_pulsetime, -it->m_weight, it->m_errorSquared) );
}
if (!more_events.hasWeights())
{
//We're adding a list without weights.
//Make sure that THIS has weights too.
this->switchToWeightedEvents();
//Loop through the unweighted input, convert them to -1.0 weight, and concatenate.
const vector<TofEvent> & rel = more_events.getEvents();
std::vector<TofEvent>::const_iterator it;
for(it = rel.begin(); it != rel.end(); it++)
this->weightedEvents.push_back( WeightedEvent(*it, -1.0, 1.0) );
}
//No guaranteed order
this->order = UNSORTED;
//NOTE: What to do about detector ID's
return *this;
}
// --------------------------------------------------------------------------
/** Equality operator between EventList's
* @param rhs :: other EventList to compare
*/
bool EventList::operator==(const EventList& rhs) const
{
if (this->getNumberEvents() != rhs.getNumberEvents())
return false;
if (this->has_weights != rhs.has_weights)
return false;
if (events != rhs.events)
return false;
if (weightedEvents != rhs.weightedEvents)
return false;
return true;
}
/** Inequality comparator
* @param rhs :: other EventList to compare
*/
bool EventList::operator!=(const EventList& rhs) const
{
return (!this->operator==(rhs));
}
Janik Zikovsky
committed
// --------------------------------------------------------------------------
Janik Zikovsky
committed
/** Append an event to the histogram, without clearing the cache, to make it faster.
* @param event TofEvent to add at the end of the list.
* */
void EventList::addEventQuickly(const TofEvent &event)
{
Janik Zikovsky
committed
if (has_weights)
this->weightedEvents.push_back(WeightedEvent(event));
else
this->events.push_back(event);
}
// --------------------------------------------------------------------------
/** Append an event to the histogram, without clearing the cache, to make it faster.
* @param event TofEvent to add at the end of the list.
* */
void EventList::addEventQuickly(const WeightedEvent &event)
{
this->weightedEvents.push_back(event);
Janik Zikovsky
committed
}
Janik Zikovsky
committed
Janik Zikovsky
committed
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
// --------------------------------------------------------------------------
/** Add a detector ID to the set of detector IDs
*
* @param detID detector ID to insert in set.
*/
void EventList::addDetectorID(const int detID)
{
this->detectorIDs.insert( detID );
}
// --------------------------------------------------------------------------
/** Return true if the given detector ID is in the list for this eventlist */
bool EventList::hasDetectorID(const int detID) const
{
return ( detectorIDs.find(detID) != detectorIDs.end() );
}
// --------------------------------------------------------------------------
/** Get a const reference to the detector IDs set.
*/
const std::set<int>& EventList::getDetectorIDs() const
{
return this->detectorIDs;
}
/** Get a mutable reference to the detector IDs set.
*/
std::set<int>& EventList::getDetectorIDs()
{
return this->detectorIDs;
}
Janik Zikovsky
committed
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
/** Return true if the event list has weights */
bool EventList::hasWeights() const
{
return has_weights;
}
// -----------------------------------------------------------------------------------------------
/** Switch the EventList to use WeightedEvents instead
* of TofEvent.
*/
void EventList::switchToWeightedEvents()
{
//Do nothing if already there
if (has_weights)
return;
has_weights = true;
weightedEvents.clear();
//Convert and copy all TofEvents to the weightedEvents list.
std::vector<TofEvent>::const_iterator it;
for(it = events.begin(); it != events.end(); it++)
this->weightedEvents.push_back( WeightedEvent(*it) );
//Get rid of the old events
events.clear();
}
// ==============================================================================================
// --- Handling the event list -------------------------------------------------------------------
Janik Zikovsky
committed
// ==============================================================================================
/** Return the const list of TofEvents contained.
* @return a const reference to the list of non-weighted events
* */
Janik Zikovsky
committed
const std::vector<TofEvent> & EventList::getEvents() const
Janik Zikovsky
committed
if (has_weights)
throw std::runtime_error("EventList::getEvents() called for an EventList that has weights. Use getWeightedEvents().");
return this->events;
}
/** Return the list of TofEvents contained.
* @return a reference to the list of non-weighted events
* */
std::vector<TofEvent>& EventList::getEvents()
Janik Zikovsky
committed
if (has_weights)
throw std::runtime_error("EventList::getEvents() called for an EventList that has weights. Use getWeightedEvents().");
return this->events;
}
/** Return the list of WeightedEvent contained.
* @return a reference to the list of weighted events
* */
Janik Zikovsky
committed
std::vector<WeightedEvent>& EventList::getWeightedEvents()
{
if (!has_weights)
throw std::runtime_error("EventList::getWeightedEvents() called for an EventList that does not have weights. Use getEvents().");
return this->weightedEvents;
}
/** Return the list of WeightedEvent contained.
* @return a const reference to the list of weighted events
* */
Janik Zikovsky
committed
const std::vector<WeightedEvent>& EventList::getWeightedEvents() const
{
if (!has_weights)
throw std::runtime_error("EventList::getWeightedEvents() called for an EventList that does not have weights. Use getEvents().");
return this->weightedEvents;
}
Janik Zikovsky
committed
/** Clear the list of events and any
* associated detector ID's.
* */
void EventList::clear()
{
Janik Zikovsky
committed
this->events.clear();
Janik Zikovsky
committed
this->weightedEvents.clear();
Janik Zikovsky
committed
this->detectorIDs.clear();
Janik Zikovsky
committed
/** Resrve a certain number of entries in the (NOT-WEIGHTED) event list. Do NOT call
* on weighted events!
*
* Calls std::vector<>::reserve() in order to pre-allocate the length of the event list vector.
*
* @param num :: number of events that will be in this EventList
*/
void EventList::reserve(size_t num)
{
this->events.reserve(num);
}
Janik Zikovsky
committed
// ==============================================================================================
// --- Sorting functions -----------------------------------------------------
// ==============================================================================================
// --------------------------------------------------------------------------
Janik Zikovsky
committed
/** Sort events by TOF or Frame
* @param order Order by which to sort.
* */
Janik Zikovsky
committed
void EventList::sort(const EventSortType order) const
{
if (order == UNSORTED)
{
return; // don't bother doing anything. Why did you ask to unsort?
}
else if (order == TOF_SORT)
{
this->sortTof();
}
Janik Zikovsky
committed
else if (order == PULSETIME_SORT)
Janik Zikovsky
committed
this->sortPulseTime();
}
else
{
throw runtime_error("Invalid sort type in EventList::sort(EventSortType)");
}
}
Janik Zikovsky
committed
// --------------------------------------------------------------------------
Janik Zikovsky
committed
/** Sort events by TOF */
Janik Zikovsky
committed
void EventList::sortTof() const
{
if (this->order == TOF_SORT)
{
return; // nothing to do
}
//Perform sort.
Janik Zikovsky
committed
if (has_weights)
std::sort(weightedEvents.begin(), weightedEvents.end(), compareEventTof);
else
std::sort(events.begin(), events.end(), compareEventTof);
//Save the order to avoid unnecessary re-sorting.
this->order = TOF_SORT;
Janik Zikovsky
committed
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
// // MergeSort from: http://en.literateprograms.org/Merge_sort_%28C_Plus_Plus%29#chunk%20def:merge
// template<typename IT, typename VT> void insert(IT begin, IT end, const VT &v)
// {
// while(begin+1!=end && *(begin+1)<v) {
// std::swap(*begin, *(begin+1));
// ++begin;
// }
// *begin=v;
// }
//
// template<typename IT> void merge(IT begin, IT begin_right, IT end)
// {
// for(;begin<begin_right; ++begin) {
// if(*begin>*begin_right) {
// typename std::iterator_traits<IT>::value_type v(*begin);
// *begin=*begin_right;
// insert(begin_right, end, v);
// }
// }
// }
//
// template<typename IT> void mergesort(IT begin, IT end)
// {
// size_t size(end-begin);
// //std::cout << "mergesort called on " << size << "\n";
// if(size<2) return;
//
// IT begin_right=begin+size/2;
//
// mergesort(begin, begin_right);
// mergesort(begin_right, end);
// merge(begin, begin_right, end);
// }
//----------------------------------------------------------------------------------------------------
/** Merge two sorted lists into one sorted vector.
*
* @tparam T :: the type in the vector.
* @param begin1 :: iterator at the start of the first list.
* @param end1 :: iterator at the end of the first list.
* @param begin2 :: iterator at the start of the second list.
* @param end2 :: iterator at the end of the second list.
* @param result_vector :: a vector (by reference) that will be filled with the result.
* */
template<typename T>
void merge(typename std::vector<T>::iterator begin1, typename std::vector<T>::iterator end1,
typename std::vector<T>::iterator begin2, typename std::vector<T>::iterator end2,
typename std::vector<T> & result_vector)
{
typename std::vector<T>::iterator it1=begin1;
typename std::vector<T>::iterator it2=begin2;
while (!((it1 == end1) && (it2 == end2)))
{
if (it1 == end1)
{
// Only it2 makes sense
result_vector.push_back(*it2);
it2++;
}
else if (it2 == end2)
{
// Only it1 makes sense
result_vector.push_back(*it1);
it1++;
}
else
{
// Both iterators are valid. Which is smaller?
if (*it1 < *it2)
{
result_vector.push_back(*it1);
it1++;
}
else
{
result_vector.push_back(*it2);
it2++;
}
}
}
}
//----------------------------------------------------------------------------------------------------
/** Perform a parallelized sort on a provided vector, using 2 threads.
* NOTE: Will temporarily use twice the memory used by the incoming vector.
*
* @param vec :: a vector, by refe/rence, that will be sorted-in place.
*/
template<typename T>
void parallel_sort2(typename std::vector<T> & vec)
{
size_t size = vec.size();
typename std::vector<T>::iterator begin = vec.begin();
typename std::vector<T>::iterator middle = begin + size/2;
typename std::vector<T>::iterator end = vec.end();
PRAGMA_OMP(parallel sections)
{
PRAGMA_OMP(section)
{
std::sort(begin, middle);
//std::cout << " ----------- Part 1 --------------\n"; for (typename std::vector<T>::iterator it = begin; it != middle; it++) std::cout << *it << "\n";
}
PRAGMA_OMP(section)
{
std::sort(middle, end);
// std::cout << " ----------- Part 2 --------------\n";for (typename std::vector<T>::iterator it = middle; it != end; it++) std::cout << *it << "\n";
}
}
// Now merge back
typename std::vector<T> temp;
merge(begin, middle, middle, end, temp);
//std::cout << " ----------- Part 1+2 --------------\n"; for (typename std::vector<T>::iterator it = temp.begin(); it != temp.end(); it++) std::cout << *it << "\n";
// Swap storage with the temp vector
vec.swap(temp);
// Which we can now clear
temp.clear();
}
//----------------------------------------------------------------------------------------------------
/** Perform a parallelized sort on a provided vector, using 4 threads.
* NOTE: Will temporarily use twice the memory used by the incoming vector.
*
* @param vec :: a vector, by refe/rence, that will be sorted-in place.
*/
template<typename T>
void parallel_sort4(std::vector<T> & vec)
{
//int num_cores = PARALLEL_NUMBER_OF_THREADS;
size_t size = vec.size();
typename std::vector<T>::iterator begin = vec.begin();
typename std::vector<T>::iterator middle1 = begin + size/4;
typename std::vector<T>::iterator middle2 = begin + size/2;
typename std::vector<T>::iterator middle3 = begin + 3*size/4;
typename std::vector<T>::iterator end = vec.end();
PRAGMA_OMP(parallel sections)
{
PRAGMA_OMP(section)
{
std::sort(begin, middle1);
}
PRAGMA_OMP(section)
{
std::sort(middle1, middle2);
}
PRAGMA_OMP(section)
{
std::sort(middle2, middle3);
}
PRAGMA_OMP(section)
{
std::sort(middle3, end);
}
}
// Now merge back
typename std::vector<T> temp1, temp2;
//PRAGMA_OMP(parallel sections)
{
//PRAGMA_OMP(section)
{
merge(begin, middle1, middle1, middle2, temp1);
}
//PRAGMA_OMP(section)
{
merge(middle2, middle3, middle3, end, temp2);
}
}
// We can clear the incoming vector to free up memory now,
// because it is copied already in temp1, temp2
vec.clear();
// Final merge
typename std::vector<T> temp;
merge(temp1.begin(), temp1.end(), temp2.begin(), temp2.end(), temp);
// Swap storage with the temp vector
vec.swap(temp);
// Which we can now clear
temp.clear();
}
// --------------------------------------------------------------------------
/** Sort events by TOF, using two threads.
*
* Performance for 5e7 events:
* - 40.5 secs with sortTof() (one thread)
* - 21.1 secs with sortTof2() (two threads)
* - 18.2 secs with sortTof4() (four threads)
* Performance gain tends to go up with longer event lists.
* */
void EventList::sortTof2() const
{
if (this->order == TOF_SORT)
{
return; // nothing to do
}
if (has_weights)
parallel_sort2(weightedEvents);
else
parallel_sort2(events);
//Save the order to avoid unnecessary re-sorting.
this->order = TOF_SORT;
}
// --------------------------------------------------------------------------
/** Sort events by TOF, using four threads.
*
* Performance for 5e7 events:
* - 40.5 secs with sortTof() (one thread)
* - 21.1 secs with sortTof2() (two threads)
* - 18.2 secs with sortTof4() (four threads)
* Performance gain tends to go up with longer event lists.
* */
void EventList::sortTof4() const
{
if (this->order == TOF_SORT)
{
return; // nothing to do
}
if (has_weights)
parallel_sort4(weightedEvents);
else
parallel_sort4(events);
//Save the order to avoid unnecessary re-sorting.
this->order = TOF_SORT;
}
Janik Zikovsky
committed
// --------------------------------------------------------------------------
Janik Zikovsky
committed
/** Sort events by Frame */
Janik Zikovsky
committed
void EventList::sortPulseTime() const
Janik Zikovsky
committed
if (this->order == PULSETIME_SORT)
{
return; // nothing to do
}
//Perform sort.
Janik Zikovsky
committed
if (has_weights)
std::sort(weightedEvents.begin(), weightedEvents.end(), compareEventPulseTime);
else
std::sort(events.begin(), events.end(), compareEventPulseTime);
//Save the order to avoid unnecessary re-sorting.
Janik Zikovsky
committed
this->order = PULSETIME_SORT;
Peterson, Peter
committed
Janik Zikovsky
committed
// --------------------------------------------------------------------------
Janik Zikovsky
committed
/** Return true if the event list is sorted by TOF */
bool EventList::isSortedByTof() const
{
return (this->order == TOF_SORT);
}
Janik Zikovsky
committed
// --------------------------------------------------------------------------
Janik Zikovsky
committed
/** Reverse the histogram boundaries and the associated events if they are sorted. */
Peterson, Peter
committed
void EventList::reverse()
{
// reverse the histogram bin parameters
Janik Zikovsky
committed
MantidVec x = this->refX.access();
Peterson, Peter
committed
std::reverse(x.begin(), x.end());
this->refX.access() = x;
// flip the events if they are tof sorted
if (this->isSortedByTof())
Janik Zikovsky
committed
{
if (has_weights)
std::reverse(this->weightedEvents.begin(), this->weightedEvents.end());
else
std::reverse(this->events.begin(), this->events.end());
//And we are still sorted! :)
}
Peterson, Peter
committed
else
this->order = UNSORTED;
}
// --------------------------------------------------------------------------
Janik Zikovsky
committed
/** Return the number of events in the list.
* NOTE: If the events have weights, this returns the NUMBER of WeightedEvent's in the
* list, and NOT the sum of their weights (which may be two different numbers).
Janik Zikovsky
committed
*
* @return the number of events in the list.
Janik Zikovsky
committed
* */
Janik Zikovsky
committed
if (has_weights)
return this->weightedEvents.size();
else
return this->events.size();
// --------------------------------------------------------------------------
/** @return :: the memory used by the EventList, in bytes.
* */
size_t EventList::getMemorySize() const
{
if (has_weights)
return this->weightedEvents.size() * sizeof(WeightedEvent) + sizeof(EventList);
else
return this->events.size() * sizeof(TofEvent) + sizeof(EventList);
}
Janik Zikovsky
committed
// --------------------------------------------------------------------------
Janik Zikovsky
committed
/** Return the size of the histogram data.
* @return the size of the histogram representation of the data (size of Y) **/
Janik Zikovsky
committed
size_t EventList::histogram_size() const
{
size_t x_size = refX->size();
if (x_size > 1)
return x_size - 1;
else
return 0;
Janik Zikovsky
committed
}
Janik Zikovsky
committed
// ==============================================================================================
// --- Setting the Histrogram X axis, without recalculating the histogram -----------------------
// ==============================================================================================
Janik Zikovsky
committed
/** Set the x-component for the histogram view. This will NOT cause the histogram to be calculated.
* @param X :: The vector of doubles to set as the histogram limits.
*/
Janik Zikovsky
committed
void EventList::setX(const MantidVecPtr::ptr_type& X)
Peterson, Peter
committed
{
this->refX = X;
Peterson, Peter
committed
}
Janik Zikovsky
committed
/** Set the x-component for the histogram view. This will NOT cause the histogram to be calculated.
* @param X :: The vector of doubles to set as the histogram limits.
*/
Janik Zikovsky
committed
void EventList::setX(const MantidVecPtr& X)
{
this->refX = X;
}
Janik Zikovsky
committed
/** Set the x-component for the histogram view. This will NOT cause the histogram to be calculated.
* @param X :: The vector of doubles to set as the histogram limits.
*/
Janik Zikovsky
committed
void EventList::setX(const MantidVec& X)
{
this->refX.access()=X;
}
Peterson, Peter
committed
Janik Zikovsky
committed
// ==============================================================================================
// --- Return Data Vectors --------------------------------------------------
Janik Zikovsky
committed
// ==============================================================================================
// Note: these will only be called from a const class; e.g
// const EventList el;
// el.dataX(); <<<<< this works
// EventList el2;
// el2.dataX(); <<<<< this throws an error.
Janik Zikovsky
committed
/** Returns the x data.
* @return a const reference to the X (bin) vector.
* */
Janik Zikovsky
committed
const MantidVec& EventList::dataX() const
return *(this->refX);
Janik Zikovsky
committed
Janik Zikovsky
committed
/** Returns a reference to the X data
* @return a cow_ptr to the X (bin) vector.
* */
Janik Zikovsky
committed
Kernel::cow_ptr<MantidVec> EventList::getRefX() const
{
return refX;
}
Peterson, Peter
committed
/** Calculates and returns a pointer to the Y histogrammed data.
* Remember to delete your pointer after use!
Janik Zikovsky
committed
*
* @return a pointer to a MantidVec
Janik Zikovsky
committed
MantidVec * EventList::dataY() const
Janik Zikovsky
committed
MantidVec * Y = new MantidVec();
generateCountsHistogram(*this->refX, *Y);
return Y;
Janik Zikovsky
committed
/** Calculates and returns a pointer to the E histogrammed data.
* Remember to delete your pointer after use!
Janik Zikovsky
committed
*
* @return a pointer to a MantidVec
Janik Zikovsky
committed
MantidVec * EventList::dataE() const
Janik Zikovsky
committed
{
Janik Zikovsky
committed
if (has_weights)
{
MantidVec Y;
MantidVec * E = new MantidVec();
generateHistogramsForWeights(*this->refX, Y, *E);
//Y is unused.
return E;
}
else
{
MantidVec Y;
generateCountsHistogram(*this->refX, Y);
MantidVec * E = new MantidVec();
generateErrorsHistogram(Y, *E);
return E;
}
}