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