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