Skip to main content

gondola_core/database/
tracker_gain.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 crate::database::schema;
11use diesel::prelude::*;
12
13use std::io::{
14  self,
15  BufRead,
16  BufReader
17};
18
19/// The db insert companion to TrackerStripGain
20#[derive(Debug,PartialEq, Clone, Insertable)]
21#[diesel(table_name = schema::tof_db_trackerstripgain)]
22#[allow(non_snake_case)]
23#[cfg_attr(feature="pybindings", pyclass)]
24struct NewTrackerStripGain {
25  pub strip_id            : i32,    
26  pub volume_id           : i64,    
27  pub utc_timestamp_start : i64,
28  pub utc_timestamp_stop  : i64,
29  pub name                : Option<String>,
30  pub gain                : f32,
31  pub gain_is_mean        : bool,
32}
33
34impl NewTrackerStripGain {
35  pub fn from(gain : &TrackerStripGain) -> Self {
36    Self {
37      strip_id            : gain.strip_id            ,    
38      volume_id           : gain.volume_id           ,    
39      utc_timestamp_start : gain.utc_timestamp_start ,
40      utc_timestamp_stop  : gain.utc_timestamp_stop  ,
41      name                : gain.name.clone()        ,
42      gain                : gain.gain       , 
43      gain_is_mean        : gain.gain_is_mean      , 
44    }
45  }
46}
47
48/// Common noise subtraction - pulse channels on the wafers and get the average adc. 
49/// The gain is available as well. Data from Mengjiao's group 
50#[derive(Debug,PartialEq, Clone,Queryable, Selectable, serde::Serialize, serde::Deserialize)]
51#[diesel(table_name = schema::tof_db_trackerstripgain)]
52#[diesel(primary_key(data_id))]
53#[allow(non_snake_case)]
54#[cfg_attr(feature="pybindings", pyclass)]
55pub struct TrackerStripGain {   
56  pub data_id              : i32,
57  pub strip_id             : i32,    
58  pub volume_id            : i64,    
59  pub utc_timestamp_start  : i64,    
60  pub utc_timestamp_stop   : i64,    
61  pub name                 : Option<String>, 
62  pub gain                 : f32,
63  pub gain_is_mean         : bool,
64} 
65
66impl TrackerStripGain {
67
68  pub fn new() -> Self {
69    Self {
70      data_id             : 0,
71      strip_id            : 0,    
72      volume_id           : 0,    
73      utc_timestamp_start : 0,   
74      utc_timestamp_stop  : 0,
75      name                : None, 
76      gain                : 0.0, 
77      gain_is_mean        : false,
78    }
79  }
80  
81  pub fn parse_from_file<P: AsRef<Path>>(path: P) -> io::Result<Vec<Self>> {
82    let file = File::open(path)?;
83    let reader = BufReader::new(file);
84    let mut gains = Vec::<Self>::new();
85    let hid_vid_map = get_hid_vid_maps().unwrap().1;
86    let mut n_entries = 0u64;
87    let mut mean_gain = 0.0f64;
88    for line in reader.lines() {
89      let line = line?;
90      if line.starts_with("#") || line.starts_with("Layer") || line.starts_with("layer") {
91        continue;
92      }
93      let mut gain = Self::new();
94      let parts: Vec<&str> = line.split_whitespace().collect();
95      if parts.len() == 5 {
96        // Parse the first number as a standard decimal
97        let layer   = parts[0].parse::<u8>()
98          .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
99        let row     = parts[1].parse::<u8>()
100          .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
101        let module   = parts[2].parse::<u8>()
102          .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
103        let channel  = parts[3].parse::<u8>()
104          .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
105        gain.strip_id  = TrackerStrip::create_stripid(layer, row, module, channel) as i32; 
106        gain.volume_id = *hid_vid_map.get(&(gain.strip_id as u32)).unwrap() as i64; // critical error is good here,
107        gain.gain      = parts[4].parse::<f32>()
108          .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
109        mean_gain += gain.gain as f64;
110        gains.push(gain); 
111        n_entries += 1;
112      }
113    }
114    mean_gain /= n_entries as f64;
115    let mut fixed_gains = Vec::<TrackerStripGain>::with_capacity(gains.len());
116    for g in gains.iter_mut() {
117      if g.gain == 0.0 {
118        g.gain = mean_gain as f32;
119        g.gain_is_mean = true;
120      }
121      fixed_gains.push(g.clone());
122    }
123    Ok(fixed_gains)
124  }
125  
126  pub fn all_names() -> Result<Vec<String>, ConnectionError> {
127    let mut conn = connect_to_db()?;
128    let mut names = Vec::<String>::new();
129    let unique_names =
130      schema::tof_db_trackerstripgain::table.select(
131      schema::tof_db_trackerstripgain::name)
132      .distinct()
133      .load::<Option<String>>(&mut conn).expect("Error getting names from db!");
134    for k in unique_names {
135      if let Some(n) = k {
136        names.push(n);
137      }
138    }
139    Ok(names)
140  }
141  
142  /// Get Tracker strip cmn noise data for a certain dataset 
143  ///
144  /// # Returns:
145  ///   * HashMap<u32 [strip id], TrackerStripTransferFn> 
146  pub fn as_dict_by_name(fname : &str) -> Result<HashMap<u32,Self>, ConnectionError> {
147    use schema::tof_db_trackerstripgain::dsl::*;
148    let mut strips = HashMap::<u32, Self>::new();
149    if fname == "" {
150      match Self::all() {
151        None => {
152          error!("Unable to retrive ANY TrackerStripCMNNoise Data (pulser)");
153          return Ok(strips);
154        }
155        Some(_strips) => {
156          for k in _strips {
157            strips.insert(k.strip_id as u32, k);
158          }
159          return Ok(strips);
160        }
161      }
162    }
163    let mut conn = connect_to_db()?;
164    match tof_db_trackerstripgain.filter(
165      schema::tof_db_trackerstripgain::name.eq(fname)).load::<Self>(&mut conn) {
166      Err(err) => {
167        error!("We can't find any tracker strip common noise information with that name in the database! {err}");
168        return Ok(strips);
169      }
170      Ok(peds_) => {
171        for s in peds_ {
172          strips.insert(s.strip_id as u32, s );
173        }
174      }
175    }
176    return Ok(strips);
177  }
178
179  /// Get all tracker strip transfer functions from the database
180  ///
181  /// # Returns:
182  ///   * HashMap<u32 [strip id], TrackeStripTransferFunction> 
183  pub fn all() -> Option<Vec<Self>> {
184    use schema::tof_db_trackerstripgain::dsl::*;
185    let mut conn = connect_to_db().ok()?;
186    match tof_db_trackerstripgain.load::<Self>(&mut conn) {
187      Err(err) => {
188        error!("Unable to load tracker transfer functions from db! {err}");
189        return None;
190      }
191      Ok(strips) => {
192        return Some(strips);
193      }
194    }
195  }
196}
197
198impl fmt::Display for TrackerStripGain {
199  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
200    let mut repr = format!("<TrackerStripGain [{}]:", self.strip_id);
201    repr += &(format!("\n   vid              : {}", self.volume_id));
202    repr += "\n   UTC Timestamps (Begin/End):";
203    repr += &(format!("\n   {}/{}", self.utc_timestamp_start, self.utc_timestamp_stop));    
204    if self.gain_is_mean {
205      repr += &(String::from("\n -- Gain is mean value!"));
206    }
207    if self.name.is_some() {
208      repr += &(format!("\n   name     : {}", self.name.clone().unwrap())); 
209    }
210    repr += &(format!("\n   gain : {}>", self.gain));
211    write!(f, "{}", repr)
212  }
213}
214
215#[cfg(feature="pybindings")]
216#[pymethods]
217impl TrackerStripGain {
218  
219  #[staticmethod]
220  #[pyo3(name="all")]
221  pub fn all_py() -> Option<Vec<Self>> {
222    Self::all()
223  } 
224 
225  #[staticmethod]
226  #[pyo3(name="all_names")]
227  /// Get all names for registered datasets. These
228  /// can be used in .as_dict_by_name() to query 
229  /// the db for a set of values
230  pub fn all_names_py() -> Option<Vec<String>> {
231    match Self::all_names() {
232      Err(_) => {
233        return None;
234      }
235      Ok(names) => {
236        return Some(names);
237      }
238    }
239  }
240
241  #[staticmethod]
242  #[pyo3(name="as_dict_by_name")]
243  pub fn all_as_dict_py(name : &str) -> Option<HashMap<u32,Self>> {
244    match Self::as_dict_by_name(name) {
245      Err(err) => {
246        error!("Unable to retrieve tracker strip gain dictionary. {err}. Did you laod the setup-env.sh shell?");
247        return None;
248      }
249      Ok(_data) => {
250        return Some(_data);
251      }
252    }
253  } 
254  
255  #[getter]
256  fn get_strip_id     (&self) -> i32 {    
257    self.strip_id
258  }
259  
260  #[getter]
261  fn get_volume_id    (&self) -> i64 {    
262    self.volume_id
263  }
264  
265  #[getter]
266  fn get_utc_timestamp_start(&self) -> i64 {
267    self.utc_timestamp_start
268  }
269  
270  #[getter]
271  fn get_utc_timestamp_stop(&self) -> i64 {
272    self.utc_timestamp_stop
273  }
274  
275  #[setter]
276  fn set_utc_timestamp_start(&mut self, value : i64) {
277    self.utc_timestamp_start = value;
278  }
279  
280  #[setter]
281  fn set_utc_timestamp_stop(&mut self, value : i64) {
282    self.utc_timestamp_stop = value;
283  }
284
285  #[getter]
286  fn get_name(&self) -> Option<String> {
287    self.name.clone()
288  }
289  
290  #[setter]
291  fn set_name(&mut self, value : String) {
292    self.name = Some(value);
293  }
294      
295  #[getter]
296  fn get_gain(&self) -> f32 {
297    self.gain
298  }
299  
300  #[getter]
301  fn get_gain_is_mean(&self) -> bool {
302    self.gain_is_mean
303  }
304  
305  #[staticmethod]
306  #[pyo3(name="parse_from_file")]
307  fn parse_from_file_py(fname : &str) -> Option<Vec<Self>> {
308    let result = Self::parse_from_file(fname);
309    if result.is_ok() {
310      return Some(result.unwrap());
311    } else {
312      error!("An error occured when parsing {} : '{}'", fname, result.unwrap_err());
313      return None;
314    }
315  } 
316}
317
318#[cfg(feature="pybindings")]
319pythonize!(TrackerStripGain);
320
321#[cfg_attr(feature="pybindings", pyfunction)]
322pub fn create_trk_gain_table( db_path: &str, gains: Vec<TrackerStripGain>) { 
323  use schema::tof_db_trackerstripgain::dsl::*;
324  let mut conn = SqliteConnection::establish(db_path).ok().unwrap(); 
325  let mut _query_result = diesel::sql_query("
326      CREATE TABLE IF NOT EXISTS tof_db_trackerstripgain (
327          data_id INTEGER PRIMARY KEY AUTOINCREMENT,
328          strip_id INTEGER NOT NULL,
329          volume_id BIGINT NOT NULL,
330          utc_timestamp_start BIGINT NOT NULL,
331          utc_timestamp_stop BIGINT NOT NULL,
332          name TEXT,
333          gain FLOAT,
334          gain_is_mean BOOL
335      )
336  ").execute(&mut conn);
337  let mut new_gains = Vec::<NewTrackerStripGain>::new();
338  for g in gains {
339    let ng = NewTrackerStripGain::from(&g);
340    new_gains.push(ng);
341  }
342  _query_result = diesel::insert_into(tof_db_trackerstripgain)
343    .values(&new_gains)
344    .execute(&mut conn);
345}
346