1use std::collections::VecDeque;
2
3use crossbeam_channel::{
4 Sender,
5 Receiver
6};
7
8use ndhistogram::{
10 ndhistogram,
11 Histogram,
12 Hist1D,
13};
14
15use ndhistogram::axis::{
16 Uniform,
17};
18
19use ratatui::{
20 layout::{
22 Alignment,
23 Constraint,
24 Direction,
25 Layout,
26 Rect
27 },
28 style::{
29 Style
32 },
33 Frame,
36 widgets::{
37 Block,
38 BorderType,
42 Sparkline,
45 Borders,
46 Paragraph
47 },
48};
49
50use gondola_core::prelude::*;
51use crate::colors::{
58 ColorTheme,
59};
60
61use crate::widgets::{
62 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 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 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 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 match self.ts_receiver.try_recv() {
119 Err(_err) => {
120 trace!("Unable to receive new TofEvent!");
121 },
122 Ok(ts) => {
123 self.n_trg_pdl_histo.fill(&(ts.n_trigger_paddles as f32));
125 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 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 }
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 .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 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 .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 for k in 0..spl_data.len() {
251 spl_data[k] += 1;
252 }
253 let sparkline = Sparkline::default()
254 .style(self.theme.style())
255 .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}