liftof_tui/tabs/
tab_tofsummary.rs

1use std::collections::VecDeque;
2
3use crossbeam_channel::{
4  Sender,
5  Receiver
6};
7
8//extern crate ndhistogram;
9use ndhistogram::{
10  ndhistogram,
11  Histogram,
12  Hist1D,
13};
14
15use ndhistogram::axis::{
16  Uniform,
17};
18
19use ratatui::{
20  //symbols,
21  layout::{
22      Alignment,
23      Constraint,
24      Direction,
25      Layout,
26      Rect
27  },
28  style::{
29      //Color,
30      //Modifier,
31      Style
32  },
33  //text::Span,
34  //terminal::Frame,
35  Frame,
36  widgets::{
37      Block,
38      //Dataset,
39      //Axis,
40      //GraphType,
41      BorderType,
42      //Chart,
43      //BarChart,
44      Sparkline,
45      Borders,
46      Paragraph
47  },
48};
49
50use gondola_core::prelude::*;
51////use tof_dataclasses::packets::TofPacket;
52//use tof_dataclasses::events::TofEvent;
53//use tof_dataclasses::errors::SerializationError;
54////use tof_dataclasses::serialization::Serialization;
55//use tof_dataclasses::database::DsiJChPidMapping;
56
57use crate::colors::{
58    ColorTheme,
59};
60
61use crate::widgets::{
62    //clean_data,
63    prep_data,
64    create_labels,
65    histogram,
66    gauge,
67};
68
69#[derive(Debug, Clone)]
70pub struct TofSummaryTab {
71  pub ts_receiver     : Receiver<TofEvent>,
72  /// pass our events on when we are done with them!
73  pub ts_sender       : Sender<TofEvent>,
74  pub summary_queue   : VecDeque<TofEvent>,
75  pub queue_size      : usize,
76  pub n_trg_pdl_histo : Hist1D<Uniform<f32>>, 
77  pub theme           : ColorTheme,
78
79  // missing event analysis
80  pub event_id_test   : Vec<u32>,
81  pub evid_test_info  : String,
82  pub evid_test_len   : usize,
83  pub n_evid_test     : usize,
84  pub evid_test_chnks : VecDeque<u64>,
85
86  // missing HG hit analysis
87  pub miss_hg_hits    : Hist1D<Uniform<f32>>,
88  pub pid_map         : DsiJChPidMapping,
89}
90
91impl TofSummaryTab {
92  pub fn new(ts_receiver  : Receiver<TofEvent>,
93             ts_sender    : Sender<TofEvent>,
94             dsijchpidmap : &DsiJChPidMapping,
95             theme        : ColorTheme) -> Self {
96    
97    let bins          = Uniform::new(25, 0.0, 25.0).unwrap();
98    let mhg_bins      = Uniform::new(160, 0.0, 160.0).unwrap();
99    Self {
100      ts_receiver     : ts_receiver,
101      ts_sender       : ts_sender,
102      summary_queue   : VecDeque::<TofEvent>::new(),
103      queue_size      : 10000,
104      n_trg_pdl_histo : ndhistogram!(bins),
105      theme           : theme,
106      event_id_test   : Vec::<u32>::with_capacity(100000),
107      evid_test_info  : String::from("Missing event id analysis"),
108      evid_test_len   : 20000,
109      n_evid_test     : 0,
110      evid_test_chnks : VecDeque::<u64>::new(),
111      miss_hg_hits    : ndhistogram!(mhg_bins),
112      pid_map         : dsijchpidmap.clone(),
113    }
114  }
115
116  pub fn receive_packet(&mut self) -> Result<(), SerializationError> {
117    //let mut ts = TofEvent::new();
118    match self.ts_receiver.try_recv() {
119      Err(_err)  => {
120        trace!("Unable to receive new TofEvent!");
121      },
122      Ok(ts)    => {
123        // triggerd paddles histogram
124        self.n_trg_pdl_histo.fill(&(ts.n_trigger_paddles as f32));
125        // missing hg hits for paddles histogram
126        let missing_hg = ts.get_missing_paddles_hg(&self.pid_map);
127        for pid in &missing_hg {
128            self.miss_hg_hits.fill(&(*pid as f32));
129        }
130        if self.event_id_test.len() != self.evid_test_len {
131          self.event_id_test.push(ts.event_id);
132        } else {
133          //let mut miss_pos = Vec::<usize>::new();
134          let mut missing = 0usize;
135          let mut evid = self.event_id_test[0];
136          for _ in 0..self.event_id_test.len() {
137            if !self.event_id_test.contains(&evid) {
138              missing += 1;
139              //miss_pos.push(k);
140            }
141            evid += 1;
142          }
143          self.n_evid_test += 1;
144          self.evid_test_chnks.push_back(missing as u64);
145          if self.evid_test_chnks.len() > 100 {
146            self.evid_test_chnks.pop_front();
147          }
148          self.evid_test_info  = format!("Missing event ID search [{}]", self.n_evid_test);
149          self.evid_test_info += &(format!("\n-- in a chunk of {} event ids", self.evid_test_len)); 
150          self.evid_test_info += &(format!("\n-- we found {} event ids missing ({}%)", missing, 100.0*(missing as f64)/self.event_id_test.len() as f64));
151          self.evid_test_info += &(format!("\n-- -- previous: {:?}", self.evid_test_chnks));
152          self.event_id_test.clear();
153        }
154        self.summary_queue.push_back(ts.clone());
155        if self.summary_queue.len() > self.queue_size {
156          self.summary_queue.pop_front();
157        }
158        match self.ts_sender.send(ts) {
159          Ok(_)    => (),
160          Err(err) => error!("Unable to pass on TofEvent! {err}")
161        }
162      }
163    }
164    Ok(())
165  }
166  
167  pub fn render(&mut self, main_window : &Rect, frame : &mut Frame) {
168    let layout = Layout::default()
169      .direction(Direction::Horizontal)
170      .constraints(
171          [Constraint::Percentage(30),
172           Constraint::Percentage(70)].as_ref(),
173      )
174      .split(*main_window);
175   
176    let histo_view = Layout::default()
177      .direction(Direction::Vertical)
178      .constraints(
179          [Constraint::Percentage(33),
180           Constraint::Percentage(33),
181           Constraint::Percentage(34)].as_ref(),
182      )  
183      .split(layout[1]);
184
185    let evid_test_view = Layout::default()
186      .direction(Direction::Vertical)
187      .constraints(
188        [Constraint::Percentage(70),
189         Constraint::Percentage(30)].as_ref(),
190      )
191      .split(histo_view[2]);
192    
193    let evid_test_view_0 = Layout::default()
194      .direction(Direction::Horizontal)
195      .constraints(
196        [Constraint::Percentage(30),
197         Constraint::Percentage(70)].as_ref(),
198      )
199      .split(evid_test_view[0]);
200
201    let last_ts = self.summary_queue.back();
202    let view_string : String;
203    match last_ts {
204      Some(ts) => { 
205        view_string = ts.to_string();
206      }, 
207      None => {
208        view_string = String::from("TofEvent QUEUE EMPTY!");
209      }
210    }
211    let event_view = Paragraph::new(view_string)
212      .style(Style::default().fg(self.theme.fg0))
213      .alignment(Alignment::Left)
214      //.scroll((5, 10))
215      .block(
216        Block::default()
217          .borders(Borders::ALL)
218          .style(self.theme.style())
219          .title("Last TofEvent")
220          .border_type(BorderType::Rounded),
221      );
222    frame.render_widget(event_view, layout[0]);
223     
224    // histograms
225    let th_labels  = create_labels(&self.n_trg_pdl_histo);
226    let th_data    = prep_data(&self.n_trg_pdl_histo, &th_labels, 5, true); 
227    let th_chart   = histogram(th_data, String::from("N Trig Paddles"), 2, 0, &self.theme);
228    frame.render_widget(th_chart, histo_view[0]); 
229   
230    let mhg_labels = create_labels(&self.miss_hg_hits);
231    let mhg_data   = prep_data(&self.miss_hg_hits, &mhg_labels, 10, true);
232    let mhg_chart  = histogram(mhg_data, String::from("Missing HG hits"), 1, 0, &self.theme);
233    frame.render_widget(mhg_chart, histo_view[1]);
234
235    let evid_test_data = Paragraph::new(self.evid_test_info.clone())
236      .style(Style::default().fg(self.theme.fg0))
237      .alignment(Alignment::Left)
238      //.scroll((5, 10))
239      .block(
240        Block::default()
241          .borders(Borders::ALL)
242          .style(self.theme.style())
243          .title("Missing event ID test")
244          .border_type(BorderType::Rounded),
245      );
246    let mut spl_data  = Vec::<u64>::new();
247    spl_data.extend_from_slice(self.evid_test_chnks.make_contiguous());
248    // that the sparkline does something, it can't be zero. 
249    // There is no axis marker, so we just add 1 to every bin
250    for k in 0..spl_data.len() {
251      spl_data[k] += 1;
252    }
253    let sparkline = Sparkline::default()
254      .style(self.theme.style())
255      //.direction(RenderDirection::LeftToRight)
256      //.data(self.evid_test_chnks.make_contiguous())
257      .data(&spl_data)
258      .block(
259        Block::default()
260        .borders(Borders::ALL)
261        .style(self.theme.style())
262        .title("Missing event IDs in chunks")
263      );
264
265    frame.render_widget(evid_test_data, evid_test_view_0[0]);
266    frame.render_widget(sparkline, evid_test_view_0[1]);
267    let ratio = self.event_id_test.len() as f64 / self.evid_test_len as f64;
268    let test_gauge = gauge(String::from("Missing event ID check"), String::from("Gathering data"), ratio, &self.theme);
269    frame.render_widget(test_gauge, evid_test_view[1]);
270  }
271}