Skip to main content

gondola_core/database/
tof_paddle_temps.rs

1// This file is part of gaps-online-software and published 
2// under the GPLv3 license
3
4use crate::prelude::*;
5use crate::database::schema;
6
7use diesel::prelude::*;
8use std::io::BufRead;
9
10#[cfg_attr(feature="pybindings", pyfunction)]
11pub fn create_tof_paddle_temp_table( db_path: &str, paddle_temps: Vec<TofPaddleTemp>) { 
12  use schema::tof_db_tofpaddletemp::dsl::*;
13  let mut conn = SqliteConnection::establish(db_path).ok().unwrap();
14  
15  let mut _query_result = diesel::sql_query("
16      CREATE TABLE IF NOT EXISTS tof_db_tofpaddletemp (
17          data_id INTEGER PRIMARY KEY AUTOINCREMENT,
18          paddle_id SMALLINT NOT NULL, 
19          utc_timestamp BIGINT NOT NULL,
20          temp_a FLOAT NOT NULL,
21          temp_b FLOAT NOT NULL,
22          meta TEXT
23      )
24  ").execute(&mut conn);
25  match _query_result {
26    Ok(_) => {
27      println!("Created table successfully!");
28    }
29    Err(err) => {
30      println!("Error occured when creating tof_db_tofpaddletemp table! {err}");
31    }
32  }
33  _query_result = diesel::insert_into(tof_db_tofpaddletemp)
34    .values(&paddle_temps)
35    .execute(&mut conn);
36  match _query_result {
37    Ok(_) => {
38      println!("Entered data into db successfully!");
39    }
40    Err(err) => {
41      println!("Error occured when entering data in the db! {err}");
42    }
43  }
44}
45
46#[derive(Debug, PartialEq, Clone)]
47#[allow(non_snake_case)]
48#[cfg_attr(feature="pybindings", pyclass)]
49pub struct TofPaddleTempDataSeries {
50  pub temp_a         : Vec<f32>,
51  pub temp_b         : Vec<f32>,
52  pub utc_timestamps : Vec<u64>,
53  pub paddle_id      : u8
54}
55
56impl TofPaddleTempDataSeries {
57  pub fn new() -> Self {
58    Self {
59      temp_a         : Vec::<f32>::new(),
60      temp_b         : Vec::<f32>::new(),
61      utc_timestamps : Vec::<u64>::new(),
62      paddle_id      : 0
63    }
64  }
65
66  pub fn add(&mut self, pdl_t : &TofPaddleTemp) {
67    if pdl_t.paddle_id == self.paddle_id as i16 {
68      self.temp_a.push(pdl_t.temp_a);
69      self.temp_b.push(pdl_t.temp_b);
70      self.utc_timestamps.push(pdl_t.utc_timestamp as u64);
71    }
72  }
73
74  pub fn get_for_ts(&self, utc_timestamp : u64) -> (f32, f32) {
75    let mut result = (-273.0, -273.0); 
76    let idx_opt = self.utc_timestamps.partition_point(|&t| t < utc_timestamp)
77        .checked_sub(1);
78    if let Some(idx) = idx_opt {
79      if self.temp_a.len() > idx as usize && self.temp_b.len() > idx {
80        result.0 = self.temp_a[idx]; 
81        result.1 = self.temp_b[idx];
82      }
83    }
84    result
85  }
86
87  pub fn sort(&mut self) {
88    let mut indices: Vec<usize> = (0..self.utc_timestamps.len()).collect();
89    indices.sort_unstable_by_key(|&i| self.utc_timestamps[i]);
90    let timestamps_sorted: Vec<u64> =
91      indices.iter().map(|&i| self.utc_timestamps[i]).collect();
92    let values_a_sorted: Vec<f32> =
93      indices.iter().map(|&i| self.temp_a[i]).collect();
94    let values_b_sorted: Vec<f32> =
95      indices.iter().map(|&i| self.temp_b[i]).collect();
96    self.utc_timestamps = timestamps_sorted;
97    self.temp_a = values_a_sorted;
98    self.temp_b = values_b_sorted;
99    //self.utc_timestamps.sort_unstable();
100  }
101}
102
103impl fmt::Display for TofPaddleTempDataSeries {
104  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
105    let mut repr = String::from("<TofPaddleTempDataSeries:");
106    repr += &(format!("\n  Paddle ID : {}", self.paddle_id));
107    repr += &(format!("\n  Values    : {}", self.temp_a.len()));
108    repr += ">";
109    write!(f, "{}", repr)
110  }
111}
112
113/// Recorded Temperature of each paddle end. The SiPM preamp board 
114/// is equipped with a temeperature sensor, which allows to calibrate 
115/// the gain of the SiPm
116#[derive(Debug,PartialEq, Clone, Queryable, Selectable, Insertable, serde::Serialize, serde::Deserialize)]
117#[diesel(table_name = schema::tof_db_tofpaddletemp)]
118#[diesel(primary_key(data_id))]
119#[allow(non_snake_case)]
120#[cfg_attr(feature="pybindings", pyclass)]
121pub struct TofPaddleTemp {
122  #[diesel(deserialize_as = i32)]
123  pub data_id             : Option<i32>,
124  pub paddle_id           : i16, 
125  pub utc_timestamp       : i64,
126  pub temp_a              : f32,
127  pub temp_b              : f32,
128  pub meta                : Option<String>, 
129}
130
131impl TofPaddleTemp {
132
133  pub fn new() -> Self {
134    Self {
135      data_id             : None,
136      paddle_id           : 0,
137      utc_timestamp       : 0,
138      temp_a              : 0.0,
139      temp_b              : 0.0,
140      meta                : None, 
141    }
142  }
143 
144  /// Retrieve all paddle temperatures
145  /// stroed in the database
146  ///
147  /// # Returns:
148  ///   * Vec<Self>  : All paddle temperatures as they are 
149  ///                  stored in the db
150  pub fn all() -> Option<Vec<Self>> {
151    use schema::tof_db_tofpaddletemp::dsl::*;
152    let mut conn = connect_to_db().ok()?;
153    match tof_db_tofpaddletemp.load::<Self>(&mut conn) {
154      Err(err) => {
155        error!("Unable to load TOF paddle temperature data from db! {err}");
156        return None;
157      }
158      Ok(tpts) => {
159        return Some(tpts);
160      }
161    }
162  }
163  
164  /// Retrieve all paddle temperatures for a specific paddle id
165  ///
166  /// # Returns:
167  ///   * Vec<Self>  : All paddle tempereaturs as they are 
168  ///                  stored in the db for this paddle id
169  pub fn all_data() -> Option<HashMap<u8,TofPaddleTempDataSeries>> {
170    use schema::tof_db_tofpaddletemp::dsl::*;
171    let mut conn = connect_to_db().ok()?;
172    let results = tof_db_tofpaddletemp
173      //.filter(paddle_id.eq(pid as i16))
174      .load::<Self>(&mut conn);
175    let mut all_ds = HashMap::<u8, TofPaddleTempDataSeries>::new();
176    for k in 1..161u8 {
177      let mut new_series = TofPaddleTempDataSeries::new();
178      new_series.paddle_id = k;
179      all_ds.insert(k, new_series); 
180    }
181    
182    match results {
183      Err(err) => {
184        error!("Unable to load TOF paddle temperature data from db! {err}");
185        return None;
186      }
187      Ok(tpts) => {
188        for tp in tpts {
189          all_ds.get_mut(&(tp.paddle_id as u8)).unwrap().add(&tp);
190          //ds.add(&tp);
191        }
192      }
193    }
194    for k in 1..161 {
195      all_ds.get_mut(&k).unwrap().sort(); 
196    }
197    //return Some(tpts);
198    return Some(all_ds);
199  }
200
201  //pub fn from_telemetry_packet(pack : &TelemetryPacket) -> Self { 
202  //  let mut tpt = Self::new();
203  //  tpt.utc_timestamp = pack.header.get_gcutime() as i64;
204  //  return tpt;
205  //}
206
207
208  //pub fn from_pa_monidata(&PAMoniData) -> Self {
209  //  let mut tpt = Self::new();  
210  //  tpt
211  //  return tpt;
212  //}
213}
214
215impl Default for TofPaddleTemp {
216  fn default() -> Self {
217    Self::new()
218  }
219}
220
221impl fmt::Display for TofPaddleTemp {
222  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
223    let mut repr = String::from("<TofPaddleTemp:");
224    repr += &(format!("\n  Paddle ID     : {}", self.paddle_id));
225    repr += &(format!("\n  UTC Timstamp  : {} [{}|]", self.utc_timestamp, get_utc_timestamp_from_unix(self.utc_timestamp as f64).unwrap_or(String::from("0"))));    
226    repr += &(format!("\n  Temp [C]      : A {} // B {}", self.temp_a, self.temp_b)); 
227    if self.meta.is_some() {
228      repr += &(format!("\n  meta info     : {}", self.meta.clone().unwrap())); 
229    }
230    repr += ">";
231    write!(f, "{}", repr)
232  }
233}
234
235#[cfg(feature="pybindings")]
236#[pymethods]
237impl TofPaddleTempDataSeries {
238  #[pyo3(name="get_for_ts")]
239  pub fn get_for_ts_py(&self, timestamp : u64) -> (f32, f32) {
240    self.get_for_ts(timestamp)
241  }
242  
243  #[getter]
244  fn get_first_ts(&self) -> Option<&u64> {
245    self.utc_timestamps.first() 
246  }
247  
248  #[getter]
249  fn get_last_ts(&self) -> Option<&u64> {
250    self.utc_timestamps.last() 
251  }
252}
253
254#[cfg(feature="pybindings")]
255pythonize!(TofPaddleTempDataSeries);
256
257#[cfg(feature="pybindings")]
258#[pymethods]
259impl TofPaddleTemp {
260  
261  #[staticmethod]
262  #[pyo3(name="all")]
263  pub fn all_py() -> Option<Vec<Self>> {
264    Self::all()
265  } 
266  
267  /// Retrieve all paddle temperatures for a specific paddle id
268  ///
269  /// # Returns:
270  ///   * Vec<Self>  : All paddle tempereaturs as they are 
271  ///                  stored in the db for this paddle id
272  #[staticmethod]
273  #[pyo3(name="all_data")]
274  fn all_data_py() -> Option<HashMap<u8,TofPaddleTempDataSeries>> {
275    Self::all_data()
276  } 
277
278  #[getter]
279  fn get_utc_timestamp(&self) -> i64 {
280    self.utc_timestamp
281  }
282  
283  #[setter]
284  fn set_utc_timestamp(&mut self, ts : i64) {
285    self.utc_timestamp = ts;
286  }
287   
288  #[getter]
289  fn get_meta    (&self) -> Option<String> {
290    self.meta.clone()
291  }  
292  
293  #[getter]
294  fn get_paddle_id(&self) -> i16 { 
295    self.paddle_id 
296  }
297  
298  #[getter]
299  fn get_temp_a(&self)    -> f32 { 
300    self.temp_a 
301  }
302  
303  #[getter]
304  fn get_temp_b(&self)    -> f32 {
305    self.temp_b
306  }
307  
308  #[setter]
309  fn set_paddle_id(&mut self, pid : i16) { 
310    self.paddle_id = pid;
311  }
312  
313  #[setter]
314  fn set_temp_a(&mut self, t : f32) { 
315    self.temp_a = t;
316  }
317  
318  #[setter]
319  fn set_temp_b(&mut self, t : f32) {
320    self.temp_b = t;
321  }
322}
323
324#[cfg(feature="pybindings")]
325pythonize!(TofPaddleTemp);
326