gondola_core/calibration/
tracker.rs1use crate::prelude::*;
7
8#[cfg_attr(feature="pybindings", pyclass)]
9pub struct TrackerOfflineCalibration {
10 pub mask_map : HashMap<u32,TrackerStripMask>,
11 pub tf_map : HashMap<u32,TrackerStripTransferFunction>,
12 pub ped_map : HashMap<u32,TrackerStripPedestal>,
13 pub gain_map : HashMap<u32,TrackerStripGain>,
14 pub pulse_map : HashMap<u32,TrackerStripPulse>,
15 pub adc_sig_cut : HashMap<u32,f32>,
16 pub remove_cmn : bool,
17 pub ped_sigma_cut : f32,
18 pub remove_pulsed : bool,
19}
20
21impl TrackerOfflineCalibration {
22
23 pub fn new() -> Self {
24 Self {
25 mask_map : HashMap::<u32, TrackerStripMask>::new(),
26 tf_map : HashMap::<u32, TrackerStripTransferFunction>::new(),
27 ped_map : HashMap::<u32, TrackerStripPedestal>::new(),
28 adc_sig_cut : HashMap::<u32,f32>::new(),
29 gain_map : HashMap::<u32,TrackerStripGain>::new(),
30 pulse_map : HashMap::<u32,TrackerStripPulse>::new(),
31 remove_cmn : false,
32 ped_sigma_cut : 0.0,
33 remove_pulsed : false,
34 }
35 }
36
37 pub fn get_common_noise(&self, hit : &TrackerHit, event_hits : &Vec<TrackerHit>) -> (f32, bool) {
42 let mut cmn_level = 0.0f32;
43 let strip_gain : f32;
45 let mut pulse_gain = 1.0f32;
46 let mut pulse_avg = 0.0f32;
47 let mut pulse_chn = -1i32;
48 let mut pulse_adc = 0.0f32;
49 let is_pulser : bool;
50 if let Some(cmn_strip) = self.gain_map.get(&hit.get_stripid()) {
52 strip_gain = cmn_strip.gain;
53 } else {
54 debug!("There is no entry for the strip gain for {}, default is 1.0", &hit.get_stripid());
55 strip_gain = 1.0;
56 }
57 if let Some(pulse_chn_) = self.pulse_map.get(&hit.get_stripid()) {
58 pulse_chn = pulse_chn_.pulse_chn;
59 pulse_avg = pulse_chn_.pulse_avg;
60 }
62 is_pulser = pulse_chn == hit.channel as i32;
63 if pulse_chn < 0 || pulse_avg > 400.0 {
64 return (0.0, is_pulser)
65 }
66 let pulse_id = TrackerStrip::create_stripid(hit.layer, hit.row, hit.module, pulse_chn as u8);
67 let mut p_hit = TrackerHit::new();
69 p_hit.layer = hit.layer;
70 p_hit.row = hit.row;
71 p_hit.module = hit.module;
72 p_hit.channel = pulse_chn as u8;
73 let mut found = false;
74 for h in event_hits {
75 if h.get_stripid() == p_hit.get_stripid() {
76 pulse_adc = h.adc as f32;
77 found = true;
78 break; }
80 }
81 if let Some(pulse_gain_) = self.gain_map.get(&pulse_id) {
82 pulse_gain = pulse_gain_.gain;
83 }
84 if found {
85 let adc_pulc_diff = pulse_adc - pulse_avg;
86 if adc_pulc_diff < 250.0 && pulse_avg > 0.0 {
87 cmn_level = adc_pulc_diff / pulse_gain;
88 }
89 }
90 debug!("Calculated common level of {} gain {}", cmn_level, strip_gain);
91 if cmn_level < 0.0 {
92 }
95 return (cmn_level * strip_gain, is_pulser);
96 }
97
98 pub fn mask_hits(&self, event_hits : &mut Vec<TrackerHit>) {
99 let mut active_strips = Vec::<u32>::new();
100 for h in event_hits.iter() {
101 if let Some(mask) = self.mask_map.get(&h.get_stripid()) {
102 if mask.active {
103 active_strips.push(h.get_stripid());
104 }
105 } else {
106 warn!("No mask information for strip {}", h.get_stripid());
107 }
108 }
109 event_hits.retain(|x| active_strips.contains(&x.get_stripid()));
110 }
111
112 pub fn calibrate_event(&self, event : &mut TelemetryEvent) -> Result<(),CalibrationError> {
113 self.calibrate(&mut event.tracker_hits)?;
114 Ok(())
115 }
116
117 pub fn calibrate(&self, event_hits : &mut Vec<TrackerHit>) -> Result<(),CalibrationError> {
132 let mut calibrated_hits = Vec::<TrackerHit>::with_capacity(event_hits.len());
133 let mut c_hit : TrackerHit; let mv_2_kev = 0.841f32;for hit in event_hits.iter() {
136 let mut hit_ped = 0.0f32;
137 let mut energy = hit.adc as f32;
138 let hit_tf : Option<&TrackerStripTransferFunction>;
139 if let Some(ped) = self.ped_map.get(&hit.get_stripid()) {
140 hit_ped = ped.pedestal_mean;
141 energy -= hit_ped;
142 } else {
152 error!("No entry for {} in pedestal map", hit);
153 }
156 let mut hit_is_pulser = false;
157 if self.remove_cmn {
158 let cmn = self.get_common_noise(hit, event_hits);
159 energy -= cmn.0;
160 hit_is_pulser = cmn.1;
161 }
162 hit_tf = self.tf_map.get(&hit.get_stripid());
164 if let Some(tf) = hit_tf {
165 energy = tf.transfer_fn(energy);
167 } else {
169 error!("Trying to calibrate {}, but we don't have a transfer function for that!", hit.get_stripid());
170 energy = 0.0;
171 }
173 if hit_is_pulser {
175 if let Some(pulse) = self.pulse_map.get(&hit.get_stripid()) {
176 let mut p_avg = pulse.pulse_avg;
177 if p_avg > 0.0 {
178 if p_avg > 400.0 && self.remove_pulsed {
179 continue;
180 }
181 p_avg -= hit_ped;
182 if let Some(tf) = hit_tf {
183 p_avg = tf.transfer_fn(p_avg);
184 energy -= p_avg;
185 }
186 }
187 } else {
188 warn!("Hit is from the pulser, but we don't have any information about that strip in the cmn map!");
189 }
190 }
191 c_hit = hit.clone();
192 energy *= mv_2_kev/1000.0;
193 c_hit.energy = energy;
194 calibrated_hits.push(c_hit);
196 if energy < -0.13 {
197 error!("Small energy!");
198 error!("{}", c_hit);
199 }
200 }
201 event_hits.clear();
202 *event_hits = calibrated_hits;
203 Ok(())
204 }
205}
206
207impl fmt::Display for TrackerOfflineCalibration {
208 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
209 let mut repr = String::from("<TrackerOfflineCalibration:");
210 repr += &(format!("\n N masks : {}", self.mask_map.len()));
211 repr += &(format!("\n N pedest : {}", self.ped_map.len()));
212 repr += &(format!("\n N tf_fns : {}", self.tf_map.len()));
213 repr += &(format!("\n N gains : {}", self.gain_map.len()));
214 repr += &(format!("\n N pulses : {}", self.pulse_map.len()));
215 repr += ">";
216 write!(f, "{}", repr)
217 }
218}
219
220#[cfg(feature="pybindings")]
221#[pymethods]
222impl TrackerOfflineCalibration {
223
224 #[pyo3(name="calibrate_hits")]
225 fn calibrate_hits_py(&self, mut hits : Vec<TrackerHit>) -> Vec<TrackerHit> {
226 let _ = self.calibrate(&mut hits);
227 hits
228 }
229
230 #[getter]
236 #[pyo3(name="remove_cmn")]
237 fn get_remove_cmn_py(&self) -> bool {
238 self.remove_cmn
239 }
240 #[getter]
241 #[pyo3(name="ped_sigma_cut")]
242 fn get_ped_sigma_cut_py(&self) -> f32 {
243 self.ped_sigma_cut
244 }
245
246 #[getter]
247 #[pyo3(name="remove_pulsed")]
248 fn get_remove_pulsed_py(&self) -> bool {
249 self.remove_pulsed
250 }
251
252 #[setter]
253 #[pyo3(name="remove_cmn")]
254 fn set_remove_cmn_py(&mut self, value : bool) {
255 self.remove_cmn = value;
256 }
257
258 #[setter]
259 #[pyo3(name="ped_sigma_cut")]
260 fn set_ped_sigma_cut_py(&mut self, value : f32) {
261 self.ped_sigma_cut = value;
262 }
263
264 #[setter]
265 #[pyo3(name="remove_pulsed")]
266 fn set_remove_pulsed_py(&mut self, value : bool) {
267 self.remove_pulsed = value;
268 }
269
270 #[getter]
271 #[pyo3(name="mask_map")]
272 fn get_mask_map_py(&self) -> HashMap<u32,TrackerStripMask> {
273 self.mask_map.clone()
274 }
275 #[setter]
276 #[pyo3(name="mask_map")]
277 fn set_mask_map_py(&mut self, value : HashMap<u32,TrackerStripMask>) {
278 self.mask_map = value;
279 }
280
281 #[getter]
282 #[pyo3(name="tf_map")]
283 fn get_tf_map_py(&self) -> HashMap<u32,TrackerStripTransferFunction> {
284 self.tf_map.clone()
285 }
286 #[setter]
287 #[pyo3(name="tf_map")]
288 fn set_tf_map_py(&mut self, value : HashMap<u32, TrackerStripTransferFunction>) {
289 self.tf_map = value;
290 }
291
292 #[getter]
293 #[pyo3(name="ped_map")]
294 fn get_ped_map_py(&self) -> HashMap<u32,TrackerStripPedestal> {
295 self.ped_map.clone()
296 }
297 #[setter]
298 #[pyo3(name="ped_map")]
299 fn set_ped_map_py(&mut self, value : HashMap<u32,TrackerStripPedestal>) {
300 self.ped_map = value;
301 }
302
303 #[getter]
304 #[pyo3(name="pulse_map")]
305 fn get_pulse_map_py(&self) -> HashMap<u32, TrackerStripPulse> {
306 self.pulse_map.clone()
307 }
308
309 #[setter]
310 #[pyo3(name="pulse_map")]
311 fn set_pulse_map_py(&mut self, value : HashMap<u32,TrackerStripPulse>) {
312 self.pulse_map = value;
313 }
314
315 #[getter]
316 #[pyo3(name="gain_map")]
317 fn get_gain_map_py(&self) -> HashMap<u32, TrackerStripGain> {
318 self.gain_map.clone()
319 }
320 #[setter]
321 #[pyo3(name="gain_map")]
322 fn set_gain_map_py(&mut self, value : HashMap<u32,TrackerStripGain>) {
323 self.gain_map = value;
324 }
325
326 #[getter]
327 #[pyo3(name="adc_sig_cut")]
328 fn get_adc_sig_cut_py(&self) -> HashMap<u32,f32> {
329 self.adc_sig_cut.clone()
330 }
331 #[setter]
332 #[pyo3(name="adc_sig_cut")]
333 fn set_adc_sig_cut_py(&mut self, value : HashMap<u32,f32>) {
334 self.adc_sig_cut = value;
335 }
336}
337
338#[cfg(feature="pybindings")]
339pythonize!(TrackerOfflineCalibration);
340