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::*;
51
52use crate::colors::{
53 ColorTheme,
54};
55
56use crate::widgets::{
57 prep_data,
59 create_labels,
60 histogram,
61 gauge,
62};
63
64#[derive(Debug, Clone)]
65pub struct TofSummaryTab {
66 pub ts_receiver : Receiver<TofPacket>,
67 pub ts_sender : Sender<TofEvent>,
69 pub rbe_sender : Sender<RBEvent>,
70 pub mte_sender : Sender<TofEvent>,
71 pub summary_queue : VecDeque<TofEvent>,
72 pub queue_size : usize,
73 pub n_trg_pdl_histo : Hist1D<Uniform<f32>>,
74 pub theme : ColorTheme,
75
76 pub event_id_test : Vec<u32>,
78 pub evid_test_info : String,
79 pub evid_test_len : usize,
80 pub n_evid_test : usize,
81 pub evid_test_chnks : VecDeque<u64>,
82
83 pub miss_hg_hits : Hist1D<Uniform<f32>>,
85 pub pid_map : DsiJChPidMapping,
86}
87
88impl TofSummaryTab {
89 pub fn new(ts_receiver : Receiver<TofPacket>,
90 ts_sender : Sender<TofEvent>,
91 mte_sender : Sender<TofEvent>,
92 rbe_sender : Sender<RBEvent>,
93 dsijchpidmap : &DsiJChPidMapping,
94 theme : ColorTheme) -> Self {
95
96 let bins = Uniform::new(25, 0.0, 25.0).unwrap();
97 let mhg_bins = Uniform::new(160, 0.0, 160.0).unwrap();
98 Self {
99 ts_receiver : ts_receiver,
100 ts_sender : ts_sender,
101 mte_sender : mte_sender,
102 rbe_sender : rbe_sender,
103 summary_queue : VecDeque::<TofEvent>::new(),
104 queue_size : 10000,
105 n_trg_pdl_histo : ndhistogram!(bins),
106 theme : theme,
107 event_id_test : Vec::<u32>::with_capacity(100000),
108 evid_test_info : String::from("Missing event id analysis"),
109 evid_test_len : 20000,
110 n_evid_test : 0,
111 evid_test_chnks : VecDeque::<u64>::new(),
112 miss_hg_hits : ndhistogram!(mhg_bins),
113 pid_map : dsijchpidmap.clone(),
114 }
115 }
116
117 pub fn receive_packet(&mut self) -> Result<(), SerializationError> {
118 match self.ts_receiver.try_recv() {
120 Err(_err) => {
121 trace!("Unable to receive new TofEvent!");
122 },
123 Ok(tp) => {
124 let ts = tp.unpack::<TofEvent>()?;
125 self.n_trg_pdl_histo.fill(&(ts.n_trigger_paddles as f32));
136 let missing_hg = ts.get_missing_paddles_hg(&self.pid_map);
138 for pid in &missing_hg {
139 self.miss_hg_hits.fill(&(*pid as f32));
140 }
141 if self.event_id_test.len() != self.evid_test_len {
142 self.event_id_test.push(ts.event_id);
143 } else {
144 let mut missing = 0usize;
146 let mut evid = self.event_id_test[0];
147 for _ in 0..self.event_id_test.len() {
148 if !self.event_id_test.contains(&evid) {
149 missing += 1;
150 }
152 evid += 1;
153 }
154 self.n_evid_test += 1;
155 self.evid_test_chnks.push_back(missing as u64);
156 if self.evid_test_chnks.len() > 100 {
157 self.evid_test_chnks.pop_front();
158 }
159 self.evid_test_info = format!("Missing event ID search [{}]", self.n_evid_test);
160 self.evid_test_info += &(format!("\n-- in a chunk of {} event ids", self.evid_test_len));
161 self.evid_test_info += &(format!("\n-- we found {} event ids missing ({}%)", missing, 100.0*(missing as f64)/self.event_id_test.len() as f64));
162 self.evid_test_info += &(format!("\n-- -- previous: {:?}", self.evid_test_chnks));
163 self.event_id_test.clear();
164 }
165 for rbev in &ts.rb_events {
167 match self.rbe_sender.send(rbev.clone()) {
168 Ok(_) => (),
169 Err(err) => error!("Unable to pass on RBEvent! {err}")
170 }
171 }
172 self.summary_queue.push_back(ts.clone());
173 if self.summary_queue.len() > self.queue_size {
174 self.summary_queue.pop_front();
175 }
176
177 match self.ts_sender.send(ts.clone()) {
178 Ok(_) => (),
179 Err(err) => error!("Unable to pass on TofEvent! {err}")
180 }
181 match self.mte_sender.send(ts) {
182 Ok(_) => (),
183 Err(err) => error!("Unable to pass on TofEvent! {err}")
184 }
185 }
186 }
187 Ok(())
188 }
189
190 pub fn render(&mut self, main_window : &Rect, frame : &mut Frame) {
191 let layout = Layout::default()
192 .direction(Direction::Horizontal)
193 .constraints(
194 [Constraint::Percentage(30),
195 Constraint::Percentage(70)].as_ref(),
196 )
197 .split(*main_window);
198
199 let histo_view = Layout::default()
200 .direction(Direction::Vertical)
201 .constraints(
202 [Constraint::Percentage(33),
203 Constraint::Percentage(33),
204 Constraint::Percentage(34)].as_ref(),
205 )
206 .split(layout[1]);
207
208 let evid_test_view = Layout::default()
209 .direction(Direction::Vertical)
210 .constraints(
211 [Constraint::Percentage(70),
212 Constraint::Percentage(30)].as_ref(),
213 )
214 .split(histo_view[2]);
215
216 let evid_test_view_0 = Layout::default()
217 .direction(Direction::Horizontal)
218 .constraints(
219 [Constraint::Percentage(30),
220 Constraint::Percentage(70)].as_ref(),
221 )
222 .split(evid_test_view[0]);
223
224 let last_ts = self.summary_queue.back();
225 let view_string : String;
226 match last_ts {
227 Some(ts) => {
228 view_string = ts.to_string();
229 },
230 None => {
231 view_string = String::from("TofEvent QUEUE EMPTY!");
232 }
233 }
234 let event_view = Paragraph::new(view_string)
235 .style(Style::default().fg(self.theme.fg0))
236 .alignment(Alignment::Left)
237 .block(
239 Block::default()
240 .borders(Borders::ALL)
241 .style(self.theme.style())
242 .title("Last TofEvent")
243 .border_type(BorderType::Rounded),
244 );
245 frame.render_widget(event_view, layout[0]);
246
247 let th_labels = create_labels(&self.n_trg_pdl_histo);
249 let th_data = prep_data(&self.n_trg_pdl_histo, &th_labels, 5, true);
250 let th_chart = histogram(th_data, String::from("N Trig Paddles"), 2, 0, &self.theme);
251 frame.render_widget(th_chart, histo_view[0]);
252
253 let mhg_labels = create_labels(&self.miss_hg_hits);
254 let mhg_data = prep_data(&self.miss_hg_hits, &mhg_labels, 10, true);
255 let mhg_chart = histogram(mhg_data, String::from("Missing HG hits"), 1, 0, &self.theme);
256 frame.render_widget(mhg_chart, histo_view[1]);
257
258 let evid_test_data = Paragraph::new(self.evid_test_info.clone())
259 .style(Style::default().fg(self.theme.fg0))
260 .alignment(Alignment::Left)
261 .block(
263 Block::default()
264 .borders(Borders::ALL)
265 .style(self.theme.style())
266 .title("Missing event ID test")
267 .border_type(BorderType::Rounded),
268 );
269 let mut spl_data = Vec::<u64>::new();
270 spl_data.extend_from_slice(self.evid_test_chnks.make_contiguous());
271 for k in 0..spl_data.len() {
274 spl_data[k] += 1;
275 }
276 let sparkline = Sparkline::default()
277 .style(self.theme.style())
278 .data(&spl_data)
281 .block(
282 Block::default()
283 .borders(Borders::ALL)
284 .style(self.theme.style())
285 .title("Missing event IDs in chunks")
286 );
287
288 frame.render_widget(evid_test_data, evid_test_view_0[0]);
289 frame.render_widget(sparkline, evid_test_view_0[1]);
290 let ratio = self.event_id_test.len() as f64 / self.evid_test_len as f64;
291 let test_gauge = gauge(String::from("Missing event ID check"), String::from("Gathering data"), ratio, &self.theme);
292 frame.render_widget(test_gauge, evid_test_view[1]);
293 }
294}