-
Notifications
You must be signed in to change notification settings - Fork 121
/
EventList.cpp
4285 lines (3769 loc) · 139 KB
/
EventList.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
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
287
288
289
290
291
292
293
294
295
296
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
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
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
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
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
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
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#include "MantidAPI/MemoryManager.h"
#include "MantidDataObjects/EventList.h"
#include "MantidDataObjects/EventWorkspaceMRU.h"
#include "MantidKernel/DateAndTime.h"
#include "MantidKernel/Exception.h"
#include "MantidKernel/Logger.h"
#include "MantidKernel/MultiThreaded.h"
#include <cfloat>
#include <functional>
#include <iostream>
#include <limits>
#include <math.h>
#include <Poco/ScopedLock.h>
#include <stdexcept>
using std::ostream;
using std::runtime_error;
using std::size_t;
using std::vector;
using Mantid::Kernel::Mutex;
namespace Mantid
{
namespace DataObjects
{
using Kernel::Exception::NotImplementedError;
using Kernel::DateAndTime;
using namespace Mantid::API;
namespace
{
/// The number of events to split for parallel sorting.
const size_t NUM_EVENTS_PARALLEL_THRESHOLD = 500000;
}
//==========================================================================
/// --------------------- TofEvent Comparators ----------------------------------
//==========================================================================
/** Compare two events' TOF, return true if e1 should be before e2.
* @param e1 :: first event
* @param e2 :: second event
* */
template< typename T>
bool compareEventTof(const T & e1, const T & e2)
{
return (e1.tof() < e2.tof());
}
/** Compare two events' FRAME id, return true if e1 should be before e2.
* @param e1 :: first event
* @param e2 :: second event
* */
bool compareEventPulseTime(const TofEvent& e1, const TofEvent& e2)
{
return (e1.pulseTime() < e2.pulseTime());
}
/** Compare two events' FRAME id, return true if e1 should be before e2.
* Assuming that if e1's pulse time is earlier than e2's, then e1 must be earlier regardless TOF value
* @param e1 :: first event
* @param e2 :: second event
* */
bool compareEventPulseTimeTOF(const TofEvent& e1, const TofEvent& e2)
{
if (e1.pulseTime() < e2.pulseTime()){
return true;
}
else if ( (e1.pulseTime() == e2.pulseTime()) && (e1.tof() < e2.tof()) ){
return true;
}
return false;
}
//==========================================================================
// ---------------------- EventList stuff ----------------------------------
//==========================================================================
// --- Constructors -------------------------------------------------------------------
/// Constructor (empty)
EventList::EventList() :
eventType(TOF), order(UNSORTED), mru(NULL), m_lockedMRU(false)
{
}
/** Constructor with a MRU list
* @param mru :: pointer to the MRU of the parent EventWorkspace
* @param specNo :: the spectrum number for the event list
*/
EventList::EventList(EventWorkspaceMRU * mru, specid_t specNo)
: IEventList(specNo),
eventType(TOF), order(UNSORTED), mru(mru), m_lockedMRU(false)
{
}
/** Constructor copying from an existing event list
* @param rhs :: EventList object to copy*/
EventList::EventList(const EventList& rhs)
: IEventList(rhs), mru(rhs.mru), m_lockedMRU(false)
{
//Call the copy operator to do the job,
this->operator=(rhs);
}
/** Constructor, taking a vector of events.
* @param events :: Vector of TofEvent's */
EventList::EventList(const std::vector<TofEvent> &events)
: mru(NULL), m_lockedMRU(false)
{
this->events.assign(events.begin(), events.end());
this->eventType = TOF;
this->order = UNSORTED;
}
/** Constructor, taking a vector of events.
* @param events :: Vector of WeightedEvent's */
EventList::EventList(const std::vector<WeightedEvent> &events)
: mru(NULL), m_lockedMRU(false)
{
this->weightedEvents.assign(events.begin(), events.end());
this->eventType = WEIGHTED;
this->order = UNSORTED;
}
/** Constructor, taking a vector of events.
* @param events :: Vector of WeightedEventNoTime's */
EventList::EventList(const std::vector<WeightedEventNoTime> &events)
: mru(NULL), m_lockedMRU(false)
{
this->weightedEventsNoTime.assign(events.begin(), events.end());
this->eventType = WEIGHTED_NOTIME;
this->order = UNSORTED;
}
/// Destructor
EventList::~EventList()
{
// 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:
clear();
//this->events.clear();
//std::vector<TofEvent>().swap(events); //Trick to release the vector memory.
}
// --------------------------------------------------------------------------
/** Create an EventList from a histogram. This converts bins to weighted
* events.
* Any existing events are cleared.
*
* @param inSpec :: ISpectrum ptr to histogram data.
* @param GenerateZeros :: if true, generate event(s) for empty bins
* @param GenerateMultipleEvents :: if true, create several evenly-spaced fake events inside the bin
* @param MaxEventsPerBin :: max number of events to generate in one bin, if GenerateMultipleEvents
*/
void EventList::createFromHistogram(const ISpectrum * inSpec, bool GenerateZeros, bool GenerateMultipleEvents, int MaxEventsPerBin)
{
// Fresh start
this->clear(true);
// Cached values for later checks
double inf = std::numeric_limits<double>::infinity();
double ninf = -inf;
// For thread safety
inSpec->lockData();
// Get the input histogram
const MantidVec & X = inSpec->readX();
const MantidVec & Y = inSpec->readY();
const MantidVec & E = inSpec->readE();
if (Y.size()+1 != X.size())
throw std::runtime_error("Expected a histogram (X vector should be 1 longer than the Y vector)");
// Copy detector IDs and spectra
this->copyInfoFrom( *inSpec );
// We need weights but have no way to set the time. So use weighted, no time
this->switchTo(WEIGHTED_NOTIME);
if (GenerateZeros)
this->weightedEventsNoTime.reserve(Y.size());
for (size_t i=0; i<X.size()-1; i++)
{
double weight = Y[i];
if ((weight != 0.0 || GenerateZeros)
&& (weight == weight) /*NAN check*/
&& (weight != inf) && (weight != ninf))
{
double error = E[i];
// Also check that the error is not a bad number
if ((error == error) /*NAN check*/
&& (error != inf) && (error != ninf))
{
if (GenerateMultipleEvents)
{
// --------- Multiple events per bin ----------
double errorSquared = error * error;
// Find how many events to fake
double val = weight / E[i];
val *= val;
// Convert to int with slight rounding up. This is to avoid rounding errors
int numEvents = int(val + 0.2);
if (numEvents < 1) numEvents = 1;
if (numEvents > MaxEventsPerBin) numEvents = MaxEventsPerBin;
// Scale the weight and error for each
weight /= numEvents;
errorSquared /= numEvents;
// Spread the TOF. e.g. 2 events = 0.25, 0.75.
double tofStep = (X[i+1] - X[i]) / (numEvents);
for (size_t j=0; j<size_t(numEvents); j++)
{
double tof = X[i] + tofStep * (0.5 + double(j));
// Create and add the event
// TODO: try emplace_back() here.
weightedEventsNoTime.push_back( WeightedEventNoTime(tof, weight, errorSquared) );
}
}
else
{
// --------- Single event per bin ----------
// TOF = midpoint of the bin
double tof = (X[i] + X[i+1]) / 2.0;
// Error squared is carried in the event
double errorSquared = E[i];
errorSquared *= errorSquared;
// Create and add the event
weightedEventsNoTime.push_back( WeightedEventNoTime(tof, weight, errorSquared) );
}
} // error is nont NAN or infinite
} // weight is non-zero, not NAN, and non-infinite
} // (each bin)
// Set the X binning parameters
this->setX( inSpec->ptrX() );
// Manually set that this is sorted by TOF, since it is. This will make it "threadSafe" in other algos.
this->setSortOrder( TOF_SORT );
inSpec->unlockData();
}
// --------------------------------------------------------------------------
// --- Operators -------------------------------------------------------------------
/** 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());
this->weightedEvents.assign(rhs.weightedEvents.begin(), rhs.weightedEvents.end());
this->weightedEventsNoTime.assign(rhs.weightedEventsNoTime.begin(), rhs.weightedEventsNoTime.end());
this->eventType = rhs.eventType;
this->refX = rhs.refX;
this->order = rhs.order;
//Copy the detector ID set
this->detectorIDs = rhs.detectorIDs;
return *this;
}
// --------------------------------------------------------------------------
/** Append an event to the histogram.
* @param event :: TofEvent to add at the end of the list.
* @return reference to this
* */
EventList& EventList::operator+=(const TofEvent &event)
{
switch (this->eventType)
{
case TOF:
//Simply push the events
this->events.push_back(event);
break;
case WEIGHTED:
this->weightedEvents.push_back(WeightedEvent(event));
break;
case WEIGHTED_NOTIME:
this->weightedEventsNoTime.push_back(WeightedEventNoTime(event));
break;
}
this->order = UNSORTED;
return *this;
}
// --------------------------------------------------------------------------
/** Append a list of events to the histogram.
* The internal event list will switch to the required type.
*
* @param more_events :: A vector of events to append.
* @return reference to this
* */
EventList& EventList::operator+=(const std::vector<TofEvent> & more_events)
{
switch (this->eventType)
{
case TOF:
//Simply push the events
this->events.insert(this->events.end(), more_events.begin(), more_events.end());
break;
case WEIGHTED:
//Add default weights to all the un-weighted incoming events from the list.
// and append to the list
this->weightedEvents.reserve( this->weightedEvents.size() + more_events.size());
for(std::vector<TofEvent>::const_iterator it = more_events.begin(); it != more_events.end(); ++it)
this->weightedEvents.push_back( WeightedEvent(*it) );
break;
case WEIGHTED_NOTIME:
//Add default weights to all the un-weighted incoming events from the list.
// and append to the list
this->weightedEventsNoTime.reserve( this->weightedEventsNoTime.size() + more_events.size());
for(std::vector<TofEvent>::const_iterator it = more_events.begin(); it != more_events.end(); ++it)
this->weightedEventsNoTime.push_back( WeightedEventNoTime(*it) );
break;
}
this->order = UNSORTED;
return *this;
}
// --------------------------------------------------------------------------
/** 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
* */
EventList& EventList::operator+=(const WeightedEvent &event)
{
this->switchTo(WEIGHTED);
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
* */
EventList& EventList::operator+=(const std::vector<WeightedEvent> & more_events)
{
switch (this->eventType)
{
case TOF:
//Need to switch to weighted
this->switchTo(WEIGHTED);
// Fall through to the insertion!
case WEIGHTED:
// Append the two lists
this->weightedEvents.insert(weightedEvents.end(), more_events.begin(), more_events.end());
break;
case WEIGHTED_NOTIME:
//Add default weights to all the un-weighted incoming events from the list.
// and append to the list
this->weightedEventsNoTime.reserve( this->weightedEventsNoTime.size() + more_events.size());
for(std::vector<WeightedEvent>::const_iterator it = more_events.begin(); it != more_events.end(); ++it)
this->weightedEventsNoTime.push_back( WeightedEventNoTime(*it) );
break;
}
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
* */
EventList& EventList::operator+=(const std::vector<WeightedEventNoTime> & more_events)
{
switch (this->eventType)
{
case TOF:
case WEIGHTED:
//Need to switch to weighted with no time
this->switchTo(WEIGHTED_NOTIME);
// Fall through to the insertion!
case WEIGHTED_NOTIME:
// Simple appending of the two lists
this->weightedEventsNoTime.insert(weightedEventsNoTime.end(), more_events.begin(), more_events.end());
break;
}
this->order = UNSORTED;
return *this;
}
// --------------------------------------------------------------------------
/** Append another EventList to this event list.
* The event lists are concatenated, and a union of the sets of detector ID's is done.
* Switching of event types may occur if the two are different.
*
* @param more_events :: Another EventList.
* @return reference to this
* */
EventList& EventList::operator+=(const EventList& more_events)
{
// We'll let the += operator for the given vector of event lists handle it
switch (more_events.getEventType())
{
case TOF:
this->operator+=(more_events.events);
break;
case WEIGHTED:
this->operator+=(more_events.weightedEvents);
break;
case WEIGHTED_NOTIME:
this->operator+=(more_events.weightedEventsNoTime);
break;
}
//No guaranteed order
this->order = UNSORTED;
//Do a union between the detector IDs of both lists
std::set<detid_t>::const_iterator it;
for (it = more_events.detectorIDs.begin(); it != more_events.detectorIDs.end(); ++it )
this->detectorIDs.insert( *it );
return *this;
}
// --------------------------------------------------------------------------
/** SUBTRACT another EventList from this event list.
* The event lists are concatenated, but the weights of the incoming
* list are multiplied by -1.0.
*
* @tparam T1, T2 :: TofEvent, WeightedEvent or WeightedEventNoTime
* @param events :: The event vector being changed.
* @param more_events :: Another event vector being subtracted from this.
* @return reference to this
* */
template<class T1, class T2>
void EventList::minusHelper(std::vector<T1> & events, const std::vector<T2> & more_events)
{
// Make the end vector big enough in one go (avoids repeated re-allocations).
events.reserve( events.size() + more_events.size() );
typename std::vector<T2>::const_iterator itev;
/* In the event of subtracting in place, calling the end() vector would make it point
* at the wrong place
* Using it caused a segault, Ticket #2306.
* So we cache the end (this speeds up too).
*/
typename std::vector<T2>::const_iterator more_begin = more_events.begin();
typename std::vector<T2>::const_iterator more_end = more_events.end();
for (itev = more_begin; itev != more_end; itev++ )
{
// We call the constructor for T1. In the case of WeightedEventNoTime, the pulse time will just be ignored.
events.push_back( T1(itev->tof(), itev->pulseTime(), itev->weight()*(-1.0), itev->errorSquared()) );
}
}
// --------------------------------------------------------------------------
/** 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 (this == &more_events)
{
//Special case, ticket #3844 part 2.
// When doing this = this - this,
// simply clear the input event list. Saves memory!
this->clearData();
return *this;
}
// We'll let the -= operator for the given vector of event lists handle it
switch (this->getEventType())
{
case TOF:
this->switchTo(WEIGHTED);
// Fall through
case WEIGHTED:
switch (more_events.getEventType())
{
case TOF:
minusHelper(this->weightedEvents, more_events.events);
break;
case WEIGHTED:
minusHelper(this->weightedEvents, more_events.weightedEvents);
break;
case WEIGHTED_NOTIME:
// TODO: Should this throw?
minusHelper(this->weightedEvents, more_events.weightedEventsNoTime);
break;
}
case WEIGHTED_NOTIME:
switch (more_events.getEventType())
{
case TOF:
minusHelper(this->weightedEventsNoTime, more_events.events);
break;
case WEIGHTED:
minusHelper(this->weightedEventsNoTime, more_events.weightedEvents);
break;
case WEIGHTED_NOTIME:
minusHelper(this->weightedEventsNoTime, more_events.weightedEventsNoTime);
break;
}
}
//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
* @return :: true if equal.
*/
bool EventList::operator==(const EventList& rhs) const
{
if (this->getNumberEvents() != rhs.getNumberEvents())
return false;
if (this->eventType != rhs.eventType)
return false;
// Check all event lists; The empty ones will compare equal
if (events != rhs.events) return false;
if (weightedEvents != rhs.weightedEvents) return false;
if (weightedEventsNoTime != rhs.weightedEventsNoTime) return false;
return true;
}
/** Inequality comparator
* @param rhs :: other EventList to compare
* @return :: true if not equal.
*/
bool EventList::operator!=(const EventList& rhs) const
{
return (!this->operator==(rhs));
}
bool EventList::equals(const EventList& rhs, const double tolTof,
const double tolWeight, const int64_t tolPulse) const
{
// generic checks
if (this->getNumberEvents() != rhs.getNumberEvents())
return false;
if (this->eventType != rhs.eventType)
return false;
// loop over the events
size_t numEvents = this->getNumberEvents();
switch (this->eventType) {
case TOF:
for (size_t i=0; i < numEvents; ++i)
{
if (! this->events[i].equals(rhs.events[i], tolTof, tolPulse))
return false;
}
break;
case WEIGHTED:
for (size_t i=0; i < numEvents; ++i)
{
if (! this->weightedEvents[i].equals(rhs.weightedEvents[i], tolTof, tolWeight, tolPulse))
return false;
}
break;
case WEIGHTED_NOTIME:
for (size_t i=0; i < numEvents; ++i)
{
if (! this->weightedEventsNoTime[i].equals(rhs.weightedEventsNoTime[i], tolTof, tolWeight))
return false;
}
break;
default:
break;
}
// anything that gets this far is equal within tolerances
return true;
}
// -----------------------------------------------------------------------------------------------
/** Return the type of Event vector contained within.
* @return :: a EventType value.
*/
EventType EventList::getEventType() const
{
return eventType;
}
// -----------------------------------------------------------------------------------------------
/** Switch the EventList to use the given EventType (TOF, WEIGHTED, or WEIGHTED_NOTIME)
*/
void EventList::switchTo(EventType newType)
{
switch(newType)
{
case TOF:
if (eventType != TOF)
throw std::runtime_error("EventList::switchTo() called on an EventList with weights to go down to TofEvent's. This would remove weight information and therefore is not possible.");
break;
case WEIGHTED:
switchToWeightedEvents();
break;
case WEIGHTED_NOTIME:
switchToWeightedEventsNoTime();
break;
}
// Make sure to free memory
this->clearUnused();
}
// -----------------------------------------------------------------------------------------------
/** Switch the EventList to use WeightedEvents instead
* of TofEvent.
*/
void EventList::switchToWeightedEvents()
{
switch(eventType)
{
case WEIGHTED:
// Do nothing; it already is weighted
return;
case WEIGHTED_NOTIME:
throw std::runtime_error("EventList::switchToWeightedEvents() called on an EventList with WeightedEventNoTime's. It has lost the pulse time information and can't go back to WeightedEvent's.");
break;
case TOF:
weightedEvents.clear();
weightedEventsNoTime.clear();
//Convert and copy all TofEvents to the weightedEvents list.
std::vector<TofEvent>::const_iterator it;
std::vector<TofEvent>::const_iterator it_end = events.end(); // Cache for speed
for(it = events.begin(); it != it_end; ++it)
this->weightedEvents.push_back( WeightedEvent(*it) );
//Get rid of the old events
events.clear();
eventType = WEIGHTED;
break;
}
}
// -----------------------------------------------------------------------------------------------
/** Switch the EventList to use WeightedEventNoTime's instead
* of TofEvent.
*/
void EventList::switchToWeightedEventsNoTime()
{
switch(eventType)
{
case WEIGHTED_NOTIME:
//Do nothing if already there
return;
case TOF:
{
//Convert and copy all TofEvents to the weightedEvents list.
weightedEventsNoTime.clear();
std::vector<TofEvent>::const_iterator it;
std::vector<TofEvent>::const_iterator it_end = events.end(); // Cache for speed
for(it = events.begin(); it != it_end; ++it)
this->weightedEventsNoTime.push_back( WeightedEventNoTime(*it) );
//Get rid of the old events
events.clear();
weightedEvents.clear();
eventType = WEIGHTED_NOTIME;
}
break;
case WEIGHTED:
{
//Convert and copy all TofEvents to the weightedEvents list.
weightedEventsNoTime.clear();
std::vector<WeightedEvent>::const_iterator it;
std::vector<WeightedEvent>::const_iterator it_end = weightedEvents.end(); // Cache for speed
for(it = weightedEvents.begin(); it != it_end; ++it)
this->weightedEventsNoTime.push_back( WeightedEventNoTime(*it) );
//Get rid of the old events
events.clear();
weightedEvents.clear();
eventType = WEIGHTED_NOTIME;
}
break;
}
}
// ==============================================================================================
// --- Testing functions (mostly) ---------------------------------------------------------------
// ==============================================================================================
/** Return the given event in the list.
* Handles the different types of events by converting to WeightedEvent (the most general type).
* @param event_number :: the index of the event to retrieve
* @return a WeightedEvent
*/
WeightedEvent EventList::getEvent(size_t event_number)
{
switch (eventType)
{
case TOF:
return WeightedEvent(events[event_number]);
case WEIGHTED:
return weightedEvents[event_number];
case WEIGHTED_NOTIME:
return WeightedEvent(weightedEventsNoTime[event_number].tof(), 0, weightedEventsNoTime[event_number].weight(), weightedEventsNoTime[event_number].errorSquared());
}
throw std::runtime_error("EventList: invalid event type value was found.");
}
// ==============================================================================================
// --- Handling the event list -------------------------------------------------------------------
// ==============================================================================================
/** Return the const list of TofEvents contained.
* NOTE! This should be used for testing purposes only, as much as possible. The EventList
* may contain weighted events, requiring use of getWeightedEvents() instead.
*
* @return a const reference to the list of non-weighted events
* */
const std::vector<TofEvent> & EventList::getEvents() const
{
if (eventType != TOF)
throw std::runtime_error("EventList::getEvents() called for an EventList that has weights. Use getWeightedEvents() or getWeightedEventsNoTime().");
return this->events;
}
/** Return the list of TofEvents contained.
* NOTE! This should be used for testing purposes only, as much as possible. The EventList
* may contain weighted events, requiring use of getWeightedEvents() instead.
*
* @return a reference to the list of non-weighted events
* */
std::vector<TofEvent>& EventList::getEvents()
{
if (eventType != TOF)
throw std::runtime_error("EventList::getEvents() called for an EventList that has weights. Use getWeightedEvents() or getWeightedEventsNoTime().");
return this->events;
}
/** Return the list of WeightedEvent contained.
* NOTE! This should be used for testing purposes only, as much as possible. The EventList
* may contain un-weighted events, requiring use of getEvents() instead.
*
* @return a reference to the list of weighted events
* */
std::vector<WeightedEvent>& EventList::getWeightedEvents()
{
if (eventType != WEIGHTED)
throw std::runtime_error("EventList::getWeightedEvents() called for an EventList not of type WeightedEvent. Use getEvents() or getWeightedEventsNoTime().");
return this->weightedEvents;
}
/** Return the list of WeightedEvent contained.
* NOTE! This should be used for testing purposes only, as much as possible. The EventList
* may contain un-weighted events, requiring use of getEvents() instead.
*
* @return a const reference to the list of weighted events
* */
const std::vector<WeightedEvent>& EventList::getWeightedEvents() const
{
if (eventType != WEIGHTED)
throw std::runtime_error("EventList::getWeightedEvents() called for an EventList not of type WeightedEvent. Use getEvents() or getWeightedEventsNoTime().");
return this->weightedEvents;
}
/** Return the list of WeightedEvent contained.
* NOTE! This should be used for testing purposes only, as much as possible.
*
* @return a reference to the list of weighted events
* */
std::vector<WeightedEventNoTime>& EventList::getWeightedEventsNoTime()
{
if (eventType != WEIGHTED_NOTIME)
throw std::runtime_error("EventList::getWeightedEvents() called for an EventList not of type WeightedEventNoTime. Use getEvents() or getWeightedEvents().");
return this->weightedEventsNoTime;
}
/** Return the list of WeightedEventNoTime contained.
* NOTE! This should be used for testing purposes only, as much as possible.
*
* @return a const reference to the list of weighted events
* */
const std::vector<WeightedEventNoTime>& EventList::getWeightedEventsNoTime() const
{
if (eventType != WEIGHTED_NOTIME)
throw std::runtime_error("EventList::getWeightedEventsNoTime() called for an EventList not of type WeightedEventNoTime. Use getEvents() or getWeightedEvents().");
return this->weightedEventsNoTime;
}
/** Clear the list of events and any
* associated detector ID's.
* */
void EventList::clear(const bool removeDetIDs)
{
this->events.clear();
std::vector<TofEvent>().swap(this->events); //STL Trick to release memory
this->weightedEvents.clear();
std::vector<WeightedEvent>().swap(this->weightedEvents); //STL Trick to release memory
this->weightedEventsNoTime.clear();
std::vector<WeightedEventNoTime>().swap(this->weightedEventsNoTime); //STL Trick to release memory
if (removeDetIDs)
this->detectorIDs.clear();
}
/** Clear any unused event lists (the ones that do not
* match the currently used type).
* Memory is freed.
* */
void EventList::clearUnused()
{
if (eventType != TOF)
{
this->events.clear();
std::vector<TofEvent>().swap(this->events); //STL Trick to release memory
}
if (eventType != WEIGHTED)
{
this->weightedEvents.clear();
std::vector<WeightedEvent>().swap(this->weightedEvents); //STL Trick to release memory
}
if (eventType != WEIGHTED_NOTIME)
{
this->weightedEventsNoTime.clear();
std::vector<WeightedEventNoTime>().swap(this->weightedEventsNoTime); //STL Trick to release memory
}
}
/// Mask the spectrum to this value. Removes all events.
void EventList::clearData()
{
this->clear(false);
}
/** Sets the MRU list for this event list
*
* @param newMRU :: new MRU for the workspace containing this EventList
*/
void EventList::setMRU(EventWorkspaceMRU * newMRU)
{
mru = newMRU;
}
/** Return the MRU list for this event list */
EventWorkspaceMRU * EventList::getMRU()
{
return mru;
}
/** Reserve 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);
}
// ---------------------------------------------------------
/** Lock access to the data so that it does not get deleted while reading.
* Call this BEFORE readY() and readE().
*/
void EventList::lockData() const
{
m_lockedMRU = true;
}
/** Unlock access to the data so that it can again get deleted.
* Call this once you are done with using the Y or E data.
*/
void EventList::unlockData() const
{
m_lockedMRU = false;
}
// ==============================================================================================
// --- Sorting functions -----------------------------------------------------
// ==============================================================================================
// --------------------------------------------------------------------------
/** Sort events by TOF or Frame
* @param order :: Order by which to sort.
* */
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();
}
else if (order == PULSETIME_SORT)
{
this->sortPulseTime();
}
else if (order == PULSETIMETOF_SORT){
this->sortPulseTimeTOF();
}
else
{
throw runtime_error("Invalid sort type in EventList::sort(EventSortType)");
}
}
// --------------------------------------------------------------------------
/** Manually set the event list sort order value. No actual sorting takes place.
* SHOULD ONLY BE USED IN TESTS or if you know what you are doing.
* @param order :: sort order to set.
*/
void EventList::setSortOrder(const EventSortType order) const
{
this->order = order;
}
// // 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);