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