1use crate::prelude::*;
6
7#[cfg(feature="database")]
8use std::f32::consts::PI;
9use std::cmp::Ordering;
10
11#[derive(Debug, Clone, PartialEq)]
30#[cfg_attr(feature="pybindings", pyclass)]
31pub struct TofEvent {
32 pub status : EventStatus,
33 pub version : ProtocolVersion,
42 pub quality : EventQuality,
43 pub trigger_sources : u16,
44
45 pub n_trigger_paddles : u8,
49 pub event_id : u32,
50 pub run_id : u16,
51 pub timestamp32 : u32,
52 pub timestamp16 : u16,
53 pub drs_dead_lost_hits : u16,
57 pub dsi_j_mask : u32,
58 pub channel_mask : Vec<u16>,
59 pub mtb_link_mask : u64,
60 pub hits : Vec<TofHit>,
61 pub mt_trigger_sources : u16,
66 pub mt_tiu_gps16 : u16,
67 pub mt_tiu_gps32 : u32,
68 pub mt_timestamp : u32,
69 pub mt_tiu_timestamp : u32,
70 pub n_hits_umb : u8,
74 pub n_hits_cbe : u8,
75 pub n_hits_cor : u8,
76 pub tot_edep_umb : f32,
77 pub tot_edep_cbe : f32,
78 pub tot_edep_cor : f32,
79 pub paddles_set : bool,
80 pub rb_events : Vec<RBEvent>,
84 pub creation_time : Instant,
86 pub write_to_disk : bool,
87}
88
89impl TofEvent {
90
91 pub fn new() -> Self {
92 Self {
93 status : EventStatus::Unknown,
94 version : ProtocolVersion::Unknown,
95 n_hits_umb : 0,
96 n_hits_cbe : 0,
97 n_hits_cor : 0,
98 tot_edep_umb : 0.0,
99 tot_edep_cbe : 0.0,
100 tot_edep_cor : 0.0,
101 quality : EventQuality::Unknown,
102 trigger_sources : 0,
103 n_trigger_paddles : 0,
104 event_id : 0,
105 run_id : 0,
106 timestamp32 : 0,
107 timestamp16 : 0,
108 drs_dead_lost_hits : 0,
109 dsi_j_mask : 0,
110 channel_mask : Vec::<u16>::new(),
111 mtb_link_mask : 0,
112 hits : Vec::<TofHit>::new(),
113 mt_trigger_sources : 0,
114 mt_tiu_gps16 : 0,
115 mt_tiu_gps32 : 0,
116 mt_timestamp : 0,
117 mt_tiu_timestamp : 0,
118 paddles_set : false,
119 rb_events : Vec::<RBEvent>::new(),
120 creation_time : Instant::now(),
121 write_to_disk : true,
122 }
123 }
124
125 pub fn strip_rbevents(&mut self) {
127 self.rb_events.clear();
128 }
129
130 pub fn age(&self) -> u64 {
131 self.creation_time.elapsed().as_secs()
132 }
133
134 pub fn is_complete(&self) -> bool {
137 self.get_rb_link_ids().len() == self.rb_events.len()
138 }
139
140 pub fn get_lost_hits(&self) -> u16 {
143 let mut lost_hits = 0u16;
144 for rbev in &self.rb_events {
145 if rbev.header.drs_lost_trigger() {
146 let mut nhits = rbev.header.get_nchan() as u16;
147 if nhits > 0 {
148 nhits -= 1;
149 }
150 lost_hits += nhits;
151 }
152 }
153 lost_hits
154 }
155
156
157 pub fn prepare_for_gcu(&mut self, strip_rbevents : bool) {
165 if strip_rbevents {
166 self.strip_rbevents();
167 }
168 self.version = ProtocolVersion::V1;
169 for h in &self.hits {
170 if h.paddle_id <= 60 {
171 self.n_hits_cbe += 1;
172 self.tot_edep_cbe += h.get_edep();
173 }
174 else if h.paddle_id <= 108 && h.paddle_id > 60 {
175 self.n_hits_umb += 1;
176 self.tot_edep_umb += h.get_edep();
177 }
178 else {
179 self.n_hits_cor += 1;
180 self.tot_edep_cor += h.get_edep();
181 }
182 }
183 }
184
185 pub fn decode_depr_tofevent_size_header(mask : &u32)
188 -> (usize, usize) {
189 let rb_event_len = (mask & 0xFF) as usize;
190 let miss_len = ((mask & 0xFF00) >> 8) as usize;
191 (rb_event_len, miss_len)
192 }
193
194 #[cfg(feature="database")]
199 pub fn set_timing_offsets(&mut self, offsets : &HashMap<u8, f32>) {
200 for h in self.hits.iter_mut() {
201 if offsets.contains_key(&h.paddle_id) {
202 h.timing_offset = offsets[&h.paddle_id];
203 }
204 }
205 }
206
207 pub fn lightspeed_cleaning(&mut self, t_err : f32) -> (Vec<u8>, Vec<f32>) {
219 if self.hits.len() == 0 {
221 return (Vec::<u8>::new(), Vec::<f32>::new());
222 }
223 let mut twindows = Vec::<f32>::new();
224 self.hits.sort_by(|a,b| (a.event_t0).partial_cmp(&b.event_t0).unwrap_or(Ordering::Greater));
225 let first_hit = self.hits[0].clone(); let mut clean_hits = Vec::<TofHit>::new();
229 let mut rm_hits = Vec::<u8>::new();
230 clean_hits.push(first_hit.clone());
232 let mut prior_hit = first_hit;
234 for h in self.hits.iter().skip(1) {
236 let min_tdiff_cvac = 1e9*1e-3*prior_hit.distance(h)/299792458.0;
237 let twindow = prior_hit.event_t0 + min_tdiff_cvac;
238
239 if h.event_t0 + 2.0*t_err < twindow {
248 rm_hits.push(h.paddle_id);
249 twindows.push(twindow);
250 continue;
251 }
252 prior_hit = h.clone();
268 clean_hits.push(*h);
269 }
270 self.hits = clean_hits;
271 (rm_hits, twindows)
272 }
273
274
275 pub fn remove_non_causal_hits(&mut self) -> Vec<u8> {
285 let mut clean_hits = Vec::<TofHit>::new();
286 let mut removed_pids = Vec::<u8>::new();
287 for h in &self.hits {
288 if h.obeys_causality() {
289 clean_hits.push(*h);
290 } else {
291 removed_pids.push(h.paddle_id);
292 }
293 }
294 self.hits = clean_hits;
295 removed_pids
296 }
297
298 #[cfg(feature="database")]
299 pub fn normalize_hit_times(&mut self) {
300 if self.hits.len() == 0 {
301 return;
302 }
303 if self.hits[0].event_t0 == 0.0 {
305 return;
306 }
307
308 let phase0 = self.hits[0].phase.to_f32();
309 for h in &mut self.hits {
310 let t0 = h.get_t0_uncorrected() + h.get_cable_delay();
311 let mut phase_diff = h.phase.to_f32() - phase0;
312 while phase_diff < - PI/2.0 {
313 phase_diff += 2.0*PI;
314 }
315 while phase_diff > PI/2.0 {
316 phase_diff -= 2.0*PI;
317 }
318 let t_shift = 50.0*phase_diff/(2.0*PI);
319 h.event_t0 = t0 + t_shift;
320 }
321 self.hits.sort_by(|a,b| (a.event_t0).partial_cmp(&b.event_t0).unwrap_or(Ordering::Greater));
323 let t0_first_hit = self.hits[0].event_t0;
324 for h in self.hits.iter_mut() {
325 h.event_t0 -= t0_first_hit
326 }
327 }
328
329 #[cfg(feature="database")]
330 pub fn set_paddles(&mut self, paddles : &HashMap<u8, TofPaddle>) {
331 let mut nerror = 0u8;
332 for h in &mut self.hits {
333 match paddles.get(&h.paddle_id) {
334 None => {
335 error!("Got paddle id {} which is not in given map!", h.paddle_id);
336 nerror += 1;
337 continue;
338 }
339 Some(pdl) => {
340 h.set_paddle(pdl);
341 }
342 }
343 }
344 if nerror == 0 {
345 self.paddles_set = true;
346 }
347 }
348
349 pub fn get_pointcloud(&self) -> Option<Vec<(f32,f32,f32,f32,f32)>> {
354 let mut pc = Vec::<(f32,f32,f32,f32,f32)>::new();
355 if !self.paddles_set {
356 error!("Before getting the pointcloud, paddle information needs to be set for this event. Call TofEvent;:set_paddle");
357 return None;
358 }
359 for h in &self.hits {
360 let result = (h.x, h.y, h.z, h.get_t0(), h.get_edep());
361 pc.push(result);
362 }
363 Some(pc)
364 }
365
366 #[cfg(feature="database")]
375 pub fn get_missing_paddles_hg(&self, pid_map : &DsiJChPidMapping) -> Vec<u8> {
376 let mut missing = Vec::<u8>::new();
377 for th in self.get_trigger_hits() {
378 let pid = pid_map.get(&th.0).unwrap().get(&th.1).unwrap().get(&th.2.0).unwrap().0;
379 let mut found = false;
380 for h in &self.hits {
381 if h.paddle_id == pid {
382 found = true;
383 break
384 }
385 }
386 if !found {
387 missing.push(pid);
388 }
389 }
390 missing
391 }
392
393 #[cfg(feature="database")]
397 pub fn get_triggered_paddles(&self, pid_map : &DsiJChPidMapping) -> Vec<u8> {
398 let mut paddles = Vec::<u8>::with_capacity(3);
399 for th in &self.get_trigger_hits() {
400 let pid = pid_map.get(&th.0).unwrap().get(&th.1).unwrap().get(&th.2.0).unwrap().0;
401 paddles.push(pid);
402 }
403 paddles
404 }
405
406 pub fn get_rb_link_ids(&self) -> Vec<u8> {
408 let mut links = Vec::<u8>::new();
409 for k in 0..64 {
410 if (self.mtb_link_mask >> k) as u64 & 0x1 == 1 {
411 links.push(k as u8);
412 }
413 }
414 links
415 }
416
417 pub fn get_trigger_hits(&self) -> Vec<(u8, u8, (u8, u8), LTBThreshold)> {
430 let mut hits = Vec::<(u8,u8,(u8,u8),LTBThreshold)>::with_capacity(5);
431 let n_masks_needed = self.dsi_j_mask.count_ones();
433 if self.channel_mask.len() < n_masks_needed as usize {
434 error!("We need {} hit masks, but only have {}! This is bad!", n_masks_needed, self.channel_mask.len());
435 return hits;
436 }
437 let mut n_mask = 0;
438 trace!("Expecting {} hit masks", n_masks_needed);
439 trace!("ltb channels {:?}", self.dsi_j_mask);
440 trace!("hit masks {:?}", self.channel_mask);
441 for k in 0..32 {
445 if (self.dsi_j_mask >> k) as u32 & 0x1 == 1 {
446 let mut dsi = 0u8;
447 let mut j = 0u8;
448 if k < 5 {
449 dsi = 1;
450 j = k as u8 + 1;
451 } else if k < 10 {
452 dsi = 2;
453 j = k as u8 - 5 + 1;
454 } else if k < 15 {
455 dsi = 3;
456 j = k as u8- 10 + 1;
457 } else if k < 20 {
458 dsi = 4;
459 j = k as u8- 15 + 1;
460 } else if k < 25 {
461 dsi = 5;
462 j = k as u8 - 20 + 1;
463 }
464 let channels = self.channel_mask[n_mask];
468 for (i,ch) in LTB_CHANNELS.iter().enumerate() {
469 let ph_chn = PHYSICAL_CHANNELS[i];
471 let thresh_bits = ((channels & ch) >> (i*2)) as u8;
474 if thresh_bits > 0 { hits.push((dsi, j, ph_chn, LTBThreshold::from(thresh_bits)));
477 }
478 }
479 n_mask += 1;
480 } }
482 hits
483 }
484
485 pub fn get_trigger_sources(&self) -> Vec<TriggerType> {
487 TriggerType::transcode_trigger_sources(self.trigger_sources)
488 }
489
490 pub fn get_timestamp48(&self) -> u64 {
491 ((self.timestamp16 as u64) << 32) | self.timestamp32 as u64
492 }
493
494 pub fn get_edep_umbrella(&self) -> f32 {
499 let mut tot_edep = 0.0f32;
500 for h in &self.hits {
501 if h.paddle_id < 61 || h.paddle_id > 108 {
502 continue;
503 }
504 tot_edep += h.get_edep();
505 }
506 tot_edep
507 }
508
509 pub fn get_edep_cube(&self) -> f32 {
514 let mut tot_edep = 0.0f32;
515 for h in &self.hits {
516 if h.paddle_id > 60 {
517 continue;
518 }
519 tot_edep += h.get_edep();
520 }
521 tot_edep
522 }
523
524 pub fn get_edep_cortina(&self) -> f32 {
529 let mut tot_edep = 0.0f32;
530 for h in &self.hits {
531 if h.paddle_id < 109 {
532 continue;
533 }
534 tot_edep += h.get_edep();
535 }
536 tot_edep
537 }
538
539 pub fn get_edep(&self) -> f32 {
544 let mut tot_edep = 0.0f32;
545 for h in &self.hits {
546 tot_edep += h.get_edep();
547 }
548 tot_edep
549 }
550
551 pub fn get_nhits_umb(&self) -> usize {
552 let mut nhit = 0;
553 for h in &self.hits {
554 if h.paddle_id > 60 && h.paddle_id < 109 {
555 nhit += 1;
556 }
557 }
558 nhit
559 }
560
561 pub fn get_nhits_cbe(&self) -> usize {
562 let mut nhit = 0;
563 for h in &self.hits {
564 if h.paddle_id < 61 {
565 nhit += 1;
566 }
567 }
568 nhit
569 }
570
571 pub fn get_nhits_cor(&self) -> usize {
572 let mut nhit = 0;
573 for h in &self.hits {
574 if h.paddle_id > 108 {
575 nhit += 1;
576 }
577 }
578 nhit
579 }
580
581 pub fn get_nhits(&self) -> usize {
582 self.hits.len()
583 }
584
585 pub fn has_any_mangling(&self) -> bool {
588 for rbev in &self.rb_events {
589 if rbev.status == EventStatus::CellAndChnSyncErrors
590 || rbev.status == EventStatus::CellSyncErrors
591 || rbev.status == EventStatus::ChnSyncErrors {
592 return true;
593 }
594 }
595 false
596 }
597
598 pub fn get_waveforms(&self) -> Vec<RBWaveform> {
603 let mut wfs = Vec::<RBWaveform>::new();
604 for ev in &self.rb_events {
605 for wf in &ev.get_rbwaveforms() {
606 wfs.push(wf.clone());
607 }
608 }
609 wfs
610 }
611}
612
613impl TofPackable for TofEvent {
614 const TOF_PACKET_TYPE : TofPacketType = TofPacketType::TofEvent;
616 const TOF_PACKET_TYPE_ALT : TofPacketType = TofPacketType::TofEventDeprecated;
617}
618
619impl Serialization for TofEvent {
620
621 const HEAD : u16 = 43690; const TAIL : u16 = 21845; fn to_bytestream(&self) -> Vec<u8> {
625 let mut stream = Vec::<u8>::new();
626 stream.extend_from_slice(&Self::HEAD.to_le_bytes());
627 let status_version = self.status as u8 | self.version.to_u8();
628 stream.push(status_version);
629 stream.extend_from_slice(&self.trigger_sources.to_le_bytes());
630 stream.extend_from_slice(&self.n_trigger_paddles.to_le_bytes());
631 stream.extend_from_slice(&self.event_id.to_le_bytes());
632 if self.version == ProtocolVersion::V1 {
634 stream.extend_from_slice(&self.n_hits_umb .to_le_bytes());
635 stream.extend_from_slice(&self.n_hits_cbe .to_le_bytes());
636 stream.extend_from_slice(&self.n_hits_cor .to_le_bytes());
637 stream.extend_from_slice(&self.tot_edep_umb.to_le_bytes());
638 stream.extend_from_slice(&self.tot_edep_cbe.to_le_bytes());
639 stream.extend_from_slice(&self.tot_edep_cor.to_le_bytes());
640 }
641 stream.extend_from_slice(&(self.quality as u8).to_le_bytes());
642 stream.extend_from_slice(&self.timestamp32.to_le_bytes());
643 stream.extend_from_slice(&self.timestamp16.to_le_bytes());
644 stream.extend_from_slice(&self.run_id.to_le_bytes());
645 stream.extend_from_slice(&self.drs_dead_lost_hits.to_le_bytes());
646 stream.extend_from_slice(&self.dsi_j_mask.to_le_bytes());
647 let n_channel_masks = self.channel_mask.len();
648 stream.push(n_channel_masks as u8);
649 for k in 0..n_channel_masks {
650 stream.extend_from_slice(&self.channel_mask[k].to_le_bytes());
651 }
652 stream.extend_from_slice(&self.mtb_link_mask.to_le_bytes());
653 let nhits = self.hits.len() as u16;
654 stream.extend_from_slice(&nhits.to_le_bytes());
655 for k in 0..self.hits.len() {
656 stream.extend_from_slice(&self.hits[k].to_bytestream());
657 }
658 if self.version == ProtocolVersion::V2 {
661 stream.push(self.rb_events.len() as u8);
662 for rbev in &self.rb_events {
663 stream.extend_from_slice(&rbev.to_bytestream());
664 }
665 }
666 stream.extend_from_slice(&Self::TAIL.to_le_bytes());
667 stream
668 }
669
670 fn from_bytestream(stream : &Vec<u8>,
671 pos : &mut usize)
672 -> Result<Self, SerializationError>{
673 let mut event = Self::new();
674 let head = parse_u16(stream, pos);
675 if head != Self::HEAD {
676 error!("Decoding of HEAD failed! Got {} instead!", head);
677 return Err(SerializationError::HeadInvalid);
678 }
679 let status_version_u8 = parse_u8(stream, pos);
680 let status = EventStatus::from(status_version_u8 & 0x3f);
681 let version = ProtocolVersion::from(status_version_u8 & 0xc0);
682 event.status = status;
683 event.version = version;
684 event.trigger_sources = parse_u16(stream, pos);
685 event.n_trigger_paddles = parse_u8(stream, pos);
686 event.event_id = parse_u32(stream, pos);
687 if event.version == ProtocolVersion::V1 {
688 event.n_hits_umb = parse_u8(stream, pos);
689 event.n_hits_cbe = parse_u8(stream, pos);
690 event.n_hits_cor = parse_u8(stream, pos);
691 event.tot_edep_umb = parse_f32(stream, pos);
692 event.tot_edep_cbe = parse_f32(stream, pos);
693 event.tot_edep_cor = parse_f32(stream, pos);
694 }
695 event.quality = EventQuality::from(parse_u8(stream, pos));
696 event.timestamp32 = parse_u32(stream, pos);
697 event.timestamp16 = parse_u16(stream, pos);
698 event.run_id = parse_u16(stream, pos);
699 event.drs_dead_lost_hits = parse_u16(stream, pos);
700 event.dsi_j_mask = parse_u32(stream, pos);
701 let n_channel_masks = parse_u8(stream, pos);
702 for _ in 0..n_channel_masks {
703 event.channel_mask.push(parse_u16(stream, pos));
704 }
705 event.mtb_link_mask = parse_u64(stream, pos);
706 let nhits = parse_u16(stream, pos);
707 for _ in 0..nhits {
708 event.hits.push(TofHit::from_bytestream(stream, pos)?);
709 }
710 if event.version == ProtocolVersion::V2 {
711 let n_rb_events = parse_u8(stream, pos);
713 if n_rb_events > 0 {
714 for _ in 0..n_rb_events {
715 event.rb_events.push(RBEvent::from_bytestream(stream, pos)?);
716 }
717 }
718 }
719
720 let tail = parse_u16(stream, pos);
721 if tail != Self::TAIL {
722 error!("Decoding of TAIL failed for version {}! Got {} instead!", version, tail);
723 return Err(SerializationError::TailInvalid);
724 }
725 Ok(event)
726 }
727
728 fn from_bytestream_alt(stream : &Vec<u8>,
734 pos : &mut usize)
735 -> Result<Self, SerializationError> {
736 let head = parse_u16(stream, pos);
737 if head != TofEvent::HEAD {
738 return Err(SerializationError::HeadInvalid);
739 }
740 let mut te = Self::new();
741 let _compression_level = parse_u8(stream, pos);
743
744 te.quality = EventQuality::from(parse_u8(stream, pos));
745 *pos += 2; te.run_id = parse_u32(stream, pos) as u16;
751 *pos += 43 - 6;*pos += 2; let event_status = parse_u8 (stream, pos);
756 te.status = EventStatus::from(event_status);
757 if te.has_any_mangling() {
758 te.status = EventStatus::AnyDataMangling;
759 }
760 te.event_id = parse_u32(stream, pos);
761 let mtb_timestamp = parse_u32(stream, pos);
762 let tiu_timestamp = parse_u32(stream, pos);
763 let tiu_gps32 = parse_u32(stream, pos);
764 let _tiu_gps16 = parse_u16(stream,pos);
765 let _crc = parse_u32(stream, pos);
766 let mt_timestamp = (mt_event_get_timestamp_abs48(mtb_timestamp, tiu_gps32, tiu_timestamp ) as f64/1000.0).floor() as u64;
767 te.timestamp32 = (mt_timestamp & 0x00000000ffffffff ) as u32;
768 te.timestamp16 = ((mt_timestamp & 0x0000ffff00000000 ) >> 32) as u16;
769 te.trigger_sources = parse_u16(stream, pos);
770 te.dsi_j_mask = parse_u32(stream, pos);
771 let n_channel_masks = parse_u8(stream, pos);
772 for _ in 0..n_channel_masks {
773 te.channel_mask.push(parse_u16(stream, pos));
774 }
775
776 te.mtb_link_mask = parse_u64(stream, pos);
777 let mt_event_tail = parse_u16(stream, pos);
778 if mt_event_tail != Self::TAIL {
779 error!("Parsed TAIL from MT event is incorrect! Got {} instead of {} at pos {}", mt_event_tail, Self::TAIL, pos);
781 }
782 let v_sizes = Self::decode_depr_tofevent_size_header(&parse_u32(stream, pos));
784 for _ in 0..v_sizes.0 {
786 let next_rb_event = RBEvent::from_bytestream(stream, pos)?;
789 te.rb_events.push(next_rb_event);
791 }
792 let tail = parse_u16(stream, pos);
793 if tail != Self::TAIL {
794 error!("Decoding of TAIL failed! Got {} instead!", tail);
795 return Err(SerializationError::TailInvalid);
796 }
797 for rbev in &te.rb_events {
803 for h in &rbev.hits {
804 te.hits.push(*h);
805 }
806 }
807 return Ok(te);
808 }
809}
810
811impl Default for TofEvent {
812 fn default() -> Self {
813 Self::new()
814 }
815}
816
817impl fmt::Display for TofEvent {
818 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
819 let mut repr = format!("<TofEvent (version {})", self.version);
820 repr += &(format!("\n EventID : {}", self.event_id));
821 repr += &(format!("\n RunID : {}", self.run_id));
822 repr += &(format!("\n EventStatus : {}", self.status));
823 repr += &(format!("\n TriggerSources : {:?}", self.get_trigger_sources()));
824 repr += &(format!("\n NTrigPaddles : {}", self.n_trigger_paddles));
825 repr += &(format!("\n DRS dead hits : {}", self.drs_dead_lost_hits));
826 repr += &(format!("\n timestamp32 : {}", self.timestamp32));
827 repr += &(format!("\n timestamp16 : {}", self.timestamp16));
828 repr += &(format!("\n |-> timestamp48 : {}", self.get_timestamp48()));
829 repr += &(format!("\n ** ** TRIGGER HITS (DSI/J/CH) [{} LTBS] ** **", self.dsi_j_mask.count_ones()));
832 for k in self.get_trigger_hits() {
833 repr += &(format!("\n => {}/{}/({},{}) ({}) ", k.0, k.1, k.2.0, k.2.1, k.3));
834 }
835 repr += "\n ** ** MTB LINK IDs ** **";
836 let mut mtblink_str = String::from("\n => ");
837 for k in self.get_rb_link_ids() {
838 mtblink_str += &(format!("{} ", k))
839 }
840 repr += &mtblink_str;
841 repr += &(format!("\n == Trigger hits {}, expected RBEvents {}",
842 self.get_trigger_hits().len(),
843 self.get_rb_link_ids().len()));
844 repr += &String::from("\n ** ** ** HITS ** ** **");
845 for h in &self.hits {
846 repr += &(format!("\n {}", h));
847 }
848 if self.rb_events.len() > 0 {
849 repr += &format!("\n -- has {} RBEvents with waveforms!", self.rb_events.len());
850 repr += "\n -- -- boards: ";
851 for b in &self.rb_events {
852 repr += &format!("{} ", b.header.rb_id);
853 }
854 }
855 repr += ">";
856 write!(f, "{}", repr)
857 }
858}
859
860#[cfg(feature="random")]
861impl FromRandom for TofEvent {
862
863 fn from_random() -> Self {
864 let mut event = Self::new();
865 let mut rng = rand::rng();
866 let status = EventStatus::from_random();
867 let version = ProtocolVersion::from_random();
868 if version == ProtocolVersion::V1 {
869 event.n_hits_umb = rng.random::<u8>();
870 event.n_hits_cbe = rng.random::<u8>();
871 event.n_hits_cor = rng.random::<u8>();
872 event.tot_edep_umb = rng.random::<f32>();
873 event.tot_edep_cbe = rng.random::<f32>();
874 event.tot_edep_cor = rng.random::<f32>();
875 event.quality = EventQuality::from_random();
876 }
877 event.status = status;
878 event.version = version;
879 event.trigger_sources = rng.random::<u16>();
881 event.n_trigger_paddles = rng.random::<u8>();
882 event.event_id = rng.random::<u32>();
883 event.timestamp32 = rng.random::<u32>();
884 event.timestamp16 = rng.random::<u16>();
885 event.drs_dead_lost_hits = rng.random::<u16>();
886 event.dsi_j_mask = rng.random::<u32>();
887 let n_channel_masks = rng.random::<u8>();
888 for _ in 0..n_channel_masks {
889 event.channel_mask.push(rng.random::<u16>());
890 }
891 event.mtb_link_mask = rng.random::<u64>();
892 let nhits: u16 = rng.random_range(0..5);
894 for _ in 0..nhits {
895 event.hits.push(TofHit::from_random());
896 }
897 if event.version == ProtocolVersion::V2 {
898 let n_rb_events = rng.random_range(0..4);
899 for _ in 0..n_rb_events {
900 event.rb_events.push(RBEvent::from_random());
901 }
902 }
903 event
904 }
905}
906
907#[cfg(feature="pybindings")]
910#[pymethods]
911impl TofEvent {
912
913 fn copy(&self) -> Self {
915 self.clone()
916 }
917
918 #[pyo3(name="set_timing_offsets")]
919 pub fn set_timing_offsets_py(&mut self, timing_offsets : HashMap<u8, f32>) {
920 self.set_timing_offsets(&timing_offsets);
921 }
922
923 #[pyo3(name="normalize_hit_times")]
924 pub fn normalize_hit_times_py(&mut self) {
925 self.normalize_hit_times();
926 }
927
928 #[pyo3(name="lightspeed_cleaning")]
936 pub fn lightspeed_cleaning_py(&mut self, t_err : f32) -> (Vec<u16>, Vec<f32>) {
937 let mut pids = Vec::<u16>::new();
940 let (pids_rm, twindows) = self.lightspeed_cleaning(t_err);
941 for pid in pids_rm {
942 pids.push(pid as u16);
943 }
944 (pids, twindows)
945 }
946
947
948 #[pyo3(name="remove_non_causal_hits")]
953 fn remove_non_causal_hits_py(&mut self) -> Vec<u16> {
954 let mut pids = Vec::<u16>::new();
957 for pid in self.remove_non_causal_hits() {
958 pids.push(pid as u16);
959 }
960 pids
961 }
962
963 #[getter]
964 fn pointcloud(&self) -> Option<Vec<(f32,f32,f32,f32,f32)>> {
965 self.get_pointcloud()
966 }
967
968 #[getter]
969 #[pyo3(name="has_any_mangling")]
970 fn has_any_mangling_py(&self) -> bool {
971 self.has_any_mangling()
972 }
973
974 #[getter]
975 fn get_event_id(&self) -> u32 {
976 self.event_id
977 }
978
979 #[getter]
980 fn get_event_status(&self) -> EventStatus {
981 self.status
982 }
983
984 #[pyo3(name="get_missing_paddles_hg")]
987 fn get_missing_paddles_hg_py(&self, mapping : DsiJChPidMapping) -> Vec<u8> {
988 self.get_missing_paddles_hg(&mapping)
989 }
990
991 #[pyo3(name="get_triggered_paddles")]
993 fn get_triggered_paddles_py(&self, mapping : DsiJChPidMapping) -> Vec<u8> {
994 self.get_triggered_paddles(&mapping)
995 }
996
997 #[getter]
1000 fn lost_hits(&self) -> u16 {
1001 self.drs_dead_lost_hits
1002 }
1003
1004 #[getter]
1007 fn rb_link_ids(&self) -> Vec<u32> {
1008 self.get_rb_link_ids().into_iter().map(|byte| byte as u32).collect()
1009 }
1010
1011 #[getter]
1013 fn get_rb_events(&self) -> Vec<RBEvent> {
1014 self.rb_events.clone()
1015 }
1016
1017 #[getter]
1019 pub fn trigger_hits(&self) -> PyResult<Vec<(u8, u8, (u8, u8), LTBThreshold)>> {
1020 Ok(self.get_trigger_hits())
1021 }
1022
1023 #[getter]
1026 pub fn trigger_sources(&self) -> Vec<TriggerType> {
1027 self.get_trigger_sources()
1028 }
1029
1030 #[getter]
1031 #[pyo3(name="hits")]
1032 pub fn hits_py<'_py>(&self) -> Vec<TofHit> {
1033 self.hits.clone()
1037 }
1038
1039 #[getter]
1040 #[pyo3(name="hitmap")]
1041 pub fn hitmap<'_py>(&self) -> HashMap<u8,TofHit> {
1042 let mut hitmap = HashMap::<u8, TofHit>::new();
1046 for h in &self.hits {
1047 hitmap.insert(h.paddle_id, *h);
1048 }
1049 hitmap
1050 }
1051
1052 #[getter]
1057 #[pyo3(name="get_edep_umbrella")]
1058 pub fn get_edep_umbrella_py(&self) -> f32 {
1059 self.get_edep_umbrella()
1060 }
1061
1062 #[getter]
1067 #[pyo3(name="get_edep_cube")]
1068 pub fn get_edep_cube_py(&self) -> f32 {
1069 self.get_edep_cube()
1070 }
1071
1072 #[getter]
1077 #[pyo3(name="get_edep_cortina")]
1078 pub fn get_edep_cortina_py(&self) -> f32 {
1079 self.get_edep_cortina()
1080 }
1081
1082 #[getter]
1087 #[pyo3(name="get_edep")]
1088 pub fn get_edep_py(&self) -> f32 {
1089 self.get_edep()
1090 }
1091
1092 #[getter]
1093 #[pyo3(name="nhits")]
1094 pub fn nhits_py(&self) -> usize {
1095 self.get_nhits()
1096 }
1097
1098 #[getter]
1099 #[pyo3(name="nhits_umb")]
1100 pub fn nhits_umb_py(&self) -> usize {
1101 self.get_nhits_umb()
1102 }
1103
1104 #[getter]
1105 #[pyo3(name="nhits_cbe")]
1106 fn get_nhits_cbe_py(&self) -> usize {
1107 self.get_nhits_cbe()
1108 }
1109
1110 #[getter]
1111 #[pyo3(name="nhits_cor")]
1112 fn get_nhits_cor_py(&self) -> usize {
1113 self.get_nhits_cor()
1114 }
1115
1116 #[getter]
1117 fn get_timestamp16(&self) -> u16 {
1118 self.timestamp16
1119 }
1120
1121 #[getter]
1122 fn get_timestamp32(&self) -> u32 {
1123 self.timestamp32
1124 }
1125
1126 #[getter]
1127 fn timestamp48(&self) -> u64 {
1128 self.get_timestamp48()
1129 }
1130
1131 #[getter]
1132 fn get_status(&self) -> EventStatus {
1133 self.status
1134 }
1135
1136 #[getter]
1137 #[pyo3(name="waveforms")]
1138 fn get_waveforms_py(&self) -> Vec<RBWaveform> {
1139 self.get_waveforms()
1140 }
1141}
1142
1143#[cfg(feature="pybindings")]
1144pythonize_packable!(TofEvent);
1145
1146#[test]
1149fn packable_tofeventv0() {
1150 for _ in 0..500 {
1151 let mut data = TofEvent::from_random();
1152 if data.version != ProtocolVersion::Unknown {
1153 continue;
1154 }
1155 let mut test : TofEvent = data.pack().unpack().unwrap();
1156 let fix_time = Instant::now();
1163 test.creation_time = fix_time;
1164 data.creation_time = fix_time;
1165 for h in &mut test.hits {
1166 h.paddle_len = 0.0;
1167 h.coax_cable_time = 0.0;
1168 h.hart_cable_time = 0.0;
1169 h.x = 0.0;
1170 h.y = 0.0;
1171 h.z = 0.0;
1172 h.event_t0 = 0.0;
1173 }
1174 assert_eq!(data, test);
1175 }
1176}
1177
1178#[test]
1179fn packable_tofeventv1() {
1180 for _ in 0..500 {
1181 let mut data = TofEvent::from_random();
1182 if data.version != ProtocolVersion::V1 {
1183 continue;
1184 }
1185 let mut test : TofEvent = data.pack().unpack().unwrap();
1186 let fix_time = Instant::now();
1191 test.creation_time = fix_time;
1192 data.creation_time = fix_time;
1193 for h in &mut test.hits {
1194 h.paddle_len = 0.0;
1195 h.coax_cable_time = 0.0;
1196 h.hart_cable_time = 0.0;
1197 h.x = 0.0;
1198 h.y = 0.0;
1199 h.z = 0.0;
1200 h.event_t0 = 0.0;
1201 }
1202 assert_eq!(data, test);
1203 }
1204}
1205
1206#[test]
1207fn packable_tofeventv2() {
1208 for _ in 0..500 {
1209 let mut data = TofEvent::from_random();
1210 if data.version != ProtocolVersion::V2 {
1211 continue;
1212 }
1213 let mut test : TofEvent = data.pack().unpack().unwrap();
1214 let fix_time = Instant::now();
1219 test.creation_time = fix_time;
1220 data.creation_time = fix_time;
1221 for h in &mut test.hits {
1222 h.paddle_len = 0.0;
1223 h.coax_cable_time = 0.0;
1224 h.hart_cable_time = 0.0;
1225 h.x = 0.0;
1226 h.y = 0.0;
1227 h.z = 0.0;
1228 h.event_t0 = 0.0;
1229 }
1230 assert_eq!(data, test);
1231 }
1232}
1233
1234
1235