gondola_core/database.rs
1//! Database access & entities for gaps-online-software
2//!
3//! A local .sqlite database is shipped with gaps-online-software,
4//! pre-populated with relevant meta data for the GAPS experiment.
5// This file is part of gaps-online-software and published
6// under the GPLv3 license
7
8use crate::prelude::*;
9
10use std::fs::File;
11use std::io::{self, BufRead, BufReader};
12use std::path::Path;
13
14use diesel::prelude::*;
15use diesel::FromSqlRow;
16use diesel::AsExpression;
17use diesel::serialize;
18use diesel::deserialize;
19use diesel::sqlite::Sqlite;
20use diesel::deserialize::FromSql;
21use diesel::serialize::Output;
22use diesel::sql_types::Integer;
23use diesel::serialize::ToSql;
24use diesel::backend::Backend;
25
26mod schema;
27use schema::tof_db_rat::dsl::*;
28
29mod tracker_mask;
30pub use tracker_mask::{
31 TrackerStripMask,
32 create_trk_mask_table
33};
34
35mod tracker_pedestal;
36pub use tracker_pedestal::create_trk_pedestal_table;
37
38mod tracker_transfer_fn;
39pub use tracker_transfer_fn::{
40 TrackerStripTransferFunction,
41 create_trk_transfer_fn_table
42};
43
44mod tracker_gain;
45pub use tracker_gain::{
46 TrackerStripGain,
47 create_trk_gain_table
48};
49
50mod tracker_pulse;
51pub use tracker_pulse::{
52 TrackerStripPulse,
53 create_trk_pulse_table
54};
55
56mod tracker_cali_times;
57pub use tracker_cali_times::{
58 TrackerCaliTimeWindow,
59 is_in_tracker_cali_window,
60 create_trk_cali_tw_table,
61};
62
63mod tof_paddle_temps;
64pub use tof_paddle_temps::{
65 TofPaddleTemp,
66 TofPaddleTempDataSeries,
67 create_tof_paddle_temp_table
68};
69
70/// Low gain/LTB connections to paddle ID
71pub type DsiJChPidMapping = HashMap<u8, HashMap<u8, HashMap<u8, (u8, u8)>>>;
72/// Low gain/LTB connections to rb ID
73pub type DsiJChRbMapping = HashMap<u8, HashMap<u8, HashMap<u8, u8>>>;
74/// RB ID and RB Ch to paddle ID mapping
75pub type RbChPidMapping = HashMap<u8, HashMap<u8, u8>>;
76
77//--------------------------------------------------------------
78
79/// Describe the contents of a byte sequence ("packet") typicially
80/// crafted for telemetry. The numbers are defined by the 'bfsw'
81/// software package.
82#[derive(Debug, Hash, Eq, PartialEq, Clone, Copy, FromRepr, AsRefStr, EnumIter,AsExpression, FromSqlRow)]
83#[cfg_attr(feature = "pybindings", pyclass(eq, eq_int))]
84#[diesel(sql_type = Integer)]
85pub enum TrackerCalibrationFileType {
86 Unknown = 0,
87 Pedestal = 200,
88 TransferFn = 201,
89 ChannelMask = 202,
90 PulsedChannels = 203,
91 Gains = 204,
92 Any = 255,
93}
94
95impl ToSql<Integer, Sqlite> for TrackerCalibrationFileType {
96 fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Sqlite>) -> serialize::Result {
97 out.set_value(*self as i32);
98 Ok(serialize::IsNull::No)
99 }
100}
101
102impl FromSql<Integer, Sqlite> for TrackerCalibrationFileType {
103 fn from_sql(bytes: <Sqlite as Backend>::RawValue<'_>) -> deserialize::Result<Self> {
104 let v = i32::from_sql(bytes)?;
105 match v {
106 0 => Ok(TrackerCalibrationFileType::Unknown),
107 200 => Ok(TrackerCalibrationFileType::Pedestal),
108 201 => Ok(TrackerCalibrationFileType::TransferFn),
109 202 => Ok(TrackerCalibrationFileType::ChannelMask),
110 203 => Ok(TrackerCalibrationFileType::PulsedChannels),
111 204 => Ok(TrackerCalibrationFileType::Gains),
112 255 => Ok(TrackerCalibrationFileType::Any),
113 _ => {
114 error!("Unable to understand type {v}");
115 return Err("Unrecognized calibration file type".into());
116 }
117 }
118 }
119}
120
121impl fmt::Display for TrackerCalibrationFileType {
122 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
123 let mut repr = String::from("<TrackerCalFileType::");
124 match self {
125 Self::Unknown => { repr += "Unknown>";}
126 Self::Pedestal => { repr += "Pedestal>";}
127 Self::TransferFn => { repr += "TransferFn>";}
128 Self::ChannelMask => { repr += "ChannelMask>";}
129 Self::PulsedChannels => { repr += "PulsedChannels>";}
130 Self::Gains => { repr += "Gains>";}
131 Self::Any => { repr += "Any>";}
132 }
133 write!(f, "{}", repr)
134 }
135}
136
137//expand_and_test_enum!(TrackerCalibrationFileType, test_telemetrypackettype_repr);
138
139//--------------------------------------------------------------
140
141/// This loads the calbration DB for SimpleDet as provided by Elena
142/// and INFN.
143///
144/// This calibration db is basically a list of files and timestamps
145/// Exitence of these paths is not guaranteed.
146#[cfg_attr(feature="pybindings", pyfunction)]
147#[cfg_attr(feature="pybindings", pyo3(signature = (db_path, cali_ftype = TrackerCalibrationFileType::Any)))]
148pub fn load_calibration_db_elena(db_path : &str, cali_ftype : TrackerCalibrationFileType) -> Option<Vec<TrackerCalibrationFile>> {
149 use schema::calibration_files::dsl::*;
150 info!("Will load SD calibration DB from {}", db_path);
151 let mut conn = SqliteConnection::establish(db_path).ok()?;
152 match calibration_files.load::<TrackerCalibrationFile>(&mut conn) {
153 Err(err) => {
154 error!("Unable to load tracker calibration files from db! {err}");
155 return None;
156 }
157 Ok(mut files) => {
158 match cali_ftype {
159 TrackerCalibrationFileType::Any => {
160 return Some(files);
161 }
162 _ => {
163 files.retain(|x| x.file_type == cali_ftype);
164 return Some(files);
165 }
166 }
167 }
168 }
169}
170
171//--------------------------------------------------------------
172
173
174/// Connect to a database at a given location
175pub fn connect_to_db_path(db_path : &str) -> Result<diesel::SqliteConnection, ConnectionError> {
176 info!("Will set GONDOLA_DB_URL to {}", db_path);
177 warn!("Setting environment variables is not thread safe!");
178 unsafe {
179 //env::set_var("GONDOLA_DB_URL", db_path);
180 env::set_var("GONDOLA_DB_URL", db_path);
181 }
182 SqliteConnection::establish(db_path)
183}
184
185//---------------------------------------------------------------------
186
187/// Connect to the default database at the standard location
188pub fn connect_to_db() -> Result<diesel::SqliteConnection, ConnectionError> {
189 let db_path = env::var("GONDOLA_DB_URL").unwrap_or_else(|_| "".to_string());
190 if db_path == "" {
191 error!("Empty GONDOLA_DB_URL. Did you forget to load the gaps-online-software setup-env.sh shell?");
192 }
193 SqliteConnection::establish(&db_path)
194}
195
196//---------------------------------------------------------------------
197
198/// Create a mapping of DSI/J(LTB) -> PaddleID
199///
200/// This will basically tell you for a given LTB hit which paddle has
201/// triggered.
202pub fn get_dsi_j_ch_pid_map(paddles : &Vec<TofPaddle>) -> DsiJChPidMapping {
203 let mut mapping = DsiJChPidMapping::new();
204 for dsi in 1..6 {
205 let mut jmap = HashMap::<u8, HashMap<u8, (u8, u8)>>::new();
206 for j in 1..6 {
207 let mut rbidch_map : HashMap<u8, (u8,u8)> = HashMap::new();
208 for ch in 1..17 {
209 let rbidch = (0,0);
210 rbidch_map.insert(ch,rbidch);
211 //map[dsi] =
212 }
213 jmap.insert(j,rbidch_map);
214 }
215 mapping.insert(dsi,jmap);
216 }
217 for pdl in paddles {
218 let dsi = pdl.dsi as u8;
219 let j = pdl.j_ltb as u8;
220 let ch_a = pdl.ltb_chA as u8;
221 let ch_b = pdl.ltb_chB as u8;
222 let pid = pdl.paddle_id as u8;
223 let panel_id = pdl.panel_id as u8;
224 mapping.get_mut(&dsi).unwrap().get_mut(&j).unwrap().insert(ch_a,(pid, panel_id));
225 mapping.get_mut(&dsi).unwrap().get_mut(&j).unwrap().insert(ch_b,(pid, panel_id));
226 }
227 return mapping;
228}
229
230//---------------------------------------------------------------------
231
232/// Create a mapping of DSI/J(LTB) -> RBID
233///
234/// This will basically tell you for a given LTB hit which rb has
235/// triggered.
236pub fn get_dsi_j_ch_rb_map(paddles : &Vec<TofPaddle>) -> DsiJChRbMapping {
237 let mut mapping = DsiJChRbMapping::new();
238 for dsi in 1..6 {
239 let mut jmap = HashMap::<u8, HashMap<u8, u8>>::new();
240 for j in 1..6 {
241 let mut rbidch_map : HashMap<u8, u8> = HashMap::new();
242 for ch in 1..17 {
243 let rbidch = 0u8;
244 rbidch_map.insert(ch,rbidch);
245 //map[dsi] =
246 }
247 jmap.insert(j,rbidch_map);
248 }
249 mapping.insert(dsi,jmap);
250 }
251 for pdl in paddles {
252 let dsi = pdl.dsi as u8;
253 let j = pdl.j_ltb as u8;
254 let ch_a = pdl.ltb_chA as u8;
255 let ch_b = pdl.ltb_chB as u8;
256 let rb_id = pdl.paddle_id as u8;
257 mapping.get_mut(&dsi).unwrap().get_mut(&j).unwrap().insert(ch_a,rb_id);
258 mapping.get_mut(&dsi).unwrap().get_mut(&j).unwrap().insert(ch_b,rb_id);
259 }
260 return mapping;
261}
262
263//---------------------------------------------------------------------
264
265/// Get a mapping of which pb controls paddles connected to which RB
266#[cfg_attr(feature="pybindings", pyfunction)]
267pub fn get_rbids_for_pbid(pbid : u8) -> Option<(u8, u8)> {
268 let rats = RAT::all()?;
269 for rat in rats {
270 if rat.pb_id as u8 == pbid {
271 return Some((rat.rb1_id as u8, rat.rb2_id as u8));
272 }
273 }
274 None
275}
276
277pub fn get_rbid_pbchannel_pid_map(paddles : &Vec<TofPaddle>) -> Option<(RbChPidMapping, RbChPidMapping)> {
278 let mut map_a = RbChPidMapping::new();
279 let mut map_b = RbChPidMapping::new();
280
281 let rats = RAT::all().unwrap();
282 let mut rb1rb2map = HashMap::<u8,u8>::new();
283 let mut rb2rb1map = HashMap::<u8,u8>::new();
284 for r in rats {
285 // these vectors are sorted now
286 // the index is the smae for each rat
287 rb1rb2map.insert(r.rb1_id as u8, r.rb2_id as u8);
288 rb2rb1map.insert(r.rb2_id as u8, r.rb1_id as u8);
289 }
290 // for the map, what we want is that for
291 // BOTH rbs in the rat, we have the SAME
292 // PB channels/pids
293 // For the PB, we don't care to which
294 // RB the data channels are connected to
295 // The rb here is a stand-in for the
296 // "any rb in that RAT"
297 for pdl in paddles {
298 let rb_id = pdl.rb_id as u8;
299 let pb_ch_a = pdl.pb_chA as u8;
300 let pb_ch_b = pdl.pb_chB as u8;
301 let pid = pdl.paddle_id as u8;
302 // chheck if it is rb1 or 2
303 let other_rb : u8;
304 if rb1rb2map.contains_key(&rb_id) {
305 other_rb = *rb1rb2map.get(&rb_id).unwrap();
306 } else {
307 other_rb = *rb2rb1map.get(&rb_id).unwrap();
308 }
309
310 for rid in [rb_id,other_rb] {
311 if map_a.contains_key(&rid) {
312 map_a.get_mut(&rid).unwrap().insert(pb_ch_a, pid);
313 } else {
314 let mut ch_map = HashMap::<u8,u8>::new();
315 ch_map.insert(pb_ch_a, pid);
316 map_a.insert(rid , ch_map);
317 }
318 if map_b.contains_key(&rid) {
319 map_b.get_mut(&rid).unwrap().insert(pb_ch_b, pid);
320 } else{
321 let mut ch_map = HashMap::<u8,u8>::new();
322 ch_map.insert(pb_ch_b, pid);
323 map_b.insert(rid , ch_map);
324 }
325 }
326 }
327 Some((map_a, map_b))
328}
329
330//---------------------------------------------------------------------
331
332/// Create a mapping of DSI/J(LTB) -> RBID
333///
334/// This will basically tell you for a given LTB hit which rb has
335/// triggered.
336#[cfg(feature="pybindings")]
337#[pyfunction]
338#[pyo3(name="get_dsi_j_ch_rb_map")]
339pub fn get_dsi_j_ch_rb_map_py() -> Option<DsiJChRbMapping> {
340 if let Some(paddles) = TofPaddle::all() {
341 return Some(get_dsi_j_ch_rb_map(&paddles));
342 } else {
343 return None;
344 }
345}
346
347
348
349
350//---------------------------------------------------------------------
351
352/// Create a mapping of RB/PB Channel -> PaddleID
353///
354/// Find out to which paddle ends the sipms are connected
355/// on the powerboard.
356/// Per each RAT, there is one RB which controls the
357/// PB (powerboard). For a given RB id, find out which
358/// PB is in the same RAT and return the connected
359/// paddle id
360///
361/// # Returns:
362/// * tuple(dict (rb_id, dict(pb_ch, pid)),..)
363/// The returned tuple contains two dictionaries.
364/// The first is for paddle end A, the second for
365/// paddle end B
366#[cfg(feature="pybindings")]
367#[pyfunction]
368#[pyo3(name="get_rbid_pbchannel_pid_map")]
369pub fn get_rbid_pbchannel_pid_map_py() -> Option<(RbChPidMapping, RbChPidMapping)> {
370 if let Some(paddles) = TofPaddle::all() {
371 return Some(get_rbid_pbchannel_pid_map(&paddles).unwrap());
372 } else {
373 return None;
374 }
375}
376
377//---------------------------------------------------------------------
378
379/// Create a mapping of DSI/J(LTB) -> PaddleID
380///
381/// This will basically tell you for a given LTB hit which paddle has
382/// triggered.
383#[cfg(feature="pybindings")]
384#[pyfunction]
385#[pyo3(name="get_dsi_j_ch_pid_map")]
386pub fn get_dsi_j_ch_pid_map_py() -> Option<DsiJChPidMapping> {
387 if let Some(paddles) = TofPaddle::all() {
388 return Some(get_dsi_j_ch_pid_map(&paddles));
389 } else {
390 return None;
391 }
392}
393
394//---------------------------------------------------------------------
395
396/// Map the detector ids ("hardware" ids) to volume ids as used in the
397/// simulation
398///
399/// Get the map first and then query it
400///
401/// ```python
402/// m = gondola.db.get_hid_vid_maps()
403/// print (m[0][160]) # volume id for paddle 160
404/// ```
405///
406/// # Returns:
407/// * tuple (dict,dict) : Two maps, the first for the tof, the second
408/// for the tracker
409#[cfg_attr(feature="pybindings", pyfunction)]
410pub fn get_hid_vid_maps() -> Option<(HashMap<u32, u64>, HashMap<u32, u64>)> {
411 // FIXME - error catching
412 let pdls = TofPaddle::all_as_dict().unwrap();
413 let strips = TrackerStrip::all_as_dict().unwrap();
414 let mut hid_vid_map_tof = HashMap::<u32, u64>::new();
415 let mut hid_vid_map_trk = HashMap::<u32, u64>::new();
416 for k in pdls.keys() {
417 hid_vid_map_tof.insert(*k as u32, pdls[k].volume_id as u64);
418 }
419 for k in strips.keys() {
420 hid_vid_map_trk.insert(*k as u32,strips[k].volume_id as u64);
421 }
422 Some((hid_vid_map_tof, hid_vid_map_trk))
423}
424
425//---------------------------------------------------------------------
426
427/// Map the volume id as it is used in the simulation to the actual
428/// ("hardware") detector ids
429///
430/// Get the map first and then query it
431/// ```python
432/// m = gondola.db.get_vid_hid_maps()
433/// print (m[0][100000000]) # tof paddle 1
434/// ```
435///
436/// # Returns:
437/// * tuple (dict,dict) : Two maps, the first for the tof, the second
438/// for the tracker
439#[cfg_attr(feature="pybindings", pyfunction)]
440pub fn get_vid_hid_maps() -> Option<(HashMap<u64, u32>, HashMap<u64,u32>)> {
441 // FIXME - error catching
442 let pdls = TofPaddle::all_as_dict().unwrap();
443 let strips = TrackerStrip::all_as_dict().unwrap();
444 let mut vid_hid_map_tof = HashMap::<u64, u32>::new();
445 let mut vid_hid_map_trk = HashMap::<u64, u32>::new();
446 for k in pdls.keys() {
447 vid_hid_map_tof.insert(pdls[k].volume_id as u64, *k as u32);
448 }
449 for k in strips.keys() {
450 vid_hid_map_trk.insert(strips[k].volume_id as u64, *k);
451 }
452 Some((vid_hid_map_tof, vid_hid_map_trk))
453}
454
455//---------------------------------------------------------------------
456
457/// Create a mapping of mtb link ids to rb ids
458//#[cfg_attr(feature="pybindings", pyfunction)]
459pub fn get_linkid_rbid_map(rbs : &Vec<ReadoutBoard>) -> HashMap<u8, u8>{
460 let mut mapping = HashMap::<u8, u8>::new();
461 for rb in rbs {
462 mapping.insert(rb.mtb_link_id, rb.rb_id);
463 }
464 mapping
465}
466
467//---------------------------------------------------------------------
468
469/// Create a map for rbid, ch -> paddle id. This is only for the A
470/// side and will not have an entry in case the given RB channel
471/// is connected to the B side of the paddle
472pub fn get_rb_ch_pid_a_map() -> Option<RbChPidMapping> {
473 let paddles = TofPaddle::all()?;
474 let mut mapping = RbChPidMapping::new();
475 for rbid in 1..51 {
476 let mut chmap = HashMap::<u8, u8>::new();
477 for ch in 1..9 {
478 chmap.insert(ch,0);
479 }
480 mapping.insert(rbid,chmap);
481 }
482 for pdl in paddles {
483 let rb_id = pdl.rb_id as u8;
484 let ch_a = pdl.rb_chA as u8;
485 let pid = pdl.paddle_id as u8;
486 *mapping.get_mut(&rb_id).unwrap().get_mut(&ch_a).unwrap() = pid;
487 }
488 Some(mapping)
489}
490
491//---------------------------------------------------------------------
492
493/// Create a map for rbid, ch -> paddle id. This is only for the B
494/// side and will not have an entry in case the given RB channel
495/// is connected to the A side of the paddle
496pub fn get_rb_ch_pid_b_map() -> Option<RbChPidMapping> {
497 let mut mapping = RbChPidMapping::new();
498 let paddles = TofPaddle::all()?;
499 for rbid in 1..51 {
500 let mut chmap = HashMap::<u8, u8>::new();
501 for ch in 1..9 {
502 chmap.insert(ch,0);
503 }
504 mapping.insert(rbid,chmap);
505 }
506
507 for pdl in paddles {
508 let rb_id = pdl.rb_id as u8;
509 let ch_b = pdl.rb_chB as u8;
510 let pid = pdl.paddle_id as u8;
511 *mapping.get_mut(&rb_id).unwrap().get_mut(&ch_b).unwrap() = pid;
512 }
513 Some(mapping)
514}
515
516//---------------------------------------------------------------------
517
518/// Create a map for rbid, ch -> paddle id.
519///
520/// This version is oblivious to the paddle ends
521pub fn get_rb_ch_pid() -> Option<RbChPidMapping> {
522 let paddles = TofPaddle::all()?;
523 let mut mapping = RbChPidMapping::new();
524 for rbid in 1..51 {
525 let mut chmap = HashMap::<u8, u8>::new();
526 for ch in 1..9 {
527 chmap.insert(ch,0);
528 }
529 mapping.insert(rbid,chmap);
530 }
531 for pdl in paddles {
532 let rb_id = pdl.rb_id as u8;
533 let ch_a = pdl.rb_chA as u8;
534 let ch_b = pdl.rb_chB as u8;
535 let pid = pdl.paddle_id as u8;
536 *mapping.get_mut(&rb_id).unwrap().get_mut(&ch_a).unwrap() = pid;
537 *mapping.get_mut(&rb_id).unwrap().get_mut(&ch_b).unwrap() = pid;
538 }
539 Some(mapping)
540}
541
542//---------------------------------------------------------------------
543
544/// Get all rb ids from paddles which are stored in the
545/// database
546#[cfg_attr(feature="pybindings", pyfunction)]
547pub fn get_all_rbids_in_db() -> Option<Vec<u8>> {
548 match TofPaddle::all() {
549 None => {
550 error!("Can not load paddles from DB! Did you load the setup-env.sh shell?");
551 return None;
552 }
553 Some(paddles) => {
554 let mut rbids : Vec<u8> = paddles.iter().map(|p| p.rb_id as u8).collect();
555 rbids.sort();
556 rbids.dedup();
557 return Some(rbids);
558 }
559 }
560}
561
562//---------------------------------------------------------------------
563
564#[cfg_attr(feature="pybindings", pyfunction)]
565pub fn get_all_pbids_in_db() -> Option<Vec<u8>> {
566 match TofPaddle::all() {
567 None => {
568 error!("Can not load paddles from DB! Did you load the setup-env.sh shell?");
569 return None;
570 }
571 Some(paddles) => {
572 let mut rbids : Vec<u8> = paddles.iter().map(|p| p.pb_id as u8).collect();
573 rbids.sort();
574 rbids.dedup();
575 return Some(rbids);
576 }
577 }
578}
579
580//---------------------------------------------------------------------
581
582/// A single TOF paddle with 2 ends comnected
583#[derive(Debug,PartialEq, Clone, Queryable, Selectable, Insertable, serde::Serialize, serde::Deserialize)]
584#[diesel(table_name = schema::tof_db_paddle)]
585#[diesel(primary_key(paddle_id))]
586#[allow(non_snake_case)]
587#[cfg_attr(feature="pybindings", pyclass)]
588pub struct TofPaddle {
589 pub paddle_id : i16,
590 pub volume_id : i64,
591 pub panel_id : i16,
592 pub mtb_link_id : i16,
593 pub rb_id : i16,
594 pub rb_chA : i16,
595 pub rb_chB : i16,
596 pub ltb_id : i16,
597 pub ltb_chA : i16,
598 pub ltb_chB : i16,
599 pub pb_id : i16,
600 pub pb_chA : i16,
601 pub pb_chB : i16,
602 pub cable_len : f32,
603 pub dsi : i16,
604 pub j_rb : i16,
605 pub j_ltb : i16,
606 pub height : f32,
607 pub width : f32,
608 pub length : f32,
609 pub normal_x : f32,
610 pub normal_y : f32,
611 pub normal_z : f32,
612 pub global_pos_x_l0 : f32,
613 pub global_pos_y_l0 : f32,
614 pub global_pos_z_l0 : f32,
615 pub global_pos_x_l0_A : f32,
616 pub global_pos_y_l0_A : f32,
617 pub global_pos_z_l0_A : f32,
618 pub global_pos_x_l0_B : f32,
619 pub global_pos_y_l0_B : f32,
620 pub global_pos_z_l0_B : f32,
621 pub coax_cable_time : f32,
622 pub harting_cable_time: f32,
623}
624
625impl TofPaddle {
626 pub fn new() -> Self {
627 Self {
628 paddle_id : 0,
629 volume_id : 0,
630 panel_id : 0,
631 mtb_link_id : 0,
632 rb_id : 0,
633 rb_chA : 0,
634 rb_chB : 0,
635 ltb_id : 0,
636 ltb_chA : 0,
637 ltb_chB : 0,
638 pb_id : 0,
639 pb_chA : 0,
640 pb_chB : 0,
641 cable_len : 0.0,
642 dsi : 0,
643 j_rb : 0,
644 j_ltb : 0,
645 height : 0.0,
646 width : 0.0,
647 length : 0.0,
648 normal_x : 0.0,
649 normal_y : 0.0,
650 normal_z : 0.0,
651 global_pos_x_l0 : 0.0,
652 global_pos_y_l0 : 0.0,
653 global_pos_z_l0 : 0.0,
654 global_pos_x_l0_A : 0.0,
655 global_pos_y_l0_A : 0.0,
656 global_pos_z_l0_A : 0.0,
657 global_pos_x_l0_B : 0.0,
658 global_pos_y_l0_B : 0.0,
659 global_pos_z_l0_B : 0.0,
660 coax_cable_time : 0.0,
661 harting_cable_time: 0.0
662 }
663 }
664
665 /// Save myself to the database
666 pub fn save(&self) {
667 use schema::tof_db_paddle::dsl::*;
668 //let conn = connect_to_db().unwrap();
669 let _ = diesel::insert_into(tof_db_paddle)
670 .values(self);
671 }
672
673 /// Return the lowest channel number (either A or B)
674 /// to be able to sort the paddles into RBs
675 pub fn get_lowest_rb_ch(&self) -> u8 {
676 if self.rb_chA < self.rb_chB {
677 return self.rb_chA as u8;
678 }
679 else {
680 return self.rb_chB as u8;
681 }
682 }
683
684 /// Get all TofPaddles which are connected to a certain
685 /// Readoutboard
686 ///
687 /// # Arguments:
688 /// * rbid : The RB id identifier (1-50)
689 pub fn by_rbid(rbid : u8) -> Option<Vec<TofPaddle>> {
690 if rbid > 50 {
691 error!("We don't have any RBs with an ID > 50!");
692 return None
693 }
694 use schema::tof_db_paddle::dsl::*;
695 let mut conn = connect_to_db().ok()?;
696 let rbid_tmp = rbid as i16;
697
698 let paddles = tof_db_paddle.filter(rb_id.eq(rbid_tmp))
699 .load::<TofPaddle>(&mut conn);
700
701 match paddles {
702 Err(err) => {
703 error!("Unable to load paddles from db! {err}");
704 return None;
705 }
706 Ok(pdls) => {
707 return Some(pdls);
708 }
709 }
710 }
711
712 /// Retrieve all 160 paddles from the database
713 pub fn all() -> Option<Vec<TofPaddle>> {
714 use schema::tof_db_paddle::dsl::*;
715 let mut conn = connect_to_db().ok()?;
716 match tof_db_paddle.load::<TofPaddle>(&mut conn) {
717 Err(err) => {
718 error!("Unable to load paddles from db! {err}");
719 return None;
720 }
721 Ok(pdls) => {
722 return Some(pdls);
723 }
724 }
725 }
726
727 /// Retrive all paddles from the database, but return a
728 /// HashMap <paddle_id, TofPaddle>
729 pub fn all_as_dict() -> Result<HashMap<u8,Self>, ConnectionError> {
730 let mut paddles = HashMap::<u8, Self>::new();
731 match Self::all() {
732 None => {
733 error!("We can't find any paddles in the database!");
734 return Ok(paddles);
735 }
736 Some(pdls) => {
737 for p in pdls {
738 paddles.insert(p.paddle_id as u8, p.clone());
739 }
740 }
741 }
742 return Ok(paddles);
743 }
744
745 /// The principal is the direction along the longest
746 /// dimension from A -> B
747 pub fn principal(&self) -> (f32,f32,f32) {
748 let mut pr = (self.global_pos_x_l0_B - self.global_pos_x_l0_A,
749 self.global_pos_y_l0_B - self.global_pos_y_l0_A,
750 self.global_pos_z_l0_B - self.global_pos_z_l0_A);
751 let length = f32::sqrt(pr.0.powf(2.0) + pr.1.powf(2.0) + pr.2.powf(2.0));
752 pr = (pr.0/length, pr.1/length, pr.2/length);
753 return pr;
754 }
755
756 /// Normal vector of the paddle
757 pub fn normal(&self) -> (f32, f32, f32) {
758 (self.normal_x, self.normal_y, self.normal_z)
759 }
760
761 pub fn center_pos(&self) -> (f32,f32,f32) {
762 (self.global_pos_x_l0, self.global_pos_y_l0, self.global_pos_z_l0)
763 }
764
765 #[allow(non_snake_case)]
766 pub fn sideA_pos(&self) -> (f32,f32,f32) {
767 (self.global_pos_x_l0_A, self.global_pos_y_l0_A, self.global_pos_z_l0_A)
768 }
769
770 #[allow(non_snake_case)]
771 pub fn sideB_pos(&self) -> (f32,f32,f32) {
772 (self.global_pos_x_l0_B, self.global_pos_y_l0_B, self.global_pos_z_l0_B)
773 }
774
775 ///Convert DSI and J connection to the actual
776 ///slot they are plugged in on the MTB (0-24)
777 pub fn rb_slot(&self) -> i16 {
778 (self.dsi-1)*5 + self.j_rb - 1
779 }
780
781 /// Convert DSI and J connection to the actual
782 /// slot they are plugged in on the MTB (0-24)
783 pub fn lt_slot(&self) -> i16 {
784 (self.dsi-1)*5 + self.j_ltb - 1
785 }
786}
787
788#[cfg(feature="pybindings")]
789#[pymethods]
790impl TofPaddle {
791
792 /// Get the (numerically) lower of the two
793 /// RB channels the TOF paddle is connected with
794 /// to its associate ReadoutBoard
795 #[getter]
796 fn get_lowest_rb_ch_py(&self) -> u8 {
797 self.get_lowest_rb_ch()
798 }
799
800 /// The paddle id of the paddle in range [1,160]
801 #[getter]
802 fn get_paddle_id (&self) -> i16 {
803 self.paddle_id
804 }
805
806 /// Retrieve the volume id. The volume id is
807 /// assigned by the simulation
808 #[getter]
809 fn get_volume_id (&self) -> i64 {
810 self.volume_id
811 }
812
813 /// Retrieve the panel id.
814 ///
815 /// Panel 1-6 : Cube
816 /// Panel 7-14 : Umbrella
817 /// Panel > 14 : Cortina
818 #[getter]
819 fn get_panel_id (&self) -> i16 {
820 self.panel_id
821 }
822
823 /// The MTB link id is an internal number
824 /// used by the MTB to identify ReadoutBoards
825 #[getter]
826 fn get_mtb_link_id (&self) -> i16 {
827 self.mtb_link_id
828 }
829
830 /// Retrieve the Readoutboard id for the
831 /// Readoutboard the paddle is connected to
832 #[getter]
833 fn get_rb_id (&self) -> i16 {
834 self.rb_id
835 }
836
837 /// Get the ReadoutBoard channel to which
838 /// the A-side of the Paddle is connected
839 #[getter]
840 #[allow(non_snake_case)]
841 fn get_rb_chA (&self) -> i16 {
842 self.rb_chA
843 }
844
845 /// Get the ReadoutBoard channel to which
846 /// the b-side of the Paddle is connected
847 #[getter]
848 #[allow(non_snake_case)]
849 fn get_rb_chB (&self) -> i16 {
850 self.rb_chB
851 }
852
853 /// Get the LTB id the low-gain channels
854 /// of this paddle are connected to
855 #[getter]
856 fn get_ltb_id (&self) -> i16 {
857 self.ltb_id
858 }
859
860 /// Get the LTB channel the A-side of this
861 /// paddle is connected to
862 #[getter]
863 #[allow(non_snake_case)]
864 fn get_ltb_chA (&self) -> i16 {
865 self.ltb_chA
866 }
867
868 /// Get the LTB channel the B-side of this
869 /// paddle is connected to
870 #[getter]
871 #[allow(non_snake_case)]
872 fn get_ltb_chB (&self) -> i16 {
873 self.ltb_chB
874 }
875
876 /// Get the powerboard id for the respective
877 /// powerboard which provides the driving
878 /// voltage for this paddle
879 #[getter]
880 fn get_pb_id (&self) -> i16 {
881 self.pb_id
882 }
883
884 /// Get the channel on the powerboard
885 /// the paddle A-side is connected to
886 #[getter]
887 #[allow(non_snake_case)]
888 fn get_pb_chA (&self) -> i16 {
889 self.pb_chA
890 }
891
892 /// Get the channel on the powerboard
893 /// the paddle b-side is connected to
894 #[getter]
895 #[allow(non_snake_case)]
896 fn get_pb_chB (&self) -> i16 {
897 self.pb_chB
898 }
899
900 /// DEPRECATED - the length of the Harting
901 /// cable connected to this paddle
902 #[getter]
903 fn get_cable_len (&self) -> f32 {
904 self.cable_len
905 }
906
907 /// Retrive the DSI connector this paddle
908 /// is connected through the RB/LTB to
909 /// the MTB
910 #[getter]
911 fn get_dsi (&self) -> i16 {
912 self.dsi
913 }
914
915 /// Retrieve the j address of the DSI connector
916 /// this paddle is connected through the RB
917 /// to the MTB
918 #[getter]
919 fn get_j_rb (&self) -> i16 {
920 self.j_rb
921 }
922
923 /// Retrieve the j address of the DSI connector
924 /// this paddle is connected through the LTB
925 /// to the MTB
926 #[getter]
927 fn get_j_ltb (&self) -> i16 {
928 self.j_ltb
929 }
930
931 /// Get the (local) height of the paddle
932 #[getter]
933 fn get_height (&self) -> f32 {
934 self.height
935 }
936
937 /// Get the (local) width of the paddle
938 #[getter]
939 fn get_width (&self) -> f32 {
940 self.width
941 }
942
943 /// Get the (local) length of the paddle
944 #[getter]
945 fn get_length (&self) -> f32 {
946 self.length
947 }
948
949 /// Retrieve all 160 paddles from the database
950 #[staticmethod]
951 #[pyo3(name="all")]
952 pub fn all_py() -> Option<Vec<Self>> {
953 TofPaddle::all()
954 }
955
956 /// Retrieve all paddles connected to a certain
957 /// ReadoutBoard from the database
958 ///
959 /// # Arguments
960 /// * rbid : RB id of the desired ReadoutBoard (typically < 50)
961 #[staticmethod]
962 #[pyo3(name="by_rbid")]
963 pub fn by_rbid_py(rbid : u8) -> Option<Vec<Self>> {
964 TofPaddle::by_rbid(rbid)
965 }
966
967 /// Retrieve all paddles from the database and return
968 /// a dictionary as dict([rbid, TofPaddle])
969 // FIXME use PyResult
970 #[staticmethod]
971 #[pyo3(name="all_as_dict")]
972 pub fn all_as_dict_py() -> Option<HashMap<u8,Self>> {
973 match TofPaddle::all_as_dict() {
974 Err(err) => {
975 error!("Unable to retrieve paddle dictionary. {err}. Did you laod the setup-env.sh shell?");
976 return None;
977 }
978 Ok(_paddles) => {
979 return Some(_paddles);
980 }
981 }
982 }
983
984 /// The principal is the direction along the longest
985 /// dimension from A -> B
986 #[getter]
987 #[pyo3(name="principal")]
988 pub fn principal_py(&self) -> (f32,f32,f32) {
989 let mut pr = (self.global_pos_x_l0_B - self.global_pos_x_l0_A,
990 self.global_pos_y_l0_B - self.global_pos_y_l0_A,
991 self.global_pos_z_l0_B - self.global_pos_z_l0_A);
992 let length = f32::sqrt(pr.0.powf(2.0) + pr.1.powf(2.0) + pr.2.powf(2.0));
993 pr = (pr.0/length, pr.1/length, pr.2/length);
994 return pr;
995 }
996
997 /// Return normal axis - that is orthogonal to the principal ans
998 /// paralel to the axis of "width"
999 #[getter]
1000 #[pyo3(name="normal")]
1001 pub fn normal_py(&self) -> (f32, f32, f32) {
1002 self.normal()
1003 }
1004
1005 /// The center position of the paddle (middle of all 3 local dimensions)
1006 #[getter]
1007 #[pyo3(name="center_pos")]
1008 pub fn center_pos_py(&self) -> (f32,f32,f32) {
1009 (self.global_pos_x_l0, self.global_pos_y_l0, self.global_pos_z_l0)
1010 }
1011
1012 /// The position of the SiPm at the A-side
1013 #[getter]
1014 #[pyo3(name="sideA_pos")]
1015 #[allow(non_snake_case)]
1016 pub fn sideA_pos_py(&self) -> (f32,f32,f32) {
1017 (self.global_pos_x_l0_A, self.global_pos_y_l0_A, self.global_pos_z_l0_A)
1018 }
1019
1020 /// The position of the SiPm at the B-side
1021 #[getter]
1022 #[pyo3(name="sideB_pos")]
1023 #[allow(non_snake_case)]
1024 pub fn sideB_pos_py(&self) -> (f32,f32,f32) {
1025 (self.global_pos_x_l0_B, self.global_pos_y_l0_B, self.global_pos_z_l0_B)
1026 }
1027
1028 ///Convert DSI and J connection to the actual
1029 ///slot they are plugged in on the MTB (0-24)
1030 #[getter]
1031 #[pyo3(name="rb_slot")]
1032 pub fn rb_slot_py(&self) -> i16 {
1033 self.rb_slot()
1034 }
1035
1036 /// Convert DSI and J connection to the actual
1037 /// slot they are plugged in on the MTB (0-24)
1038 #[getter]
1039 #[pyo3(name="lt_slot")]
1040 pub fn lt_slot_py(&self) -> i16 {
1041 self.lt_slot()
1042 }
1043
1044 /// The x-coordinate of the center position of the paddle
1045 #[getter]
1046 #[pyo3(name="global_pos_x_l0")]
1047 fn get_global_pos_x_l0(&self) -> f32 {
1048 self.global_pos_x_l0
1049 }
1050
1051 /// The y-coordinate of the center position of the paddle
1052 #[getter]
1053 #[pyo3(name="global_pos_y_l0")]
1054 fn get_global_pos_y_l0(&self) -> f32 {
1055 self.global_pos_y_l0
1056 }
1057
1058 /// The z-coordinate of the center position of the paddle
1059 #[getter]
1060 #[pyo3(name="global_pos_z_l0")]
1061 fn get_global_pos_z_l0(&self) -> f32 {
1062 self.global_pos_z_l0
1063 }
1064}
1065
1066
1067#[cfg_attr(feature="pybindings", pymethods)]
1068impl TofPaddle {
1069}
1070
1071//---------------------------------------------------------------------
1072
1073impl fmt::Display for TofPaddle {
1074 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1075 let mut repr = String::from("<TofPaddle:");
1076 repr += "\n** identifiers **";
1077 repr += &(format!("\n pid : {}", self.paddle_id));
1078 repr += &(format!("\n vid : {}", self.volume_id));
1079 repr += &(format!("\n panel id : {}", self.panel_id));
1080 repr += "\n ** connedtions **";
1081 repr += &(format!("\n DSI/J/CH (LG) [A] : {} | {} | {:02}", self.dsi, self.j_ltb, self.ltb_chA));
1082 repr += &(format!("\n DSI/J/CH (HG) [A] : {} | {} | {:02}", self.dsi, self.j_rb, self.rb_chA));
1083 repr += &(format!("\n DSI/J/CH (LG) [B] : {} | {} | {:02}", self.dsi, self.j_ltb, self.ltb_chB));
1084 repr += &(format!("\n DSI/J/CH (HG) [B] : {} | {} | {:02}", self.dsi, self.j_rb, self.rb_chB));
1085 repr += &(format!("\n RB/CH [A] : {:02} | {}", self.rb_id, self.rb_chA));
1086 repr += &(format!("\n RB/CH [B] : {:02} | {}", self.rb_id, self.rb_chB));
1087 repr += &(format!("\n LTB/CH [A] : {:02} | {}", self.ltb_id, self.ltb_chA));
1088 repr += &(format!("\n LTB/CH [B] : {:02} | {}", self.ltb_id, self.ltb_chB));
1089 repr += &(format!("\n PB/CH [A] : {:02} | {}", self.pb_id, self.pb_chA));
1090 repr += &(format!("\n PB/CH [B] : {:02} | {}", self.pb_id, self.pb_chB));
1091 repr += &(format!("\n MTB Link ID : {:02}", self.mtb_link_id));
1092 repr += "\n cable len [cm] :";
1093 repr += &(format!("\n \u{21B3} {:.2}", self.cable_len));
1094 repr += "\n (Harting -> RB)";
1095 repr += "\n cable times [ns] (JAZ) :";
1096 repr += &(format!("\n \u{21B3} {:.2} {:.2}", self.coax_cable_time, self.harting_cable_time));
1097 repr += "\n ** Coordinates (L0) & dimensions **";
1098 repr += "\n length, width, height [mm]";
1099 repr += &(format!("\n \u{21B3} [{:.2}, {:.2}, {:.2}]", self.length, self.width, self.height));
1100 repr += "\n center [mm]:";
1101 repr += &(format!("\n \u{21B3} [{:.2}, {:.2}, {:.2}]", self.global_pos_x_l0, self.global_pos_y_l0, self.global_pos_z_l0));
1102 repr += "\n normal vector:";
1103 repr += &(format!("\n \u{21B3} [{:.2}, {:.2}, {:.2}]", self.normal_x, self.normal_y, self.normal_z));
1104 repr += "\n A-side [mm]:";
1105 repr += &(format!("\n \u{21B3} [{:.2}, {:.2}, {:.2}]>", self.global_pos_x_l0_A, self.global_pos_y_l0_A, self.global_pos_z_l0_A));
1106 repr += "\n B-side [mm]:";
1107 repr += &(format!("\n \u{21B3} [{:.2}, {:.2}, {:.2}]>", self.global_pos_x_l0_B, self.global_pos_y_l0_B, self.global_pos_z_l0_B));
1108 write!(f, "{}", repr)
1109 }
1110}
1111
1112//---------------------------------------------------------------------
1113
1114#[cfg(feature="pybindings")]
1115pythonize!(TofPaddle);
1116
1117//---------------------------------------------------------------------
1118
1119/// A Readoutboard with paddles connected
1120#[derive(Debug, Clone)]
1121#[allow(non_snake_case)]
1122#[cfg_attr(feature="pybindings", pyclass)]
1123pub struct ReadoutBoard {
1124 pub rb_id : u8,
1125 pub dsi : u8,
1126 pub j : u8,
1127 pub mtb_link_id : u8,
1128 pub paddle12 : TofPaddle,
1129 //pub paddle12_chA : u8,
1130 pub paddle34 : TofPaddle,
1131 //pub paddle34_chA : u8,
1132 pub paddle56 : TofPaddle,
1133 //pub paddle56_chA : u8,
1134 pub paddle78 : TofPaddle,
1135 //pub paddle78_chA : u8,
1136 // extra stuff, not from the db
1137 // or maybe in the future?
1138 pub calib_file_path : String,
1139 pub calibration : RBCalibrations,
1140}
1141
1142impl ReadoutBoard {
1143
1144 pub fn new() -> Self {
1145 Self {
1146 rb_id : 0,
1147 dsi : 0,
1148 j : 0,
1149 mtb_link_id : 0,
1150 paddle12 : TofPaddle::new(),
1151 //paddle12_chA : 0,
1152 paddle34 : TofPaddle::new(),
1153 //paddle34_chA : 0,
1154 paddle56 : TofPaddle::new(),
1155 //paddle56_chA : 0,
1156 paddle78 : TofPaddle::new(),
1157 //paddle78_chA : 0,
1158 calib_file_path : String::from(""),
1159 calibration : RBCalibrations::new(0),
1160 }
1161 }
1162
1163 #[allow(non_snake_case)]
1164 pub fn get_paddle12_chA(&self) -> u8 {
1165 self.paddle12.rb_chA as u8
1166 }
1167
1168 #[allow(non_snake_case)]
1169 pub fn get_paddle34_chA(&self) -> u8 {
1170 self.paddle34.rb_chA as u8
1171 }
1172
1173 #[allow(non_snake_case)]
1174 pub fn get_paddle56_chA(&self) -> u8 {
1175 self.paddle56.rb_chA as u8
1176 }
1177
1178 #[allow(non_snake_case)]
1179 pub fn get_paddle78_chA(&self) -> u8 {
1180 self.paddle78.rb_chA as u8
1181 }
1182
1183 pub fn by_rbid(rbid : u8) -> Option<Self> {
1184 let paddles = TofPaddle::by_rbid(rbid);
1185 if paddles.is_none() {
1186 return None;
1187 }
1188 let mut rb_paddles = paddles.unwrap();
1189 if rb_paddles.len() != 4 {
1190 panic!("Found more than 4 paddles for this RB! DB inconsistency! Abort!");
1191 }
1192 rb_paddles.sort_by_key(|paddle| paddle.get_lowest_rb_ch());
1193 // we ensured earlier that the vector is of len 4
1194 let paddle78 = rb_paddles.pop().unwrap();
1195 let paddle56 = rb_paddles.pop().unwrap();
1196 let paddle34 = rb_paddles.pop().unwrap();
1197 let paddle12 = rb_paddles.pop().unwrap();
1198
1199 Some(ReadoutBoard {
1200 rb_id : rbid,
1201 dsi : paddle12.dsi as u8,
1202 j : paddle12.j_rb as u8,
1203 mtb_link_id : paddle12.mtb_link_id as u8,
1204 paddle12 : paddle12,
1205 //paddle12_chA : paddle12,
1206 paddle34 : paddle34,
1207 //paddle34_chA : 0,
1208 paddle56 : paddle56,
1209 //paddle56_chA : 0,
1210 paddle78 : paddle78,
1211 //paddle78_chA : 0,
1212 calib_file_path : String::from(""),
1213 calibration : RBCalibrations::new(0),
1214 })
1215 }
1216
1217 /// Returns the ip address following a convention
1218 ///
1219 /// This does NOT GUARANTEE that the address is correct!
1220 pub fn guess_address(&self) -> String {
1221 format!("tcp://10.0.1.1{:02}:42000", self.rb_id)
1222 }
1223
1224 pub fn get_paddle_ids(&self) -> [u8;4] {
1225 let pid0 = self.paddle12.paddle_id as u8;
1226 let pid1 = self.paddle34.paddle_id as u8;
1227 let pid2 = self.paddle56.paddle_id as u8;
1228 let pid3 = self.paddle78.paddle_id as u8;
1229 [pid0, pid1, pid2, pid3]
1230 }
1231
1232 #[allow(non_snake_case)]
1233 pub fn get_A_sides(&self) -> [u8;4] {
1234 let pa_0 = self.get_paddle12_chA();
1235 let pa_1 = self.get_paddle34_chA();
1236 let pa_2 = self.get_paddle56_chA();
1237 let pa_3 = self.get_paddle78_chA();
1238 [pa_0, pa_1, pa_2, pa_3]
1239 }
1240
1241 #[allow(non_snake_case)]
1242 pub fn get_pid_rbchA(&self, pid : u8) -> Option<u8> {
1243 if self.paddle12.paddle_id as u8 == pid {
1244 let rv = self.paddle12.rb_chA as u8;
1245 return Some(rv);
1246 } else if self.paddle34.paddle_id as u8 == pid {
1247 let rv = self.paddle34.rb_chA as u8;
1248 return Some(rv);
1249 } else if self.paddle56.paddle_id as u8 == pid {
1250 let rv = self.paddle56.rb_chA as u8;
1251 return Some(rv);
1252 } else if self.paddle78.paddle_id as u8== pid {
1253 let rv = self.paddle78.rb_chA as u8;
1254 return Some(rv);
1255 } else {
1256 return None;
1257 }
1258 }
1259
1260 #[allow(non_snake_case)]
1261 pub fn get_pid_rbchB(&self, pid : u8) -> Option<u8> {
1262 if self.paddle12.paddle_id as u8 == pid {
1263 let rv = self.paddle12.rb_chB as u8;
1264 return Some(rv);
1265 } else if self.paddle34.paddle_id as u8== pid {
1266 let rv = self.paddle34.rb_chB as u8;
1267 return Some(rv);
1268 } else if self.paddle56.paddle_id as u8== pid {
1269 let rv = self.paddle56.rb_chB as u8;
1270 return Some(rv);
1271 } else if self.paddle78.paddle_id as u8 == pid {
1272 let rv = self.paddle78.rb_chB as u8;
1273 return Some(rv);
1274 } else {
1275 return None;
1276 }
1277 }
1278
1279 pub fn get_paddle_length(&self, pid : u8) -> Option<f32> {
1280 if self.paddle12.paddle_id as u8 == pid {
1281 let rv = self.paddle12.length;
1282 return Some(rv);
1283 } else if self.paddle34.paddle_id as u8== pid {
1284 let rv = self.paddle34.length;
1285 return Some(rv);
1286 } else if self.paddle56.paddle_id as u8== pid {
1287 let rv = self.paddle56.length;
1288 return Some(rv);
1289 } else if self.paddle78.paddle_id as u8 == pid {
1290 let rv = self.paddle78.length;
1291 return Some(rv);
1292 } else {
1293 return None;
1294 }
1295 }
1296
1297 pub fn all() -> Option<Vec<Self>> {
1298 let all_rbs = get_all_rbids_in_db();
1299 match all_rbs {
1300 None => {
1301 error!("Can not get TofPaddle information from DB, and thus can't construct ReadoutBoard instances. Did you load the setup-env.sh shell?");
1302 return None;
1303 }
1304 Some(all_rbids) => {
1305 let mut rbs = Vec::<Self>::new();
1306 for k in all_rbids {
1307 rbs.push(ReadoutBoard::by_rbid(k)?);
1308 }
1309 return Some(rbs);
1310 }
1311 }
1312 }
1313
1314 /// Get all Readoutboards from the database
1315 ///
1316 /// # Returns:
1317 /// * dict [rbid->Readoutboard]
1318 pub fn all_as_dict() -> Result<HashMap<u8,Self>, ConnectionError> {
1319 let mut rbs = HashMap::<u8, Self>::new();
1320 match Self::all() {
1321 None => {
1322 error!("We can't find any readoutboards in the database!");
1323 return Ok(rbs);
1324 }
1325 Some(rbs_) => {
1326 for rb in rbs_ {
1327 rbs.insert(rb.rb_id, rb );
1328 }
1329 }
1330 }
1331 return Ok(rbs);
1332 }
1333
1334 pub fn to_summary_str(&self) -> String {
1335 let mut repr = String::from("<ReadoutBoard:");
1336 repr += &(format!("\n Board id : {}",self.rb_id));
1337 repr += &(format!("\n MTB Link ID : {}",self.mtb_link_id));
1338 repr += &(format!("\n RAT : {}",self.paddle12.ltb_id));
1339 repr += &(format!("\n DSI/J : {}/{}",self.dsi,self.j));
1340 repr += "\n **Connected paddles**";
1341 repr += &(format!("\n Channel 1/2 : {:02} (panel {:01})", self.paddle12.paddle_id, self.paddle12.panel_id));
1342 repr += &(format!("\n Channel 3/4 : {:02} (panel {:01})", self.paddle34.paddle_id, self.paddle34.panel_id));
1343 repr += &(format!("\n Channel 5/6 : {:02} (panel {:01})", self.paddle56.paddle_id, self.paddle56.panel_id));
1344 repr += &(format!("\n Channel 7/8 : {:02} (panel {:01})", self.paddle78.paddle_id, self.paddle78.panel_id));
1345 repr
1346 }
1347
1348 /// Load the newest calibration from the calibration file path
1349 pub fn load_latest_calibration(&mut self) -> Result<(), Box<dyn std::error::Error>> {
1350 // files look like RB20_2024_01_26-08_15_54.cali.tof.gaps
1351 //let re = Regex::new(r"(\d{4}_\d{2}_\d{2}-\d{2}_\d{2}_\d{2})")?;
1352 let re = Regex::new(r"(\d{6}_\d{6})")?;
1353 // Define your file pattern (e.g., "logs/*.log" for all .log files in the logs directory)
1354 let pattern = format!("{}/RB{:02}_*", self.calib_file_path, self.rb_id); // Adjust this pattern to your files' naming convention
1355 let timestamp = DateTime::<Utc>::from_timestamp(0,0).unwrap(); // I am not sure what to do here
1356 // otherwise than unwrap. How is
1357 // this allowed to fail?
1358 //let mut newest_file = (String::from(""), NaiveDateTime::from_timestamp(0, 0));
1359 let mut newest_file = (String::from(""), timestamp);
1360
1361 // Iterate over files that match the pattern
1362 let mut filename : String;
1363 for entry in glob(&pattern)? {
1364 if let Ok(path) = entry {
1365 // Get the filename as a string
1366 //let cpath = path.clone();
1367 match path.file_name() {
1368 None => continue,
1369 Some(fname) => {
1370 // the expect might be ok, since this is something done during initialization
1371 filename = fname.to_os_string().into_string().expect("Unwrapping filename failed!");
1372 }
1373 }
1374 if let Some(caps) = re.captures(&filename) {
1375 if let Some(timestamp_str) = caps.get(0).map(|m| m.as_str()) {
1376 //println!("timestamp_str {}, {}",timestamp_str, HUMAN_TIMESTAMP_FORMAT);
1377 //let timestamp = NaiveDateTime::parse_from_str(timestamp_str, "%Y_%m_%d-%H_%M_%S")?;
1378 //let timestamp = DateTime::<Utc>::parse_from_str(timestamp_str, "%Y_%m_%d-%H_%M_%S")?;
1379 let footzstring = format!("{}+0000", timestamp_str);
1380 let timestamp = DateTime::parse_from_str(&footzstring, "%y%m%d_%H%M%S%z")?;
1381 //let timestamp = DateTime::parse_from_str(&footzstring, HUMAN_TIMESTAMP_FORMAT)?;
1382 //println!("parse successful");
1383 //let _timestamp = DateTime
1384 if timestamp > newest_file.1 {
1385 // FIXME - into might panic?
1386 newest_file.1 = timestamp.into();
1387 newest_file.0 = filename.clone();
1388 }
1389 }
1390 }
1391 }
1392 }
1393
1394 if newest_file.0.is_empty() {
1395 error!("No matching calibration available for board {}!", self.rb_id);
1396 } else {
1397 let file_to_load = format!("{}/{}", self.calib_file_path, newest_file.0);
1398 info!("Loading calibration from file: {}", file_to_load);
1399 self.calibration = RBCalibrations::from_file(file_to_load, true)?;
1400 }
1401 Ok(())
1402 }
1403}
1404
1405impl fmt::Display for ReadoutBoard {
1406 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1407 let mut repr = String::from("<ReadoutBoard:");
1408 repr += &(format!("\n Board id : {}",self.rb_id));
1409 repr += &(format!("\n MTB Link ID : {}",self.mtb_link_id));
1410 repr += &(format!("\n DSI/J : {}/{}",self.dsi,self.j));
1411 repr += "\n **Connected paddles**";
1412 repr += &(format!("\n Ch0/1(1/2) : {}",self.paddle12));
1413 repr += &(format!("\n A-side : {}", self.get_paddle12_chA()));
1414 repr += &(format!("\n Ch1/2(2/3) : {}",self.paddle34));
1415 repr += &(format!("\n A-side : {}", self.get_paddle34_chA()));
1416 repr += &(format!("\n Ch2/3(3/4) : {}",self.paddle56));
1417 repr += &(format!("\n A-side : {}", self.get_paddle56_chA()));
1418 repr += &(format!("\n Ch3/4(4/5) : {}>",self.paddle78));
1419 repr += &(format!("\n A-side : {}", self.get_paddle78_chA()));
1420 repr += "** calibration will be loaded from this path:";
1421 repr += &(format!("\n \u{021B3} {}", self.calib_file_path));
1422 repr += &(format!("\n calibration : {}>", self.calibration));
1423 write!(f, "{}", repr)
1424 }
1425}
1426
1427//---------------------------------------------------------------------
1428
1429#[cfg(feature="pybindings")]
1430#[pymethods]
1431impl ReadoutBoard {
1432
1433 #[getter]
1434 fn get_rb_id(&self) -> u8 {
1435 self.rb_id
1436 }
1437
1438 #[getter]
1439 fn get_dsi(&self) -> u8 {
1440 self.dsi
1441 }
1442
1443 #[getter]
1444 fn get_j(&self) -> u8 {
1445 self.j
1446 }
1447
1448 #[getter]
1449 fn get_mtb_link_id(&self) -> u8 {
1450 self.mtb_link_id
1451 }
1452
1453 #[getter]
1454 fn get_paddle12(&self) -> TofPaddle {
1455 self.paddle12.clone()
1456 }
1457
1458 #[getter]
1459 fn get_paddle34(&self) -> TofPaddle {
1460 self.paddle34.clone()
1461 }
1462
1463 #[getter]
1464 fn get_paddle56(&self) -> TofPaddle {
1465 self.paddle56.clone()
1466 }
1467
1468 #[getter]
1469 fn get_paddle78(&self) -> TofPaddle {
1470 self.paddle78.clone()
1471 }
1472
1473 #[staticmethod]
1474 #[pyo3(name="all")]
1475 pub fn all_py() -> Option<Vec<Self>> {
1476 Self::all()
1477 }
1478
1479 /// Load a calibration file for this specific Readoutboard
1480 #[pyo3(name="load_calibration")]
1481 pub fn load_calibration_py(&mut self, path : &Bound<'_,PyAny>) -> PyResult<()> {
1482 let mut string_value = String::from("foo");
1483 if let Ok(s) = path.extract::<String>() {
1484 string_value = s;
1485 } //else if let Ok(p) = filename_or_directory.extract::<&Path>() {
1486 if let Ok(fspath_method) = path.getattr("__fspath__") {
1487 if let Ok(fspath_result) = fspath_method.call0() {
1488 if let Ok(py_string) = fspath_result.extract::<String>() {
1489 string_value = py_string;
1490 }
1491 }
1492 }
1493 self.calib_file_path = string_value;
1494 match self.load_latest_calibration() {
1495 Ok(_) => {
1496 return Ok(())
1497 }
1498 Err(err) => {
1499 return Err(PyValueError::new_err(err.to_string()));
1500 }
1501 }
1502 }
1503
1504 #[staticmethod]
1505 #[pyo3(name="all_as_dict")]
1506 pub fn all_as_dict_py() -> Option<HashMap<u8,Self>> {
1507 match Self::all_as_dict() {
1508 Err(err) => {
1509 error!("Unable to retrieve RB dictionary. {err}. Did you laod the setup-env.sh shell?");
1510 return None;
1511 }
1512 Ok(_data) => {
1513 return Some(_data);
1514 }
1515 }
1516 }
1517}
1518//paddle12 : TofPaddle::new(),
1519////paddle12_chA : 0,
1520//paddle34 : TofPaddle::new(),
1521////paddle34_chA : 0,
1522//paddle56 : TofPaddle::new(),
1523////paddle56_chA : 0,
1524//paddle78 : TofPaddle::new(),
1525////paddle78_chA : 0,
1526//calib_file_path : String::from(""),
1527//calibration : RBCalibrations::new(0),
1528//}
1529
1530#[cfg(feature="pybindings")]
1531pythonize!(ReadoutBoard);
1532
1533//---------------------------------------------------------------------
1534
1535#[derive(Debug,Queryable, Selectable, serde::Serialize, serde::Deserialize)]
1536#[diesel(table_name = schema::tof_db_rat)]
1537#[diesel(primary_key(rat_id))]
1538#[allow(non_snake_case)]
1539#[cfg_attr(feature="pybindings", pyclass)]
1540pub struct RAT {
1541 pub rat_id : i16,
1542 pub pb_id : i16,
1543 pub rb1_id : i16,
1544 pub rb2_id : i16,
1545 pub ltb_id : i16,
1546 pub ltb_harting_cable_length : i16,
1547}
1548
1549impl RAT {
1550 pub fn new() -> Self {
1551 Self {
1552 rat_id : 0,
1553 pb_id : 0,
1554 rb1_id : 0,
1555 rb2_id : 0,
1556 ltb_id : 0,
1557 ltb_harting_cable_length : 0,
1558 }
1559 }
1560
1561 /// Get the RAT where rb2id matched the argument
1562 pub fn where_rb2id(rb2id : u8) -> Option<Vec<RAT>> {
1563
1564 let mut result = Vec::<RAT>::new();
1565 match RAT::all() {
1566 Some(rats) => {
1567 for rat in rats {
1568 if rat.rb2_id == rb2id as i16 {
1569 result.push(rat);
1570 }
1571 }
1572 return Some(result);
1573 }
1574 None => ()
1575 }
1576 Some(result)
1577 }
1578
1579 /// Get the RAT where rb1id (the rb id of rb"1" in the RAT) matched the argument
1580 pub fn where_rb1id(rb2id : u8) -> Option<Vec<RAT>> {
1581 let mut result = Vec::<RAT>::new();
1582 match RAT::all() {
1583 Some(rats) => {
1584 for rat in rats {
1585 if rat.rb1_id == rb2id as i16 {
1586 result.push(rat);
1587 }
1588 }
1589 return Some(result);
1590 }
1591 None => ()
1592 }
1593 Some(result)
1594 }
1595
1596 pub fn all() -> Option<Vec<RAT>> {
1597 use schema::tof_db_rat::dsl::*;
1598 let mut conn = connect_to_db().ok()?;
1599 match tof_db_rat.load::<RAT>(&mut conn) {
1600 Err(err) => {
1601 error!("Unable to load RATs from db! {err}");
1602 return None;
1603 }
1604 Ok(rats) => {
1605 return Some(rats);
1606 }
1607 }
1608 }
1609
1610}
1611
1612impl fmt::Display for RAT {
1613 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1614 let mut repr = String::from("<RAT");
1615 repr += &(format!("\n ID : {}", self.rat_id));
1616 repr += &(format!("\n PB : {} ", self.pb_id));
1617 repr += &(format!("\n RB1 : {}", self.rb1_id));
1618 repr += &(format!("\n RB2 : {}", self.rb2_id));
1619 repr += &(format!("\n LTB : {}", self.ltb_id));
1620 repr += &(format!("\n H. cable len [cm] : {}>", self.ltb_harting_cable_length));
1621 write!(f, "{}", repr)
1622 }
1623}
1624
1625///// Get all trackerstrips from the database
1626//pub fn get_trackerstrips() -> Result<HashMap<u32,TrackerStrip>, ConnectionError> {
1627// let db_path = env::var("GONDOLA_DB_URL").unwrap_or_else(|_| "".to_string());
1628// let mut conn = connect_to_db(db_path)?;
1629// let mut strips = HashMap::<u32, TrackerStrip>::new();
1630// match TrackerStrip::all(&mut conn) {
1631// None => {
1632// error!("We can't find any tracker strips in the database!");
1633// return Ok(strips);
1634// }
1635// Some(ts) => {
1636// for s in ts {
1637// strips.insert(s.get_stripid() as u32, s.clone());
1638// }
1639// }
1640// }
1641// return Ok(strips);
1642//}
1643//
1644///// Create a mapping of mtb link ids to rb ids
1645//pub fn get_linkid_rbid_map(rbs : &Vec<ReadoutBoard>) -> HashMap<u8, u8>{
1646// let mut mapping = HashMap::<u8, u8>::new();
1647// for rb in rbs {
1648// mapping.insert(rb.mtb_link_id, rb.rb_id);
1649// }
1650// mapping
1651//}
1652//
1653///// Create a mapping of rb id to mtb link ids
1654//pub fn get_rbid_linkid_map(rbs : &Vec<ReadoutBoard>) -> HashMap<u8, u8> {
1655// let mut mapping = HashMap::<u8, u8>::new();
1656// for rb in rbs {
1657// mapping.insert(rb.rb_id, rb.mtb_link_id);
1658// }
1659// mapping
1660//}
1661//
1662
1663
1664
1665
1666///// Create a map for rbid, ch -> paddle id. This is for both sides
1667///// and will always return a paddle id independent of A or B
1668//pub fn get_rb_ch_pid_map(paddles : &Vec<Paddle>) -> RbChPidMapping {
1669// let mut mapping = RbChPidMapping::new();
1670// for rbid in 1..51 {
1671// let mut chmap = HashMap::<u8, u8>::new();
1672// for ch in 1..9 {
1673// chmap.insert(ch,0);
1674// }
1675// mapping.insert(rbid,chmap);
1676// }
1677// for pdl in paddles {
1678// let rb_id = pdl.rb_id as u8;
1679// let ch_a = pdl.rb_chA as u8;
1680// let ch_b = pdl.rb_chB as u8;
1681// let pid = pdl.paddle_id as u8;
1682// //println!("rb_id {rb_id}, chA {ch_a}, chB {ch_b}");
1683// *mapping.get_mut(&rb_id).unwrap().get_mut(&ch_a).unwrap() = pid;
1684// *mapping.get_mut(&rb_id).unwrap().get_mut(&ch_b).unwrap() = pid;
1685// }
1686// mapping
1687//}
1688//
1689///// Create a map for rbid, ch -> paddle id. This is only for the A
1690///// side and will not have an entry in case the given RB channel
1691///// is connected to the B side of the paddle
1692//pub fn get_rb_ch_pid_a_map(paddles : &Vec<Paddle>) -> RbChPidMapping {
1693// let mut mapping = RbChPidMapping::new();
1694// for rbid in 1..51 {
1695// let mut chmap = HashMap::<u8, u8>::new();
1696// for ch in 1..9 {
1697// chmap.insert(ch,0);
1698// }
1699// mapping.insert(rbid,chmap);
1700// }
1701// for pdl in paddles {
1702// let rb_id = pdl.rb_id as u8;
1703// let ch_a = pdl.rb_chA as u8;
1704// let pid = pdl.paddle_id as u8;
1705// *mapping.get_mut(&rb_id).unwrap().get_mut(&ch_a).unwrap() = pid;
1706// }
1707// mapping
1708//}
1709//
1710//
1711///// Create a map for rbid, ch -> paddle id. This is only for the B
1712///// side and will not have an entry in case the given RB channel
1713///// is connected to the A side of the paddle
1714//pub fn get_rb_ch_pid_b_map(paddles : &Vec<Paddle>) -> RbChPidMapping {
1715// let mut mapping = RbChPidMapping::new();
1716// for rbid in 1..51 {
1717// let mut chmap = HashMap::<u8, u8>::new();
1718// for ch in 1..9 {
1719// chmap.insert(ch,0);
1720// }
1721// mapping.insert(rbid,chmap);
1722// }
1723// for pdl in paddles {
1724// let rb_id = pdl.rb_id as u8;
1725// let ch_b = pdl.rb_chB as u8;
1726// let pid = pdl.paddle_id as u8;
1727// *mapping.get_mut(&rb_id).unwrap().get_mut(&ch_b).unwrap() = pid;
1728// }
1729// mapping
1730//}
1731//
1732///// A representation of a run
1733//#[derive(Debug, Clone, Queryable,Insertable, Selectable, serde::Serialize, serde::Deserialize)]
1734//#[diesel(table_name = schema::tof_db_run)]
1735//#[diesel(primary_key(run_id))]
1736//pub struct Run {
1737// pub run_id : i64,
1738// pub runtime_secs : Option<i64>,
1739// pub calib_before : Option<bool>,
1740// pub shifter : Option<i16>,
1741// pub run_type : Option<i16>,
1742// pub run_path : Option<String>,
1743//}
1744//
1745//impl Run {
1746// pub fn new() -> Self {
1747// Self {
1748// run_id : 0,
1749// runtime_secs : Some(0),
1750// calib_before : Some(true),
1751// shifter : Some(0),
1752// run_type : Some(0),
1753// run_path : Some(String::from("")),
1754// }
1755// }
1756//
1757// pub fn get_last_run(conn: &mut SqliteConnection) -> Option<u32> {
1758// use schema::tof_db_run::dsl::*;
1759// match tof_db_run.load::<Run>(conn) {
1760// Err(err) => {
1761// error!("Unable to load DSICards from db! {err}");
1762// return None;
1763// }
1764// Ok(_runs) => {
1765// //return Some(runs);
1766// }
1767// }
1768// let _results = tof_db_run
1769// //.filter(published.eq(true))
1770// .limit(1)
1771// //.select(Run::as_select())
1772// .load::<Run>(conn)
1773// .expect("Error loading posts");
1774// None
1775// }
1776//}
1777//
1778//impl fmt::Display for Run {
1779// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1780// let mut repr = String::from("<Run");
1781// repr += &(format!("\n RunID : {}", self.run_id));
1782// repr += &(format!("\n - auto cali : {}", self.calib_before.unwrap_or(false)));
1783// repr += &(format!("\n runtime [sec] : {}", self.runtime_secs.unwrap_or(-1)));
1784// repr += &(format!("\n shifter : {}", self.shifter.unwrap_or(-1)));
1785// repr += &(format!("\n run_type : {}", self.run_type.unwrap_or(-1)));
1786// repr += &(format!("\n run_path : {}", self.run_path.clone().unwrap_or(String::from(""))));
1787// write!(f, "{}", repr)
1788// }
1789//}
1790//
1791///// Representation of a local trigger board.
1792/////
1793///// The individual LTB channels do not map directly to PaddleEnds. Rather two of them
1794///// map to a paddle and then the whole paddle should get read out.
1795///// To be more specific about this. The LTB has 16 channels, but we treat them as 8.
1796///// Each 2 LTB channels get "married" internally in the board and will then continue
1797///// on as 1 LTB channel, visible to the outside. The information about which end of
1798///// the Paddle crossed which threshhold is lost.
1799///// How it works is that the two channels will be combined by the trigger logic:
1800///// - There are 4 states (2 bits)
1801///// - 0 - no hit
1802///// - 1 - Hit
1803///// - 2 - Beta
1804///// - 3 - Veto
1805/////
1806///// Each defining an individual threshold. If that is crossed, the whole paddle
1807///// (ends A+B) will be read out by the ReadoutBoard
1808/////
1809///// The LTB channels here are labeled 1-8. This is as it is in the TOF spreadsheet.
1810///// Also dsi is labeled as in the spreadsheet and will start from one.
1811/////
1812///// It is NOT clear from this which ch on the rb is connected to which side, for that
1813///// the paddle/RB tables need to be consulted.
1814///// Again: rb_ch0 does NOT necessarily correspond to the A side!
1815/////
1816//#[derive(Debug,Queryable, Selectable, serde::Serialize, serde::Deserialize)]
1817//#[diesel(table_name = schema::tof_db_rat)]
1818//#[diesel(primary_key(rat_id))]
1819//pub struct RAT {
1820// pub rat_id : i16,
1821// pub pb_id : i16,
1822// pub rb1_id : i16,
1823// pub rb2_id : i16,
1824// pub ltb_id : i16,
1825// pub ltb_harting_cable_length : i16,
1826//}
1827//
1828//impl RAT {
1829// pub fn new() -> Self {
1830// Self {
1831// rat_id : 0,
1832// pb_id : 0,
1833// rb1_id : 0,
1834// rb2_id : 0,
1835// ltb_id : 0,
1836// ltb_harting_cable_length : 0,
1837// }
1838// }
1839//
1840// /// Get the RAT where rb2id matched the argument
1841// pub fn where_rb2id(conn: &mut SqliteConnection, rb2id : u8) -> Option<Vec<RAT>> {
1842// let mut result = Vec::<RAT>::new();
1843// match RAT::all(conn) {
1844// Some(rats) => {
1845// for rat in rats {
1846// if rat.rb2_id == rb2id as i16 {
1847// result.push(rat);
1848// }
1849// }
1850// return Some(result);
1851// }
1852// None => ()
1853// }
1854// Some(result)
1855// }
1856//
1857// /// Get the RAT where rb1id (the rb id of rb"1" in the RAT) matched the argument
1858// pub fn where_rb1id(conn: &mut SqliteConnection, rb2id : u8) -> Option<Vec<RAT>> {
1859// let mut result = Vec::<RAT>::new();
1860// match RAT::all(conn) {
1861// Some(rats) => {
1862// for rat in rats {
1863// if rat.rb1_id == rb2id as i16 {
1864// result.push(rat);
1865// }
1866// }
1867// return Some(result);
1868// }
1869// None => ()
1870// }
1871// Some(result)
1872// }
1873//
1874// pub fn all(conn: &mut SqliteConnection) -> Option<Vec<RAT>> {
1875// match tof_db_rat.load::<RAT>(conn) {
1876// Err(err) => {
1877// error!("Unable to load RATs from db! {err}");
1878// return None;
1879// }
1880// Ok(rats) => {
1881// return Some(rats);
1882// }
1883// }
1884// }
1885//
1886//}
1887//
1888//impl fmt::Display for RAT {
1889// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1890// let mut repr = String::from("<RAT");
1891// repr += &(format!("\n ID : {}", self.rat_id));
1892// repr += &(format!("\n PB : {} ", self.pb_id));
1893// repr += &(format!("\n RB1 : {}", self.rb1_id));
1894// repr += &(format!("\n RB2 : {}", self.rb2_id));
1895// repr += &(format!("\n LTB : {}", self.ltb_id));
1896// repr += &(format!("\n H. cable len [cm] : {}>", self.ltb_harting_cable_length));
1897// write!(f, "{}", repr)
1898// }
1899//}
1900//
1901//
1902///// A DSI card which is plugged into one of five slots on the MTB
1903///// The DSI card provides the connection to RBs and LTBs and has
1904///// a subdivision, which is called 'j'
1905//#[derive(Queryable, Selectable)]
1906//#[diesel(primary_key(dsi_id))]
1907//#[diesel(table_name = schema::tof_db_dsicard)]
1908//pub struct DSICard {
1909// pub dsi_id : i16,
1910// pub j1_rat_id : Option<i16>,
1911// pub j2_rat_id : Option<i16>,
1912// pub j3_rat_id : Option<i16>,
1913// pub j4_rat_id : Option<i16>,
1914// pub j5_rat_id : Option<i16>,
1915//}
1916//
1917//
1918//impl DSICard {
1919// pub fn new() -> Self {
1920// Self {
1921// dsi_id : 0,
1922// j1_rat_id : None,
1923// j2_rat_id : None,
1924// j3_rat_id : None,
1925// j4_rat_id : None,
1926// j5_rat_id : None,
1927// }
1928// }
1929//
1930// /// True if this RAT box is plugged in to any of the j
1931// /// connectors on this specific DSI card
1932// pub fn has_rat(&self, r_id : u8) -> bool {
1933// if let Some(rid) = self.j1_rat_id {
1934// if rid as u8 == r_id {
1935// return true;
1936// }
1937// }
1938// if let Some(rid) = self.j2_rat_id {
1939// if rid as u8 == r_id {
1940// return true;
1941// }
1942// }
1943// if let Some(rid) = self.j3_rat_id {
1944// if rid as u8 == r_id {
1945// return true;
1946// }
1947// }
1948// if let Some(rid) = self.j4_rat_id {
1949// if rid as u8 == r_id {
1950// return true;
1951// }
1952// }
1953// if let Some(rid) = self.j5_rat_id {
1954// if rid as u8 == r_id {
1955// return true;
1956// }
1957// }
1958// return false;
1959// }
1960//
1961// /// Get the j connetor for this specific RAT
1962// /// Raises ValueError if the RAT is not connected
1963// pub fn get_j(&self, r_id : u8) -> Option<u8> {
1964// if !self.has_rat(r_id) {
1965// return None;
1966// }
1967// if let Some(rid) = self.j1_rat_id {
1968// if rid as u8 == r_id {
1969// let _j = self.j1_rat_id.unwrap() as u8;
1970// return Some(_j);
1971// }
1972// }
1973// if let Some(rid) = self.j2_rat_id {
1974// if rid as u8 == r_id {
1975// let _j = self.j2_rat_id.unwrap() as u8;
1976// return Some(_j);
1977// }
1978// }
1979// if let Some(rid) = self.j3_rat_id {
1980// if rid as u8 == r_id {
1981// let _j = self.j3_rat_id.unwrap() as u8;
1982// return Some(_j);
1983// }
1984// }
1985// if let Some(rid) = self.j4_rat_id {
1986// if rid as u8 == r_id {
1987// let _j = self.j4_rat_id.unwrap() as u8;
1988// return Some(_j);
1989// }
1990// }
1991// if let Some(rid) = self.j5_rat_id {
1992// if rid as u8 == r_id {
1993// let _j = self.j5_rat_id.unwrap() as u8;
1994// return Some(_j);
1995// }
1996// }
1997// None
1998// }
1999//
2000// pub fn all(conn: &mut SqliteConnection) -> Option<Vec<DSICard>> {
2001// match tof_db_dsicard.load::<DSICard>(conn) {
2002// Err(err) => {
2003// error!("Unable to load DSICards from db! {err}");
2004// return None;
2005// }
2006// Ok(dsis) => {
2007// return Some(dsis);
2008// }
2009// }
2010// }
2011//}
2012//
2013//impl fmt::Display for DSICard {
2014// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2015// let mut repr = String::from("<DSI Card:");
2016// repr += &(format!("\n ID : {}", self.dsi_id));
2017// repr += "\n -- -- -- --";
2018// if let Some(_j) = self.j1_rat_id {
2019// repr += &(format!("\n J1 RAT : {}",_j));
2020// } else {
2021// repr += "\n J1 RAT : Not connected";
2022// }
2023// if let Some(_j) = self.j2_rat_id {
2024// repr += &(format!("\n J2 RAT : {}",_j));
2025// } else {
2026// repr += "\n J2 RAT : Not connected";
2027// }
2028// if let Some(_j) = self.j3_rat_id {
2029// repr += &(format!("\n J3 RAT : {}",_j));
2030// } else {
2031// repr += "\n J3 RAT : Not connected";
2032// }
2033// if let Some(_j) = self.j4_rat_id {
2034// repr += &(format!("\n J4 RAT : {}",_j));
2035// } else {
2036// repr += "\n J4 RAT : Not connected";
2037// }
2038// if let Some(_j) = self.j5_rat_id {
2039// repr += &(format!("\n J5 RAT : {}>",_j));
2040// } else {
2041// repr += "\n J5 RAT : Not connected>";
2042// }
2043// write!(f, "{}", repr)
2044// }
2045//}
2046//
2047
2048/// A single Tracker strip
2049#[derive(Debug,PartialEq, Clone,Queryable, Selectable, serde::Serialize, serde::Deserialize)]
2050#[diesel(table_name = schema::tof_db_trackerstrip)]
2051#[diesel(primary_key(strip_id))]
2052#[allow(non_snake_case)]
2053#[cfg_attr(feature="pybindings", pyclass)]
2054pub struct TrackerStrip {
2055 pub strip_id : i32,
2056 pub layer : i32,
2057 pub row : i32,
2058 pub module : i32,
2059 pub channel : i32,
2060 pub global_pos_x_l0 : f32,
2061 pub global_pos_y_l0 : f32,
2062 pub global_pos_z_l0 : f32,
2063 pub global_pos_x_det_l0 : f32,
2064 pub global_pos_y_det_l0 : f32,
2065 pub global_pos_z_det_l0 : f32,
2066 pub principal_x : f32,
2067 pub principal_y : f32,
2068 pub principal_z : f32,
2069 pub volume_id : i64,
2070}
2071
2072impl TrackerStrip {
2073 pub fn new() -> Self {
2074 Self {
2075 strip_id : 0,
2076 layer : 0,
2077 row : 0,
2078 module : 0,
2079 channel : 0,
2080 global_pos_x_l0 : 0.0,
2081 global_pos_y_l0 : 0.0,
2082 global_pos_z_l0 : 0.0,
2083 global_pos_x_det_l0 : 0.0,
2084 global_pos_y_det_l0 : 0.0,
2085 global_pos_z_det_l0 : 0.0,
2086 principal_x : 0.0,
2087 principal_y : 0.0,
2088 principal_z : 0.0,
2089 volume_id : 0,
2090 }
2091 }
2092
2093 /// Factory method for the strip id following tracker convention
2094 pub fn create_stripid(layer : u8, row :u8, module : u8, channel : u8) -> u32 {
2095 channel as u32 + (module as u32)*100 + (row as u32)*10000 + (layer as u32)*100000
2096 }
2097
2098 /// FIXME - why use this at all and not just get the one from the db??
2099 pub fn get_stripid(&self) -> u32 {
2100 self.channel as u32 + (self.module as u32)*100 + (self.row as u32)*10000 + (self.layer as u32)*100000
2101 }
2102
2103 /// Get all TRK strips from the database
2104 pub fn all_as_dict() -> Result<HashMap<u32,Self>, ConnectionError> {
2105 let mut strips = HashMap::<u32, Self>::new();
2106 match Self::all() {
2107 None => {
2108 error!("We can't find any tracker strips in the database!");
2109 return Ok(strips);
2110 }
2111 Some(strips_) => {
2112 for s in strips_ {
2113 strips.insert(s.strip_id as u32, s );
2114 }
2115 }
2116 }
2117 return Ok(strips);
2118 }
2119
2120 pub fn all() -> Option<Vec<Self>> {
2121 use schema::tof_db_trackerstrip::dsl::*;
2122 let mut conn = connect_to_db().ok()?;
2123 match tof_db_trackerstrip.load::<Self>(&mut conn) {
2124 Err(err) => {
2125 error!("Unable to load tracker strips from db! {err}");
2126 return None;
2127 }
2128 Ok(strips) => {
2129 return Some(strips);
2130 }
2131 }
2132 }
2133
2134 pub fn get_coordinates(&self) -> (f32, f32, f32) {
2135 (self.global_pos_x_l0, self.global_pos_y_l0, self.global_pos_z_l0)
2136 }
2137
2138 pub fn get_detcoordinates(&self) -> (f32, f32, f32) {
2139 (self.global_pos_x_det_l0, self.global_pos_y_det_l0, self.global_pos_z_det_l0)
2140 }
2141}
2142
2143impl fmt::Display for TrackerStrip {
2144 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2145 let mut repr = format!("<TrackerStrip [{}]:", self.strip_id);
2146 repr += &(format!("\n vid : {}", self.volume_id));
2147 repr += &(format!("\n layer : {}", self.layer));
2148 repr += &(format!("\n row : {}", self.row));
2149 repr += &(format!("\n module : {}", self.module));
2150 repr += &(format!("\n channel : {}", self.channel));
2151 repr += "\n strip center [mm]:";
2152 repr += &(format!("\n \u{21B3} [{:.2}, {:.2}, {:.2}]", self.global_pos_x_l0, self.global_pos_y_l0, self.global_pos_z_l0));
2153 repr += "\n detector (disk) center [mm]:";
2154 repr += &(format!("\n \u{21B3} [{:.2}, {:.2}, {:.2}]", self.global_pos_x_det_l0, self.global_pos_y_det_l0, self.global_pos_z_det_l0));
2155 repr += "\n strip principal direction:";
2156 repr += &(format!("\n \u{21B3} [{:.2}, {:.2}, {:.2}]", self.principal_x, self.principal_y, self.principal_z));
2157 write!(f, "{}", repr)
2158 }
2159}
2160
2161#[cfg(feature="pybindings")]
2162#[pymethods]
2163impl TrackerStrip {
2164 #[getter]
2165 fn get_strip_id (&self) -> i32 {
2166 self.strip_id
2167 }
2168
2169 #[getter]
2170 fn get_layer (&self) -> i32 {
2171 self.layer
2172 }
2173
2174 #[getter]
2175 fn get_row (&self) -> i32 {
2176 self.row
2177 }
2178
2179 #[getter]
2180 fn get_module (&self) -> i32 {
2181 self.module
2182 }
2183
2184 #[getter]
2185 fn get_channel (&self) -> i32 {
2186 self.channel
2187 }
2188
2189 #[getter]
2190 fn get_global_pos_x_l0 (&self) -> f32 {
2191 self.global_pos_x_l0
2192 }
2193
2194 #[getter]
2195 fn get_global_pos_y_l0 (&self) -> f32 {
2196 self.global_pos_y_l0
2197 }
2198
2199 #[getter]
2200 fn get_global_pos_z_l0 (&self) -> f32 {
2201 self.global_pos_z_l0
2202 }
2203
2204 #[getter]
2205 fn get_global_pos_x_det_l0(&self) -> f32 {
2206 self.global_pos_x_det_l0
2207 }
2208
2209 #[getter]
2210 fn get_global_pos_y_det_l0(&self) -> f32 {
2211 self.global_pos_y_det_l0
2212 }
2213
2214 #[getter]
2215 fn get_global_pos_z_det_l0(&self) -> f32 {
2216 self.global_pos_z_det_l0
2217 }
2218
2219 #[getter]
2220 fn coordinates(&self) -> (f32, f32, f32) {
2221 self.get_coordinates()
2222 }
2223
2224 #[getter]
2225 fn detector_coordinates(&self) -> (f32, f32, f32) {
2226 self.get_detcoordinates()
2227 }
2228
2229 #[getter]
2230 fn get_principal_x (&self) -> f32 {
2231 self.principal_x
2232 }
2233 #[getter]
2234 fn get_principal_y (&self) -> f32 {
2235 self.principal_y
2236 }
2237 #[getter]
2238 fn get_principal_z (&self) -> f32 {
2239 self.principal_z
2240 }
2241 #[getter]
2242 fn get_volume_id (&self) -> i64 {
2243 self.volume_id
2244 }
2245
2246 #[staticmethod]
2247 #[pyo3(name="all")]
2248 pub fn all_py() -> Option<Vec<Self>> {
2249 Self::all()
2250 }
2251
2252 #[staticmethod]
2253 #[pyo3(name="all_as_dict")]
2254 pub fn all_as_dict_py() -> Option<HashMap<u32,Self>> {
2255 match Self::all_as_dict() {
2256 Err(err) => {
2257 error!("Unable to retrieve tracker strip dictionary. {err}. Did you laod the setup-env.sh shell?");
2258 return None;
2259 }
2260 Ok(_data) => {
2261 return Some(_data);
2262 }
2263 }
2264 }
2265}
2266
2267#[cfg(feature="pybindings")]
2268pythonize!(TrackerStrip);
2269
2270//------------------------------------------------
2271
2272/// Masking of unusable strips as curated by the tracker team
2273#[derive(Debug,PartialEq, Clone,Queryable, Selectable, serde::Serialize, serde::Deserialize)]
2274#[diesel(table_name = schema::tof_db_tofpaddletimingconstant)]
2275#[diesel(primary_key(data_id))]
2276#[allow(non_snake_case)]
2277#[cfg_attr(feature="pybindings", pyclass)]
2278pub struct TofPaddleTimingConstant {
2279 pub data_id : i32,
2280 pub paddle_id : i32,
2281 pub volume_id : i64,
2282 pub utc_timestamp_start : i64,
2283 pub utc_timestamp_stop : i64,
2284 pub name : Option<String>,
2285 pub version : Option<i32>,
2286 pub timing_constant : f32,
2287 pub paddle_constant : f32,
2288 pub panel_constant : f32,
2289}
2290
2291impl TofPaddleTimingConstant {
2292
2293 pub fn new() -> Self {
2294 Self {
2295 data_id : 0,
2296 paddle_id : 0,
2297 volume_id : 0,
2298 utc_timestamp_start : 0,
2299 utc_timestamp_stop : 0,
2300 name : None,
2301 version : None,
2302 timing_constant : 0.0,
2303 paddle_constant : 0.0,
2304 panel_constant : 0.0,
2305 }
2306 }
2307
2308 /// Retrieve the names under which the timing constants are
2309 /// saved
2310 pub fn all_names() -> Result<Vec<String>, ConnectionError> {
2311 let mut conn = connect_to_db()?;
2312 let mut names = Vec::<String>::new();
2313 let unique_names =
2314 schema::tof_db_tofpaddletimingconstant::table.select(
2315 schema::tof_db_tofpaddletimingconstant::name)
2316 .distinct()
2317 .load::<Option<String>>(&mut conn).expect("Error getting names from db!");
2318 for k in unique_names {
2319 if let Some(n) = k {
2320 names.push(n);
2321 }
2322 }
2323 Ok(names)
2324 }
2325
2326 /// Get Tof timing constants as associated with a distinct name
2327 ///
2328 /// # Returns:
2329 /// * HashMap<u32 \[paddle id\], Self>
2330 pub fn as_dict_by_name(fname : &str) -> Result<HashMap<u8,Self>, ConnectionError> {
2331 use schema::tof_db_tofpaddletimingconstant::dsl::*;
2332 let mut paddles = HashMap::<u8, Self>::new();
2333 if fname == "" {
2334 match Self::all() {
2335 None => {
2336 error!("Unable to retrive ANY TofPaddleTimingConstant");
2337 return Ok(paddles);
2338 }
2339 Some(_paddles) => {
2340 for k in _paddles {
2341 paddles.insert(k.paddle_id as u8, k);
2342 }
2343 return Ok(paddles);
2344 }
2345 }
2346 }
2347 let mut conn = connect_to_db()?;
2348 match tof_db_tofpaddletimingconstant.filter(
2349 schema::tof_db_tofpaddletimingconstant::name.eq(fname)).load::<Self>(&mut conn) {
2350 Err(err) => {
2351 error!("We can't find any TOF paddle timing constants in the database! {err}");
2352 return Ok(paddles);
2353 }
2354 Ok(paddles_) => {
2355 for p in paddles_ {
2356 paddles.insert(p.paddle_id as u8, p );
2357 }
2358 }
2359 }
2360 return Ok(paddles);
2361 }
2362
2363 /// Get all timing calibration constants we have from the database
2364 /// - not recommended, this will be mixing different versions
2365 ///
2366 /// # Returns:
2367 /// * HashMap<u32 [strip id], TrackeStripMask>
2368 pub fn all() -> Option<Vec<Self>> {
2369 use schema::tof_db_tofpaddletimingconstant::dsl::*;
2370 let mut conn = connect_to_db().ok()?;
2371 match tof_db_tofpaddletimingconstant.load::<Self>(&mut conn) {
2372 Err(err) => {
2373 error!("Unable to load TOF paddle timing constants from db! {err}");
2374 return None;
2375 }
2376 Ok(tc) => {
2377 return Some(tc);
2378 }
2379 }
2380 }
2381}
2382
2383impl Default for TofPaddleTimingConstant {
2384 fn default() -> Self {
2385 Self::new()
2386 }
2387}
2388
2389impl fmt::Display for TofPaddleTimingConstant {
2390 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2391 let mut repr = format!("<TofPaddleTimingConstant [paddle {}]:", self.paddle_id);
2392 repr += &(format!("\n volume id : {}", self.volume_id));
2393 repr += "\n UTC Timestamps (Begin/End) :";
2394 repr += &(format!("\n {}/{}", self.utc_timestamp_start, self.utc_timestamp_stop));
2395 if self.name.is_some() {
2396 repr += &(format!("\n name : {}", self.name.clone().unwrap()));
2397 }
2398 if self.version.is_some() {
2399 repr += &(format!("\n version : {}", self.version.unwrap()));
2400 }
2401 repr += &(format!("\n paddle const. : {}", self.paddle_constant));
2402 repr += &(format!("\n panel const. : {}", self.panel_constant));
2403 repr += &(format!("\n timing const. : {}", self.timing_constant));
2404 write!(f, "{}", repr)
2405 }
2406}
2407
2408#[cfg(feature="pybindings")]
2409#[pymethods]
2410impl TofPaddleTimingConstant {
2411
2412 #[staticmethod]
2413 #[pyo3(name="all")]
2414 pub fn all_py() -> Option<Vec<Self>> {
2415 Self::all()
2416 }
2417
2418 #[staticmethod]
2419 #[pyo3(name="all_names")]
2420 /// Get all names for registered datasets. These
2421 /// can be used in .as_dict_by_name() to query
2422 /// the db for a set of values
2423 pub fn all_names_py() -> Option<Vec<String>> {
2424 match Self::all_names() {
2425 Err(_) => {
2426 return None;
2427 }
2428 Ok(names) => {
2429 return Some(names);
2430 }
2431 }
2432 }
2433
2434 /// Get the TOF paddle timing constants as associated by a specific
2435 /// name
2436 ///
2437 /// # Arguments
2438 /// * name : The name the constants are associated with
2439 #[staticmethod]
2440 #[pyo3(name="as_dict_by_name")]
2441 pub fn all_as_dict_py(name : &str) -> Option<HashMap<u8,Self>> {
2442 match Self::as_dict_by_name(name) {
2443 Err(err) => {
2444 error!("Unable to retrieve TOF paddle timing constants dictionary. {err}. Did you laod the setup-env.sh shell?");
2445 return None;
2446 }
2447 Ok(_data) => {
2448 return Some(_data);
2449 }
2450 }
2451 }
2452
2453 #[getter]
2454 fn get_paddle_id (&self) -> i32 {
2455 self.paddle_id
2456 }
2457
2458 #[getter]
2459 fn get_volume_id (&self) -> i64 {
2460 self.volume_id
2461 }
2462
2463 #[getter]
2464 fn get_utc_timestamp_start(&self) -> i64 {
2465 self.utc_timestamp_start
2466 }
2467
2468 #[getter]
2469 fn get_utc_timestamp_stop(&self) -> i64 {
2470 self.utc_timestamp_stop
2471 }
2472
2473 #[getter]
2474 fn get_name (&self) -> Option<String> {
2475 self.name.clone()
2476 }
2477
2478 #[getter]
2479 fn get_version (&self) -> Option<i32> {
2480 self.version.clone()
2481 }
2482
2483 #[getter]
2484 fn get_timing_constant (&self) -> f32 {
2485 self.timing_constant
2486 }
2487
2488 #[getter]
2489 fn get_paddle_constant (&self) -> f32 {
2490 self.paddle_constant
2491 }
2492
2493 #[getter]
2494 fn get_panel_constant (&self) -> f32 {
2495 self.panel_constant
2496 }
2497
2498 /// Completely reset the timing constant and
2499 /// NOT use the one from the db, but an own
2500 fn set_timing_constan(&mut self, tc : f32) {
2501 self.timing_constant = tc;
2502 }
2503
2504}
2505
2506#[cfg(feature="pybindings")]
2507pythonize!(TofPaddleTimingConstant);
2508
2509//----------------------------------
2510
2511/// Measurement of tracker pedestal values for each strip
2512#[derive(Debug,PartialEq, Clone,Queryable, Selectable, serde::Serialize, serde::Deserialize)]
2513#[diesel(table_name = schema::tof_db_trackerstrippedestal)]
2514#[diesel(primary_key(data_id))]
2515#[allow(non_snake_case)]
2516#[cfg_attr(feature="pybindings", pyclass)]
2517pub struct TrackerStripPedestal {
2518 pub data_id : i32,
2519 pub strip_id : i32,
2520 pub volume_id : i64,
2521 pub utc_timestamp_start : i64,
2522 pub utc_timestamp_stop : i64,
2523 pub name : Option<String>,
2524 pub pedestal_mean : f32,
2525 pub pedestal_sigma : f32,
2526 pub is_mean_value : bool,
2527}
2528
2529impl TrackerStripPedestal {
2530
2531 pub fn new() -> Self {
2532 Self {
2533 data_id : 0,
2534 strip_id : 0,
2535 volume_id : 0,
2536 utc_timestamp_start : 0,
2537 utc_timestamp_stop : 0,
2538 name : None,
2539 pedestal_mean : 0.0,
2540 pedestal_sigma : 0.0,
2541 is_mean_value : false
2542 }
2543 }
2544
2545 /// Get Tracker strip pedestals for a certain dataset
2546 ///
2547 /// # Returns:
2548 /// * HashMap<u32 [strip id], TrackerStripMask>
2549 pub fn as_dict_by_name(fname : &str) -> Result<HashMap<u32,Self>, ConnectionError> {
2550 use schema::tof_db_trackerstrippedestal::dsl::*;
2551 let mut strips = HashMap::<u32, Self>::new();
2552 if fname == "" {
2553 match Self::all() {
2554 None => {
2555 error!("Unable to retrive ANY TrackerStripPedestal");
2556 return Ok(strips);
2557 }
2558 Some(_strips) => {
2559 for k in _strips {
2560 strips.insert(k.strip_id as u32, k);
2561 }
2562 return Ok(strips);
2563 }
2564 }
2565 }
2566 let mut conn = connect_to_db()?;
2567 match tof_db_trackerstrippedestal.filter(
2568 schema::tof_db_trackerstrippedestal::name.eq(fname)).load::<Self>(&mut conn) {
2569 Err(err) => {
2570 error!("We can't find any tracker strip masks in the database! {err}");
2571 return Ok(strips);
2572 }
2573 Ok(peds_) => {
2574 for s in peds_ {
2575 strips.insert(s.strip_id as u32, s );
2576 }
2577 }
2578 }
2579 return Ok(strips);
2580 }
2581
2582 pub fn all_names() -> Result<Vec<String>, ConnectionError> {
2583 let mut conn = connect_to_db()?;
2584 let mut names = Vec::<String>::new();
2585 let unique_names =
2586 schema::tof_db_trackerstrippedestal::table.select(
2587 schema::tof_db_trackerstrippedestal::name)
2588 .distinct()
2589 .load::<Option<String>>(&mut conn).expect("Error getting names from db!");
2590 for k in unique_names {
2591 if let Some(n) = k {
2592 names.push(n);
2593 }
2594 }
2595 Ok(names)
2596 }
2597
2598 /// Get all tracker strip mask from the database
2599 ///
2600 /// # Returns:
2601 /// * HashMap<u32 [strip id], TrackeStripMask>
2602 pub fn all() -> Option<Vec<Self>> {
2603 use schema::tof_db_trackerstrippedestal::dsl::*;
2604 let mut conn = connect_to_db().ok()?;
2605 match tof_db_trackerstrippedestal.load::<Self>(&mut conn) {
2606 Err(err) => {
2607 error!("Unable to load tracker strips pedestals from db! {err}");
2608 return None;
2609 }
2610 Ok(strips) => {
2611 return Some(strips);
2612 }
2613 }
2614 }
2615
2616 ///
2617 pub fn parse_from_file<P: AsRef<Path>>(path: P) -> io::Result<Vec<Self>> {
2618 let file = File::open(path)?;
2619 let reader = BufReader::new(file);
2620 let mut pedestals = Vec::<Self>::new();
2621 let hid_vid_map = get_hid_vid_maps().unwrap().1;
2622 for line in reader.lines() {
2623 let line = line?;
2624 if line.starts_with("#") || line.starts_with("Layer") || line.starts_with("layer") {
2625 continue;
2626 }
2627 let mut ped = TrackerStripPedestal::new();
2628 let parts: Vec<&str> = line.split_whitespace().collect();
2629 if parts.len() == 6 {
2630 // Parse the first number as a standard decimal
2631 let layer = parts[0].parse::<u8>()
2632 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
2633 let row = parts[1].parse::<u8>()
2634 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
2635 let module = parts[2].parse::<u8>()
2636 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
2637 let channel = parts[3].parse::<u8>()
2638 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
2639 ped.strip_id = TrackerStrip::create_stripid(layer, row, module, channel) as i32;
2640 ped.volume_id = *hid_vid_map.get(&(ped.strip_id as u32)).unwrap() as i64; // critical error is good here,
2641 // should alert the user
2642 ped.pedestal_mean = parts[4].parse::<f32>()
2643 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
2644 ped.pedestal_sigma = parts[5].parse::<f32>()
2645 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
2646 pedestals.push(ped);
2647 }
2648 }
2649 Ok(pedestals)
2650 }
2651}
2652
2653impl Default for TrackerStripPedestal {
2654 fn default() -> Self {
2655 Self::new()
2656 }
2657}
2658
2659impl fmt::Display for TrackerStripPedestal {
2660 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2661 let mut repr = format!("<TrackerStripPedestal [{}]:", self.strip_id);
2662 repr += &(format!("\n vid : {}", self.volume_id));
2663 repr += "\n UTC Timestamps (Begin/End):";
2664 repr += &(format!("\n {}/{}", self.utc_timestamp_start, self.utc_timestamp_stop));
2665 if self.name.is_some() {
2666 repr += &(format!("\n name : {}", self.name.clone().unwrap()));
2667 }
2668 repr += &(format!("\n pedestal_mean : {}", self.pedestal_mean));
2669 repr += &(format!("\n pedestal_sigma : {}", self.pedestal_sigma));
2670 repr += &(format!("\n is_mean_value : {}", self.is_mean_value));
2671 write!(f, "{}", repr)
2672 }
2673}
2674
2675#[cfg(feature="pybindings")]
2676#[pymethods]
2677impl TrackerStripPedestal {
2678
2679 #[staticmethod]
2680 #[pyo3(name="parse_from_file")]
2681 fn parse_from_file_py(fname : &str) -> Option<Vec<Self>> {
2682 let result = Self::parse_from_file(fname);
2683 if result.is_ok() {
2684 return Some(result.unwrap());
2685 } else {
2686 error!("An error occured when parsing {} : '{}'", fname, result.unwrap_err());
2687 return None;
2688 }
2689 }
2690
2691 #[staticmethod]
2692 #[pyo3(name="all")]
2693 pub fn all_py() -> Option<Vec<Self>> {
2694 Self::all()
2695 }
2696
2697 #[staticmethod]
2698 #[pyo3(name="all_names")]
2699 /// Get all names for registered datasets. These
2700 /// can be used in .as_dict_by_name() to query
2701 /// the db for a set of values
2702 pub fn all_names_py() -> Option<Vec<String>> {
2703 match Self::all_names() {
2704 Err(_) => {
2705 return None;
2706 }
2707 Ok(names) => {
2708 return Some(names);
2709 }
2710 }
2711 }
2712
2713 #[staticmethod]
2714 #[pyo3(name="as_dict_by_name")]
2715 pub fn all_as_dict_py(name : &str) -> Option<HashMap<u32,Self>> {
2716 match Self::as_dict_by_name(name) {
2717 Err(err) => {
2718 error!("Unable to retrieve tracker strip pedestal dictionary. {err}. Did you laod the setup-env.sh shell?");
2719 return None;
2720 }
2721 Ok(_data) => {
2722 return Some(_data);
2723 }
2724 }
2725 }
2726
2727 #[getter]
2728 #[pyo3(name="name")]
2729 fn get_name_py (&self) -> Option<String> {
2730 self.name.clone()
2731 }
2732
2733 #[setter]
2734 #[pyo3(name="name")]
2735 fn set_name_py(&mut self, value : String) {
2736 self.name = Some(value);
2737 }
2738
2739 #[getter]
2740 fn get_strip_id (&self) -> i32 {
2741 self.strip_id
2742 }
2743
2744 #[getter]
2745 fn get_volume_id (&self) -> i64 {
2746 self.volume_id
2747 }
2748
2749 #[getter]
2750 fn get_utc_timestamp_start(&self) -> i64 {
2751 self.utc_timestamp_start
2752 }
2753
2754 #[getter]
2755 fn get_utc_timestamp_stop(&self) -> i64 {
2756 self.utc_timestamp_stop
2757 }
2758
2759 #[setter]
2760 fn set_utc_timestamp_start(&mut self, value : i64) {
2761 self.utc_timestamp_start = value;
2762 }
2763
2764 #[setter]
2765 fn set_utc_timestamp_stop(&mut self, value : i64) {
2766 self.utc_timestamp_stop = value;
2767 }
2768
2769 #[getter]
2770 fn get_pedestal_mean (&self) -> f32 {
2771 self.pedestal_mean
2772 }
2773
2774 #[getter]
2775 fn get_pedestal_sigam (&self) -> f32 {
2776 self.pedestal_sigma
2777 }
2778
2779 #[getter]
2780 fn get_is_mean_value (&self) -> bool {
2781 self.is_mean_value
2782 }
2783}
2784
2785#[cfg(feature="pybindings")]
2786pythonize!(TrackerStripPedestal);
2787
2788//-------------------------------------------------
2789
2790/// Common noise subtraction - pulse channels on the wafers and get the average adc.
2791/// The gain is available as well. Data from Mengjiao's group
2792#[derive(Debug,PartialEq, Clone,Queryable, Selectable, serde::Serialize, serde::Deserialize)]
2793#[diesel(table_name = schema::tof_db_trackerstripcmnnoise)]
2794#[diesel(primary_key(data_id))]
2795#[allow(non_snake_case)]
2796#[cfg_attr(feature="pybindings", pyclass)]
2797pub struct TrackerStripCmnNoise {
2798 pub data_id : i32,
2799 pub strip_id : i32,
2800 pub volume_id : i64,
2801 pub utc_timestamp_start : i64,
2802 pub utc_timestamp_stop : i64,
2803 pub name : Option<String>,
2804 pub gain : f32,
2805 pub pulse_chn : i32,
2806 pub pulse_avg : f32,
2807 pub gain_is_mean : bool,
2808 pub pulse_is_mean : bool,
2809}
2810
2811impl TrackerStripCmnNoise {
2812
2813 pub fn new() -> Self {
2814 Self {
2815 data_id : 0,
2816 strip_id : 0,
2817 volume_id : 0,
2818 utc_timestamp_start : 0,
2819 utc_timestamp_stop : 0,
2820 name : None,
2821 gain : 0.0,
2822 pulse_chn : 0,
2823 pulse_avg : 0.0,
2824 gain_is_mean : false,
2825 pulse_is_mean : false
2826 }
2827 }
2828
2829 pub fn all_names() -> Result<Vec<String>, ConnectionError> {
2830 let mut conn = connect_to_db()?;
2831 let mut names = Vec::<String>::new();
2832 let unique_names =
2833 schema::tof_db_trackerstripcmnnoise::table.select(
2834 schema::tof_db_trackerstripcmnnoise::name)
2835 .distinct()
2836 .load::<Option<String>>(&mut conn).expect("Error getting names from db!");
2837 for k in unique_names {
2838 if let Some(n) = k {
2839 names.push(n);
2840 }
2841 }
2842 Ok(names)
2843 }
2844
2845 /// Get Tracker strip cmn noise data for a certain dataset
2846 ///
2847 /// # Returns:
2848 /// * HashMap<u32 [strip id], TrackerStripTransferFn>
2849 pub fn as_dict_by_name(fname : &str) -> Result<HashMap<u32,Self>, ConnectionError> {
2850 use schema::tof_db_trackerstripcmnnoise::dsl::*;
2851 let mut strips = HashMap::<u32, Self>::new();
2852 if fname == "" {
2853 match Self::all() {
2854 None => {
2855 error!("Unable to retrive ANY TrackerStripCMNNoise Data (pulser)");
2856 return Ok(strips);
2857 }
2858 Some(_strips) => {
2859 for k in _strips {
2860 strips.insert(k.strip_id as u32, k);
2861 }
2862 return Ok(strips);
2863 }
2864 }
2865 }
2866 let mut conn = connect_to_db()?;
2867 match tof_db_trackerstripcmnnoise.filter(
2868 schema::tof_db_trackerstripcmnnoise::name.eq(fname)).load::<Self>(&mut conn) {
2869 Err(err) => {
2870 error!("We can't find any tracker strip common noise information with that name in the database! {err}");
2871 return Ok(strips);
2872 }
2873 Ok(peds_) => {
2874 for s in peds_ {
2875 strips.insert(s.strip_id as u32, s );
2876 }
2877 }
2878 }
2879 return Ok(strips);
2880 }
2881
2882 /// Get all tracker strip transfer functions from the database
2883 ///
2884 /// # Returns:
2885 /// * HashMap<u32 [strip id], TrackeStripTransferFunction>
2886 pub fn all() -> Option<Vec<Self>> {
2887 use schema::tof_db_trackerstripcmnnoise::dsl::*;
2888 let mut conn = connect_to_db().ok()?;
2889 match tof_db_trackerstripcmnnoise.load::<Self>(&mut conn) {
2890 Err(err) => {
2891 error!("Unable to load tracker transfer functions from db! {err}");
2892 return None;
2893 }
2894 Ok(strips) => {
2895 return Some(strips);
2896 }
2897 }
2898 }
2899}
2900
2901impl fmt::Display for TrackerStripCmnNoise {
2902 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2903 let mut repr = format!("<TrackerStripCmnNoise [{}]:", self.strip_id);
2904 repr += &(format!("\n vid : {}", self.volume_id));
2905 repr += "\n UTC Timestamps (Begin/End):";
2906 repr += &(format!("\n {}/{}", self.utc_timestamp_start, self.utc_timestamp_stop));
2907 if self.gain_is_mean {
2908 repr += &(String::from("\n -- Gain is mean value!"));
2909 }
2910 if self.pulse_is_mean {
2911 repr += &(String::from("\n -- Pulse is mean value!"));
2912 }
2913 if self.name.is_some() {
2914 repr += &(format!("\n name : {}", self.name.clone().unwrap()));
2915 }
2916 repr += &(format!("\n gain : {} pulse ch : {} pulse avg : {}>", self.gain, self.pulse_chn, self.pulse_avg));
2917 write!(f, "{}", repr)
2918 }
2919}
2920
2921
2922
2923#[cfg(feature="pybindings")]
2924#[pymethods]
2925impl TrackerStripCmnNoise {
2926
2927 #[staticmethod]
2928 #[pyo3(name="all")]
2929 pub fn all_py() -> Option<Vec<Self>> {
2930 Self::all()
2931 }
2932
2933 #[staticmethod]
2934 #[pyo3(name="all_names")]
2935 /// Get all names for registered datasets. These
2936 /// can be used in .as_dict_by_name() to query
2937 /// the db for a set of values
2938 pub fn all_names_py() -> Option<Vec<String>> {
2939 match Self::all_names() {
2940 Err(_) => {
2941 return None;
2942 }
2943 Ok(names) => {
2944 return Some(names);
2945 }
2946 }
2947 }
2948
2949 #[staticmethod]
2950 #[pyo3(name="as_dict_by_name")]
2951 pub fn all_as_dict_py(name : &str) -> Option<HashMap<u32,Self>> {
2952 match Self::as_dict_by_name(name) {
2953 Err(err) => {
2954 error!("Unable to retrieve tracker strip cmn noise dictionary. {err}. Did you laod the setup-env.sh shell?");
2955 return None;
2956 }
2957 Ok(_data) => {
2958 return Some(_data);
2959 }
2960 }
2961 }
2962
2963 #[getter]
2964 fn get_strip_id (&self) -> i32 {
2965 self.strip_id
2966 }
2967
2968 #[getter]
2969 fn get_volume_id (&self) -> i64 {
2970 self.volume_id
2971 }
2972
2973 #[getter]
2974 fn get_utc_timestamp_start(&self) -> i64 {
2975 self.utc_timestamp_start
2976 }
2977
2978 #[getter]
2979 fn get_utc_timestamp_stop(&self) -> i64 {
2980 self.utc_timestamp_stop
2981 }
2982
2983 #[getter]
2984 fn get_name(&self) -> Option<String> {
2985 self.name.clone()
2986 }
2987
2988 #[getter]
2989 fn get_gain(&self) -> f32 {
2990 self.gain
2991 }
2992
2993 #[getter]
2994 fn get_pulse_cn(&self) -> u32 {
2995 self.pulse_chn as u32
2996 }
2997
2998 #[getter]
2999 fn get_gain_is_mean(&self) -> bool {
3000 self.gain_is_mean
3001 }
3002
3003 #[getter]
3004 fn get_pulse_is_mean(&self) -> bool {
3005 self.pulse_is_mean
3006 }
3007
3008 #[getter]
3009 fn get_pulse_avg(&self) -> f32 {
3010 self.pulse_avg
3011 }
3012
3013 //fn get_common_level(&self, adc : f32) -> f32 {
3014 // self.common_level(adc)
3015 //}
3016
3017}
3018
3019#[cfg(feature="pybindings")]
3020pythonize!(TrackerStripCmnNoise);
3021
3022//-------------------------------------------------
3023
3024#[derive(Debug, Queryable, Selectable)]
3025#[diesel(table_name = schema::calibration_files)]
3026#[diesel(primary_key(id))]
3027#[allow(non_snake_case)]
3028#[cfg_attr(feature="pybindings", pyclass)]
3029pub struct TrackerCalibrationFile {
3030 pub id : i32,
3031 pub file_type : TrackerCalibrationFileType,
3032 pub path : String,
3033 pub from_timestamp : i64,
3034 pub to_timestamp : i64,
3035}
3036
3037impl TrackerCalibrationFile {
3038 pub fn new() -> Self {
3039 Self {
3040 id : 0,
3041 file_type : TrackerCalibrationFileType::Unknown,
3042 path : String::from(""),
3043 from_timestamp : 0,
3044 to_timestamp : 0,
3045 }
3046 }
3047}
3048
3049impl Default for TrackerCalibrationFile {
3050 fn default() -> Self {
3051 Self::new()
3052 }
3053}
3054
3055impl fmt::Display for TrackerCalibrationFile {
3056 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3057 let mut repr = String::from("<TrackerCalibrationFile:");
3058 repr += &(format!("\n id : {}", self.id));
3059 repr += &(format!("\n file_type : {}", self.file_type));
3060 repr += &(format!("\n path : {}", self.path));
3061 repr += &(format!("\n from ts : {} [{}]", self.from_timestamp, get_utc_timestamp_from_unix(self.from_timestamp as f64).unwrap()));
3062 repr += &(format!("\n to ts : {} [{}]", self.to_timestamp, get_utc_timestamp_from_unix(self.to_timestamp as f64).unwrap()));
3063 write!(f, "{}", repr)
3064 }
3065}
3066
3067#[cfg(feature="pybindings")]
3068pythonize!(TrackerCalibrationFile);
3069
3070#[cfg(feature="pybindings")]
3071#[pymethods]
3072impl TrackerCalibrationFile {
3073
3074 #[getter]
3075 fn get_id(&self) -> i32 {
3076 self.id
3077 }
3078
3079 #[getter]
3080 fn get_file_type(&self) -> TrackerCalibrationFileType {
3081 self.file_type
3082 }
3083
3084#[getter]
3085 fn get_path(&self) -> String {
3086 self.path.clone()
3087 }
3088
3089#[getter]
3090 fn get_from_timestamp(&self) -> i64 {
3091 self.from_timestamp
3092 }
3093
3094#[getter]
3095 fn get_to_timestamp(&self) -> i64 {
3096 self.to_timestamp
3097 }
3098}
3099
3100//-------------------------------------------------
3101
3102//
3103//
3104//
3105//
3106//// Summary of DSI/J/LTBCH (0-319)
3107//// This is not "official" but provides a way of indexing all
3108//// the individual channels
3109//#[derive(Debug,PartialEq,Queryable, Selectable)]
3110//#[diesel(table_name = schema::tof_db_mtbchannel)]
3111//#[diesel(primary_key(mtb_ch))]
3112//#[allow(non_snake_case)]
3113//pub struct MTBChannel {
3114// pub mtb_ch : i64,
3115// pub dsi : Option<i16>,
3116// pub j : Option<i16>,
3117// pub ltb_id : Option<i16>,
3118// pub ltb_ch : Option<i16>,
3119// pub rb_id : Option<i16>,
3120// pub rb_ch : Option<i16>,
3121// pub mtb_link_id : Option<i16>,
3122// pub paddle_id : Option<i16>,
3123// pub paddle_isA : Option<bool>,
3124// pub hg_ch : Option<i16>,
3125// pub lg_ch : Option<i16>,
3126//}
3127//
3128//impl MTBChannel {
3129//
3130// pub fn new() -> Self {
3131// Self {
3132// mtb_ch : -1,
3133// dsi : None,
3134// j : None,
3135// ltb_id : None,
3136// ltb_ch : None,
3137// rb_id : None,
3138// rb_ch : None,
3139// mtb_link_id : None,
3140// paddle_id : None,
3141// paddle_isA : None,
3142// hg_ch : None,
3143// lg_ch : None,
3144// }
3145// }
3146//
3147// pub fn all(conn: &mut SqliteConnection) -> Option<Vec<MTBChannel>> {
3148// use schema::tof_db_mtbchannel::dsl::*;
3149// match tof_db_mtbchannel.load::<MTBChannel>(conn) {
3150// Err(err) => {
3151// error!("Unable to load RATs from db! {err}");
3152// return None;
3153// }
3154// Ok(mtbch) => {
3155// return Some(mtbch);
3156// }
3157// }
3158// }
3159//}
3160//
3161//
3162//impl fmt::Display for MTBChannel {
3163// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3164// let mut repr = String::from("<MTBChannel");
3165// repr += &(format!("\n Channel ID : {}", self.mtb_ch));
3166// repr += &(format!("\n DSI/J/ : {}/{}", self.dsi.unwrap_or(-1), self.j.unwrap_or(-1)));
3167// repr += "\n LTB ID/CH => RB ID/CH";
3168// repr += &(format!("\n |-> {}/{} => {}/{}", self.ltb_id.unwrap_or(-1), self.ltb_ch.unwrap_or(-1), self.rb_id.unwrap_or(-1), self.rb_ch.unwrap_or(-1)));
3169// repr += &(format!("\n MTB Link ID [RB] : {}", self.mtb_link_id.unwrap_or(-1)));
3170// repr += "\n LG CH => HG CH";
3171// repr += &(format!("\n |-> {} => {}", self.lg_ch.unwrap_or(-1), self.hg_ch.unwrap_or(-1)));
3172// repr += &(format!("\n Paddle Id: {}", self.paddle_id.unwrap_or(-1)));
3173// let mut pend = "None";
3174// if !self.paddle_isA.is_none() {
3175// if self.paddle_isA.unwrap() {
3176// pend = "A";
3177// } else {
3178// pend = "B";
3179// }
3180// }
3181// repr += &(format!("\n Paddle End: {}>", pend));
3182// write!(f, "{}", repr)
3183// }
3184//}
3185//
3186//
3187/////////////////////////////////////////////////////
3188////
3189//// The following models exceed a bit the capabilities
3190//// of Diesel, or my Diesel skill.
3191//// These models contain multiple ForeignKeys, in all
3192//// cases these link to the paddle table.
3193////
3194//// For each of LocalTriggerBoard, ReadoutBoard, Panel
3195//// we have 2 structs:
3196//// One called DB<entity> and the other <entity>. The
3197//// first does have the ForeignKeys as SmallInt, and
3198//// the latter looks them up and fills in the blanks
3199////
3200////
3201////
3202//
3203///// The DB wrapper for the LocalTriggerBoard, for
3204///// easy implementation there are no joins, we do
3205///// them manually in the public implementation
3206///// of the LocaltriggerBoard
3207//#[derive(Queryable, Selectable, Identifiable, Associations)]
3208//#[diesel(table_name = schema::tof_db_localtriggerboard)]
3209//#[diesel(primary_key(board_id))]
3210//#[diesel(belongs_to(Paddle, foreign_key=paddle1_id))]
3211//pub struct DBLocalTriggerBoard {
3212// pub board_id : i16,
3213// pub dsi : Option<i16>,
3214// pub j : Option<i16>,
3215// pub rat : Option<i16>,
3216// pub ltb_id : Option<i16>,
3217// pub cable_len : f32,
3218// pub paddle1_id : Option<i16>,
3219// pub paddle2_id : Option<i16>,
3220// pub paddle3_id : Option<i16>,
3221// pub paddle4_id : Option<i16>,
3222// pub paddle5_id : Option<i16>,
3223// pub paddle6_id : Option<i16>,
3224// pub paddle7_id : Option<i16>,
3225// pub paddle8_id : Option<i16>,
3226//}
3227//
3228//impl DBLocalTriggerBoard {
3229//
3230// //pub fn new() -> Self {
3231// // Self {
3232// // board_id : 0,
3233// // dsi : None,
3234// // j : None,
3235// // rat : None,
3236// // ltb_id : None,
3237// // cable_len : 0.0,
3238// // paddle1_id : None,
3239// // paddle2_id : None,
3240// // paddle3_id : None,
3241// // paddle4_id : None,
3242// // paddle5_id : None,
3243// // paddle6_id : None,
3244// // paddle7_id : None,
3245// // paddle8_id : None,
3246// // }
3247// //}
3248//
3249// /// True if sane dsi and j values are
3250// /// assigned to this board
3251// pub fn connected(&self) -> bool {
3252// self.dsi != None && self.j != None
3253// }
3254//
3255// /// True if all fields are filled with
3256// /// reasonable values and not the default
3257// pub fn valid(&self) -> bool {
3258// self.board_id > 0 &&
3259// self.dsi .is_some() &&
3260// self.j .is_some() &&
3261// self.rat .is_some() &&
3262// // right now, we explicitly don't care
3263// // about the ltb_id
3264// //self.ltb_id .is_some() &&
3265// self.cable_len > 0.0 &&
3266// self.paddle1_id.is_some() &&
3267// self.paddle2_id.is_some() &&
3268// self.paddle3_id.is_some() &&
3269// self.paddle4_id.is_some() &&
3270// self.paddle5_id.is_some() &&
3271// self.paddle6_id.is_some() &&
3272// self.paddle7_id.is_some() &&
3273// self.paddle8_id.is_some()
3274// }
3275//
3276// pub fn all(conn: &mut SqliteConnection) -> Option<Vec<DBLocalTriggerBoard>> {
3277// use schema::tof_db_localtriggerboard::dsl::*;
3278// match tof_db_localtriggerboard
3279// //.inner_join(tof_db_localtriggerboard.on(schema::tof_db_paddle::dsl::paddle_id.eq(schema::tof_db_localtriggerboard::dsl::paddle1_id)))
3280// .load::<DBLocalTriggerBoard>(conn) {
3281// Err(err) => {
3282// error!("Unable to load LocalTriggerBoards from db! {err}");
3283// return None;
3284// }
3285// Ok(ltbs) => {
3286// return Some(ltbs);
3287// }
3288// }
3289// }
3290//}
3291//
3292//impl fmt::Display for DBLocalTriggerBoard {
3293// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3294// let mut repr : String;
3295// if !self.connected() {
3296// repr = format!("<DBLocalTriggerBoard: ID {} - UNCONNECTED>", self.board_id);
3297// } else {
3298// repr = String::from("<DBLocalTriggerBoard:");
3299// repr += &(format!("\n LTB ID : {}", self.board_id));
3300// }
3301// repr += &(format!("\n DSI/J : {}/{}", self.dsi.unwrap(), self.j.unwrap()));
3302// repr += &(format!("\n RAT ID : {}", self.rat.unwrap()));
3303// repr += "\n H. cable len (MTB connection):";
3304// repr += &(format!("\n -> {}", self.cable_len));
3305// repr += "\n -- -- -- -- -- -- -- -- -- -- -- -- -- --";
3306// repr += "\n Paddle IDs:";
3307// repr += &(format!("\n {:02}", self.paddle1_id.unwrap_or(-1)));
3308// repr += &(format!("\n {:02}", self.paddle2_id.unwrap_or(-1)));
3309// repr += &(format!("\n {:02}", self.paddle3_id.unwrap_or(-1)));
3310// repr += &(format!("\n {:02}", self.paddle4_id.unwrap_or(-1)));
3311// repr += &(format!("\n {:02}", self.paddle5_id.unwrap_or(-1)));
3312// repr += &(format!("\n {:02}", self.paddle6_id.unwrap_or(-1)));
3313// repr += &(format!("\n {:02}", self.paddle7_id.unwrap_or(-1)));
3314// repr += &(format!("\n {:02}", self.paddle8_id.unwrap_or(-1)));
3315// write!(f, "{}", repr)
3316// }
3317//}
3318//
3319//#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
3320//pub struct LocalTriggerBoard {
3321// pub board_id : u8,
3322// pub dsi : u8,
3323// pub j : u8,
3324// pub rat : u8,
3325// pub ltb_id : u8,
3326// pub cable_len : f32,
3327// pub paddle1 : Paddle,
3328// pub paddle2 : Paddle,
3329// pub paddle3 : Paddle,
3330// pub paddle4 : Paddle,
3331// pub paddle5 : Paddle,
3332// pub paddle6 : Paddle,
3333// pub paddle7 : Paddle,
3334// pub paddle8 : Paddle,
3335//}
3336//
3337//impl LocalTriggerBoard {
3338//
3339// pub fn new() -> Self {
3340// Self {
3341// board_id : 0,
3342// dsi : 0,
3343// j : 0,
3344// rat : 0,
3345// ltb_id : 0,
3346// cable_len : 0.0,
3347// paddle1 : Paddle::new(),
3348// paddle2 : Paddle::new(),
3349// paddle3 : Paddle::new(),
3350// paddle4 : Paddle::new(),
3351// paddle5 : Paddle::new(),
3352// paddle6 : Paddle::new(),
3353// paddle7 : Paddle::new(),
3354// paddle8 : Paddle::new(),
3355// }
3356// }
3357//
3358// pub fn all(conn: &mut SqliteConnection) -> Option<Vec<LocalTriggerBoard>> {
3359// use schema::tof_db_localtriggerboard::dsl::*;
3360// let db_ltbs : Vec<DBLocalTriggerBoard>;
3361// match tof_db_localtriggerboard
3362// //.inner_join(tof_db_localtriggerboard.on(schema::tof_db_paddle::dsl::paddle_id.eq(schema::tof_db_localtriggerboard::dsl::paddle1_id)))
3363// .load::<DBLocalTriggerBoard>(conn) {
3364// Err(err) => {
3365// error!("Unable to load LocalTriggerBoards from db! {err}");
3366// return None;
3367// }
3368// Ok(ltbs) => {
3369// db_ltbs = ltbs;
3370// }
3371// }
3372// let paddles_op = Paddle::all(conn);
3373// match paddles_op {
3374// None => {
3375// return None;
3376// }
3377// Some(_) => ()
3378// }
3379// let paddles = paddles_op.unwrap();
3380// // This is not the best and fastest, but since our diesel skills
3381// // are a merely 3, we can't do it right now.
3382// let mut ltbs = Vec::<LocalTriggerBoard>::new();
3383// //println!("Iterating over {} ltbs in the DB!", db_ltbs.len());
3384// for dbltb in db_ltbs {
3385// let mut ltb = LocalTriggerBoard::new();
3386// for pdl in paddles.iter() {
3387// // this call ensures that the following unwraps
3388// // go through
3389// if !dbltb.valid() {
3390// error!("Got unpopulated LTB from DB for LTB {}", dbltb);
3391// continue;
3392// }
3393// if pdl.paddle_id == dbltb.paddle1_id.unwrap() {
3394// ltb.board_id = dbltb.board_id as u8;
3395// ltb.dsi = dbltb.dsi.unwrap_or(0) as u8;
3396// ltb.j = dbltb.j.unwrap_or(0) as u8;
3397// ltb.rat = dbltb.rat.unwrap_or(0) as u8;
3398// ltb.ltb_id = dbltb.ltb_id.unwrap_or(0) as u8;
3399// ltb.cable_len = dbltb.cable_len;
3400// ltb.paddle1 = pdl.clone();
3401// }
3402// if pdl.paddle_id == dbltb.paddle2_id.unwrap() {
3403// ltb.paddle2 = pdl.clone();
3404// }
3405// if pdl.paddle_id == dbltb.paddle3_id.unwrap() {
3406// ltb.paddle3 = pdl.clone();
3407// }
3408// if pdl.paddle_id == dbltb.paddle4_id.unwrap() {
3409// ltb.paddle4 = pdl.clone();
3410// }
3411// if pdl.paddle_id == dbltb.paddle5_id.unwrap() {
3412// ltb.paddle5 = pdl.clone();
3413// }
3414// if pdl.paddle_id == dbltb.paddle6_id.unwrap() {
3415// ltb.paddle6 = pdl.clone();
3416// }
3417// if pdl.paddle_id == dbltb.paddle7_id.unwrap() {
3418// ltb.paddle7 = pdl.clone();
3419// }
3420// if pdl.paddle_id == dbltb.paddle8_id.unwrap() {
3421// ltb.paddle8 = pdl.clone();
3422// }
3423// }
3424// ltbs.push(ltb);
3425// }
3426// Some(ltbs)
3427// }
3428//}
3429//
3430//impl fmt::Display for LocalTriggerBoard {
3431// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3432// let mut repr : String;
3433// repr = String::from("<LocalTriggerBoard:");
3434// repr += &(format!("\n LTB ID : {}", self.board_id));
3435// repr += &(format!("\n DSI/J : {}/{}", self.dsi, self.j));
3436// repr += &(format!("\n RAT ID : {}", self.rat));
3437// repr += "\n H. cable len (MTB connection):";
3438// repr += &(format!("\n -> {}", self.cable_len));
3439// repr += "\n -- -- -- -- -- -- -- -- -- -- -- -- -- --";
3440// repr += "\n LTB Ch -> RB Id, RB chn, Pdl ID, Pan ID:";
3441// repr += &(format!("\n {:02} | {},{} | {:03} | {:02}", self.paddle1.rb_id, self.paddle1.rb_chA, self.paddle1.rb_chB, self.paddle1.paddle_id, self.paddle1.panel_id));
3442// repr += &(format!("\n {:02} | {},{} | {:03} | {:02}", self.paddle2.rb_id, self.paddle2.rb_chA, self.paddle2.rb_chB, self.paddle2.paddle_id, self.paddle2.panel_id));
3443// repr += &(format!("\n {:02} | {},{} | {:03} | {:02}", self.paddle3.rb_id, self.paddle3.rb_chA, self.paddle3.rb_chB, self.paddle3.paddle_id, self.paddle3.panel_id));
3444// repr += &(format!("\n {:02} | {},{} | {:03} | {:02}", self.paddle4.rb_id, self.paddle4.rb_chA, self.paddle4.rb_chB, self.paddle4.paddle_id, self.paddle4.panel_id));
3445// repr += &(format!("\n {:02} | {},{} | {:03} | {:02}", self.paddle5.rb_id, self.paddle5.rb_chA, self.paddle5.rb_chB, self.paddle5.paddle_id, self.paddle5.panel_id));
3446// repr += &(format!("\n {:02} | {},{} | {:03} | {:02}", self.paddle6.rb_id, self.paddle6.rb_chA, self.paddle6.rb_chB, self.paddle6.paddle_id, self.paddle6.panel_id));
3447// repr += &(format!("\n {:02} | {},{} | {:03} | {:02}", self.paddle7.rb_id, self.paddle7.rb_chA, self.paddle7.rb_chB, self.paddle7.paddle_id, self.paddle7.panel_id));
3448// repr += &(format!("\n {:02} | {},{} | {:03} | {:02}>", self.paddle8.rb_id, self.paddle8.rb_chA, self.paddle8.rb_chB, self.paddle8.paddle_id, self.paddle8.panel_id));
3449// write!(f, "{}", repr)
3450// }
3451//}
3452//
3453///// A Readoutboard with paddles connected
3454/////
3455//#[derive(Debug,PartialEq, Clone,Queryable, Selectable, serde::Serialize, serde::Deserialize)]
3456//#[diesel(table_name = schema::tof_db_readoutboard)]
3457//#[diesel(primary_key(rb_id_id))]
3458//#[allow(non_snake_case)]
3459//pub struct DBReadoutBoard {
3460// // FIXME - this HAS TO BE (MUST!) the same order
3461// // as in schema.rs !!
3462// pub rb_id : i16,
3463// pub dsi : i16,
3464// pub j : i16,
3465// pub mtb_link_id : i16,
3466// pub paddle12_chA : Option<i16>,
3467// pub paddle34_chA : Option<i16>,
3468// pub paddle56_chA : Option<i16>,
3469// pub paddle78_chA : Option<i16>,
3470// pub paddle12_id : Option<i16>,
3471// pub paddle34_id : Option<i16>,
3472// pub paddle56_id : Option<i16>,
3473// pub paddle78_id : Option<i16>,
3474//}
3475//
3476//impl DBReadoutBoard {
3477// pub fn all(conn: &mut SqliteConnection) -> Option<Vec<DBReadoutBoard>> {
3478// use schema::tof_db_readoutboard::dsl::*;
3479// match tof_db_readoutboard
3480// //.inner_join(tof_db_localtriggerboard.on(schema::tof_db_paddle::dsl::paddle_id.eq(schema::tof_db_localtriggerboard::dsl::paddle1_id)))
3481// .load::<DBReadoutBoard>(conn) {
3482// Err(err) => {
3483// error!("Unable to load ReadoutBoards from db! {err}");
3484// return None;
3485// }
3486// Ok(rbs) => {
3487// return Some(rbs);
3488// }
3489// }
3490// }
3491//}
3492//
3493//impl fmt::Display for DBReadoutBoard {
3494// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3495// let mut repr = String::from("<ReadoutBoard:");
3496// repr += &(format!("\n Board id : {}",self.rb_id));
3497// repr += &(format!("\n MTB Link ID : {}",self.mtb_link_id));
3498// repr += &(format!("\n DSI/J : {}/{}",self.dsi,self.j));
3499// repr += "\n **Connected paddles**";
3500// repr += &(format!("\n Ch0/1(1/2) : {}", self.paddle12_id.unwrap_or(-1)));
3501// repr += &(format!("\n Ch1/2(2/3) : {}", self.paddle34_id.unwrap_or(-1)));
3502// repr += &(format!("\n Ch2/3(3/4) : {}", self.paddle56_id.unwrap_or(-1)));
3503// repr += &(format!("\n Ch3/4(4/5) : {}>",self.paddle78_id.unwrap_or(-1)));
3504// write!(f, "{}", repr)
3505// }
3506//}
3507//
3508///// A Readoutboard with paddles connected
3509//#[derive(Debug, Clone)]
3510//#[allow(non_snake_case)]
3511//pub struct ReadoutBoard {
3512// pub rb_id : u8,
3513// pub dsi : u8,
3514// pub j : u8,
3515// pub mtb_link_id : u8,
3516// pub paddle12 : Paddle,
3517// pub paddle12_chA : u8,
3518// pub paddle34 : Paddle,
3519// pub paddle34_chA : u8,
3520// pub paddle56 : Paddle,
3521// pub paddle56_chA : u8,
3522// pub paddle78 : Paddle,
3523// pub paddle78_chA : u8,
3524// // extra stuff, not from the db
3525// // or maybe in the future?
3526// pub calib_file_path : String,
3527// pub calibration : RBCalibrations,
3528//}
3529//
3530//impl ReadoutBoard {
3531//
3532// pub fn new() -> Self {
3533// Self {
3534// rb_id : 0,
3535// dsi : 0,
3536// j : 0,
3537// mtb_link_id : 0,
3538// paddle12 : Paddle::new(),
3539// paddle12_chA : 0,
3540// paddle34 : Paddle::new(),
3541// paddle34_chA : 0,
3542// paddle56 : Paddle::new(),
3543// paddle56_chA : 0,
3544// paddle78 : Paddle::new(),
3545// paddle78_chA : 0,
3546// calib_file_path : String::from(""),
3547// calibration : RBCalibrations::new(0),
3548// }
3549// }
3550//
3551// /// Returns the ip address following a convention
3552// ///
3553// /// This does NOT GUARANTEE that the address is correct!
3554// pub fn guess_address(&self) -> String {
3555// format!("tcp://10.0.1.1{:02}:42000", self.rb_id)
3556// }
3557//
3558// pub fn get_paddle_ids(&self) -> [u8;4] {
3559// let pid0 = self.paddle12.paddle_id as u8;
3560// let pid1 = self.paddle34.paddle_id as u8;
3561// let pid2 = self.paddle56.paddle_id as u8;
3562// let pid3 = self.paddle78.paddle_id as u8;
3563// [pid0, pid1, pid2, pid3]
3564// }
3565//
3566// #[allow(non_snake_case)]
3567// pub fn get_A_sides(&self) -> [u8;4] {
3568// let pa_0 = self.paddle12_chA;
3569// let pa_1 = self.paddle34_chA;
3570// let pa_2 = self.paddle56_chA;
3571// let pa_3 = self.paddle78_chA;
3572// [pa_0, pa_1, pa_2, pa_3]
3573// }
3574//
3575// #[allow(non_snake_case)]
3576// pub fn get_pid_rbchA(&self, pid : u8) -> Option<u8> {
3577// if self.paddle12.paddle_id as u8 == pid {
3578// let rv = self.paddle12.rb_chA as u8;
3579// return Some(rv);
3580// } else if self.paddle34.paddle_id as u8 == pid {
3581// let rv = self.paddle34.rb_chA as u8;
3582// return Some(rv);
3583// } else if self.paddle56.paddle_id as u8 == pid {
3584// let rv = self.paddle56.rb_chA as u8;
3585// return Some(rv);
3586// } else if self.paddle78.paddle_id as u8== pid {
3587// let rv = self.paddle78.rb_chA as u8;
3588// return Some(rv);
3589// } else {
3590// return None;
3591// }
3592// }
3593//
3594// #[allow(non_snake_case)]
3595// pub fn get_pid_rbchB(&self, pid : u8) -> Option<u8> {
3596// if self.paddle12.paddle_id as u8 == pid {
3597// let rv = self.paddle12.rb_chB as u8;
3598// return Some(rv);
3599// } else if self.paddle34.paddle_id as u8== pid {
3600// let rv = self.paddle34.rb_chB as u8;
3601// return Some(rv);
3602// } else if self.paddle56.paddle_id as u8== pid {
3603// let rv = self.paddle56.rb_chB as u8;
3604// return Some(rv);
3605// } else if self.paddle78.paddle_id as u8 == pid {
3606// let rv = self.paddle78.rb_chB as u8;
3607// return Some(rv);
3608// } else {
3609// return None;
3610// }
3611// }
3612//
3613// pub fn get_paddle_length(&self, pid : u8) -> Option<f32> {
3614// if self.paddle12.paddle_id as u8 == pid {
3615// let rv = self.paddle12.length;
3616// return Some(rv);
3617// } else if self.paddle34.paddle_id as u8== pid {
3618// let rv = self.paddle34.length;
3619// return Some(rv);
3620// } else if self.paddle56.paddle_id as u8== pid {
3621// let rv = self.paddle56.length;
3622// return Some(rv);
3623// } else if self.paddle78.paddle_id as u8 == pid {
3624// let rv = self.paddle78.length;
3625// return Some(rv);
3626// } else {
3627// return None;
3628// }
3629// }
3630//
3631// pub fn all(conn: &mut SqliteConnection) -> Option<Vec<ReadoutBoard>> {
3632// use schema::tof_db_readoutboard::dsl::*;
3633// let db_rbs : Vec<DBReadoutBoard>;
3634// match tof_db_readoutboard
3635// //.inner_join(tof_db_localtriggerboard.on(schema::tof_db_paddle::dsl::paddle_id.eq(schema::tof_db_localtriggerboard::dsl::paddle1_id)))
3636// .load::<DBReadoutBoard>(conn) {
3637// Err(err) => {
3638// error!("Unable to load ReadoutBoards from db! {err}");
3639// return None;
3640// }
3641// Ok(rbs) => {
3642// db_rbs = rbs;
3643// }
3644// }
3645// let paddles_op = Paddle::all(conn);
3646// match paddles_op {
3647// None => {
3648// return None;
3649// }
3650// Some(_) => ()
3651// }
3652// let paddles = paddles_op.unwrap();
3653// // This is not the best and fastest, but since our diesel skills
3654// // are a merely 3, we can't do it right now.
3655// let mut rbs = Vec::<ReadoutBoard>::new();
3656// //println!("Iterating over {} rbs in the DB!", db_rbs.len());
3657// for dbrb in db_rbs {
3658// let mut rb = ReadoutBoard::new();
3659// rb.rb_id = dbrb.rb_id as u8;
3660// rb.dsi = dbrb.dsi as u8;
3661// rb.j = dbrb.j as u8;
3662// rb.mtb_link_id = dbrb.mtb_link_id as u8;
3663// rb.paddle12_chA = dbrb.paddle12_chA.unwrap() as u8;
3664// rb.paddle34_chA = dbrb.paddle34_chA.unwrap() as u8;
3665// rb.paddle56_chA = dbrb.paddle56_chA.unwrap() as u8;
3666// rb.paddle78_chA = dbrb.paddle78_chA.unwrap() as u8;
3667// for pdl in paddles.iter() {
3668// // this call ensures that the following unwraps
3669// // go through
3670// //if !dbltb.valid() {
3671// // error!("Got unpopulated LTB from DB for LTB {}", dbltb);
3672// // continue;
3673// //}
3674// if pdl.paddle_id == dbrb.paddle12_id.unwrap_or(0) {
3675// rb.paddle12 = pdl.clone();
3676// }
3677// if pdl.paddle_id == dbrb.paddle34_id.unwrap_or(0) {
3678// rb.paddle34 = pdl.clone();
3679// }
3680// if pdl.paddle_id == dbrb.paddle56_id.unwrap_or(0) {
3681// rb.paddle56 = pdl.clone();
3682// }
3683// if pdl.paddle_id == dbrb.paddle78_id.unwrap_or(0) {
3684// rb.paddle78 = pdl.clone();
3685// }
3686// }
3687// rbs.push(rb);
3688// }
3689// Some(rbs)
3690// }
3691//
3692// // FIXME - better query
3693// pub fn where_rbid(conn: &mut SqliteConnection, rb_id : u8) -> Option<ReadoutBoard> {
3694// let all = ReadoutBoard::all(conn)?;
3695// for rb in all {
3696// if rb.rb_id == rb_id {
3697// return Some(rb);
3698// }
3699// }
3700// None
3701// }
3702//
3703// pub fn to_summary_str(&self) -> String {
3704// let mut repr = String::from("<ReadoutBoard:");
3705// repr += &(format!("\n Board id : {}",self.rb_id));
3706// repr += &(format!("\n MTB Link ID : {}",self.mtb_link_id));
3707// repr += &(format!("\n RAT : {}",self.paddle12.ltb_id));
3708// repr += &(format!("\n DSI/J : {}/{}",self.dsi,self.j));
3709// repr += "\n **Connected paddles**";
3710// repr += &(format!("\n Channel 1/2 : {:02} (panel {:01})", self.paddle12.paddle_id, self.paddle12.panel_id));
3711// repr += &(format!("\n Channel 3/4 : {:02} (panel {:01})", self.paddle34.paddle_id, self.paddle34.panel_id));
3712// repr += &(format!("\n Channel 5/6 : {:02} (panel {:01})", self.paddle56.paddle_id, self.paddle56.panel_id));
3713// repr += &(format!("\n Channel 7/8 : {:02} (panel {:01})", self.paddle78.paddle_id, self.paddle78.panel_id));
3714// repr
3715// }
3716//
3717// /// Load the newest calibration from the calibration file path
3718// pub fn load_latest_calibration(&mut self) -> Result<(), Box<dyn std::error::Error>> {
3719// // files look like RB20_2024_01_26-08_15_54.cali.tof.gaps
3720// //let re = Regex::new(r"(\d{4}_\d{2}_\d{2}-\d{2}_\d{2}_\d{2})")?;
3721// let re = Regex::new(r"(\d{6}_\d{6})")?;
3722// // Define your file pattern (e.g., "logs/*.log" for all .log files in the logs directory)
3723// let pattern = format!("{}/RB{:02}_*", self.calib_file_path, self.rb_id); // Adjust this pattern to your files' naming convention
3724// let timestamp = DateTime::<Utc>::from_timestamp(0,0).unwrap(); // I am not sure what to do here
3725// // otherwise than unwrap. How is
3726// // this allowed to fail?
3727// //let mut newest_file = (String::from(""), NaiveDateTime::from_timestamp(0, 0));
3728// let mut newest_file = (String::from(""), timestamp);
3729//
3730// // Iterate over files that match the pattern
3731// let mut filename : String;
3732// for entry in glob(&pattern)? {
3733// if let Ok(path) = entry {
3734// // Get the filename as a string
3735// //let cpath = path.clone();
3736// match path.file_name() {
3737// None => continue,
3738// Some(fname) => {
3739// // the expect might be ok, since this is something done during initialization
3740// filename = fname.to_os_string().into_string().expect("Unwrapping filename failed!");
3741// }
3742// }
3743// if let Some(caps) = re.captures(&filename) {
3744// if let Some(timestamp_str) = caps.get(0).map(|m| m.as_str()) {
3745// //println!("timestamp_str {}, {}",timestamp_str, HUMAN_TIMESTAMP_FORMAT);
3746// //let timestamp = NaiveDateTime::parse_from_str(timestamp_str, "%Y_%m_%d-%H_%M_%S")?;
3747// //let timestamp = DateTime::<Utc>::parse_from_str(timestamp_str, "%Y_%m_%d-%H_%M_%S")?;
3748// let footzstring = format!("{}+0000", timestamp_str);
3749// let timestamp = DateTime::parse_from_str(&footzstring, "%y%m%d_%H%M%S%z")?;
3750// //let timestamp = DateTime::parse_from_str(&footzstring, HUMAN_TIMESTAMP_FORMAT)?;
3751// //println!("parse successful");
3752// //let _timestamp = DateTime
3753// if timestamp > newest_file.1 {
3754// // FIXME - into might panic?
3755// newest_file.1 = timestamp.into();
3756// newest_file.0 = filename.clone();
3757// }
3758// }
3759// }
3760// }
3761// }
3762//
3763// if newest_file.0.is_empty() {
3764// error!("No matching calibration available for board {}!", self.rb_id);
3765// } else {
3766// let file_to_load = format!("{}/{}", self.calib_file_path, newest_file.0);
3767// info!("Loading calibration from file: {}", file_to_load);
3768// self.calibration = RBCalibrations::from_file(file_to_load, true)?;
3769// }
3770// Ok(())
3771// }
3772//}
3773//
3774//impl fmt::Display for ReadoutBoard {
3775// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3776// let mut repr = String::from("<ReadoutBoard:");
3777// repr += &(format!("\n Board id : {}",self.rb_id));
3778// repr += &(format!("\n MTB Link ID : {}",self.mtb_link_id));
3779// repr += &(format!("\n DSI/J : {}/{}",self.dsi,self.j));
3780// repr += "\n **Connected paddles**";
3781// repr += &(format!("\n Ch0/1(1/2) : {}",self.paddle12));
3782// repr += &(format!("\n A-side : {}", self.paddle12_chA));
3783// repr += &(format!("\n Ch1/2(2/3) : {}",self.paddle34));
3784// repr += &(format!("\n A-side : {}", self.paddle34_chA));
3785// repr += &(format!("\n Ch2/3(3/4) : {}",self.paddle56));
3786// repr += &(format!("\n A-side : {}", self.paddle56_chA));
3787// repr += &(format!("\n Ch3/4(4/5) : {}>",self.paddle78));
3788// repr += &(format!("\n A-side : {}", self.paddle78_chA));
3789// repr += "** calibration will be loaded from this path:";
3790// repr += &(format!("\n \u{021B3} {}", self.calib_file_path));
3791// repr += &(format!("\n calibration : {}>", self.calibration));
3792// write!(f, "{}", repr)
3793// }
3794//}
3795//
3796//
3797///// A TOF Panel is a larger unit of paddles next to each other
3798/////
3799///// TOF faces (e.g. Umbrella) can have multiple Panels
3800//#[derive(Debug, Clone,Queryable, Selectable)]
3801//#[diesel(table_name = schema::tof_db_panel)]
3802//#[diesel(primary_key(panel_id))]
3803//pub struct DBPanel {
3804// // ORDER OF THESE FIELDS HAS TO BE THE SAME AS IN schema.rs!!
3805// pub panel_id : i16 ,
3806// pub description : String ,
3807// pub normal_x : i16 ,
3808// pub normal_y : i16 ,
3809// pub normal_z : i16 ,
3810// pub dw_paddle : Option<i16>,
3811// pub dh_paddle : Option<i16>,
3812// pub paddle0_id : Option<i16>,
3813// pub paddle1_id : Option<i16>,
3814// pub paddle10_id : Option<i16>,
3815// pub paddle11_id : Option<i16>,
3816// pub paddle2_id : Option<i16>,
3817// pub paddle3_id : Option<i16>,
3818// pub paddle4_id : Option<i16>,
3819// pub paddle5_id : Option<i16>,
3820// pub paddle6_id : Option<i16>,
3821// pub paddle7_id : Option<i16>,
3822// pub paddle8_id : Option<i16>,
3823// pub paddle9_id : Option<i16>,
3824//}
3825//
3826//impl DBPanel {
3827//
3828// pub fn valid(&self) -> bool {
3829// self.panel_id > 0 &&
3830// self.description != String::from("") &&
3831// self.paddle0_id.is_some()
3832// }
3833//
3834// pub fn all(conn: &mut SqliteConnection) -> Option<Vec<DBPanel>> {
3835// use schema::tof_db_panel::dsl::*;
3836// match tof_db_panel
3837// //.inner_join(tof_db_localtriggerboard.on(schema::tof_db_paddle::dsl::paddle_id.eq(schema::tof_db_localtriggerboard::dsl::paddle1_id)))
3838// .load::<DBPanel>(conn) {
3839// Err(err) => {
3840// error!("Unable to load Panels from db! {err}");
3841// return None;
3842// }
3843// // dirty mind check
3844// Ok(pnls) => {
3845// return Some(pnls);
3846// }
3847// }
3848// }
3849//
3850// pub fn get_npaddles(&self) -> u8 {
3851// let mut npaddles = 0u8;
3852// if self.paddle0_id.is_some() {
3853// npaddles += 1;
3854// }
3855// if self.paddle1_id.is_some() {
3856// npaddles += 1;
3857// }
3858// if self.paddle2_id.is_some() {
3859// npaddles += 1;
3860// }
3861// if self.paddle3_id.is_some() {
3862// npaddles += 1;
3863// }
3864// if self.paddle4_id.is_some() {
3865// npaddles += 1;
3866// }
3867// if self.paddle5_id.is_some() {
3868// npaddles += 1;
3869// }
3870// if self.paddle6_id.is_some() {
3871// npaddles += 1;
3872// }
3873// if self.paddle7_id.is_some() {
3874// npaddles += 1;
3875// }
3876// if self.paddle8_id.is_some() {
3877// npaddles += 1;
3878// }
3879// if self.paddle9_id.is_some() {
3880// npaddles += 1;
3881// }
3882// if self.paddle10_id.is_some() {
3883// npaddles += 1;
3884// }
3885// if self.paddle11_id.is_some() {
3886// npaddles += 1;
3887// }
3888// npaddles
3889// }
3890//}
3891//
3892//impl fmt::Display for DBPanel {
3893// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3894// let mut repr = String::from("<DBPanel");
3895// repr += &(format!("\n id : {}",self.panel_id));
3896// repr += &(format!("\n descr : {}",self.description));
3897// repr += "\n orientation:";
3898// repr += &(format!("\n [{},{},{}]", self.normal_x, self.normal_y, self.normal_z));
3899// repr += &(format!("\n paddle list ({}) paddles)", self.get_npaddles()));
3900// if self.paddle0_id.is_some() {
3901// repr += &(format!("\n {}",self.paddle0_id.unwrap()));
3902// }
3903// if self.paddle1_id.is_some() {
3904// repr += &(format!("\n {}",self.paddle1_id.unwrap()));
3905// }
3906// if self.paddle2_id.is_some() {
3907// repr += &(format!("\n {}",self.paddle2_id.unwrap()));
3908// }
3909// if self.paddle3_id.is_some() {
3910// repr += &(format!("\n {}",self.paddle3_id.unwrap()));
3911// }
3912// if self.paddle4_id.is_some() {
3913// repr += &(format!("\n {}",self.paddle4_id.unwrap()));
3914// }
3915// if self.paddle5_id.is_some() {
3916// repr += &(format!("\n {}",self.paddle5_id.unwrap()));
3917// }
3918// if self.paddle6_id.is_some() {
3919// repr += &(format!("\n {}",self.paddle6_id.unwrap()));
3920// }
3921// if self.paddle7_id.is_some() {
3922// repr += &(format!("\n {}",self.paddle7_id.unwrap()));
3923// }
3924// if self.paddle8_id.is_some() {
3925// repr += &(format!("\n {}",self.paddle8_id.unwrap()));
3926// }
3927// if self.paddle9_id.is_some() {
3928// repr += &(format!("\n {}",self.paddle9_id.unwrap()));
3929// }
3930// if self.paddle10_id.is_some() {
3931// repr += &(format!("\n {}",self.paddle10_id.unwrap()));
3932// }
3933// if self.paddle11_id.is_some() {
3934// repr += &(format!("\n {}",self.paddle11_id.unwrap()));
3935// }
3936// repr += ">";
3937// write!(f, "{}", repr)
3938// }
3939//}
3940//
3941//pub struct Panel {
3942// pub panel_id : u8 ,
3943// pub description : String ,
3944// pub normal_x : u8 ,
3945// pub normal_y : u8 ,
3946// pub normal_z : u8 ,
3947// pub paddle0 : Paddle,
3948// pub paddle1 : Option<Paddle>,
3949// pub paddle2 : Option<Paddle>,
3950// pub paddle3 : Option<Paddle>,
3951// pub paddle4 : Option<Paddle>,
3952// pub paddle5 : Option<Paddle>,
3953// pub paddle6 : Option<Paddle>,
3954// pub paddle7 : Option<Paddle>,
3955// pub paddle8 : Option<Paddle>,
3956// pub paddle9 : Option<Paddle>,
3957// pub paddle10 : Option<Paddle>,
3958// pub paddle11 : Option<Paddle>,
3959// // FIXME - these are for the future
3960// // when we are buiding the geometry
3961// // from the database
3962// //pub dh_paddle : Option<>,
3963// //pub dw_paddle : Option<>,
3964//}
3965//
3966//impl Panel {
3967//
3968// pub fn new() -> Self {
3969// Self {
3970// panel_id : 0 ,
3971// description : String::from(""),
3972// normal_x : 0 ,
3973// normal_y : 0 ,
3974// normal_z : 0 ,
3975// paddle0 : Paddle::new(),
3976// paddle1 : None,
3977// paddle2 : None,
3978// paddle3 : None,
3979// paddle4 : None,
3980// paddle5 : None,
3981// paddle6 : None,
3982// paddle7 : None,
3983// paddle8 : None,
3984// paddle9 : None,
3985// paddle10 : None,
3986// paddle11 : None,
3987// }
3988// }
3989//
3990//
3991// pub fn get_npaddles(&self) -> u8 {
3992// let mut npaddles = 1u8;
3993// if self.paddle1.is_some() {
3994// npaddles += 1;
3995// }
3996// if self.paddle2.is_some() {
3997// npaddles += 1;
3998// }
3999// if self.paddle3.is_some() {
4000// npaddles += 1;
4001// }
4002// if self.paddle4.is_some() {
4003// npaddles += 1;
4004// }
4005// if self.paddle5.is_some() {
4006// npaddles += 1;
4007// }
4008// if self.paddle6.is_some() {
4009// npaddles += 1;
4010// }
4011// if self.paddle7.is_some() {
4012// npaddles += 1;
4013// }
4014// if self.paddle8.is_some() {
4015// npaddles += 1;
4016// }
4017// if self.paddle9.is_some() {
4018// npaddles += 1;
4019// }
4020// if self.paddle10.is_some() {
4021// npaddles += 1;
4022// }
4023// if self.paddle11.is_some() {
4024// npaddles += 1;
4025// }
4026// npaddles
4027// }
4028//
4029// pub fn all(conn: &mut SqliteConnection) -> Option<Vec<Panel>> {
4030// use schema::tof_db_panel::dsl::*;
4031// let db_panels : Vec<DBPanel>;
4032// match tof_db_panel
4033// //.inner_join(tof_db_localtriggerboard.on(schema::tof_db_paddle::dsl::paddle_id.eq(schema::tof_db_localtriggerboard::dsl::paddle1_id)))
4034// .load::<DBPanel>(conn) {
4035// Err(err) => {
4036// error!("Unable to load Panels from db! {err}");
4037// return None;
4038// }
4039// Ok(pnls) => {
4040// db_panels = pnls;
4041// }
4042// }
4043// let paddles_op = Paddle::all(conn);
4044// match paddles_op {
4045// None => {
4046// return None;
4047// }
4048// Some(_) => ()
4049// }
4050// let paddles = paddles_op.unwrap();
4051// // This is not the best and fastest, but since our diesel skills
4052// // are a merely 3, we can't do it right now.
4053// let mut panels = Vec::<Panel>::new();
4054// println!("Iterating over {} panels in the DB!", db_panels.len());
4055// for dbpanel in db_panels {
4056// let mut pnl = Panel::new();
4057// for pdl in paddles.iter() {
4058// // this call ensures that the following unwraps
4059// // go through
4060// if !dbpanel.valid() {
4061// error!("Got unpopulated Panel from DB for Panel {}", dbpanel);
4062// continue;
4063// }
4064// if pdl.paddle_id == dbpanel.paddle0_id.unwrap() {
4065// pnl.panel_id = dbpanel.panel_id as u8;
4066// pnl.description = dbpanel.description.clone();
4067// pnl.normal_x = dbpanel.normal_x as u8;
4068// pnl.normal_y = dbpanel.normal_y as u8;
4069// pnl.normal_z = dbpanel.normal_z as u8;
4070// pnl.paddle0 = pdl.clone();
4071// }
4072// if pdl.paddle_id == dbpanel.paddle1_id.unwrap() {
4073// pnl.paddle1 = Some(pdl.clone());
4074// }
4075// if pdl.paddle_id == dbpanel.paddle2_id.unwrap() {
4076// pnl.paddle2 = Some(pdl.clone());
4077// }
4078// if pdl.paddle_id == dbpanel.paddle3_id.unwrap() {
4079// pnl.paddle3 = Some(pdl.clone());
4080// }
4081// if pdl.paddle_id == dbpanel.paddle4_id.unwrap() {
4082// pnl.paddle4 = Some(pdl.clone());
4083// }
4084// if pdl.paddle_id == dbpanel.paddle5_id.unwrap() {
4085// pnl.paddle5 = Some(pdl.clone());
4086// }
4087// if pdl.paddle_id == dbpanel.paddle6_id.unwrap() {
4088// pnl.paddle6 = Some(pdl.clone());
4089// }
4090// if pdl.paddle_id == dbpanel.paddle7_id.unwrap() {
4091// pnl.paddle7 = Some(pdl.clone());
4092// }
4093// if pdl.paddle_id == dbpanel.paddle8_id.unwrap() {
4094// pnl.paddle8 = Some(pdl.clone());
4095// }
4096// if pdl.paddle_id == dbpanel.paddle9_id.unwrap() {
4097// pnl.paddle9 = Some(pdl.clone());
4098// }
4099// if pdl.paddle_id == dbpanel.paddle10_id.unwrap() {
4100// pnl.paddle10 = Some(pdl.clone());
4101// }
4102// if pdl.paddle_id == dbpanel.paddle11_id.unwrap() {
4103// pnl.paddle11 = Some(pdl.clone());
4104// }
4105// }
4106// panels.push(pnl);
4107// }
4108// Some(panels)
4109// }
4110//}
4111//
4112//impl fmt::Display for Panel {
4113// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4114// let mut repr = String::from("<Panel");
4115// repr += &(format!("\n id : {}",self.panel_id));
4116// repr += &(format!("\n descr : {}",self.description));
4117// repr += "\n orientation:";
4118// repr += &(format!("\n [{},{},{}]", self.normal_x, self.normal_y, self.normal_z));
4119// repr += &(format!("\n paddle list ({}) paddles)", self.get_npaddles()));
4120// repr += &(format!("\n {}",self.paddle0));
4121// if self.paddle1.is_some() {
4122// repr += &(format!("\n {}",self.paddle1.as_ref().unwrap()));
4123// }
4124// if self.paddle2.is_some() {
4125// repr += &(format!("\n {}",self.paddle2.as_ref().unwrap()));
4126// }
4127// if self.paddle3.is_some() {
4128// repr += &(format!("\n {}",self.paddle3.as_ref().unwrap()));
4129// }
4130// if self.paddle4.is_some() {
4131// repr += &(format!("\n {}",self.paddle4.as_ref().unwrap()));
4132// }
4133// if self.paddle5.is_some() {
4134// repr += &(format!("\n {}",self.paddle5.as_ref().unwrap()));
4135// }
4136// if self.paddle6.is_some() {
4137// repr += &(format!("\n {}",self.paddle6.as_ref().unwrap()));
4138// }
4139// if self.paddle7.is_some() {
4140// repr += &(format!("\n {}",self.paddle7.as_ref().unwrap()));
4141// }
4142// if self.paddle8.is_some() {
4143// repr += &(format!("\n {}",self.paddle8.as_ref().unwrap()));
4144// }
4145// if self.paddle9.is_some() {
4146// repr += &(format!("\n {}",self.paddle9.as_ref().unwrap()));
4147// }
4148// if self.paddle10.is_some() {
4149// repr += &(format!("\n {}",self.paddle10.as_ref().unwrap()));
4150// }
4151// if self.paddle11.is_some() {
4152// repr += &(format!("\n {}",self.paddle11.as_ref().unwrap()));
4153// }
4154// repr += ">";
4155// write!(f, "{}", repr)
4156// }
4157//}
4158//
4159//
4160//
4161