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