ToolDAQFramework
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
SubSample.cpp
Go to the documentation of this file.
1 #include "SubSample.h"
2 #include "Utilities.h"
3 
4 #include <algorithm>
5 
7  // Assign default values
8  m_timestamp = 0;
9  m_first_unique = 0;
10  m_start_trigger = 0;
11 }
12 
13 SubSample::SubSample(std::vector<int> PMTid, std::vector<TimeDelta::short_time_t> time, std::vector<float> charge, TimeDelta timestamp){
14  // If charge vector is empty, fill with 0s
15  if (charge.size() == 0){
16  charge = std::vector<float>(PMTid.size(), 0.);
17  }
18  // Assign values
19  m_PMTid = PMTid;
20  m_time = time;
21  m_charge = charge;
22  m_timestamp = timestamp;
23  m_first_unique = 0;
24  //set the trigger info
25  const std::vector<int> empty;
26  m_trigger_readout_windows.assign(m_time.size(), empty);
27  m_masked.assign(m_time.size(), false);
28  m_start_trigger = 0;
29 }
30 
32  //algorithm borrowed from WCSimWCDigi::SortArrayByHitTime()
33  int i, j;
34  TimeDelta::short_time_t save_time;
35  int save_PMTid;
36  double save_charge;
37  std::vector<int> save_triggers;
38  bool save_masked;
39 
40 
41  for (i = 1; i < m_PMTid.size(); ++i) {
42  save_time = m_time[i];
43  save_PMTid = m_PMTid[i];
44  save_charge = m_charge[i];
45  save_triggers = m_trigger_readout_windows[i];
46  save_masked = m_masked[i];
47  for (j = i; j > 0 && m_time[j-1] > save_time; j--) {
48  m_time[j] = m_time[j-1];
49  m_PMTid[j] = m_PMTid[j-1];
50  m_charge[j] = m_charge[j-1];
52  m_masked[j] = m_masked[j-1];
53  }//j
54  m_time[j] = save_time;
55  m_PMTid[j] = save_PMTid;
56  m_charge[j] = save_charge;
57  m_trigger_readout_windows[j] = save_triggers;
58  m_masked[j] = save_masked;
59  }//i
60 }
61 
63  int size = m_time.size();
64  for (int i=0; i<size-1; ++i){
65  if (m_time[i] > m_time[i+1]){
66  return false;
67  }
68  }
69  return true;
70 }
71 
72 std::vector<SubSample> SubSample::Split(TimeDelta target_width, TimeDelta target_overlap) const {
73 
74  // If the sample is empty, just return a copy of self
75  if (m_time.size() == 0){
76  return std::vector<SubSample>(1, *this);
77  }
78 
79  // Ensure everything is sorted
80  if (not IsSortedByTime()){
81  // Otherwise return empty vector
82  return std::vector<SubSample>();
83  }
84 
85  // Distance between SubSamples
86  TimeDelta target_stride = target_width - target_overlap;
87 
88  // The vector of samples to be returned
89  std::vector<SubSample> split_samples;
90 
91  // Temporary information for storing digits that will be added to the samples
92  std::vector<float> temp_charge;
93  std::vector<int> temp_PMTid;
94  std::vector<TimeDelta::short_time_t> temp_time;
95  TimeDelta temp_timestamp = m_timestamp;
96 
97  // Set first SubSample timestamp according to first digit time
98  // Make sure hit times are not negative:
99  while ( m_timestamp + TimeDelta(m_time.at(0)) - temp_timestamp < TimeDelta(0.) ){
100  temp_timestamp -= target_stride;
101  }
102  // Make sure first SubSample is not empty
103  while ( m_timestamp + TimeDelta(m_time.at(0)) - temp_timestamp > target_stride ){
104  temp_timestamp += target_stride;
105  }
106 
107  // Add digits to new SubSamples
108  int ihit_first_unique = 0, ihit_first = 0;
109  for (int i = 0; i < m_time.size(); ++i){
110  TimeDelta time_in_window = m_timestamp + TimeDelta(m_time.at(i)) - temp_timestamp;
111  if (time_in_window < target_width){
112  // Add digit to thin time window to current SubSample
113  temp_time.push_back(time_in_window / TimeDelta::ns);
114  temp_charge.push_back(m_charge[i]);
115  temp_PMTid.push_back(m_PMTid[i]);
116  } else {
117  // Digit outside target window
118  // Save current SubSample and rewind to prepare a new one at the overlap position
119  SubSample new_sample;
120  new_sample.Append(temp_PMTid, temp_time, temp_charge, temp_timestamp);
121  new_sample.m_first_unique = ihit_first_unique - ihit_first;
122  split_samples.push_back(new_sample);
123  ihit_first_unique = i;
124  // Reset temporary vectors
125  temp_PMTid.clear();
126  temp_time.clear();
127  temp_charge.clear();
128  // Update timestamp
129  while ( not (m_timestamp + TimeDelta(m_time.at(i)) - temp_timestamp < target_width) ){
130  temp_timestamp += target_stride;
131  }
132  // Rewind index to cover overlap
133  while ( m_timestamp + TimeDelta(m_time.at(i)) - temp_timestamp > TimeDelta(0.) ){
134  --i;
135  // This will stop when `i` is just outside the new time window
136  // Then `i` will get increased by one at the end of the loop
137  }
138  ihit_first = i + 1;
139  }
140  }//i (loop over m_time)
141  // Add final SubSample
142  SubSample new_sample;
143  new_sample.Append(temp_PMTid, temp_time, temp_charge, temp_timestamp);
144  new_sample.m_first_unique = ihit_first_unique - ihit_first;
145  split_samples.push_back(new_sample);
146 
147  return split_samples;
148 }
149 
151  return m_timestamp + TimeDelta(m_time.at(index));
152 }
153 
154 bool SubSample::Append(const SubSample& sub)
155 {
156  return Append(sub.m_PMTid, sub.m_time, sub.m_charge, sub.m_timestamp);
157 }
158 
159 bool SubSample::Append(const std::vector<int> PMTid, const std::vector<TimeDelta::short_time_t> time, const std::vector<float> charge, const TimeDelta timestamp){
160  if (not (PMTid.size() == time.size() && PMTid.size() == charge.size())){
161  return false;
162  }
163  m_PMTid.insert (m_PMTid.end(), PMTid.begin(), PMTid.end());
164  m_charge.insert(m_charge.end(), charge.begin(), charge.end());
165 
166  // If these are the first hits to be added, just use their timestamp
167  if (m_time.size() == 0){
168  m_timestamp = timestamp;
169  m_time.insert(m_time.end(), time.begin(), time.end());
170  } else {
171  // Need to shift the hit times by the difference of timestamp offsets
172  TimeDelta::short_time_t time_shift = (timestamp - m_timestamp) / TimeDelta::ns;
173  for (int i=0; i<time.size(); ++i){
174  m_time.push_back(time[i] + time_shift);
175  }
176  }
177 
178  //set the trigger info
179  const std::vector<int> empty;
181  m_time.size() - m_trigger_readout_windows.size()
182  , empty);
183  m_masked.insert(m_masked.end(),
184  m_time.size() - m_masked.size(),
185  false);
186  m_start_trigger = 0;
187 
188  return true;
189 }
190 
191 void SubSample::TellMeAboutTheTriggers(const TriggerInfo & triggers, const int verbose) {
192 
193  //loop over triggers to get the start/end of the readout & mask windows
194  const unsigned int num_triggers = triggers.m_num_triggers;
195  std::vector<util::Window> readout_windows(num_triggers - m_start_trigger);
196  std::vector<util::Window> mask_windows(num_triggers - m_start_trigger);
197  if(util::DEBUG2 <= verbose)
198  util::Log("DEBUG: Trigger times before sorting:", util::DEBUG1);
199  std::stringstream ss;
200  for(unsigned int itrigger = m_start_trigger; itrigger < num_triggers; itrigger++) {
201  util::Window readout(itrigger,
202  triggers.m_readout_start_time[itrigger],
203  triggers.m_readout_end_time[itrigger]);
204  readout_windows[itrigger - m_start_trigger] = readout;
205  util::Window mask(itrigger,
206  triggers.m_mask_start_time[itrigger],
207  triggers.m_mask_end_time[itrigger]);
208  mask_windows[itrigger - m_start_trigger] = mask;
209  if(util::DEBUG2 <= verbose) {
210  ss << "DEBUG: Trigger: " << itrigger
211  << "\tReadout windows: " << readout_windows[itrigger].m_start
212  << "\t" << readout_windows[itrigger].m_end
213  << "\tMask windows: " << mask_windows[itrigger].m_start
214  << "\t" << mask_windows[itrigger].m_end;
215  util::Log(ss, util::DEBUG2);
216  }//DEBUG1
217  }//itrigger
218 
219  //iterate m_start_trigger, so we don't try masking hits from the same triggers next time this is called
220  m_start_trigger += num_triggers;
221 
222  //sort the readout windows.
223  // Done in reverse order, so we can pop them from the
224  // end of the vector they've gone out of range in the
225  // loop over hits (hits are also time sorted)
226  std::sort(readout_windows.rbegin(), readout_windows.rend(), util::WindowSorter);
227  std::sort(mask_windows.rbegin(), mask_windows.rend(), util::WindowSorter);
228 
229  if(util::DEBUG1 <= verbose) {
230  util::Log("DEBUG: Trigger times after sorting:", util::DEBUG1);
231  for(unsigned int itrigger = 0; itrigger < readout_windows.size(); itrigger++) {
232  ss << "DEBUG: Trigger: " << itrigger
233  << "\tReadout windows: " << readout_windows[itrigger].m_start
234  << "\t" << readout_windows[itrigger].m_end
235  << "\tMask windows: " << mask_windows[itrigger].m_start
236  << "\t" << mask_windows[itrigger].m_end;
237  util::Log(ss, util::DEBUG1);
238  }//itrigger
239  }//DEBUG1
240 
241  //ensure the hits are sorted in time
242  if(!IsSortedByTime())
243  SortByTime();
244 
245  //loop over hits
246  size_t n_hits = m_time.size();
247  TimeDelta hit_time;
248  for(size_t ihit = 0; ihit < n_hits; ihit++) {
249  hit_time = AbsoluteDigitTime(ihit);
250  //Is the hit in this readout window?
251  for(std::vector<util::Window>::reverse_iterator it = readout_windows.rbegin();
252  it != readout_windows.rend(); ++it) {
253  if(util::DEBUG3 <= verbose) {
254  ss << "DEBUG: READOUT " << (*it).m_start << "\t" << (*it).m_end << "\t" << (*it).m_trigger_num;
255  util::Log(ss, util::DEBUG3);
256  }//DEBUG3
257  //the trigger time is later than this hit
258  if(hit_time < (*it).m_start) {
259  if(util::DEBUG2 <= verbose) {
260  ss << "DEBUG: Hit time " << hit_time << " earlier than all subsequent trigger readouts";
261  util::Log(ss, util::DEBUG2);
262  }//DEBUG2
263  break;
264  }
265  //the trigger time is earlier than this hit
266  else if (hit_time > (*it).m_end) {
267  if(util::DEBUG2 <= verbose) {
268  ss << "DEBUG: Hit time " << hit_time << " later than last trigger window. Removing last window from readout vector";
269  util::Log(ss, util::DEBUG2);
270  }//DEBUG2
271  readout_windows.pop_back();
272  }
273  //the hit is in this trigger
274  else {
275  if(util::DEBUG3 <= verbose) {
276  ss << "DEBUG: Hit time " << hit_time << " in trigger readout window " << (*it).m_trigger_num;
277  util::Log(ss, util::DEBUG3);
278  }//DEBUG3
279  m_trigger_readout_windows[ihit].push_back((*it).m_trigger_num);
280  }
281  }//readout_windows
282  //Is the hit in this mask window?
283  for(std::vector<util::Window>::reverse_iterator it = mask_windows.rbegin();
284  it != mask_windows.rend(); ++it) {
285  if(util::DEBUG3 <= verbose) {
286  ss << "DEBUG: MASK " << (*it).m_start << "\t" << (*it).m_end << "\t" << (*it).m_trigger_num;
287  util::Log(ss, util::DEBUG3);
288  }//DEBUG3
289  //the trigger time is later than this hit
290  if(hit_time < (*it).m_start) {
291  if(util::DEBUG2 <= verbose) {
292  ss << "DEBUG: Hit time " << hit_time << " earlier than all subsequent trigger masks";
293  util::Log(ss, util::DEBUG2);
294  }//DEBUG2
295  break;
296  }
297  //the trigger time is earlier than this hit
298  else if (hit_time > (*it).m_end) {
299  if(util::DEBUG2 <= verbose) {
300  ss << "DEBUG: Hit time " << hit_time << " later than last trigger window. Removing last window from mask vector";
301  util::Log(ss, util::DEBUG2);
302  }//DEBUG2
303  mask_windows.pop_back();
304  }
305  //the hit is in this trigger
306  else {
307  if(util::DEBUG3 <= verbose) {
308  ss << "DEBUG: Hit time " << hit_time << " in trigger mask window " << (*it).m_trigger_num;
309  util::Log(ss, util::DEBUG3);
310  }//DEBUG3
311  }
312  }//mask_windows
313  }//ihit
314 }
Contains the start and end of a time window, along with an ID (nominally trigger number) ...
Definition: Utilities.h:157
unsigned int m_first_unique
Position of the first hit that isn&#39;t overlapping with the previous SubSample.
Definition: SubSample.h:53
void SortByTime()
Sort all digits in the SubSample by their time.
Definition: SubSample.cpp:31
float short_time_t
Type for relative hit times within a SubSample. Unit = ns.
Definition: TimeDelta.h:37
std::vector< SubSample > Split(TimeDelta target_width, TimeDelta target_overlap) const
Definition: SubSample.cpp:72
bool Append(const SubSample &sub)
Definition: SubSample.cpp:154
std::vector< int > m_PMTid
Vector of PMT IDs for all hits in SubSample.
Definition: SubSample.h:40
TimeDelta m_start
Definition: Utilities.h:159
std::vector< TimeDelta > m_readout_end_time
The ending time of the trigger window.
Definition: TriggerInfo.h:36
int m_start_trigger
Which trigger are we starting from in TellMeAboutTheTriggers()?
Definition: SubSample.h:76
static bool WindowSorter(const Window &lhs, const Window &rhs)
When sorting Window structs, sort by the start time.
Definition: Utilities.h:167
std::vector< float > m_charge
Vector of charges for all hits in SubSample. Unit: photoelectrons (MC), calibrated photoelectrons (da...
Definition: SubSample.h:44
std::vector< TimeDelta > m_mask_end_time
The ending time of the hit mask.
Definition: TriggerInfo.h:40
unsigned int n_hits
Definition: library_daq.h:93
TimeDelta m_timestamp
Timestamp of the whole SubSample.
Definition: SubSample.h:27
std::vector< TimeDelta > m_mask_start_time
The starting time of the hit mask.
Definition: TriggerInfo.h:38
static const TimeDelta ns
TimeDelta of 1 ns.
Definition: TimeDelta.h:57
TimeDelta AbsoluteDigitTime(int index) const
Return the absolute time (timestamp + digit time) of a digit.
Definition: SubSample.cpp:150
std::vector< TimeDelta > m_readout_start_time
The starting time of the trigger window.
Definition: TriggerInfo.h:34
std::vector< std::vector< int > > m_trigger_readout_windows
Stores the trigger readout windows each hit is associated with.
Definition: SubSample.h:48
bool IsSortedByTime() const
Check whether all hits are in time order.
Definition: SubSample.cpp:62
void Log(const std::string &message, const int message_level)
Format messages in the same way as for tools.
Definition: Utilities.cpp:276
std::vector< TimeDelta::short_time_t > m_time
Vector of hit times relative to timestamp for all hits in SubSample. Unit: ns.
Definition: SubSample.h:42
std::vector< bool > m_masked
Is each hit masked from future trigger decisions?
Definition: SubSample.h:50
void TellMeAboutTheTriggers(const TriggerInfo &triggers, const int verbose)
Definition: SubSample.cpp:191
unsigned int m_num_triggers
The number of triggers.
Definition: TriggerInfo.h:30