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}
2270
2271impl TofPaddleTimingConstant {
2272
2273 pub fn new() -> Self {
2274 Self {
2275 data_id : 0,
2276 paddle_id : 0,
2277 volume_id : 0,
2278 utc_timestamp_start : 0,
2279 utc_timestamp_stop : 0,
2280 name : None,
2281 version : None,
2282 timing_constant : 0.0,
2283 }
2284 }
2285
2286 /// Retrieve the names under which the timing constants are
2287 /// saved
2288 pub fn all_names() -> Result<Vec<String>, ConnectionError> {
2289 let mut conn = connect_to_db()?;
2290 let mut names = Vec::<String>::new();
2291 let unique_names =
2292 schema::tof_db_tofpaddletimingconstant::table.select(
2293 schema::tof_db_tofpaddletimingconstant::name)
2294 .distinct()
2295 .load::<Option<String>>(&mut conn).expect("Error getting names from db!");
2296 for k in unique_names {
2297 if let Some(n) = k {
2298 names.push(n);
2299 }
2300 }
2301 Ok(names)
2302 }
2303
2304 /// Get Tof timing constants as associated with a distinct name
2305 ///
2306 /// # Returns:
2307 /// * HashMap<u32 \[paddle id\], Self>
2308 pub fn as_dict_by_name(fname : &str) -> Result<HashMap<u8,Self>, ConnectionError> {
2309 use schema::tof_db_tofpaddletimingconstant::dsl::*;
2310 let mut paddles = HashMap::<u8, Self>::new();
2311 if fname == "" {
2312 match Self::all() {
2313 None => {
2314 error!("Unable to retrive ANY TofPaddleTimingConstant");
2315 return Ok(paddles);
2316 }
2317 Some(_paddles) => {
2318 for k in _paddles {
2319 paddles.insert(k.paddle_id as u8, k);
2320 }
2321 return Ok(paddles);
2322 }
2323 }
2324 }
2325 let mut conn = connect_to_db()?;
2326 match tof_db_tofpaddletimingconstant.filter(
2327 schema::tof_db_tofpaddletimingconstant::name.eq(fname)).load::<Self>(&mut conn) {
2328 Err(err) => {
2329 error!("We can't find any TOF paddle timing constants in the database! {err}");
2330 return Ok(paddles);
2331 }
2332 Ok(paddles_) => {
2333 for p in paddles_ {
2334 paddles.insert(p.paddle_id as u8, p );
2335 }
2336 }
2337 }
2338 return Ok(paddles);
2339 }
2340
2341 /// Get all tracker strip mask from the database
2342 ///
2343 /// # Returns:
2344 /// * HashMap<u32 [strip id], TrackeStripMask>
2345 pub fn all() -> Option<Vec<Self>> {
2346 use schema::tof_db_tofpaddletimingconstant::dsl::*;
2347 let mut conn = connect_to_db().ok()?;
2348 match tof_db_tofpaddletimingconstant.load::<Self>(&mut conn) {
2349 Err(err) => {
2350 error!("Unable to load TOF paddle timing constants from db! {err}");
2351 return None;
2352 }
2353 Ok(tc) => {
2354 return Some(tc);
2355 }
2356 }
2357 }
2358}
2359
2360impl Default for TofPaddleTimingConstant {
2361 fn default() -> Self {
2362 Self::new()
2363 }
2364}
2365
2366impl fmt::Display for TofPaddleTimingConstant {
2367 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2368 let mut repr = format!("<TofPaddleTimingConstant [{}]:", self.paddle_id);
2369 repr += &(format!("\n vid : {}", self.volume_id));
2370 repr += "\n UTC Timestamps (Begin/End):";
2371 repr += &(format!("\n {}/{}", self.utc_timestamp_start, self.utc_timestamp_stop));
2372 if self.name.is_some() {
2373 repr += &(format!("\n name : {}", self.name.clone().unwrap()));
2374 }
2375 if self.version.is_some() {
2376 repr += &(format!("\n version : {}", self.version.unwrap()));
2377 }
2378 repr += &(format!("\n timing const. : {}", self.timing_constant));
2379 write!(f, "{}", repr)
2380 }
2381}
2382
2383#[cfg(feature="pybindings")]
2384#[pymethods]
2385impl TofPaddleTimingConstant {
2386
2387 #[staticmethod]
2388 #[pyo3(name="all")]
2389 pub fn all_py() -> Option<Vec<Self>> {
2390 Self::all()
2391 }
2392
2393 #[staticmethod]
2394 #[pyo3(name="all_names")]
2395 /// Get all names for registered datasets. These
2396 /// can be used in .as_dict_by_name() to query
2397 /// the db for a set of values
2398 pub fn all_names_py() -> Option<Vec<String>> {
2399 match Self::all_names() {
2400 Err(_) => {
2401 return None;
2402 }
2403 Ok(names) => {
2404 return Some(names);
2405 }
2406 }
2407 }
2408
2409 /// Get the TOF paddle timing constants as associated by a specific
2410 /// name
2411 ///
2412 /// # Arguments
2413 /// * name : The name the constants are associated with
2414 #[staticmethod]
2415 #[pyo3(name="as_dict_by_name")]
2416 pub fn all_as_dict_py(name : &str) -> Option<HashMap<u8,Self>> {
2417 match Self::as_dict_by_name(name) {
2418 Err(err) => {
2419 error!("Unable to retrieve TOF paddle timing constants dictionary. {err}. Did you laod the setup-env.sh shell?");
2420 return None;
2421 }
2422 Ok(_data) => {
2423 return Some(_data);
2424 }
2425 }
2426 }
2427
2428 #[getter]
2429 fn get_paddle_id (&self) -> i32 {
2430 self.paddle_id
2431 }
2432
2433 #[getter]
2434 fn get_volume_id (&self) -> i64 {
2435 self.volume_id
2436 }
2437
2438 #[getter]
2439 fn get_utc_timestamp_start(&self) -> i64 {
2440 self.utc_timestamp_start
2441 }
2442
2443 #[getter]
2444 fn get_utc_timestamp_stop(&self) -> i64 {
2445 self.utc_timestamp_stop
2446 }
2447
2448 #[getter]
2449 fn get_name (&self) -> Option<String> {
2450 self.name.clone()
2451 }
2452
2453 #[getter]
2454 fn get_version (&self) -> Option<i32> {
2455 self.version.clone()
2456 }
2457
2458 #[getter]
2459 fn get_timing_constant (&self) -> f32 {
2460 self.timing_constant
2461 }
2462}
2463
2464#[cfg(feature="pybindings")]
2465pythonize!(TofPaddleTimingConstant);
2466
2467//----------------------------------
2468
2469/// Measurement of tracker pedestal values for each strip
2470#[derive(Debug,PartialEq, Clone,Queryable, Selectable, serde::Serialize, serde::Deserialize)]
2471#[diesel(table_name = schema::tof_db_trackerstrippedestal)]
2472#[diesel(primary_key(data_id))]
2473#[allow(non_snake_case)]
2474#[cfg_attr(feature="pybindings", pyclass)]
2475pub struct TrackerStripPedestal {
2476 pub data_id : i32,
2477 pub strip_id : i32,
2478 pub volume_id : i64,
2479 pub utc_timestamp_start : i64,
2480 pub utc_timestamp_stop : i64,
2481 pub name : Option<String>,
2482 pub pedestal_mean : f32,
2483 pub pedestal_sigma : f32,
2484 pub is_mean_value : bool,
2485}
2486
2487impl TrackerStripPedestal {
2488
2489 pub fn new() -> Self {
2490 Self {
2491 data_id : 0,
2492 strip_id : 0,
2493 volume_id : 0,
2494 utc_timestamp_start : 0,
2495 utc_timestamp_stop : 0,
2496 name : None,
2497 pedestal_mean : 0.0,
2498 pedestal_sigma : 0.0,
2499 is_mean_value : false
2500 }
2501 }
2502
2503 /// Get Tracker strip pedestals for a certain dataset
2504 ///
2505 /// # Returns:
2506 /// * HashMap<u32 [strip id], TrackerStripMask>
2507 pub fn as_dict_by_name(fname : &str) -> Result<HashMap<u32,Self>, ConnectionError> {
2508 use schema::tof_db_trackerstrippedestal::dsl::*;
2509 let mut strips = HashMap::<u32, Self>::new();
2510 if fname == "" {
2511 match Self::all() {
2512 None => {
2513 error!("Unable to retrive ANY TrackerStripPedestal");
2514 return Ok(strips);
2515 }
2516 Some(_strips) => {
2517 for k in _strips {
2518 strips.insert(k.strip_id as u32, k);
2519 }
2520 return Ok(strips);
2521 }
2522 }
2523 }
2524 let mut conn = connect_to_db()?;
2525 match tof_db_trackerstrippedestal.filter(
2526 schema::tof_db_trackerstrippedestal::name.eq(fname)).load::<Self>(&mut conn) {
2527 Err(err) => {
2528 error!("We can't find any tracker strip masks in the database! {err}");
2529 return Ok(strips);
2530 }
2531 Ok(peds_) => {
2532 for s in peds_ {
2533 strips.insert(s.strip_id as u32, s );
2534 }
2535 }
2536 }
2537 return Ok(strips);
2538 }
2539
2540 pub fn all_names() -> Result<Vec<String>, ConnectionError> {
2541 let mut conn = connect_to_db()?;
2542 let mut names = Vec::<String>::new();
2543 let unique_names =
2544 schema::tof_db_trackerstrippedestal::table.select(
2545 schema::tof_db_trackerstrippedestal::name)
2546 .distinct()
2547 .load::<Option<String>>(&mut conn).expect("Error getting names from db!");
2548 for k in unique_names {
2549 if let Some(n) = k {
2550 names.push(n);
2551 }
2552 }
2553 Ok(names)
2554 }
2555
2556 /// Get all tracker strip mask from the database
2557 ///
2558 /// # Returns:
2559 /// * HashMap<u32 [strip id], TrackeStripMask>
2560 pub fn all() -> Option<Vec<Self>> {
2561 use schema::tof_db_trackerstrippedestal::dsl::*;
2562 let mut conn = connect_to_db().ok()?;
2563 match tof_db_trackerstrippedestal.load::<Self>(&mut conn) {
2564 Err(err) => {
2565 error!("Unable to load tracker strips pedestals from db! {err}");
2566 return None;
2567 }
2568 Ok(strips) => {
2569 return Some(strips);
2570 }
2571 }
2572 }
2573
2574 ///
2575 pub fn parse_from_file<P: AsRef<Path>>(path: P) -> io::Result<Vec<Self>> {
2576 let file = File::open(path)?;
2577 let reader = BufReader::new(file);
2578 let mut pedestals = Vec::<Self>::new();
2579 let hid_vid_map = get_hid_vid_maps().unwrap().1;
2580 for line in reader.lines() {
2581 let line = line?;
2582 if line.starts_with("#") || line.starts_with("Layer") || line.starts_with("layer") {
2583 continue;
2584 }
2585 let mut ped = TrackerStripPedestal::new();
2586 let parts: Vec<&str> = line.split_whitespace().collect();
2587 if parts.len() == 6 {
2588 // Parse the first number as a standard decimal
2589 let layer = parts[0].parse::<u8>()
2590 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
2591 let row = parts[1].parse::<u8>()
2592 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
2593 let module = parts[2].parse::<u8>()
2594 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
2595 let channel = parts[3].parse::<u8>()
2596 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
2597 ped.strip_id = TrackerStrip::create_stripid(layer, row, module, channel) as i32;
2598 ped.volume_id = *hid_vid_map.get(&(ped.strip_id as u32)).unwrap() as i64; // critical error is good here,
2599 // should alert the user
2600 ped.pedestal_mean = parts[4].parse::<f32>()
2601 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
2602 ped.pedestal_sigma = parts[5].parse::<f32>()
2603 .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
2604 pedestals.push(ped);
2605 }
2606 }
2607 Ok(pedestals)
2608 }
2609}
2610
2611impl Default for TrackerStripPedestal {
2612 fn default() -> Self {
2613 Self::new()
2614 }
2615}
2616
2617impl fmt::Display for TrackerStripPedestal {
2618 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2619 let mut repr = format!("<TrackerStripPedestal [{}]:", self.strip_id);
2620 repr += &(format!("\n vid : {}", self.volume_id));
2621 repr += "\n UTC Timestamps (Begin/End):";
2622 repr += &(format!("\n {}/{}", self.utc_timestamp_start, self.utc_timestamp_stop));
2623 if self.name.is_some() {
2624 repr += &(format!("\n name : {}", self.name.clone().unwrap()));
2625 }
2626 repr += &(format!("\n pedestal_mean : {}", self.pedestal_mean));
2627 repr += &(format!("\n pedestal_sigma : {}", self.pedestal_sigma));
2628 repr += &(format!("\n is_mean_value : {}", self.is_mean_value));
2629 write!(f, "{}", repr)
2630 }
2631}
2632
2633#[cfg(feature="pybindings")]
2634#[pymethods]
2635impl TrackerStripPedestal {
2636
2637 #[staticmethod]
2638 #[pyo3(name="parse_from_file")]
2639 fn parse_from_file_py(fname : &str) -> Option<Vec<Self>> {
2640 let result = Self::parse_from_file(fname);
2641 if result.is_ok() {
2642 return Some(result.unwrap());
2643 } else {
2644 error!("An error occured when parsing {} : '{}'", fname, result.unwrap_err());
2645 return None;
2646 }
2647 }
2648
2649 #[staticmethod]
2650 #[pyo3(name="all")]
2651 pub fn all_py() -> Option<Vec<Self>> {
2652 Self::all()
2653 }
2654
2655 #[staticmethod]
2656 #[pyo3(name="all_names")]
2657 /// Get all names for registered datasets. These
2658 /// can be used in .as_dict_by_name() to query
2659 /// the db for a set of values
2660 pub fn all_names_py() -> Option<Vec<String>> {
2661 match Self::all_names() {
2662 Err(_) => {
2663 return None;
2664 }
2665 Ok(names) => {
2666 return Some(names);
2667 }
2668 }
2669 }
2670
2671 #[staticmethod]
2672 #[pyo3(name="as_dict_by_name")]
2673 pub fn all_as_dict_py(name : &str) -> Option<HashMap<u32,Self>> {
2674 match Self::as_dict_by_name(name) {
2675 Err(err) => {
2676 error!("Unable to retrieve tracker strip pedestal dictionary. {err}. Did you laod the setup-env.sh shell?");
2677 return None;
2678 }
2679 Ok(_data) => {
2680 return Some(_data);
2681 }
2682 }
2683 }
2684
2685 #[getter]
2686 #[pyo3(name="name")]
2687 fn get_name_py (&self) -> Option<String> {
2688 self.name.clone()
2689 }
2690
2691 #[setter]
2692 #[pyo3(name="name")]
2693 fn set_name_py(&mut self, value : String) {
2694 self.name = Some(value);
2695 }
2696
2697 #[getter]
2698 fn get_strip_id (&self) -> i32 {
2699 self.strip_id
2700 }
2701
2702 #[getter]
2703 fn get_volume_id (&self) -> i64 {
2704 self.volume_id
2705 }
2706
2707 #[getter]
2708 fn get_utc_timestamp_start(&self) -> i64 {
2709 self.utc_timestamp_start
2710 }
2711
2712 #[getter]
2713 fn get_utc_timestamp_stop(&self) -> i64 {
2714 self.utc_timestamp_stop
2715 }
2716
2717 #[setter]
2718 fn set_utc_timestamp_start(&mut self, value : i64) {
2719 self.utc_timestamp_start = value;
2720 }
2721
2722 #[setter]
2723 fn set_utc_timestamp_stop(&mut self, value : i64) {
2724 self.utc_timestamp_stop = value;
2725 }
2726
2727 #[getter]
2728 fn get_pedestal_mean (&self) -> f32 {
2729 self.pedestal_mean
2730 }
2731
2732 #[getter]
2733 fn get_pedestal_sigam (&self) -> f32 {
2734 self.pedestal_sigma
2735 }
2736
2737 #[getter]
2738 fn get_is_mean_value (&self) -> bool {
2739 self.is_mean_value
2740 }
2741}
2742
2743#[cfg(feature="pybindings")]
2744pythonize!(TrackerStripPedestal);
2745
2746//-------------------------------------------------
2747
2748/// Common noise subtraction - pulse channels on the wafers and get the average adc.
2749/// The gain is available as well. Data from Mengjiao's group
2750#[derive(Debug,PartialEq, Clone,Queryable, Selectable, serde::Serialize, serde::Deserialize)]
2751#[diesel(table_name = schema::tof_db_trackerstripcmnnoise)]
2752#[diesel(primary_key(data_id))]
2753#[allow(non_snake_case)]
2754#[cfg_attr(feature="pybindings", pyclass)]
2755pub struct TrackerStripCmnNoise {
2756 pub data_id : i32,
2757 pub strip_id : i32,
2758 pub volume_id : i64,
2759 pub utc_timestamp_start : i64,
2760 pub utc_timestamp_stop : i64,
2761 pub name : Option<String>,
2762 pub gain : f32,
2763 pub pulse_chn : i32,
2764 pub pulse_avg : f32,
2765 pub gain_is_mean : bool,
2766 pub pulse_is_mean : bool,
2767}
2768
2769impl TrackerStripCmnNoise {
2770
2771 pub fn new() -> Self {
2772 Self {
2773 data_id : 0,
2774 strip_id : 0,
2775 volume_id : 0,
2776 utc_timestamp_start : 0,
2777 utc_timestamp_stop : 0,
2778 name : None,
2779 gain : 0.0,
2780 pulse_chn : 0,
2781 pulse_avg : 0.0,
2782 gain_is_mean : false,
2783 pulse_is_mean : false
2784 }
2785 }
2786
2787 pub fn all_names() -> Result<Vec<String>, ConnectionError> {
2788 let mut conn = connect_to_db()?;
2789 let mut names = Vec::<String>::new();
2790 let unique_names =
2791 schema::tof_db_trackerstripcmnnoise::table.select(
2792 schema::tof_db_trackerstripcmnnoise::name)
2793 .distinct()
2794 .load::<Option<String>>(&mut conn).expect("Error getting names from db!");
2795 for k in unique_names {
2796 if let Some(n) = k {
2797 names.push(n);
2798 }
2799 }
2800 Ok(names)
2801 }
2802
2803 /// Get Tracker strip cmn noise data for a certain dataset
2804 ///
2805 /// # Returns:
2806 /// * HashMap<u32 [strip id], TrackerStripTransferFn>
2807 pub fn as_dict_by_name(fname : &str) -> Result<HashMap<u32,Self>, ConnectionError> {
2808 use schema::tof_db_trackerstripcmnnoise::dsl::*;
2809 let mut strips = HashMap::<u32, Self>::new();
2810 if fname == "" {
2811 match Self::all() {
2812 None => {
2813 error!("Unable to retrive ANY TrackerStripCMNNoise Data (pulser)");
2814 return Ok(strips);
2815 }
2816 Some(_strips) => {
2817 for k in _strips {
2818 strips.insert(k.strip_id as u32, k);
2819 }
2820 return Ok(strips);
2821 }
2822 }
2823 }
2824 let mut conn = connect_to_db()?;
2825 match tof_db_trackerstripcmnnoise.filter(
2826 schema::tof_db_trackerstripcmnnoise::name.eq(fname)).load::<Self>(&mut conn) {
2827 Err(err) => {
2828 error!("We can't find any tracker strip common noise information with that name in the database! {err}");
2829 return Ok(strips);
2830 }
2831 Ok(peds_) => {
2832 for s in peds_ {
2833 strips.insert(s.strip_id as u32, s );
2834 }
2835 }
2836 }
2837 return Ok(strips);
2838 }
2839
2840 /// Get all tracker strip transfer functions from the database
2841 ///
2842 /// # Returns:
2843 /// * HashMap<u32 [strip id], TrackeStripTransferFunction>
2844 pub fn all() -> Option<Vec<Self>> {
2845 use schema::tof_db_trackerstripcmnnoise::dsl::*;
2846 let mut conn = connect_to_db().ok()?;
2847 match tof_db_trackerstripcmnnoise.load::<Self>(&mut conn) {
2848 Err(err) => {
2849 error!("Unable to load tracker transfer functions from db! {err}");
2850 return None;
2851 }
2852 Ok(strips) => {
2853 return Some(strips);
2854 }
2855 }
2856 }
2857}
2858
2859impl fmt::Display for TrackerStripCmnNoise {
2860 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2861 let mut repr = format!("<TrackerStripCmnNoise [{}]:", self.strip_id);
2862 repr += &(format!("\n vid : {}", self.volume_id));
2863 repr += "\n UTC Timestamps (Begin/End):";
2864 repr += &(format!("\n {}/{}", self.utc_timestamp_start, self.utc_timestamp_stop));
2865 if self.gain_is_mean {
2866 repr += &(String::from("\n -- Gain is mean value!"));
2867 }
2868 if self.pulse_is_mean {
2869 repr += &(String::from("\n -- Pulse is mean value!"));
2870 }
2871 if self.name.is_some() {
2872 repr += &(format!("\n name : {}", self.name.clone().unwrap()));
2873 }
2874 repr += &(format!("\n gain : {} pulse ch : {} pulse avg : {}>", self.gain, self.pulse_chn, self.pulse_avg));
2875 write!(f, "{}", repr)
2876 }
2877}
2878
2879
2880
2881#[cfg(feature="pybindings")]
2882#[pymethods]
2883impl TrackerStripCmnNoise {
2884
2885 #[staticmethod]
2886 #[pyo3(name="all")]
2887 pub fn all_py() -> Option<Vec<Self>> {
2888 Self::all()
2889 }
2890
2891 #[staticmethod]
2892 #[pyo3(name="all_names")]
2893 /// Get all names for registered datasets. These
2894 /// can be used in .as_dict_by_name() to query
2895 /// the db for a set of values
2896 pub fn all_names_py() -> Option<Vec<String>> {
2897 match Self::all_names() {
2898 Err(_) => {
2899 return None;
2900 }
2901 Ok(names) => {
2902 return Some(names);
2903 }
2904 }
2905 }
2906
2907 #[staticmethod]
2908 #[pyo3(name="as_dict_by_name")]
2909 pub fn all_as_dict_py(name : &str) -> Option<HashMap<u32,Self>> {
2910 match Self::as_dict_by_name(name) {
2911 Err(err) => {
2912 error!("Unable to retrieve tracker strip cmn noise dictionary. {err}. Did you laod the setup-env.sh shell?");
2913 return None;
2914 }
2915 Ok(_data) => {
2916 return Some(_data);
2917 }
2918 }
2919 }
2920
2921 #[getter]
2922 fn get_strip_id (&self) -> i32 {
2923 self.strip_id
2924 }
2925
2926 #[getter]
2927 fn get_volume_id (&self) -> i64 {
2928 self.volume_id
2929 }
2930
2931 #[getter]
2932 fn get_utc_timestamp_start(&self) -> i64 {
2933 self.utc_timestamp_start
2934 }
2935
2936 #[getter]
2937 fn get_utc_timestamp_stop(&self) -> i64 {
2938 self.utc_timestamp_stop
2939 }
2940
2941 #[getter]
2942 fn get_name(&self) -> Option<String> {
2943 self.name.clone()
2944 }
2945
2946 #[getter]
2947 fn get_gain(&self) -> f32 {
2948 self.gain
2949 }
2950
2951 #[getter]
2952 fn get_pulse_cn(&self) -> u32 {
2953 self.pulse_chn as u32
2954 }
2955
2956 #[getter]
2957 fn get_gain_is_mean(&self) -> bool {
2958 self.gain_is_mean
2959 }
2960
2961 #[getter]
2962 fn get_pulse_is_mean(&self) -> bool {
2963 self.pulse_is_mean
2964 }
2965
2966 #[getter]
2967 fn get_pulse_avg(&self) -> f32 {
2968 self.pulse_avg
2969 }
2970
2971 //fn get_common_level(&self, adc : f32) -> f32 {
2972 // self.common_level(adc)
2973 //}
2974
2975}
2976
2977#[cfg(feature="pybindings")]
2978pythonize!(TrackerStripCmnNoise);
2979
2980//-------------------------------------------------
2981
2982#[derive(Debug, Queryable, Selectable)]
2983#[diesel(table_name = schema::calibration_files)]
2984#[diesel(primary_key(id))]
2985#[allow(non_snake_case)]
2986#[cfg_attr(feature="pybindings", pyclass)]
2987pub struct TrackerCalibrationFile {
2988 pub id : i32,
2989 pub file_type : TrackerCalibrationFileType,
2990 pub path : String,
2991 pub from_timestamp : i64,
2992 pub to_timestamp : i64,
2993}
2994
2995impl TrackerCalibrationFile {
2996 pub fn new() -> Self {
2997 Self {
2998 id : 0,
2999 file_type : TrackerCalibrationFileType::Unknown,
3000 path : String::from(""),
3001 from_timestamp : 0,
3002 to_timestamp : 0,
3003 }
3004 }
3005}
3006
3007impl Default for TrackerCalibrationFile {
3008 fn default() -> Self {
3009 Self::new()
3010 }
3011}
3012
3013impl fmt::Display for TrackerCalibrationFile {
3014 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3015 let mut repr = String::from("<TrackerCalibrationFile:");
3016 repr += &(format!("\n id : {}", self.id));
3017 repr += &(format!("\n file_type : {}", self.file_type));
3018 repr += &(format!("\n path : {}", self.path));
3019 repr += &(format!("\n from ts : {} [{}]", self.from_timestamp, get_utc_timestamp_from_unix(self.from_timestamp as f64).unwrap()));
3020 repr += &(format!("\n to ts : {} [{}]", self.to_timestamp, get_utc_timestamp_from_unix(self.to_timestamp as f64).unwrap()));
3021 write!(f, "{}", repr)
3022 }
3023}
3024
3025#[cfg(feature="pybindings")]
3026pythonize!(TrackerCalibrationFile);
3027
3028#[cfg(feature="pybindings")]
3029#[pymethods]
3030impl TrackerCalibrationFile {
3031
3032 #[getter]
3033 fn get_id(&self) -> i32 {
3034 self.id
3035 }
3036
3037 #[getter]
3038 fn get_file_type(&self) -> TrackerCalibrationFileType {
3039 self.file_type
3040 }
3041
3042#[getter]
3043 fn get_path(&self) -> String {
3044 self.path.clone()
3045 }
3046
3047#[getter]
3048 fn get_from_timestamp(&self) -> i64 {
3049 self.from_timestamp
3050 }
3051
3052#[getter]
3053 fn get_to_timestamp(&self) -> i64 {
3054 self.to_timestamp
3055 }
3056}
3057
3058//-------------------------------------------------
3059
3060//
3061//
3062//
3063//
3064//// Summary of DSI/J/LTBCH (0-319)
3065//// This is not "official" but provides a way of indexing all
3066//// the individual channels
3067//#[derive(Debug,PartialEq,Queryable, Selectable)]
3068//#[diesel(table_name = schema::tof_db_mtbchannel)]
3069//#[diesel(primary_key(mtb_ch))]
3070//#[allow(non_snake_case)]
3071//pub struct MTBChannel {
3072// pub mtb_ch : i64,
3073// pub dsi : Option<i16>,
3074// pub j : Option<i16>,
3075// pub ltb_id : Option<i16>,
3076// pub ltb_ch : Option<i16>,
3077// pub rb_id : Option<i16>,
3078// pub rb_ch : Option<i16>,
3079// pub mtb_link_id : Option<i16>,
3080// pub paddle_id : Option<i16>,
3081// pub paddle_isA : Option<bool>,
3082// pub hg_ch : Option<i16>,
3083// pub lg_ch : Option<i16>,
3084//}
3085//
3086//impl MTBChannel {
3087//
3088// pub fn new() -> Self {
3089// Self {
3090// mtb_ch : -1,
3091// dsi : None,
3092// j : None,
3093// ltb_id : None,
3094// ltb_ch : None,
3095// rb_id : None,
3096// rb_ch : None,
3097// mtb_link_id : None,
3098// paddle_id : None,
3099// paddle_isA : None,
3100// hg_ch : None,
3101// lg_ch : None,
3102// }
3103// }
3104//
3105// pub fn all(conn: &mut SqliteConnection) -> Option<Vec<MTBChannel>> {
3106// use schema::tof_db_mtbchannel::dsl::*;
3107// match tof_db_mtbchannel.load::<MTBChannel>(conn) {
3108// Err(err) => {
3109// error!("Unable to load RATs from db! {err}");
3110// return None;
3111// }
3112// Ok(mtbch) => {
3113// return Some(mtbch);
3114// }
3115// }
3116// }
3117//}
3118//
3119//
3120//impl fmt::Display for MTBChannel {
3121// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3122// let mut repr = String::from("<MTBChannel");
3123// repr += &(format!("\n Channel ID : {}", self.mtb_ch));
3124// repr += &(format!("\n DSI/J/ : {}/{}", self.dsi.unwrap_or(-1), self.j.unwrap_or(-1)));
3125// repr += "\n LTB ID/CH => RB ID/CH";
3126// 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)));
3127// repr += &(format!("\n MTB Link ID [RB] : {}", self.mtb_link_id.unwrap_or(-1)));
3128// repr += "\n LG CH => HG CH";
3129// repr += &(format!("\n |-> {} => {}", self.lg_ch.unwrap_or(-1), self.hg_ch.unwrap_or(-1)));
3130// repr += &(format!("\n Paddle Id: {}", self.paddle_id.unwrap_or(-1)));
3131// let mut pend = "None";
3132// if !self.paddle_isA.is_none() {
3133// if self.paddle_isA.unwrap() {
3134// pend = "A";
3135// } else {
3136// pend = "B";
3137// }
3138// }
3139// repr += &(format!("\n Paddle End: {}>", pend));
3140// write!(f, "{}", repr)
3141// }
3142//}
3143//
3144//
3145/////////////////////////////////////////////////////
3146////
3147//// The following models exceed a bit the capabilities
3148//// of Diesel, or my Diesel skill.
3149//// These models contain multiple ForeignKeys, in all
3150//// cases these link to the paddle table.
3151////
3152//// For each of LocalTriggerBoard, ReadoutBoard, Panel
3153//// we have 2 structs:
3154//// One called DB<entity> and the other <entity>. The
3155//// first does have the ForeignKeys as SmallInt, and
3156//// the latter looks them up and fills in the blanks
3157////
3158////
3159////
3160//
3161///// The DB wrapper for the LocalTriggerBoard, for
3162///// easy implementation there are no joins, we do
3163///// them manually in the public implementation
3164///// of the LocaltriggerBoard
3165//#[derive(Queryable, Selectable, Identifiable, Associations)]
3166//#[diesel(table_name = schema::tof_db_localtriggerboard)]
3167//#[diesel(primary_key(board_id))]
3168//#[diesel(belongs_to(Paddle, foreign_key=paddle1_id))]
3169//pub struct DBLocalTriggerBoard {
3170// pub board_id : i16,
3171// pub dsi : Option<i16>,
3172// pub j : Option<i16>,
3173// pub rat : Option<i16>,
3174// pub ltb_id : Option<i16>,
3175// pub cable_len : f32,
3176// pub paddle1_id : Option<i16>,
3177// pub paddle2_id : Option<i16>,
3178// pub paddle3_id : Option<i16>,
3179// pub paddle4_id : Option<i16>,
3180// pub paddle5_id : Option<i16>,
3181// pub paddle6_id : Option<i16>,
3182// pub paddle7_id : Option<i16>,
3183// pub paddle8_id : Option<i16>,
3184//}
3185//
3186//impl DBLocalTriggerBoard {
3187//
3188// //pub fn new() -> Self {
3189// // Self {
3190// // board_id : 0,
3191// // dsi : None,
3192// // j : None,
3193// // rat : None,
3194// // ltb_id : None,
3195// // cable_len : 0.0,
3196// // paddle1_id : None,
3197// // paddle2_id : None,
3198// // paddle3_id : None,
3199// // paddle4_id : None,
3200// // paddle5_id : None,
3201// // paddle6_id : None,
3202// // paddle7_id : None,
3203// // paddle8_id : None,
3204// // }
3205// //}
3206//
3207// /// True if sane dsi and j values are
3208// /// assigned to this board
3209// pub fn connected(&self) -> bool {
3210// self.dsi != None && self.j != None
3211// }
3212//
3213// /// True if all fields are filled with
3214// /// reasonable values and not the default
3215// pub fn valid(&self) -> bool {
3216// self.board_id > 0 &&
3217// self.dsi .is_some() &&
3218// self.j .is_some() &&
3219// self.rat .is_some() &&
3220// // right now, we explicitly don't care
3221// // about the ltb_id
3222// //self.ltb_id .is_some() &&
3223// self.cable_len > 0.0 &&
3224// self.paddle1_id.is_some() &&
3225// self.paddle2_id.is_some() &&
3226// self.paddle3_id.is_some() &&
3227// self.paddle4_id.is_some() &&
3228// self.paddle5_id.is_some() &&
3229// self.paddle6_id.is_some() &&
3230// self.paddle7_id.is_some() &&
3231// self.paddle8_id.is_some()
3232// }
3233//
3234// pub fn all(conn: &mut SqliteConnection) -> Option<Vec<DBLocalTriggerBoard>> {
3235// use schema::tof_db_localtriggerboard::dsl::*;
3236// match tof_db_localtriggerboard
3237// //.inner_join(tof_db_localtriggerboard.on(schema::tof_db_paddle::dsl::paddle_id.eq(schema::tof_db_localtriggerboard::dsl::paddle1_id)))
3238// .load::<DBLocalTriggerBoard>(conn) {
3239// Err(err) => {
3240// error!("Unable to load LocalTriggerBoards from db! {err}");
3241// return None;
3242// }
3243// Ok(ltbs) => {
3244// return Some(ltbs);
3245// }
3246// }
3247// }
3248//}
3249//
3250//impl fmt::Display for DBLocalTriggerBoard {
3251// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3252// let mut repr : String;
3253// if !self.connected() {
3254// repr = format!("<DBLocalTriggerBoard: ID {} - UNCONNECTED>", self.board_id);
3255// } else {
3256// repr = String::from("<DBLocalTriggerBoard:");
3257// repr += &(format!("\n LTB ID : {}", self.board_id));
3258// }
3259// repr += &(format!("\n DSI/J : {}/{}", self.dsi.unwrap(), self.j.unwrap()));
3260// repr += &(format!("\n RAT ID : {}", self.rat.unwrap()));
3261// repr += "\n H. cable len (MTB connection):";
3262// repr += &(format!("\n -> {}", self.cable_len));
3263// repr += "\n -- -- -- -- -- -- -- -- -- -- -- -- -- --";
3264// repr += "\n Paddle IDs:";
3265// repr += &(format!("\n {:02}", self.paddle1_id.unwrap_or(-1)));
3266// repr += &(format!("\n {:02}", self.paddle2_id.unwrap_or(-1)));
3267// repr += &(format!("\n {:02}", self.paddle3_id.unwrap_or(-1)));
3268// repr += &(format!("\n {:02}", self.paddle4_id.unwrap_or(-1)));
3269// repr += &(format!("\n {:02}", self.paddle5_id.unwrap_or(-1)));
3270// repr += &(format!("\n {:02}", self.paddle6_id.unwrap_or(-1)));
3271// repr += &(format!("\n {:02}", self.paddle7_id.unwrap_or(-1)));
3272// repr += &(format!("\n {:02}", self.paddle8_id.unwrap_or(-1)));
3273// write!(f, "{}", repr)
3274// }
3275//}
3276//
3277//#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
3278//pub struct LocalTriggerBoard {
3279// pub board_id : u8,
3280// pub dsi : u8,
3281// pub j : u8,
3282// pub rat : u8,
3283// pub ltb_id : u8,
3284// pub cable_len : f32,
3285// pub paddle1 : Paddle,
3286// pub paddle2 : Paddle,
3287// pub paddle3 : Paddle,
3288// pub paddle4 : Paddle,
3289// pub paddle5 : Paddle,
3290// pub paddle6 : Paddle,
3291// pub paddle7 : Paddle,
3292// pub paddle8 : Paddle,
3293//}
3294//
3295//impl LocalTriggerBoard {
3296//
3297// pub fn new() -> Self {
3298// Self {
3299// board_id : 0,
3300// dsi : 0,
3301// j : 0,
3302// rat : 0,
3303// ltb_id : 0,
3304// cable_len : 0.0,
3305// paddle1 : Paddle::new(),
3306// paddle2 : Paddle::new(),
3307// paddle3 : Paddle::new(),
3308// paddle4 : Paddle::new(),
3309// paddle5 : Paddle::new(),
3310// paddle6 : Paddle::new(),
3311// paddle7 : Paddle::new(),
3312// paddle8 : Paddle::new(),
3313// }
3314// }
3315//
3316// pub fn all(conn: &mut SqliteConnection) -> Option<Vec<LocalTriggerBoard>> {
3317// use schema::tof_db_localtriggerboard::dsl::*;
3318// let db_ltbs : Vec<DBLocalTriggerBoard>;
3319// match tof_db_localtriggerboard
3320// //.inner_join(tof_db_localtriggerboard.on(schema::tof_db_paddle::dsl::paddle_id.eq(schema::tof_db_localtriggerboard::dsl::paddle1_id)))
3321// .load::<DBLocalTriggerBoard>(conn) {
3322// Err(err) => {
3323// error!("Unable to load LocalTriggerBoards from db! {err}");
3324// return None;
3325// }
3326// Ok(ltbs) => {
3327// db_ltbs = ltbs;
3328// }
3329// }
3330// let paddles_op = Paddle::all(conn);
3331// match paddles_op {
3332// None => {
3333// return None;
3334// }
3335// Some(_) => ()
3336// }
3337// let paddles = paddles_op.unwrap();
3338// // This is not the best and fastest, but since our diesel skills
3339// // are a merely 3, we can't do it right now.
3340// let mut ltbs = Vec::<LocalTriggerBoard>::new();
3341// //println!("Iterating over {} ltbs in the DB!", db_ltbs.len());
3342// for dbltb in db_ltbs {
3343// let mut ltb = LocalTriggerBoard::new();
3344// for pdl in paddles.iter() {
3345// // this call ensures that the following unwraps
3346// // go through
3347// if !dbltb.valid() {
3348// error!("Got unpopulated LTB from DB for LTB {}", dbltb);
3349// continue;
3350// }
3351// if pdl.paddle_id == dbltb.paddle1_id.unwrap() {
3352// ltb.board_id = dbltb.board_id as u8;
3353// ltb.dsi = dbltb.dsi.unwrap_or(0) as u8;
3354// ltb.j = dbltb.j.unwrap_or(0) as u8;
3355// ltb.rat = dbltb.rat.unwrap_or(0) as u8;
3356// ltb.ltb_id = dbltb.ltb_id.unwrap_or(0) as u8;
3357// ltb.cable_len = dbltb.cable_len;
3358// ltb.paddle1 = pdl.clone();
3359// }
3360// if pdl.paddle_id == dbltb.paddle2_id.unwrap() {
3361// ltb.paddle2 = pdl.clone();
3362// }
3363// if pdl.paddle_id == dbltb.paddle3_id.unwrap() {
3364// ltb.paddle3 = pdl.clone();
3365// }
3366// if pdl.paddle_id == dbltb.paddle4_id.unwrap() {
3367// ltb.paddle4 = pdl.clone();
3368// }
3369// if pdl.paddle_id == dbltb.paddle5_id.unwrap() {
3370// ltb.paddle5 = pdl.clone();
3371// }
3372// if pdl.paddle_id == dbltb.paddle6_id.unwrap() {
3373// ltb.paddle6 = pdl.clone();
3374// }
3375// if pdl.paddle_id == dbltb.paddle7_id.unwrap() {
3376// ltb.paddle7 = pdl.clone();
3377// }
3378// if pdl.paddle_id == dbltb.paddle8_id.unwrap() {
3379// ltb.paddle8 = pdl.clone();
3380// }
3381// }
3382// ltbs.push(ltb);
3383// }
3384// Some(ltbs)
3385// }
3386//}
3387//
3388//impl fmt::Display for LocalTriggerBoard {
3389// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3390// let mut repr : String;
3391// repr = String::from("<LocalTriggerBoard:");
3392// repr += &(format!("\n LTB ID : {}", self.board_id));
3393// repr += &(format!("\n DSI/J : {}/{}", self.dsi, self.j));
3394// repr += &(format!("\n RAT ID : {}", self.rat));
3395// repr += "\n H. cable len (MTB connection):";
3396// repr += &(format!("\n -> {}", self.cable_len));
3397// repr += "\n -- -- -- -- -- -- -- -- -- -- -- -- -- --";
3398// repr += "\n LTB Ch -> RB Id, RB chn, Pdl ID, Pan ID:";
3399// 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));
3400// 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));
3401// 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));
3402// 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));
3403// 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));
3404// 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));
3405// 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));
3406// 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));
3407// write!(f, "{}", repr)
3408// }
3409//}
3410//
3411///// A Readoutboard with paddles connected
3412/////
3413//#[derive(Debug,PartialEq, Clone,Queryable, Selectable, serde::Serialize, serde::Deserialize)]
3414//#[diesel(table_name = schema::tof_db_readoutboard)]
3415//#[diesel(primary_key(rb_id_id))]
3416//#[allow(non_snake_case)]
3417//pub struct DBReadoutBoard {
3418// // FIXME - this HAS TO BE (MUST!) the same order
3419// // as in schema.rs !!
3420// pub rb_id : i16,
3421// pub dsi : i16,
3422// pub j : i16,
3423// pub mtb_link_id : i16,
3424// pub paddle12_chA : Option<i16>,
3425// pub paddle34_chA : Option<i16>,
3426// pub paddle56_chA : Option<i16>,
3427// pub paddle78_chA : Option<i16>,
3428// pub paddle12_id : Option<i16>,
3429// pub paddle34_id : Option<i16>,
3430// pub paddle56_id : Option<i16>,
3431// pub paddle78_id : Option<i16>,
3432//}
3433//
3434//impl DBReadoutBoard {
3435// pub fn all(conn: &mut SqliteConnection) -> Option<Vec<DBReadoutBoard>> {
3436// use schema::tof_db_readoutboard::dsl::*;
3437// match tof_db_readoutboard
3438// //.inner_join(tof_db_localtriggerboard.on(schema::tof_db_paddle::dsl::paddle_id.eq(schema::tof_db_localtriggerboard::dsl::paddle1_id)))
3439// .load::<DBReadoutBoard>(conn) {
3440// Err(err) => {
3441// error!("Unable to load ReadoutBoards from db! {err}");
3442// return None;
3443// }
3444// Ok(rbs) => {
3445// return Some(rbs);
3446// }
3447// }
3448// }
3449//}
3450//
3451//impl fmt::Display for DBReadoutBoard {
3452// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3453// let mut repr = String::from("<ReadoutBoard:");
3454// repr += &(format!("\n Board id : {}",self.rb_id));
3455// repr += &(format!("\n MTB Link ID : {}",self.mtb_link_id));
3456// repr += &(format!("\n DSI/J : {}/{}",self.dsi,self.j));
3457// repr += "\n **Connected paddles**";
3458// repr += &(format!("\n Ch0/1(1/2) : {}", self.paddle12_id.unwrap_or(-1)));
3459// repr += &(format!("\n Ch1/2(2/3) : {}", self.paddle34_id.unwrap_or(-1)));
3460// repr += &(format!("\n Ch2/3(3/4) : {}", self.paddle56_id.unwrap_or(-1)));
3461// repr += &(format!("\n Ch3/4(4/5) : {}>",self.paddle78_id.unwrap_or(-1)));
3462// write!(f, "{}", repr)
3463// }
3464//}
3465//
3466///// A Readoutboard with paddles connected
3467//#[derive(Debug, Clone)]
3468//#[allow(non_snake_case)]
3469//pub struct ReadoutBoard {
3470// pub rb_id : u8,
3471// pub dsi : u8,
3472// pub j : u8,
3473// pub mtb_link_id : u8,
3474// pub paddle12 : Paddle,
3475// pub paddle12_chA : u8,
3476// pub paddle34 : Paddle,
3477// pub paddle34_chA : u8,
3478// pub paddle56 : Paddle,
3479// pub paddle56_chA : u8,
3480// pub paddle78 : Paddle,
3481// pub paddle78_chA : u8,
3482// // extra stuff, not from the db
3483// // or maybe in the future?
3484// pub calib_file_path : String,
3485// pub calibration : RBCalibrations,
3486//}
3487//
3488//impl ReadoutBoard {
3489//
3490// pub fn new() -> Self {
3491// Self {
3492// rb_id : 0,
3493// dsi : 0,
3494// j : 0,
3495// mtb_link_id : 0,
3496// paddle12 : Paddle::new(),
3497// paddle12_chA : 0,
3498// paddle34 : Paddle::new(),
3499// paddle34_chA : 0,
3500// paddle56 : Paddle::new(),
3501// paddle56_chA : 0,
3502// paddle78 : Paddle::new(),
3503// paddle78_chA : 0,
3504// calib_file_path : String::from(""),
3505// calibration : RBCalibrations::new(0),
3506// }
3507// }
3508//
3509// /// Returns the ip address following a convention
3510// ///
3511// /// This does NOT GUARANTEE that the address is correct!
3512// pub fn guess_address(&self) -> String {
3513// format!("tcp://10.0.1.1{:02}:42000", self.rb_id)
3514// }
3515//
3516// pub fn get_paddle_ids(&self) -> [u8;4] {
3517// let pid0 = self.paddle12.paddle_id as u8;
3518// let pid1 = self.paddle34.paddle_id as u8;
3519// let pid2 = self.paddle56.paddle_id as u8;
3520// let pid3 = self.paddle78.paddle_id as u8;
3521// [pid0, pid1, pid2, pid3]
3522// }
3523//
3524// #[allow(non_snake_case)]
3525// pub fn get_A_sides(&self) -> [u8;4] {
3526// let pa_0 = self.paddle12_chA;
3527// let pa_1 = self.paddle34_chA;
3528// let pa_2 = self.paddle56_chA;
3529// let pa_3 = self.paddle78_chA;
3530// [pa_0, pa_1, pa_2, pa_3]
3531// }
3532//
3533// #[allow(non_snake_case)]
3534// pub fn get_pid_rbchA(&self, pid : u8) -> Option<u8> {
3535// if self.paddle12.paddle_id as u8 == pid {
3536// let rv = self.paddle12.rb_chA as u8;
3537// return Some(rv);
3538// } else if self.paddle34.paddle_id as u8 == pid {
3539// let rv = self.paddle34.rb_chA as u8;
3540// return Some(rv);
3541// } else if self.paddle56.paddle_id as u8 == pid {
3542// let rv = self.paddle56.rb_chA as u8;
3543// return Some(rv);
3544// } else if self.paddle78.paddle_id as u8== pid {
3545// let rv = self.paddle78.rb_chA as u8;
3546// return Some(rv);
3547// } else {
3548// return None;
3549// }
3550// }
3551//
3552// #[allow(non_snake_case)]
3553// pub fn get_pid_rbchB(&self, pid : u8) -> Option<u8> {
3554// if self.paddle12.paddle_id as u8 == pid {
3555// let rv = self.paddle12.rb_chB as u8;
3556// return Some(rv);
3557// } else if self.paddle34.paddle_id as u8== pid {
3558// let rv = self.paddle34.rb_chB as u8;
3559// return Some(rv);
3560// } else if self.paddle56.paddle_id as u8== pid {
3561// let rv = self.paddle56.rb_chB as u8;
3562// return Some(rv);
3563// } else if self.paddle78.paddle_id as u8 == pid {
3564// let rv = self.paddle78.rb_chB as u8;
3565// return Some(rv);
3566// } else {
3567// return None;
3568// }
3569// }
3570//
3571// pub fn get_paddle_length(&self, pid : u8) -> Option<f32> {
3572// if self.paddle12.paddle_id as u8 == pid {
3573// let rv = self.paddle12.length;
3574// return Some(rv);
3575// } else if self.paddle34.paddle_id as u8== pid {
3576// let rv = self.paddle34.length;
3577// return Some(rv);
3578// } else if self.paddle56.paddle_id as u8== pid {
3579// let rv = self.paddle56.length;
3580// return Some(rv);
3581// } else if self.paddle78.paddle_id as u8 == pid {
3582// let rv = self.paddle78.length;
3583// return Some(rv);
3584// } else {
3585// return None;
3586// }
3587// }
3588//
3589// pub fn all(conn: &mut SqliteConnection) -> Option<Vec<ReadoutBoard>> {
3590// use schema::tof_db_readoutboard::dsl::*;
3591// let db_rbs : Vec<DBReadoutBoard>;
3592// match tof_db_readoutboard
3593// //.inner_join(tof_db_localtriggerboard.on(schema::tof_db_paddle::dsl::paddle_id.eq(schema::tof_db_localtriggerboard::dsl::paddle1_id)))
3594// .load::<DBReadoutBoard>(conn) {
3595// Err(err) => {
3596// error!("Unable to load ReadoutBoards from db! {err}");
3597// return None;
3598// }
3599// Ok(rbs) => {
3600// db_rbs = rbs;
3601// }
3602// }
3603// let paddles_op = Paddle::all(conn);
3604// match paddles_op {
3605// None => {
3606// return None;
3607// }
3608// Some(_) => ()
3609// }
3610// let paddles = paddles_op.unwrap();
3611// // This is not the best and fastest, but since our diesel skills
3612// // are a merely 3, we can't do it right now.
3613// let mut rbs = Vec::<ReadoutBoard>::new();
3614// //println!("Iterating over {} rbs in the DB!", db_rbs.len());
3615// for dbrb in db_rbs {
3616// let mut rb = ReadoutBoard::new();
3617// rb.rb_id = dbrb.rb_id as u8;
3618// rb.dsi = dbrb.dsi as u8;
3619// rb.j = dbrb.j as u8;
3620// rb.mtb_link_id = dbrb.mtb_link_id as u8;
3621// rb.paddle12_chA = dbrb.paddle12_chA.unwrap() as u8;
3622// rb.paddle34_chA = dbrb.paddle34_chA.unwrap() as u8;
3623// rb.paddle56_chA = dbrb.paddle56_chA.unwrap() as u8;
3624// rb.paddle78_chA = dbrb.paddle78_chA.unwrap() as u8;
3625// for pdl in paddles.iter() {
3626// // this call ensures that the following unwraps
3627// // go through
3628// //if !dbltb.valid() {
3629// // error!("Got unpopulated LTB from DB for LTB {}", dbltb);
3630// // continue;
3631// //}
3632// if pdl.paddle_id == dbrb.paddle12_id.unwrap_or(0) {
3633// rb.paddle12 = pdl.clone();
3634// }
3635// if pdl.paddle_id == dbrb.paddle34_id.unwrap_or(0) {
3636// rb.paddle34 = pdl.clone();
3637// }
3638// if pdl.paddle_id == dbrb.paddle56_id.unwrap_or(0) {
3639// rb.paddle56 = pdl.clone();
3640// }
3641// if pdl.paddle_id == dbrb.paddle78_id.unwrap_or(0) {
3642// rb.paddle78 = pdl.clone();
3643// }
3644// }
3645// rbs.push(rb);
3646// }
3647// Some(rbs)
3648// }
3649//
3650// // FIXME - better query
3651// pub fn where_rbid(conn: &mut SqliteConnection, rb_id : u8) -> Option<ReadoutBoard> {
3652// let all = ReadoutBoard::all(conn)?;
3653// for rb in all {
3654// if rb.rb_id == rb_id {
3655// return Some(rb);
3656// }
3657// }
3658// None
3659// }
3660//
3661// pub fn to_summary_str(&self) -> String {
3662// let mut repr = String::from("<ReadoutBoard:");
3663// repr += &(format!("\n Board id : {}",self.rb_id));
3664// repr += &(format!("\n MTB Link ID : {}",self.mtb_link_id));
3665// repr += &(format!("\n RAT : {}",self.paddle12.ltb_id));
3666// repr += &(format!("\n DSI/J : {}/{}",self.dsi,self.j));
3667// repr += "\n **Connected paddles**";
3668// repr += &(format!("\n Channel 1/2 : {:02} (panel {:01})", self.paddle12.paddle_id, self.paddle12.panel_id));
3669// repr += &(format!("\n Channel 3/4 : {:02} (panel {:01})", self.paddle34.paddle_id, self.paddle34.panel_id));
3670// repr += &(format!("\n Channel 5/6 : {:02} (panel {:01})", self.paddle56.paddle_id, self.paddle56.panel_id));
3671// repr += &(format!("\n Channel 7/8 : {:02} (panel {:01})", self.paddle78.paddle_id, self.paddle78.panel_id));
3672// repr
3673// }
3674//
3675// /// Load the newest calibration from the calibration file path
3676// pub fn load_latest_calibration(&mut self) -> Result<(), Box<dyn std::error::Error>> {
3677// // files look like RB20_2024_01_26-08_15_54.cali.tof.gaps
3678// //let re = Regex::new(r"(\d{4}_\d{2}_\d{2}-\d{2}_\d{2}_\d{2})")?;
3679// let re = Regex::new(r"(\d{6}_\d{6})")?;
3680// // Define your file pattern (e.g., "logs/*.log" for all .log files in the logs directory)
3681// let pattern = format!("{}/RB{:02}_*", self.calib_file_path, self.rb_id); // Adjust this pattern to your files' naming convention
3682// let timestamp = DateTime::<Utc>::from_timestamp(0,0).unwrap(); // I am not sure what to do here
3683// // otherwise than unwrap. How is
3684// // this allowed to fail?
3685// //let mut newest_file = (String::from(""), NaiveDateTime::from_timestamp(0, 0));
3686// let mut newest_file = (String::from(""), timestamp);
3687//
3688// // Iterate over files that match the pattern
3689// let mut filename : String;
3690// for entry in glob(&pattern)? {
3691// if let Ok(path) = entry {
3692// // Get the filename as a string
3693// //let cpath = path.clone();
3694// match path.file_name() {
3695// None => continue,
3696// Some(fname) => {
3697// // the expect might be ok, since this is something done during initialization
3698// filename = fname.to_os_string().into_string().expect("Unwrapping filename failed!");
3699// }
3700// }
3701// if let Some(caps) = re.captures(&filename) {
3702// if let Some(timestamp_str) = caps.get(0).map(|m| m.as_str()) {
3703// //println!("timestamp_str {}, {}",timestamp_str, HUMAN_TIMESTAMP_FORMAT);
3704// //let timestamp = NaiveDateTime::parse_from_str(timestamp_str, "%Y_%m_%d-%H_%M_%S")?;
3705// //let timestamp = DateTime::<Utc>::parse_from_str(timestamp_str, "%Y_%m_%d-%H_%M_%S")?;
3706// let footzstring = format!("{}+0000", timestamp_str);
3707// let timestamp = DateTime::parse_from_str(&footzstring, "%y%m%d_%H%M%S%z")?;
3708// //let timestamp = DateTime::parse_from_str(&footzstring, HUMAN_TIMESTAMP_FORMAT)?;
3709// //println!("parse successful");
3710// //let _timestamp = DateTime
3711// if timestamp > newest_file.1 {
3712// // FIXME - into might panic?
3713// newest_file.1 = timestamp.into();
3714// newest_file.0 = filename.clone();
3715// }
3716// }
3717// }
3718// }
3719// }
3720//
3721// if newest_file.0.is_empty() {
3722// error!("No matching calibration available for board {}!", self.rb_id);
3723// } else {
3724// let file_to_load = format!("{}/{}", self.calib_file_path, newest_file.0);
3725// info!("Loading calibration from file: {}", file_to_load);
3726// self.calibration = RBCalibrations::from_file(file_to_load, true)?;
3727// }
3728// Ok(())
3729// }
3730//}
3731//
3732//impl fmt::Display for ReadoutBoard {
3733// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3734// let mut repr = String::from("<ReadoutBoard:");
3735// repr += &(format!("\n Board id : {}",self.rb_id));
3736// repr += &(format!("\n MTB Link ID : {}",self.mtb_link_id));
3737// repr += &(format!("\n DSI/J : {}/{}",self.dsi,self.j));
3738// repr += "\n **Connected paddles**";
3739// repr += &(format!("\n Ch0/1(1/2) : {}",self.paddle12));
3740// repr += &(format!("\n A-side : {}", self.paddle12_chA));
3741// repr += &(format!("\n Ch1/2(2/3) : {}",self.paddle34));
3742// repr += &(format!("\n A-side : {}", self.paddle34_chA));
3743// repr += &(format!("\n Ch2/3(3/4) : {}",self.paddle56));
3744// repr += &(format!("\n A-side : {}", self.paddle56_chA));
3745// repr += &(format!("\n Ch3/4(4/5) : {}>",self.paddle78));
3746// repr += &(format!("\n A-side : {}", self.paddle78_chA));
3747// repr += "** calibration will be loaded from this path:";
3748// repr += &(format!("\n \u{021B3} {}", self.calib_file_path));
3749// repr += &(format!("\n calibration : {}>", self.calibration));
3750// write!(f, "{}", repr)
3751// }
3752//}
3753//
3754//
3755///// A TOF Panel is a larger unit of paddles next to each other
3756/////
3757///// TOF faces (e.g. Umbrella) can have multiple Panels
3758//#[derive(Debug, Clone,Queryable, Selectable)]
3759//#[diesel(table_name = schema::tof_db_panel)]
3760//#[diesel(primary_key(panel_id))]
3761//pub struct DBPanel {
3762// // ORDER OF THESE FIELDS HAS TO BE THE SAME AS IN schema.rs!!
3763// pub panel_id : i16 ,
3764// pub description : String ,
3765// pub normal_x : i16 ,
3766// pub normal_y : i16 ,
3767// pub normal_z : i16 ,
3768// pub dw_paddle : Option<i16>,
3769// pub dh_paddle : Option<i16>,
3770// pub paddle0_id : Option<i16>,
3771// pub paddle1_id : Option<i16>,
3772// pub paddle10_id : Option<i16>,
3773// pub paddle11_id : Option<i16>,
3774// pub paddle2_id : Option<i16>,
3775// pub paddle3_id : Option<i16>,
3776// pub paddle4_id : Option<i16>,
3777// pub paddle5_id : Option<i16>,
3778// pub paddle6_id : Option<i16>,
3779// pub paddle7_id : Option<i16>,
3780// pub paddle8_id : Option<i16>,
3781// pub paddle9_id : Option<i16>,
3782//}
3783//
3784//impl DBPanel {
3785//
3786// pub fn valid(&self) -> bool {
3787// self.panel_id > 0 &&
3788// self.description != String::from("") &&
3789// self.paddle0_id.is_some()
3790// }
3791//
3792// pub fn all(conn: &mut SqliteConnection) -> Option<Vec<DBPanel>> {
3793// use schema::tof_db_panel::dsl::*;
3794// match tof_db_panel
3795// //.inner_join(tof_db_localtriggerboard.on(schema::tof_db_paddle::dsl::paddle_id.eq(schema::tof_db_localtriggerboard::dsl::paddle1_id)))
3796// .load::<DBPanel>(conn) {
3797// Err(err) => {
3798// error!("Unable to load Panels from db! {err}");
3799// return None;
3800// }
3801// // dirty mind check
3802// Ok(pnls) => {
3803// return Some(pnls);
3804// }
3805// }
3806// }
3807//
3808// pub fn get_npaddles(&self) -> u8 {
3809// let mut npaddles = 0u8;
3810// if self.paddle0_id.is_some() {
3811// npaddles += 1;
3812// }
3813// if self.paddle1_id.is_some() {
3814// npaddles += 1;
3815// }
3816// if self.paddle2_id.is_some() {
3817// npaddles += 1;
3818// }
3819// if self.paddle3_id.is_some() {
3820// npaddles += 1;
3821// }
3822// if self.paddle4_id.is_some() {
3823// npaddles += 1;
3824// }
3825// if self.paddle5_id.is_some() {
3826// npaddles += 1;
3827// }
3828// if self.paddle6_id.is_some() {
3829// npaddles += 1;
3830// }
3831// if self.paddle7_id.is_some() {
3832// npaddles += 1;
3833// }
3834// if self.paddle8_id.is_some() {
3835// npaddles += 1;
3836// }
3837// if self.paddle9_id.is_some() {
3838// npaddles += 1;
3839// }
3840// if self.paddle10_id.is_some() {
3841// npaddles += 1;
3842// }
3843// if self.paddle11_id.is_some() {
3844// npaddles += 1;
3845// }
3846// npaddles
3847// }
3848//}
3849//
3850//impl fmt::Display for DBPanel {
3851// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3852// let mut repr = String::from("<DBPanel");
3853// repr += &(format!("\n id : {}",self.panel_id));
3854// repr += &(format!("\n descr : {}",self.description));
3855// repr += "\n orientation:";
3856// repr += &(format!("\n [{},{},{}]", self.normal_x, self.normal_y, self.normal_z));
3857// repr += &(format!("\n paddle list ({}) paddles)", self.get_npaddles()));
3858// if self.paddle0_id.is_some() {
3859// repr += &(format!("\n {}",self.paddle0_id.unwrap()));
3860// }
3861// if self.paddle1_id.is_some() {
3862// repr += &(format!("\n {}",self.paddle1_id.unwrap()));
3863// }
3864// if self.paddle2_id.is_some() {
3865// repr += &(format!("\n {}",self.paddle2_id.unwrap()));
3866// }
3867// if self.paddle3_id.is_some() {
3868// repr += &(format!("\n {}",self.paddle3_id.unwrap()));
3869// }
3870// if self.paddle4_id.is_some() {
3871// repr += &(format!("\n {}",self.paddle4_id.unwrap()));
3872// }
3873// if self.paddle5_id.is_some() {
3874// repr += &(format!("\n {}",self.paddle5_id.unwrap()));
3875// }
3876// if self.paddle6_id.is_some() {
3877// repr += &(format!("\n {}",self.paddle6_id.unwrap()));
3878// }
3879// if self.paddle7_id.is_some() {
3880// repr += &(format!("\n {}",self.paddle7_id.unwrap()));
3881// }
3882// if self.paddle8_id.is_some() {
3883// repr += &(format!("\n {}",self.paddle8_id.unwrap()));
3884// }
3885// if self.paddle9_id.is_some() {
3886// repr += &(format!("\n {}",self.paddle9_id.unwrap()));
3887// }
3888// if self.paddle10_id.is_some() {
3889// repr += &(format!("\n {}",self.paddle10_id.unwrap()));
3890// }
3891// if self.paddle11_id.is_some() {
3892// repr += &(format!("\n {}",self.paddle11_id.unwrap()));
3893// }
3894// repr += ">";
3895// write!(f, "{}", repr)
3896// }
3897//}
3898//
3899//pub struct Panel {
3900// pub panel_id : u8 ,
3901// pub description : String ,
3902// pub normal_x : u8 ,
3903// pub normal_y : u8 ,
3904// pub normal_z : u8 ,
3905// pub paddle0 : Paddle,
3906// pub paddle1 : Option<Paddle>,
3907// pub paddle2 : Option<Paddle>,
3908// pub paddle3 : Option<Paddle>,
3909// pub paddle4 : Option<Paddle>,
3910// pub paddle5 : Option<Paddle>,
3911// pub paddle6 : Option<Paddle>,
3912// pub paddle7 : Option<Paddle>,
3913// pub paddle8 : Option<Paddle>,
3914// pub paddle9 : Option<Paddle>,
3915// pub paddle10 : Option<Paddle>,
3916// pub paddle11 : Option<Paddle>,
3917// // FIXME - these are for the future
3918// // when we are buiding the geometry
3919// // from the database
3920// //pub dh_paddle : Option<>,
3921// //pub dw_paddle : Option<>,
3922//}
3923//
3924//impl Panel {
3925//
3926// pub fn new() -> Self {
3927// Self {
3928// panel_id : 0 ,
3929// description : String::from(""),
3930// normal_x : 0 ,
3931// normal_y : 0 ,
3932// normal_z : 0 ,
3933// paddle0 : Paddle::new(),
3934// paddle1 : None,
3935// paddle2 : None,
3936// paddle3 : None,
3937// paddle4 : None,
3938// paddle5 : None,
3939// paddle6 : None,
3940// paddle7 : None,
3941// paddle8 : None,
3942// paddle9 : None,
3943// paddle10 : None,
3944// paddle11 : None,
3945// }
3946// }
3947//
3948//
3949// pub fn get_npaddles(&self) -> u8 {
3950// let mut npaddles = 1u8;
3951// if self.paddle1.is_some() {
3952// npaddles += 1;
3953// }
3954// if self.paddle2.is_some() {
3955// npaddles += 1;
3956// }
3957// if self.paddle3.is_some() {
3958// npaddles += 1;
3959// }
3960// if self.paddle4.is_some() {
3961// npaddles += 1;
3962// }
3963// if self.paddle5.is_some() {
3964// npaddles += 1;
3965// }
3966// if self.paddle6.is_some() {
3967// npaddles += 1;
3968// }
3969// if self.paddle7.is_some() {
3970// npaddles += 1;
3971// }
3972// if self.paddle8.is_some() {
3973// npaddles += 1;
3974// }
3975// if self.paddle9.is_some() {
3976// npaddles += 1;
3977// }
3978// if self.paddle10.is_some() {
3979// npaddles += 1;
3980// }
3981// if self.paddle11.is_some() {
3982// npaddles += 1;
3983// }
3984// npaddles
3985// }
3986//
3987// pub fn all(conn: &mut SqliteConnection) -> Option<Vec<Panel>> {
3988// use schema::tof_db_panel::dsl::*;
3989// let db_panels : Vec<DBPanel>;
3990// match tof_db_panel
3991// //.inner_join(tof_db_localtriggerboard.on(schema::tof_db_paddle::dsl::paddle_id.eq(schema::tof_db_localtriggerboard::dsl::paddle1_id)))
3992// .load::<DBPanel>(conn) {
3993// Err(err) => {
3994// error!("Unable to load Panels from db! {err}");
3995// return None;
3996// }
3997// Ok(pnls) => {
3998// db_panels = pnls;
3999// }
4000// }
4001// let paddles_op = Paddle::all(conn);
4002// match paddles_op {
4003// None => {
4004// return None;
4005// }
4006// Some(_) => ()
4007// }
4008// let paddles = paddles_op.unwrap();
4009// // This is not the best and fastest, but since our diesel skills
4010// // are a merely 3, we can't do it right now.
4011// let mut panels = Vec::<Panel>::new();
4012// println!("Iterating over {} panels in the DB!", db_panels.len());
4013// for dbpanel in db_panels {
4014// let mut pnl = Panel::new();
4015// for pdl in paddles.iter() {
4016// // this call ensures that the following unwraps
4017// // go through
4018// if !dbpanel.valid() {
4019// error!("Got unpopulated Panel from DB for Panel {}", dbpanel);
4020// continue;
4021// }
4022// if pdl.paddle_id == dbpanel.paddle0_id.unwrap() {
4023// pnl.panel_id = dbpanel.panel_id as u8;
4024// pnl.description = dbpanel.description.clone();
4025// pnl.normal_x = dbpanel.normal_x as u8;
4026// pnl.normal_y = dbpanel.normal_y as u8;
4027// pnl.normal_z = dbpanel.normal_z as u8;
4028// pnl.paddle0 = pdl.clone();
4029// }
4030// if pdl.paddle_id == dbpanel.paddle1_id.unwrap() {
4031// pnl.paddle1 = Some(pdl.clone());
4032// }
4033// if pdl.paddle_id == dbpanel.paddle2_id.unwrap() {
4034// pnl.paddle2 = Some(pdl.clone());
4035// }
4036// if pdl.paddle_id == dbpanel.paddle3_id.unwrap() {
4037// pnl.paddle3 = Some(pdl.clone());
4038// }
4039// if pdl.paddle_id == dbpanel.paddle4_id.unwrap() {
4040// pnl.paddle4 = Some(pdl.clone());
4041// }
4042// if pdl.paddle_id == dbpanel.paddle5_id.unwrap() {
4043// pnl.paddle5 = Some(pdl.clone());
4044// }
4045// if pdl.paddle_id == dbpanel.paddle6_id.unwrap() {
4046// pnl.paddle6 = Some(pdl.clone());
4047// }
4048// if pdl.paddle_id == dbpanel.paddle7_id.unwrap() {
4049// pnl.paddle7 = Some(pdl.clone());
4050// }
4051// if pdl.paddle_id == dbpanel.paddle8_id.unwrap() {
4052// pnl.paddle8 = Some(pdl.clone());
4053// }
4054// if pdl.paddle_id == dbpanel.paddle9_id.unwrap() {
4055// pnl.paddle9 = Some(pdl.clone());
4056// }
4057// if pdl.paddle_id == dbpanel.paddle10_id.unwrap() {
4058// pnl.paddle10 = Some(pdl.clone());
4059// }
4060// if pdl.paddle_id == dbpanel.paddle11_id.unwrap() {
4061// pnl.paddle11 = Some(pdl.clone());
4062// }
4063// }
4064// panels.push(pnl);
4065// }
4066// Some(panels)
4067// }
4068//}
4069//
4070//impl fmt::Display for Panel {
4071// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4072// let mut repr = String::from("<Panel");
4073// repr += &(format!("\n id : {}",self.panel_id));
4074// repr += &(format!("\n descr : {}",self.description));
4075// repr += "\n orientation:";
4076// repr += &(format!("\n [{},{},{}]", self.normal_x, self.normal_y, self.normal_z));
4077// repr += &(format!("\n paddle list ({}) paddles)", self.get_npaddles()));
4078// repr += &(format!("\n {}",self.paddle0));
4079// if self.paddle1.is_some() {
4080// repr += &(format!("\n {}",self.paddle1.as_ref().unwrap()));
4081// }
4082// if self.paddle2.is_some() {
4083// repr += &(format!("\n {}",self.paddle2.as_ref().unwrap()));
4084// }
4085// if self.paddle3.is_some() {
4086// repr += &(format!("\n {}",self.paddle3.as_ref().unwrap()));
4087// }
4088// if self.paddle4.is_some() {
4089// repr += &(format!("\n {}",self.paddle4.as_ref().unwrap()));
4090// }
4091// if self.paddle5.is_some() {
4092// repr += &(format!("\n {}",self.paddle5.as_ref().unwrap()));
4093// }
4094// if self.paddle6.is_some() {
4095// repr += &(format!("\n {}",self.paddle6.as_ref().unwrap()));
4096// }
4097// if self.paddle7.is_some() {
4098// repr += &(format!("\n {}",self.paddle7.as_ref().unwrap()));
4099// }
4100// if self.paddle8.is_some() {
4101// repr += &(format!("\n {}",self.paddle8.as_ref().unwrap()));
4102// }
4103// if self.paddle9.is_some() {
4104// repr += &(format!("\n {}",self.paddle9.as_ref().unwrap()));
4105// }
4106// if self.paddle10.is_some() {
4107// repr += &(format!("\n {}",self.paddle10.as_ref().unwrap()));
4108// }
4109// if self.paddle11.is_some() {
4110// repr += &(format!("\n {}",self.paddle11.as_ref().unwrap()));
4111// }
4112// repr += ">";
4113// write!(f, "{}", repr)
4114// }
4115//}
4116//
4117//
4118//
4119