tof_dataclasses/events/
tof_event.rs

1//! Event strucutures for data reconrded by the tof
2//!
3
4use std::time::Instant;
5use std::fmt;
6use std::f32::consts::PI;
7use std::cmp::Ordering;
8
9cfg_if::cfg_if! {
10  if #[cfg(feature = "random")]  {
11    use crate::FromRandom;
12    use rand::Rng;
13  }
14}
15
16use crate::serialization::{
17  Serialization,
18  Packable,
19  parse_u8,
20  parse_u16,
21  parse_u32,
22  parse_u64,
23  parse_f32,
24  search_for_u16
25};
26
27use crate::packets::{
28  TofPacket,
29  PacketType
30};
31
32use crate::errors::SerializationError;
33
34use crate::events::{
35  MasterTriggerEvent,
36  RBEvent,
37  TofHit,
38  RBWaveform,
39  //RBMissingHit,
40  TriggerType,
41  EventStatus,
42  transcode_trigger_sources,
43};
44
45use crate::events::master_trigger::{
46  LTBThreshold,
47  LTB_CHANNELS
48};
49
50use crate::ProtocolVersion;
51
52cfg_if::cfg_if! {
53  if #[cfg(feature = "database")]  {
54    use crate::database::DsiJChPidMapping;
55    use crate::database::Paddle;
56    use std::collections::HashMap;
57  }
58}
59
60// #[cfg(feature ="database")]
61// use crate::database::Paddle;
62
63// This looks like a TODO
64#[derive(Debug, Copy, Clone, PartialEq, serde::Deserialize, serde::Serialize)]
65#[repr(u8)]
66pub enum CompressionLevel {
67  Unknown = 0u8,
68  None    = 10u8,
69}
70
71impl fmt::Display for CompressionLevel {
72  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
73    let r = serde_json::to_string(self).unwrap_or(
74      String::from("Error: cannot unwrap this CompressionLevel"));
75    write!(f, "<CompressionLevel: {}>", r)
76  }
77}
78
79impl From<u8> for CompressionLevel {
80  fn from(value: u8) -> Self {
81    match value {
82      0u8  => CompressionLevel::Unknown,
83      10u8 => CompressionLevel::None,
84      _    => CompressionLevel::Unknown
85    }
86  }
87}
88
89#[derive(Debug, Copy, Clone, PartialEq, serde::Deserialize, serde::Serialize)]
90#[repr(u8)]
91pub enum EventQuality {
92  Unknown        =  0u8,
93  Silver         = 10u8,
94  Gold           = 20u8,
95  Diamond        = 30u8,
96  FourLeafClover = 40u8,
97}
98
99impl fmt::Display for EventQuality {
100  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
101    let r = serde_json::to_string(self).unwrap_or(
102      String::from("Error: cannot unwrap this EventQuality"));
103    write!(f, "<EventQuality: {}>", r)
104  }
105}
106
107impl From<u8> for EventQuality {
108  fn from(value: u8) -> Self {
109    match value {
110      0u8  => EventQuality::Unknown,
111      10u8 => EventQuality::Silver,
112      20u8 => EventQuality::Gold,
113      30u8 => EventQuality::Diamond,
114      40u8 => EventQuality::FourLeafClover,
115      _    => EventQuality::Unknown
116    }
117  }
118}
119
120// FIXME - no PartialEq (or we have to implent it
121// since the times will never be equal
122#[derive(Debug, Clone)]
123pub struct TofEvent {
124
125  pub compression_level : CompressionLevel,
126  pub quality           : EventQuality,
127  pub header            : TofEventHeader,
128  pub mt_event          : MasterTriggerEvent,
129  pub rb_events         : Vec::<RBEvent>,
130  //pub missing_hits      : Vec::<RBMissingHit>, 
131  
132  // won't get serialized
133  pub creation_time     : Instant,
134  pub write_to_disk     : bool, 
135  pub paddles_set       : bool
136}
137
138impl fmt::Display for TofEvent {
139  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
140    write!(f, 
141"<TofEvent:
142     quality        :  {}
143     {} 
144     {}
145     n RBEvents      : {}>"
146            ,self.quality,
147            self.header,
148            self.mt_event,
149            self.rb_events.len())
150  }
151}
152
153impl Default for TofEvent {
154  fn default() -> Self {
155    Self::new()
156  }
157}
158
159impl TofEvent {
160
161  pub fn new() -> Self {
162    let creation_time = Instant::now();
163    Self {
164      compression_level : CompressionLevel::Unknown,
165      quality           : EventQuality::Unknown,
166      header            : TofEventHeader::new(),
167      mt_event          : MasterTriggerEvent::new(),
168      rb_events         : Vec::<RBEvent>::new(),
169      //missing_hits      : Vec::<RBMissingHit>::new(), 
170      creation_time     : creation_time,
171      write_to_disk     : true,
172      paddles_set       : false
173    }
174  }
175
176
177  #[cfg(feature="database")]
178  pub fn set_paddles(&mut self, paddles : &HashMap<u8, Paddle>) {
179    let mut nerror = 0u8;
180    for ev in &mut self.rb_events {
181      for h in &mut ev.hits {
182        match paddles.get(&h.paddle_id) {
183          None => {
184            error!("Got paddle id {} which is not in given map!", h.paddle_id);
185            nerror += 1;
186            continue;
187          }
188          Some(pdl) => {
189            h.set_paddle(pdl);
190          }
191        }
192      }
193    }
194    if nerror == 0 {
195      self.paddles_set = true;
196    }
197  }
198
199  /// Get the pointcloud of this event, sorted by time
200  /// 
201  /// # Returns
202  ///   (f32, f32, f32, f32, f32) : (x,y,z,t,edep)
203  pub fn get_pointcloud(&self) -> Option<Vec<(f32,f32,f32,f32,f32)>> {
204    let mut pc = Vec::<(f32,f32,f32,f32,f32)>::new();
205    if !self.paddles_set {
206      error!("Before getting the pointcloud, paddle information needs to be set for this event. Call TofEventSummary;:set_paddle");
207      return None;
208    }
209    for rbev in &self.rb_events {
210      for h in &rbev.hits {
211        let result = (h.x, h.y, h.z, h.get_t0(), h.get_edep());
212        pc.push(result);
213      }
214    }
215    Some(pc)
216  }
217
218  /// Compare the MasterTriggerEvent::trigger_hits with 
219  /// the actual hits to determine from which paddles
220  /// we should have received HG hits (from waveforms)
221  /// but we did not get them
222  ///
223  /// WARNING: The current implementation of this is 
224  /// rather slow and not fit for production use
225  /// FIXME - rewrite as a closure
226  #[cfg(feature="database")]
227  pub fn get_missing_paddles_hg(&self, pid_map : &DsiJChPidMapping) -> Vec<u8> {
228    let mut missing = Vec::<u8>::new();
229    for th in self.mt_event.get_trigger_hits() {
230      let pid = pid_map.get(&th.0).unwrap().get(&th.1).unwrap().get(&th.2.0).unwrap().0;
231      let mut found = false;
232      for h in self.get_hits() {
233        if h.paddle_id == pid {
234          found = true;
235          break
236        }
237      }
238      if !found {
239        missing.push(pid);
240      }
241    }
242    missing
243  }
244  
245  /// Compare the MasterTriggerEvent::trigger_hits with 
246  /// the actual hits to determine from which paddles
247  /// we have received more hits than we were supposed to.
248  /// These hits are neither in the trigger hits nor
249  /// rb_link_ids
250  ///
251  /// FIXME - this can be hits which are exclusively 
252  ///         within the RB integration window
253  #[cfg(feature="database")]
254  pub fn get_extra_paddles_hg(&self, pid_map : &DsiJChPidMapping) -> Vec<u8> {
255    let mut extra = Vec::<u8>::new();
256    let mut trigger_pids = Vec::<u8>::new(); 
257    for th in self.mt_event.get_trigger_hits() {
258      let pid = pid_map.get(&th.0).unwrap().get(&th.1).unwrap().get(&th.2.0).unwrap().0;
259      trigger_pids.push(pid);
260    }
261    for h in self.get_hits() {
262      if !trigger_pids.contains(&h.paddle_id) {
263        extra.push(h.paddle_id);
264      }
265    }
266    extra
267  }
268  
269  /// Compare the MasterTriggerEvent::trigger_hits with 
270  /// the actual recorded waveforms to determine from which paddles
271  /// we should have received waveforms from. This is 
272  /// independent of the hits, which additionally required
273  /// that the hit extraction algorithm worked.
274  #[cfg(feature="database")]
275  pub fn get_missing_paddles_wf(&self, pid_map : &DsiJChPidMapping) -> Vec<u8> {
276    let mut missing = Vec::<u8>::new();
277    let wf_pids = self.get_waveform_pids();
278    for th in self.mt_event.get_trigger_hits() {
279      let pid = pid_map.get(&th.0).unwrap().get(&th.1).unwrap().get(&th.2.0).unwrap().0;
280      // FIXME - rewrite this section so that it is more concise
281      let mut found = false;
282      for wf_pid in &wf_pids {
283        if *wf_pid == pid {
284          found = true;
285          break
286        }
287      }
288      if !found {
289        missing.push(pid);
290      }
291    }
292    missing
293  }
294
295  /// Get the triggered paddle ids
296  ///
297  /// Warning, this might be a bit slow
298  #[cfg(feature="database")]
299  pub fn get_triggered_paddles(&self, pid_map :   DsiJChPidMapping) -> Vec<u8> {
300    let mut paddles = Vec::<u8>::with_capacity(3);
301    for th in self.mt_event.get_trigger_hits() {
302      let pid = pid_map.get(&th.0).unwrap().get(&th.1).unwrap().get(&th.2.0).unwrap().0;
303      paddles.push(pid);
304    }
305    paddles
306  }
307  
308
309  pub fn extract_event_id_from_stream(stream : &Vec<u8>) 
310    -> Result<u32, SerializationError> {
311    // 2 + 2 + 2 + 2 + 4
312    let evid = parse_u32(stream, &mut 12);
313    Ok(evid)
314  }
315
316  pub fn age(&self) -> u64 {
317    self.creation_time.elapsed().as_secs()
318  }
319
320  /// Simple check if the event contains as much RBEvents 
321  /// as expected from the provided boards masks by the MTB
322  pub fn is_complete(&self) -> bool {
323    self.mt_event.get_rb_link_ids().len() == self.rb_events.len()
324  }
325 
326  /// A more advanced check, where events which are not in the 
327  /// provided mtb_link_id list don't count for completion
328  pub fn is_complete_masked(&self, mtb_link_ids_excluded : &Vec::<u8>) -> bool {
329    let mut expected_events = 0usize;
330    for k in &self.mt_event.get_rb_link_ids() {
331      if !mtb_link_ids_excluded.contains(k) {
332        expected_events += 1
333      }
334    }
335    self.rb_events.len() == expected_events
336  }
337
338  /// Encode the sizes of the vectors holding the 
339  /// into an u32
340  ///
341  /// We have one byte (256) max length per vector.
342  pub fn construct_sizes_header(&self) -> u32 {
343     let rb_event_len = self.rb_events.len() as u32;
344     // disable missing hits
345     //let miss_len     = self.missing_hits.len() as u32;
346     let miss_len     = 0u32;
347     let mut mask     = 0u32;
348     mask = mask | rb_event_len;
349     mask = mask | (miss_len << 8);
350     mask
351  }
352
353  pub fn decode_size_header(mask : &u32) 
354    -> (usize, usize) {
355    let rb_event_len = (mask & 0xFF)        as usize;
356    let miss_len     = ((mask & 0xFF00)     >> 8)  as usize;
357    (rb_event_len, miss_len)
358  }
359  
360  pub fn get_combined_vector_sizes(&self) -> usize {
361    self.rb_events.len() 
362    //+ self.missing_hits.len() 
363  }
364
365  /// Get all waveforms of all RBEvents in this event
366  pub fn get_rbwaveforms(&self) -> Vec<RBWaveform> {
367    let mut wf = Vec::<RBWaveform>::new();
368    for ev in &self.rb_events {
369      wf.extend_from_slice(&ev.get_rbwaveforms());
370    }
371    wf
372  }
373
374  /// Get all waveforms of all RBEvents in this event
375  /// ISSUE - Performance, Memory
376  /// FIXME - reimplement this things where this
377  ///         returns only a reference
378  pub fn get_waveforms(&self) -> Vec<RBWaveform> {
379    let mut wfs = Vec::<RBWaveform>::new();
380    for ev in &self.rb_events {
381      for wf in &ev.get_rbwaveforms() {
382        wfs.push(wf.clone());
383      }
384    }
385    wfs
386  }
387
388  /// Get all the paddles which have waveforms
389  pub fn get_waveform_pids(&self) -> Vec<u8> {
390    let mut pids = Vec::<u8>::new();
391    for ev in &self.rb_events {
392      for wf in &ev.get_rbwaveforms() {
393        pids.push(wf.paddle_id)
394      }
395    }
396    pids
397  }
398
399  /// Get all hits of all RBEvents in this event
400  pub fn get_hits(&self) -> Vec<TofHit> {
401    let mut hits = Vec::<TofHit>::new();
402    for ev in &self.rb_events {
403      for h in &ev.hits {
404        hits.push(*h);
405      }
406    }
407    hits
408  }
409
410  /// Check if th eassociated RBEvents have any of their
411  /// mangling stati set
412  pub fn has_any_mangling(&self) -> bool {
413    for rbev in &self.rb_events {
414      if rbev.status == EventStatus::CellAndChnSyncErrors 
415      || rbev.status == EventStatus::CellSyncErrors 
416      || rbev.status == EventStatus::ChnSyncErrors {
417        return true;
418      }
419    }
420    false
421  }
422
423  pub fn get_summary(&self) -> TofEventSummary {
424    let mut summary         = TofEventSummary::new();
425    // generate an aggregate status from all the different stati
426    summary.status          = self.mt_event.event_status;
427    if self.has_any_mangling() {
428      summary.status = EventStatus::AnyDataMangling;
429    }
430    // FIXME - this is not trigger paddles, but trigger hits!
431    summary.trigger_sources    = self.mt_event.trigger_source;
432    summary.n_trigger_paddles  = self.mt_event.get_trigger_hits().len() as u8;
433    summary.event_id           = self.header.event_id;
434    // truncate the run id to u16
435    summary.run_id             = (self.header.run_id & 0x0000ffff) as u16;
436    // FIXME we set the protocol version here, but that should propably 
437    // go elsewhere
438    summary.version            = ProtocolVersion::V1;
439    let mt_timestamp           = (self.mt_event.get_timestamp_abs48() as f64/1000.0).floor()  as u64; 
440    summary.timestamp32        = (mt_timestamp  & 0x00000000ffffffff ) as u32;
441    summary.timestamp16        = ((mt_timestamp & 0x0000ffff00000000 ) >> 32) as u16;
442    //summary.primary_beta       = self.header.primary_beta; 
443    //summary.primary_charge     = self.header.primary_charge; 
444    summary.dsi_j_mask         = self.mt_event.dsi_j_mask;
445    summary.channel_mask       = self.mt_event.channel_mask.clone();
446    summary.mtb_link_mask      = self.mt_event.mtb_link_mask;
447    summary.drs_dead_lost_hits = self.get_lost_hits();
448    summary.hits               = Vec::<TofHit>::new();
449    for ev in &self.rb_events {
450      for hit in &ev.hits {
451        let h = hit.clone();
452        if summary.version == ProtocolVersion::V1 {
453          if h.paddle_id <= 60 {
454            summary.n_hits_cbe += 1;
455            summary.tot_edep_cbe += h.get_edep();
456          }
457          else if h.paddle_id <= 108 && h.paddle_id > 60 {
458            summary.n_hits_umb += 1;
459            summary.tot_edep_umb += h.get_edep();
460          }
461          else {
462            summary.n_hits_cor += 1;
463            summary.tot_edep_cor += h.get_edep();
464          }
465        }
466        summary.hits.push(h);
467      }
468    }
469    #[cfg(feature="database")]
470    summary.normalize_hit_times();
471    summary
472  }
473  
474  /// The number of hits we did not get 
475  /// becaue of the DRS busy
476  pub fn get_lost_hits(&self) -> u16 {
477    let mut lost_hits = 0u16;
478    for rbev in &self.rb_events {
479      if rbev.header.drs_lost_trigger() {
480        let mut nhits = rbev.header.get_nchan() as u16;
481        if nhits > 0 {
482          nhits -= 1;
483        }
484        lost_hits += nhits;
485      }
486    }
487    lost_hits
488  }
489  
490  pub fn get_nhits_umb(&self) -> usize {
491    let mut nhit = 0;
492    for h in &self.get_hits() {
493      if h.paddle_id > 60 && h.paddle_id < 109 {
494        nhit += 1;
495      }
496    }
497    nhit
498  }
499  
500  pub fn get_nhits_cbe(&self) -> usize {
501    let mut nhit = 0;
502    for h in &self.get_hits() {
503      if h.paddle_id < 61 {
504        nhit += 1;
505      }
506    }
507    nhit
508  }
509
510  pub fn get_nhits_cor(&self) -> usize {
511    let mut nhit = 0;
512    for h in &self.get_hits() {
513      if h.paddle_id > 108 {
514        nhit += 1;
515      }
516    }
517    nhit
518  }
519
520  pub fn get_nhits(&self) -> usize {
521    self.get_hits().len()
522  }
523}
524
525impl Packable for TofEvent {
526  const PACKET_TYPE : PacketType = PacketType::TofEvent;
527}
528
529impl Serialization for TofEvent {
530  
531  const HEAD               : u16   = 43690; //0xAAAA
532  const TAIL               : u16   = 21845; //0x5555
533
534  // unify to_le_bytes and other in to_bytestream ? TODO
535  fn to_bytestream(&self) -> Vec<u8> {
536    let mut stream = Vec::<u8>::new();
537    stream.extend_from_slice(&Self::HEAD.to_le_bytes());
538    stream.extend_from_slice(&(self.compression_level as u8).to_le_bytes());
539    stream.extend_from_slice(&(self.quality as u8).to_le_bytes());
540    stream.extend_from_slice(&self.header.to_bytestream());
541    stream.extend_from_slice(&self.mt_event.to_bytestream());
542    let sizes_header = self.construct_sizes_header();
543    stream.extend_from_slice(&sizes_header.to_le_bytes());
544    for k in 0..self.rb_events.len() {
545      stream.extend_from_slice(&self.rb_events[k].to_bytestream());
546    }
547    //for k in 0..self.missing_hits.len() {
548    //  stream.extend_from_slice(&self.missing_hits[k].to_bytestream());
549    //}
550    stream.extend_from_slice(&Self::TAIL.to_le_bytes());
551    stream
552  }
553  
554  fn from_bytestream(stream    : &Vec<u8>, 
555                     pos       : &mut usize) 
556    -> Result<Self, SerializationError>{
557    let mut event = Self::new();
558    let head_pos = search_for_u16(Self::HEAD, stream, *pos)?; 
559    *pos = head_pos + 2;
560    event.compression_level = CompressionLevel::try_from(parse_u8(stream, pos)).unwrap();
561    event.quality           = EventQuality::try_from(parse_u8(stream, pos)).unwrap();
562    event.header            = TofEventHeader::from_bytestream(stream, pos)?;
563    event.mt_event          = MasterTriggerEvent::from_bytestream(stream, pos)?;
564    let v_sizes = Self::decode_size_header(&parse_u32(stream, pos));
565    for k in 0..v_sizes.0 {
566      match RBEvent::from_bytestream(stream, pos) {
567        Err(err) => error!("Expected RBEvent {} of {}, but got serialization error {}!", k,  v_sizes.0, err),
568        Ok(ev) => {
569          event.rb_events.push(ev);
570        }
571      }
572    }
573    let tail = parse_u16(stream, pos);
574    if tail != Self::TAIL {
575      error!("Decoding of TAIL failed! Got {} instead!", tail);
576    }
577    Ok(event)
578  }
579}
580
581#[cfg(feature="random")]
582impl FromRandom for TofEvent {
583
584  fn from_random() -> Self {
585    let mut event   = Self::new();
586    event.mt_event  = MasterTriggerEvent::from_random();
587    event.header    = TofEventHeader::from_random();
588    let mut rng     = rand::thread_rng();
589    let n_boards    = rng.gen_range(1..41) as u8;
590    //let n_boards    = rng.gen::<u8>() as usize;
591    //let n_paddles   = rng.gen::<u8>() as usize;
592    for _ in 0..n_boards {
593      event.rb_events.push(RBEvent::from_random());
594    }
595    //for _ in 0..n_missing {
596    //  event.missing_hits.push(RBMissingHit::from_random());
597    //}
598    // for now, we do not randomize CompressionLevel and qualtiy
599    //event.compression_level : CompressionLevel::,
600    //event.quality           : EventQuality::Unknown,
601    event
602  }
603}
604
605impl From<MasterTriggerEvent> for TofEvent {
606  fn from(mte : MasterTriggerEvent) -> Self {
607    let mut te : TofEvent = Default::default();
608    te.mt_event = mte;
609    te.header.event_id = te.mt_event.event_id;
610    te
611  }
612}
613
614/// The main event structure
615#[derive(Debug, Clone, PartialEq)]
616pub struct TofEventHeader  {
617
618  pub run_id       : u32,
619  pub event_id     : u32,
620  // lost hits insead of n_hit outer and n_hit inner tof
621  pub drs_dead_lost_hits  : u8,
622  pub rsvd0              : u8,
623  // the timestamp shall be comging from the master trigger
624  pub timestamp_32 : u32,
625  pub timestamp_16 : u16, // -> 14 byres
626  
627
628  // reconstructed quantities
629  pub primary_beta        : u16, 
630  pub primary_beta_unc    : u16, 
631  pub primary_charge      : u16, 
632  pub primary_charge_unc  : u16, 
633  pub primary_outer_tof_x : u16, 
634  pub primary_outer_tof_y : u16, 
635  pub primary_outer_tof_z : u16, 
636  pub primary_inner_tof_x : u16, 
637  pub primary_inner_tof_y : u16, 
638  pub primary_inner_tof_z : u16, //-> 20bytes primary 
639
640  //pub nhit_outer_tof       : u8,  
641  // no need to save this, can be 
642  // rereated from paddle_info.size() - nhit_outer_tof
643  //pub nhit_inner_tof       : u8, 
644
645  pub trigger_info         : u8,
646  pub ctr_etx              : u8,
647
648  // this field can be debated
649  // the reason we have it is 
650  // that for de/serialization, 
651  // we need to know the length 
652  // of the expected bytestream.
653  pub n_paddles           : u8, // we don't have more than 
654                               // 256 paddles.
655}
656
657impl TofEventHeader {
658  
659  pub fn new() -> Self {
660    Self {
661      run_id               : 0,
662      event_id             : 0,
663      drs_dead_lost_hits   : 0,
664      rsvd0               : 0,
665      timestamp_32         : 0,
666      timestamp_16         : 0,
667      primary_beta         : 0, 
668      primary_beta_unc     : 0, 
669      primary_charge       : 0, 
670      primary_charge_unc   : 0, 
671      primary_outer_tof_x  : 0, 
672      primary_outer_tof_y  : 0, 
673      primary_outer_tof_z  : 0, 
674      primary_inner_tof_x  : 0, 
675      primary_inner_tof_y  : 0, 
676      primary_inner_tof_z  : 0,  
677      //nhit_outer_tof       : 0,  
678      //nhit_inner_tof       : 0, 
679      trigger_info         : 0,
680      ctr_etx              : 0,
681      n_paddles            : 0  
682    }
683  }
684}
685
686impl Serialization for TofEventHeader {
687  const HEAD               : u16   = 0xAAAA;
688  const TAIL               : u16   = 0x5555;
689  const SIZE               : usize = 43; 
690
691  fn from_bytestream(stream : &Vec<u8>, pos : &mut usize)
692     -> Result<Self, SerializationError> {
693    Self::verify_fixed(stream, pos)?;
694    let mut event             = Self::new();
695    event.run_id              = parse_u32(stream, pos);
696    event.event_id            = parse_u32(stream, pos);
697    event.timestamp_32        = parse_u32(stream, pos);
698    event.timestamp_16        = parse_u16(stream, pos);
699    event.primary_beta        = parse_u16(stream, pos);
700    event.primary_beta_unc    = parse_u16(stream, pos);
701    event.primary_charge      = parse_u16(stream, pos);
702    event.primary_charge_unc  = parse_u16(stream, pos);
703    event.primary_outer_tof_x = parse_u16(stream, pos);
704    event.primary_outer_tof_y = parse_u16(stream, pos);
705    event.primary_outer_tof_z = parse_u16(stream, pos);
706    event.primary_inner_tof_x = parse_u16(stream, pos);
707    event.primary_inner_tof_y = parse_u16(stream, pos);
708    event.primary_inner_tof_z = parse_u16(stream, pos); 
709    event.drs_dead_lost_hits  = parse_u8(stream, pos);
710    event.rsvd0              = parse_u8(stream, pos);
711    //event.nhit_outer_tof      = parse_u8(stream, pos);
712    //event.nhit_inner_tof      = parse_u8(stream, pos);
713    event.trigger_info        = parse_u8(stream, pos);
714    event.ctr_etx             = parse_u8(stream, pos);
715    event.n_paddles           = parse_u8(stream, pos); 
716    *pos += 2; 
717    Ok(event) 
718  }
719  
720  fn to_bytestream(&self) -> Vec<u8> {
721    let mut bytestream = Vec::<u8>::with_capacity(Self::SIZE);
722    bytestream.extend_from_slice(&Self::HEAD                     .to_le_bytes());
723    bytestream.extend_from_slice(&self.run_id                    .to_le_bytes());
724    bytestream.extend_from_slice(&self.event_id                  .to_le_bytes());
725    bytestream.extend_from_slice(&self.timestamp_32              .to_le_bytes());
726    bytestream.extend_from_slice(&self.timestamp_16              .to_le_bytes());
727    bytestream.extend_from_slice(&self.primary_beta              .to_le_bytes());
728    bytestream.extend_from_slice(&self.primary_beta_unc          .to_le_bytes());
729    bytestream.extend_from_slice(&self.primary_charge            .to_le_bytes());
730    bytestream.extend_from_slice(&self.primary_charge_unc        .to_le_bytes());
731    bytestream.extend_from_slice(&self.primary_outer_tof_x       .to_le_bytes());
732    bytestream.extend_from_slice(&self.primary_outer_tof_y       .to_le_bytes());
733    bytestream.extend_from_slice(&self.primary_outer_tof_z       .to_le_bytes());
734    bytestream.extend_from_slice(&self.primary_inner_tof_x       .to_le_bytes());
735    bytestream.extend_from_slice(&self.primary_inner_tof_y       .to_le_bytes());
736    bytestream.extend_from_slice(&self.primary_inner_tof_z       .to_le_bytes());
737    //bytestream.extend_from_slice(&self.rb_events
738    //bytestream.extend_from_slice(&self.nhit_outer_tof            .to_le_bytes());
739    //bytestream.extend_from_slice(&self.nhit_inner_tof            .to_le_bytes());
740    bytestream.extend_from_slice(&self.drs_dead_lost_hits        .to_le_bytes());
741    bytestream.extend_from_slice(&self.rsvd0                    .to_le_bytes());
742    bytestream.extend_from_slice(&self.trigger_info              .to_le_bytes());
743    bytestream.extend_from_slice(&self.ctr_etx                   .to_le_bytes());
744    bytestream.extend_from_slice(&self.n_paddles                 .to_le_bytes());
745    bytestream.extend_from_slice(&Self::TAIL        .to_le_bytes()); 
746    bytestream
747  }
748}
749
750
751impl Default for TofEventHeader {
752  fn default() -> Self {
753    Self::new()
754  }
755}
756
757impl From<&MasterTriggerEvent> for TofEventHeader {
758  fn from(mte : &MasterTriggerEvent) -> Self {
759    let mut te               = Self::new();
760    te.event_id              = mte.event_id;
761    te.timestamp_32          = mte.timestamp;
762    te.n_paddles             = mte.get_trigger_hits().len() as u8;
763    te
764  }
765}
766
767impl fmt::Display for TofEventHeader {
768  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
769    let mut repr = String::from("<TofEventHeader"); 
770    repr += &(format!("\n  Run   ID          : {}", self.run_id              ));
771    repr += &(format!("\n  Event ID          : {}", self.event_id            ));
772    repr += &(format!("\n  Timestamp 32      : {}", self.timestamp_32        ));
773    repr += &(format!("\n  Timestamp 16      : {}", self.timestamp_16        ));
774    repr += &(format!("\n  DRS LOST HITS     : {}", self.drs_dead_lost_hits  ));
775    repr += &(format!("\n  Prim. Beta        : {}", self.primary_beta        ));
776    repr += &(format!("\n  Prim. Beta Unc    : {}", self.primary_beta_unc    ));
777    repr += &(format!("\n  Prim. Charge      : {}", self.primary_charge      ));
778    repr += &(format!("\n  Prim. Charge unc  : {}", self.primary_charge_unc  ));
779    repr += &(format!("\n  Prim. Outer Tof X : {}", self.primary_outer_tof_x ));
780    repr += &(format!("\n  Prim. Outer Tof Y : {}", self.primary_outer_tof_y ));
781    repr += &(format!("\n  Prim. Outer Tof Z : {}", self.primary_outer_tof_z ));
782    repr += &(format!("\n  Prim. Inner Tof X : {}", self.primary_inner_tof_x ));
783    repr += &(format!("\n  Prim. Inner Tof Y : {}", self.primary_inner_tof_y ));
784    repr += &(format!("\n  Prim. Inner Tof Z : {}", self.primary_inner_tof_z ));
785    //repr += &(format!("\n  NHit  Outer Tof   : {}", self.nhit_outer_tof      ));
786    //repr += &(format!("\n  NHit  Inner Tof   : {}", self.nhit_inner_tof      ));
787    repr += &(format!("\n  TriggerInfo       : {}", self.trigger_info        ));
788    repr += &(format!("\n  Ctr ETX           : {}", self.ctr_etx             ));
789    repr += &(format!("\n  NPaddles          : {}", self.n_paddles           ));
790    repr += ">";
791  write!(f,"{}", repr)
792  }
793}
794
795#[cfg(feature="random")]
796impl FromRandom for TofEventHeader {
797
798  fn from_random() -> Self {
799    let mut rng     = rand::thread_rng();
800    Self { 
801      run_id               : rng.gen::<u32>(),
802      event_id             : rng.gen::<u32>(),
803      drs_dead_lost_hits   : rng.gen::<u8>(),
804      rsvd0               : rng.gen::<u8>(),
805      timestamp_32         : rng.gen::<u32>(),
806      timestamp_16         : rng.gen::<u16>(),
807      primary_beta         : rng.gen::<u16>(), 
808      primary_beta_unc     : rng.gen::<u16>(), 
809      primary_charge       : rng.gen::<u16>(), 
810      primary_charge_unc   : rng.gen::<u16>(), 
811      primary_outer_tof_x  : rng.gen::<u16>(), 
812      primary_outer_tof_y  : rng.gen::<u16>(), 
813      primary_outer_tof_z  : rng.gen::<u16>(), 
814      primary_inner_tof_x  : rng.gen::<u16>(), 
815      primary_inner_tof_y  : rng.gen::<u16>(), 
816      primary_inner_tof_z  : rng.gen::<u16>(),  
817      trigger_info         : rng.gen::<u8>(),
818      ctr_etx              : rng.gen::<u8>(),
819      n_paddles            : rng.gen::<u8>()  
820    }
821  }
822}
823
824/// De-facto the main event class
825///
826/// TofEventSummary provides a list of extracted
827/// hits from the ReadoutBoards as well as 
828/// information about the trigger system.
829#[derive(Debug, Clone, PartialEq)]
830pub struct TofEventSummary {
831  pub status            : EventStatus,
832  pub version           : ProtocolVersion,
833  pub quality           : u8,
834  pub trigger_sources   : u16,
835
836  /// the number of triggered paddles coming
837  /// from the MTB directly. This might NOT be
838  /// the same as the number of hits!
839  pub n_trigger_paddles  : u8,
840  pub event_id           : u32,
841  /// NEW - uses the space for primary_beta,
842  /// which we won't have anyway
843  pub run_id             : u16,
844  pub timestamp32        : u32,
845  pub timestamp16        : u16,
846  /// DEPRECATED, won't get serialized
847  /// reconstructed primary beta
848  pub primary_beta       : u16, 
849  /// DEPRECATED, won't get serialized
850  /// reconstructed primary charge
851  pub primary_charge     : u16, 
852  /// scalar number of hits missed in
853  /// this event due to DRS on the RB
854  /// being busy
855  pub drs_dead_lost_hits : u16, 
856  pub dsi_j_mask         : u32,
857  pub channel_mask       : Vec<u16>,
858  pub mtb_link_mask      : u64,
859  pub hits               : Vec<TofHit>,
860  // a bunch of calculated variablels, used 
861  // for online interesting event search
862  // these will be only available in ProtocolVersion 1
863  pub n_hits_umb         : u8,
864  pub n_hits_cbe         : u8,
865  pub n_hits_cor         : u8,
866  pub tot_edep_umb       : f32,
867  pub tot_edep_cbe       : f32,
868  pub tot_edep_cor       : f32,
869  pub paddles_set        : bool,
870}
871
872impl TofEventSummary {
873
874  pub fn new() -> Self {
875    Self {
876      status             : EventStatus::Unknown,
877      version            : ProtocolVersion::Unknown,
878      n_hits_umb         : 0,
879      n_hits_cbe         : 0,
880      n_hits_cor         : 0,
881      tot_edep_umb       : 0.0,
882      tot_edep_cbe       : 0.0,
883      tot_edep_cor       : 0.0,
884      quality            : 0,
885      trigger_sources    : 0,
886      n_trigger_paddles  : 0,
887      event_id           : 0,
888      run_id             : 0,
889      timestamp32        : 0,
890      timestamp16        : 0,
891      primary_beta       : 0, 
892      primary_charge     : 0, 
893      drs_dead_lost_hits : 0,
894      dsi_j_mask         : 0,
895      channel_mask       : Vec::<u16>::new(),
896      mtb_link_mask      : 0,
897      hits               : Vec::<TofHit>::new(),
898      paddles_set        : false,
899    }
900  }
901
902  /// Set timing offsets to the event's hits
903  ///
904  /// # Arguments:
905  ///   * offsets : a hashmap paddle id -> timing offset
906  #[cfg(feature="database")]
907  pub fn set_timing_offsets(&mut self, offsets : &HashMap<u8, f32>) {
908    for h in self.hits.iter_mut() {
909      if offsets.contains_key(&h.paddle_id) {
910        h.timing_offset = offsets[&h.paddle_id]; 
911      }
912    }
913  }
914
915  /// Remove hits from the hitseries which can not 
916  /// be caused by the same particle, which means 
917  /// that for these two specific hits beta with 
918  /// respect to the first hit in the event is 
919  /// larger than one
920  /// That this works, first hits need to be 
921  /// "normalized" by calling normalize_hit_times
922  ///
923  /// # Return:
924  ///
925  ///   * removed paddle ids, twindows
926  pub fn lightspeed_cleaning(&mut self, t_err : f32) -> (Vec<u8>, Vec<f32>) {
927    // first sort the hits in time
928    if self.hits.len() == 0 {
929      return (Vec::<u8>::new(), Vec::<f32>::new());
930    }
931    let mut twindows = Vec::<f32>::new();
932
933    self.hits.sort_by(|a,b| (a.event_t0).partial_cmp(&b.event_t0).unwrap());
934    let first_hit = self.hits[0].clone(); // the clone here is a bit unfortunate, 
935                                           // this can be done better with walking 
936                                           // over the list and updating references
937    let mut clean_hits = Vec::<TofHit>::new(); 
938    let mut rm_hits    = Vec::<u8>::new();
939    // per definition, we can't remove the first hit, ever
940    clean_hits.push(first_hit.clone());
941    //error!("-----");
942    let mut prior_hit = first_hit;
943    //println!("TO FIRST {}",first_hit.event_t0);
944    for h in self.hits.iter().skip(1) {
945      let mut min_tdiff_cvac = 1e9*1e-3*prior_hit.distance(h)/299792458.0;
946      let twindow            = prior_hit.event_t0 + min_tdiff_cvac;
947      
948
949      // FIXME - implement different strategies
950      // this is the "default" strategy
951      //if h.event_t0 < twindow {
952      //  rm_hits.push(h.paddle_id);
953      //  twindows.push(twindow);
954      //  continue;
955      //}
956      // this is the "lenient" strategy
957      if h.event_t0 + 2.0*t_err < twindow {
958        rm_hits.push(h.paddle_id);
959        twindows.push(twindow);
960        continue;
961      }
962      // this is the "aggressive" strategy
963      //if h.event_t0 - 2.0*t_err < twindow {
964      //  rm_hits.push(h.paddle_id);
965      //  continue;
966      //}
967      
968      // should we remove negative beta hits?
969      //if beta < 0.0 {
970      //  rm_hits.push(h.paddle_id);
971      //  continue;
972      //}
973      // update the prior hit only 
974      // when it is a good one. If it 
975      // is bad we continue to compare
976      // to the first hit
977      prior_hit = h.clone();
978      clean_hits.push(*h);
979    }
980    self.hits = clean_hits;
981    (rm_hits, twindows)
982  }
983
984
985  /// Non causal hits have hit times in ends A and be which 
986  /// are not compatible with the speed of light in the paddle, 
987  /// that is, the hit gets registered too early. If we look 
988  /// at a plot of the reconstructed position, these hits would 
989  /// correspond to positions outside of the paddle.
990  ///
991  /// #Returns:
992  ///   A vector of paddle ids with removed hits
993  ///
994  pub fn remove_non_causal_hits(&mut self) -> Vec<u8> {
995    let mut clean_hits = Vec::<TofHit>::new();
996    let mut removed_pids = Vec::<u8>::new();
997    for h in &self.hits {
998      if h.obeys_causality() {
999        clean_hits.push(*h);
1000      } else {
1001        removed_pids.push(h.paddle_id);
1002      }
1003    }
1004    self.hits = clean_hits;
1005    removed_pids
1006  }
1007  
1008  #[cfg(feature="database")]
1009  pub fn normalize_hit_times(&mut self) {
1010    if self.hits.len() == 0 {
1011      return;
1012    }
1013    // check if hit times have already been normalized
1014    if self.hits[0].event_t0 == 0.0 {
1015      return;
1016    }
1017
1018    let phase0 = self.hits[0].phase.to_f32();
1019    for h in &mut self.hits {
1020      let t0 = h.get_t0_uncorrected() + h.get_cable_delay();
1021      let mut phase_diff = h.phase.to_f32() - phase0;
1022      while phase_diff < - PI/2.0 {
1023        phase_diff += 2.0*PI;
1024      }
1025      while phase_diff > PI/2.0 {
1026        phase_diff -= 2.0*PI;
1027      }
1028      let t_shift = 50.0*phase_diff/(2.0*PI);
1029      h.event_t0 = t0 + t_shift;
1030    }
1031    // start the first hit at 0
1032    // if a hit is NAN, assume it has a "larger" time
1033    self.hits.sort_by(|a,b| (a.event_t0).partial_cmp(&b.event_t0).unwrap_or(Ordering::Greater));
1034    let t0_first_hit = self.hits[0].event_t0;
1035    for h in self.hits.iter_mut() {
1036      h.event_t0 -= t0_first_hit
1037    }
1038  }
1039 
1040  #[cfg(feature="database")]
1041  pub fn set_paddles(&mut self, paddles : &HashMap<u8, Paddle>) {
1042    let mut nerror = 0u8;
1043    for h in &mut self.hits {
1044      match paddles.get(&h.paddle_id) {
1045        None => {
1046          error!("Got paddle id {} which is not in given map!", h.paddle_id);
1047          nerror += 1;
1048          continue;
1049        }
1050        Some(pdl) => {
1051          h.set_paddle(pdl);
1052        }
1053      }
1054    }
1055    if nerror == 0 {
1056      self.paddles_set = true;
1057    }
1058  }
1059
1060  /// Get the pointcloud of this event, sorted by time
1061  /// 
1062  /// # Returns
1063  ///   (f32, f32, f32, f32, f32) : (x,y,z,t,edep)
1064  pub fn get_pointcloud(&self) -> Option<Vec<(f32,f32,f32,f32,f32)>> {
1065    let mut pc = Vec::<(f32,f32,f32,f32,f32)>::new();
1066    if !self.paddles_set {
1067      error!("Before getting the pointcloud, paddle information needs to be set for this event. Call TofEventSummary;:set_paddle");
1068      return None;
1069    }
1070    for h in &self.hits {
1071      let result = (h.x, h.y, h.z, h.get_t0(), h.get_edep());
1072      pc.push(result);
1073    }
1074    Some(pc)
1075  }
1076
1077  /// Compare the MasterTriggerEvent::trigger_hits with 
1078  /// the actual hits to determine from which paddles
1079  /// we should have received HG hits (from waveforms)
1080  /// but we did not get them
1081  ///
1082  /// WARNING: The current implementation of this is 
1083  /// rather slow and not fit for production use
1084  /// FIXME - rewrite as a closure
1085  #[cfg(feature="database")]
1086  pub fn get_missing_paddles_hg(&self, pid_map :   &DsiJChPidMapping) -> Vec<u8> {
1087    let mut missing = Vec::<u8>::new();
1088    for th in self.get_trigger_hits() {
1089      let pid = pid_map.get(&th.0).unwrap().get(&th.1).unwrap().get(&th.2.0).unwrap().0;
1090      let mut found = false;
1091      for h in &self.hits {
1092        if h.paddle_id == pid {
1093          found = true;
1094          break
1095        }
1096      }
1097      if !found {
1098        missing.push(pid);
1099      }
1100    }
1101    missing
1102  }
1103  
1104  /// Get the triggered paddle ids
1105  ///
1106  /// Warning, this might be a bit slow
1107  #[cfg(feature="database")]
1108  pub fn get_triggered_paddles(&self, pid_map :   &DsiJChPidMapping) -> Vec<u8> {
1109    let mut paddles = Vec::<u8>::with_capacity(3);
1110    for th in &self.get_trigger_hits() {
1111      let pid = pid_map.get(&th.0).unwrap().get(&th.1).unwrap().get(&th.2.0).unwrap().0;
1112      paddles.push(pid);
1113    }
1114    paddles
1115  }
1116
1117  /// Get the RB link IDs according to the mask
1118  pub fn get_rb_link_ids(&self) -> Vec<u8> {
1119    let mut links = Vec::<u8>::new();
1120    for k in 0..64 {
1121      if (self.mtb_link_mask >> k) as u64 & 0x1 == 1 {
1122        links.push(k as u8);
1123      }
1124    }
1125    links
1126  }
1127
1128  /// Get the combination of triggered DSI/J/CH on 
1129  /// the MTB which formed the trigger. This does 
1130  /// not include further hits which fall into the 
1131  /// integration window. For those, se rb_link_mask
1132  ///
1133  /// The returned values follow the TOF convention
1134  /// to start with 1, so that we can use them to 
1135  /// look up LTB ids in the db.
1136  ///
1137  /// # Returns
1138  ///
1139  ///   Vec<(hit)> where hit is (DSI, J, CH) 
1140  pub fn get_trigger_hits(&self) -> Vec<(u8, u8, (u8, u8), LTBThreshold)> {
1141    let mut hits = Vec::<(u8,u8,(u8,u8),LTBThreshold)>::with_capacity(5); 
1142    let physical_channels = [(1u8,  2u8), (3u8,4u8), (5u8, 6u8), (7u8, 8u8),
1143                             (9u8, 10u8), (11u8,12u8), (13u8, 14u8), (15u8, 16u8)];
1144    //let n_masks_needed = self.dsi_j_mask.count_ones() / 2 + self.dsi_j_mask.count_ones() % 2;
1145    let n_masks_needed = self.dsi_j_mask.count_ones();
1146    if self.channel_mask.len() < n_masks_needed as usize {
1147      error!("We need {} hit masks, but only have {}! This is bad!", n_masks_needed, self.channel_mask.len());
1148      return hits;
1149    }
1150    let mut n_mask = 0;
1151    trace!("Expecting {} hit masks", n_masks_needed);
1152    trace!("ltb channels {:?}", self.dsi_j_mask);
1153    trace!("hit masks {:?}", self.channel_mask); 
1154    //println!("We see LTB Channels {:?} with Hit masks {:?} for {} masks requested by us!", self.dsi_j_mask, self.channel_mask, n_masks_needed);
1155    
1156    // one k here is for one ltb
1157    for k in 0..32 {
1158      if (self.dsi_j_mask >> k) as u32 & 0x1 == 1 {
1159        let mut dsi = 0u8;
1160        let mut j   = 0u8;
1161        if k < 5 {
1162          dsi = 1;
1163          j   = k as u8 + 1;
1164        } else if k < 10 {
1165          dsi = 2;
1166          j   = k as u8 - 5 + 1;
1167        } else if k < 15 {
1168          dsi = 3;
1169          j   = k as u8- 10 + 1;
1170        } else if k < 20 {
1171          dsi = 4;
1172          j   = k as u8- 15 + 1;
1173        } else if k < 25 {
1174          dsi = 5;
1175          j   = k as u8 - 20 + 1;
1176        } 
1177        //let dsi = (k as f32 / 4.0).floor() as u8 + 1;       
1178        //let j   = (k % 5) as u8 + 1;
1179        //println!("n_mask {n_mask}");
1180        let channels = self.channel_mask[n_mask]; 
1181        for (i,ch) in LTB_CHANNELS.iter().enumerate() {
1182          //let chn = *ch as u8 + 1;
1183          let ph_chn = physical_channels[i];
1184          //let chn = i as u8 + 1;
1185          //println!("i,ch {}, {}", i, ch);
1186          let thresh_bits = ((channels & ch) >> (i*2)) as u8;
1187          //println!("thresh_bits {}", thresh_bits);
1188          if thresh_bits > 0 { // hit over threshold
1189            hits.push((dsi, j, ph_chn, LTBThreshold::from(thresh_bits)));
1190          }
1191        }
1192        n_mask += 1;
1193      } // next ltb
1194    }
1195    hits
1196  }
1197  
1198  /// Get the trigger sources from trigger source byte
1199  pub fn get_trigger_sources(&self) -> Vec<TriggerType> {
1200    transcode_trigger_sources(self.trigger_sources)
1201  }
1202  
1203  pub fn get_timestamp48(&self) -> u64 {
1204    ((self.timestamp16 as u64) << 32) | self.timestamp32 as u64
1205  }
1206  
1207  /// Ttotal energy depostion in the TOF - Umbrella
1208  ///
1209  /// Utilizes Philip's formula based on 
1210  /// peak height
1211  pub fn get_edep_umbrella(&self) -> f32 {
1212    let mut tot_edep = 0.0f32;
1213    for h in &self.hits {
1214      if h.paddle_id < 61 || h.paddle_id > 108 {
1215        continue;
1216      }
1217      tot_edep += h.get_edep();
1218    }
1219    tot_edep
1220  }
1221  
1222  /// Ttotal energy depostion in the TOF - Umbrella
1223  ///
1224  /// Utilizes Philip's formula based on 
1225  /// peak height
1226  pub fn get_edep_cube(&self) -> f32 {
1227    let mut tot_edep = 0.0f32;
1228    for h in &self.hits {
1229      if h.paddle_id > 60 {
1230        continue;
1231      }
1232      tot_edep += h.get_edep();
1233    }
1234    tot_edep
1235  }
1236  
1237  /// Ttotal energy depostion in the Cortina
1238  ///
1239  /// Utilizes Philip's formula based on 
1240  /// peak height
1241  pub fn get_edep_cortina(&self) -> f32 {
1242    let mut tot_edep = 0.0f32;
1243    for h in &self.hits {
1244      if h.paddle_id < 109 {
1245        continue;
1246      }
1247      tot_edep += h.get_edep();
1248    }
1249    tot_edep
1250  }
1251  
1252  /// Ttotal energy depostion in the complete TOF
1253  ///
1254  /// Utilizes Philip's formula based on 
1255  /// peak height
1256  pub fn get_edep(&self) -> f32 {
1257    let mut tot_edep = 0.0f32;
1258    for h in &self.hits {
1259      tot_edep += h.get_edep();
1260    }
1261    tot_edep
1262  }
1263
1264  pub fn get_nhits_umb(&self) -> usize {
1265    let mut nhit = 0;
1266    for h in &self.hits {
1267      if h.paddle_id > 60 && h.paddle_id < 109 {
1268        nhit += 1;
1269      }
1270    }
1271    nhit
1272  }
1273  
1274  pub fn get_nhits_cbe(&self) -> usize {
1275    let mut nhit = 0;
1276    for h in &self.hits {
1277      if h.paddle_id < 61  {
1278        nhit += 1;
1279      }
1280    }
1281    nhit
1282  }
1283  
1284  pub fn get_nhits_cor(&self) -> usize {
1285    let mut nhit = 0;
1286    for h in &self.hits {
1287      if h.paddle_id > 108  {
1288        nhit += 1;
1289      }
1290    }
1291    nhit
1292  }
1293
1294  pub fn get_nhits(&self) -> usize {
1295    self.hits.len()
1296  }
1297
1298  /// Allows to get TofEventSummary from a packet 
1299  /// of type TofEvent. This will dismiss all the 
1300  /// waveforms and RBEvents
1301  pub fn from_tofeventpacket(pack : &TofPacket)
1302    -> Result<Self, SerializationError> {
1303    if pack.packet_type != PacketType::TofEvent {
1304      return Err(SerializationError::IncorrectPacketType);
1305    }
1306    let mut pos = 0usize;
1307    let stream  = &pack.payload;
1308    let head    = parse_u16(stream, &mut pos);
1309    if head != TofEvent::HEAD {
1310      return Err(SerializationError::HeadInvalid);
1311    }
1312    let mut te           = TofEvent::new();
1313    te.compression_level = CompressionLevel::try_from(parse_u8(stream, &mut pos)).unwrap();
1314    te.quality           = EventQuality::try_from(parse_u8(stream, &mut pos)).unwrap();
1315    te.header            = TofEventHeader::from_bytestream(stream, &mut pos)?;
1316    te.mt_event          = MasterTriggerEvent::from_bytestream(stream, &mut pos)?;
1317    
1318    let v_sizes              = TofEvent::decode_size_header(&parse_u32(stream, &mut pos));
1319    for k in 0..v_sizes.0 {
1320      match RBEvent::from_bytestream_nowaveforms(stream, &mut pos) {
1321        Err(err) => error!("Expected RBEvent {} of {}, but got serialization error {}!", k,  v_sizes.0, err),
1322        Ok(ev) => {
1323          te.rb_events.push(ev);
1324        }
1325      }
1326    }
1327    let tail = parse_u16(stream, &mut pos);
1328    if tail != Self::TAIL {
1329      error!("Decoding of TAIL failed! Got {} instead!", tail);
1330      return Err(SerializationError::TailInvalid);
1331    }
1332    let summary = te.get_summary();
1333    return Ok(summary);
1334  }
1335}
1336
1337impl Packable for TofEventSummary {
1338  const PACKET_TYPE        : PacketType = PacketType::TofEventSummary;
1339}
1340
1341impl Serialization for TofEventSummary {
1342  
1343  const HEAD               : u16   = 43690; //0xAAAA
1344  const TAIL               : u16   = 21845; //0x5555
1345  
1346  fn to_bytestream(&self) -> Vec<u8> {
1347    let mut stream = Vec::<u8>::new();
1348    stream.extend_from_slice(&Self::HEAD.to_le_bytes());
1349    let status_version = self.status.to_u8() | self.version.to_u8();
1350    stream.push(status_version);
1351    stream.extend_from_slice(&self.trigger_sources.to_le_bytes());
1352    stream.extend_from_slice(&self.n_trigger_paddles.to_le_bytes());
1353    stream.extend_from_slice(&self.event_id.to_le_bytes());
1354    // depending on the version, we send the fc event packet
1355    if self.version == ProtocolVersion::V1 {
1356      stream.extend_from_slice(&self.n_hits_umb  .to_le_bytes()); 
1357      stream.extend_from_slice(&self.n_hits_cbe  .to_le_bytes()); 
1358      stream.extend_from_slice(&self.n_hits_cor  .to_le_bytes()); 
1359      stream.extend_from_slice(&self.tot_edep_umb.to_le_bytes()); 
1360      stream.extend_from_slice(&self.tot_edep_cbe.to_le_bytes()); 
1361      stream.extend_from_slice(&self.tot_edep_cor.to_le_bytes()); 
1362    }
1363    stream.extend_from_slice(&self.quality.to_le_bytes());
1364    stream.extend_from_slice(&self.timestamp32.to_le_bytes());
1365    stream.extend_from_slice(&self.timestamp16.to_le_bytes());
1366    //stream.extend_from_slice(&self.primary_beta.to_le_bytes());
1367    stream.extend_from_slice(&self.run_id.to_le_bytes());
1368    stream.extend_from_slice(&self.drs_dead_lost_hits.to_le_bytes());
1369    //stream.extend_from_slice(&self.primary_charge.to_le_bytes());
1370    stream.extend_from_slice(&self.dsi_j_mask.to_le_bytes());
1371    let n_channel_masks = self.channel_mask.len();
1372    stream.push(n_channel_masks as u8);
1373    for k in 0..n_channel_masks {
1374      stream.extend_from_slice(&self.channel_mask[k].to_le_bytes());
1375    }
1376    stream.extend_from_slice(&self.mtb_link_mask.to_le_bytes());
1377    let nhits = self.hits.len() as u16;
1378    stream.extend_from_slice(&nhits.to_le_bytes());
1379    for k in 0..self.hits.len() {
1380      stream.extend_from_slice(&self.hits[k].to_bytestream());
1381    }
1382    stream.extend_from_slice(&Self::TAIL.to_le_bytes());
1383    stream
1384  }
1385  
1386  fn from_bytestream(stream    : &Vec<u8>, 
1387                     pos       : &mut usize) 
1388    -> Result<Self, SerializationError>{
1389    let mut summary           = Self::new();
1390    let head = parse_u16(stream, pos);
1391    if head != Self::HEAD {
1392      error!("Decoding of HEAD failed! Got {} instead!", head);
1393      return Err(SerializationError::HeadInvalid);
1394    }
1395    let status_version_u8     = parse_u8(stream, pos);
1396    let status                = EventStatus::from(status_version_u8 & 0x3f);
1397    let version               = ProtocolVersion::from(status_version_u8 & 0xc0); 
1398    summary.status            = status;
1399    summary.version           = version;
1400    summary.trigger_sources   = parse_u16(stream, pos);
1401    summary.n_trigger_paddles = parse_u8(stream, pos);
1402    summary.event_id          = parse_u32(stream, pos);
1403    if summary.version == ProtocolVersion::V1 {
1404      summary.n_hits_umb      = parse_u8(stream, pos); 
1405      summary.n_hits_cbe      = parse_u8(stream, pos); 
1406      summary.n_hits_cor      = parse_u8(stream, pos); 
1407      summary.tot_edep_umb    = parse_f32(stream, pos); 
1408      summary.tot_edep_cbe    = parse_f32(stream, pos); 
1409      summary.tot_edep_cor    = parse_f32(stream, pos); 
1410    }
1411    summary.quality            = parse_u8(stream, pos);
1412    summary.timestamp32        = parse_u32(stream, pos);
1413    summary.timestamp16        = parse_u16(stream, pos);
1414    summary.run_id             = parse_u16(stream, pos);
1415    summary.drs_dead_lost_hits = parse_u16(stream, pos);
1416    summary.dsi_j_mask         = parse_u32(stream, pos);
1417    let n_channel_masks        = parse_u8(stream, pos);
1418    for _ in 0..n_channel_masks {
1419      summary.channel_mask.push(parse_u16(stream, pos));
1420    }
1421    summary.mtb_link_mask     = parse_u64(stream, pos);
1422    let nhits                 = parse_u16(stream, pos);
1423    for _ in 0..nhits {
1424      summary.hits.push(TofHit::from_bytestream(stream, pos)?);
1425    }
1426    let tail = parse_u16(stream, pos);
1427    if tail != Self::TAIL {
1428      error!("Decoding of TAIL failed for version {}! Got {} instead!", version, tail);
1429      return Err(SerializationError::TailInvalid);
1430    }
1431    Ok(summary)
1432  }
1433}
1434    
1435impl Default for TofEventSummary {
1436  fn default() -> Self {
1437    Self::new()
1438  }
1439}
1440
1441impl fmt::Display for TofEventSummary {
1442  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1443    let mut repr = format!("<TofEventSummary (version {})", self.version);
1444    repr += &(format!("\n  EventID          : {}", self.event_id));
1445    repr += &(format!("\n  RunID            : {}", self.run_id));
1446    repr += &(format!("\n  EventStatus      : {}", self.status));
1447    repr += &(format!("\n  TriggerSources   : {:?}", self.get_trigger_sources()));
1448    repr += &(format!("\n  NTrigPaddles     : {}", self.n_trigger_paddles));
1449    repr += &(format!("\n  DRS dead hits    : {}", self.drs_dead_lost_hits));
1450    repr += &(format!("\n  timestamp32      : {}", self.timestamp32)); 
1451    repr += &(format!("\n  timestamp16      : {}", self.timestamp16)); 
1452    repr += &(format!("\n   |-> timestamp48 : {}", self.get_timestamp48())); 
1453    //repr += &(format!("\n  PrimaryBeta      : {}", self.get_beta())); 
1454    //repr += &(format!("\n  PrimaryCharge    : {}", self.primary_charge));
1455    repr += &(format!("\n  ** ** TRIGGER HITS (DSI/J/CH) [{} LTBS] ** **", self.dsi_j_mask.count_ones()));
1456    for k in self.get_trigger_hits() {
1457      repr += &(format!("\n  => {}/{}/({},{}) ({}) ", k.0, k.1, k.2.0, k.2.1, k.3));
1458    }
1459    repr += "\n  ** ** MTB LINK IDs ** **";
1460    let mut mtblink_str = String::from("\n  => ");
1461    for k in self.get_rb_link_ids() {
1462      mtblink_str += &(format!("{} ", k))
1463    }
1464    repr += &mtblink_str;
1465    repr += &(format!("\n  == Trigger hits {}, expected RBEvents {}",
1466            self.get_trigger_hits().len(),
1467            self.get_rb_link_ids().len()));
1468    repr += &String::from("\n  ** ** ** HITS ** ** **");
1469    for h in &self.hits {
1470      repr += &(format!("\n  {}", h));
1471    }
1472    write!(f, "{}", repr)
1473  }
1474}
1475
1476#[cfg(feature="random")]
1477impl FromRandom for TofEventSummary {
1478
1479  fn from_random() -> Self {
1480    let mut summary           = Self::new();
1481    let mut rng               = rand::thread_rng();
1482    let status                = EventStatus::from_random();
1483    let version               = ProtocolVersion::from_random();
1484    if version == ProtocolVersion::V1 {
1485      summary.n_hits_umb        = rng.gen::<u8>();
1486      summary.n_hits_cbe        = rng.gen::<u8>();
1487      summary.n_hits_cor        = rng.gen::<u8>();
1488      summary.tot_edep_umb      = rng.gen::<f32>();
1489      summary.tot_edep_cbe      = rng.gen::<f32>();
1490      summary.tot_edep_cor      = rng.gen::<f32>();
1491      summary.quality           = rng.gen::<u8>();
1492    }
1493    summary.status             = status;
1494    summary.version            = version;
1495    // variable packet for the FC
1496    summary.trigger_sources    = rng.gen::<u16>();
1497    summary.n_trigger_paddles  = rng.gen::<u8>();
1498    summary.event_id           = rng.gen::<u32>();
1499    summary.timestamp32        = rng.gen::<u32>();
1500    summary.timestamp16        = rng.gen::<u16>();
1501    summary.drs_dead_lost_hits = rng.gen::<u16>();
1502    summary.dsi_j_mask         = rng.gen::<u32>();
1503    let n_channel_masks        = rng.gen::<u8>();
1504    for _ in 0..n_channel_masks {
1505      summary.channel_mask.push(rng.gen::<u16>());
1506    }
1507    summary.mtb_link_mask      = rng.gen::<u64>();
1508    //let nhits                  = rng.gen::<u8>();
1509    let nhits = 1;
1510    for _ in 0..nhits {
1511      summary.hits.push(TofHit::from_random());
1512    }
1513    summary
1514  }
1515}
1516
1517//
1518// TESTS
1519//
1520// ============================================
1521
1522#[test]
1523fn packable_tofeventsummary() {
1524  for _ in 0..100 {
1525    let data = TofEventSummary::from_random();
1526    let mut test : TofEventSummary = data.pack().unpack().unwrap();
1527    //println!("{}", data.hits[0]);
1528    //println!("{}", test.hits[0]);
1529    // Manually zero these fields, since comparison with nan will fail and 
1530    // from_random did not touch these
1531    for h in &mut test.hits {
1532      h.paddle_len       = 0.0; 
1533      h.cable_len        = 0.0; 
1534      h.coax_cable_time  = 0.0; 
1535      h.hart_cable_time  = 0.0; 
1536      h.x                = 0.0; 
1537      h.y                = 0.0; 
1538      h.z                = 0.0; 
1539      h.event_t0         = 0.0;
1540    }
1541    assert_eq!(data, test);
1542  }
1543}  
1544
1545#[test]
1546fn emit_tofeventsummary() {
1547  for _ in 0..100 {
1548    let data = TofEvent::from_random();
1549    let summary = data.get_summary();
1550    let test : TofEventSummary = summary.pack().unpack().unwrap();
1551    assert_eq!(summary, test);
1552  }
1553}
1554
1555#[test]
1556#[cfg(feature = "random")]
1557fn tofevent_sizes_header() {
1558  for _ in 0..100 {
1559    let data = TofEvent::from_random();
1560    let mask = data.construct_sizes_header();
1561    let size = TofEvent::decode_size_header(&mask);
1562    assert_eq!(size.0, data.rb_events.len());
1563    //assert_eq!(size.1, data.missing_hits.len());
1564  }
1565}
1566
1567#[test]
1568#[cfg(feature = "random")]
1569fn packable_tofevent() {
1570  for _ in 0..5 {
1571    let data = TofEvent::from_random();
1572    let test : TofEvent = data.pack().unpack().unwrap();
1573    assert_eq!(data.header, test.header);
1574    assert_eq!(data.compression_level, test.compression_level);
1575    assert_eq!(data.quality, test.quality);
1576    assert_eq!(data.mt_event, test.mt_event);
1577    assert_eq!(data.rb_events.len(), test.rb_events.len());
1578    //assert_eq!(data.missing_hits.len(), test.missing_hits.len());
1579    //assert_eq!(data.missing_hits, test.missing_hits);
1580    assert_eq!(data.rb_events, test.rb_events);
1581    //assert_eq!(data, test);
1582    //println!("{}", data);
1583  }
1584}
1585
1586#[test]
1587#[cfg(feature = "random")]
1588fn serialize_tofeventheader() {
1589  let data = TofEventHeader::from_random();
1590  let test = TofEventHeader::from_bytestream(&data.to_bytestream(), &mut 0).unwrap();
1591  assert_eq!(data, test);
1592}
1593