gondola_core/events/
tracker_hit.rs1use crate::prelude::*;
6
7#[cfg(feature="pybindings")]
8use pyo3::basic::CompareOp;
9
10use std::cmp::Ordering;
11
12#[derive(Debug, Copy, Clone)]
14#[cfg_attr(feature="pybindings", pyclass)]
15pub struct TrackerHit {
16 pub layer : u8,
17 pub row : u8,
18 pub module : u8,
19 pub channel : u8,
20 pub adc : u16,
21 pub oscillator : u64,
22 pub asic_event_code : u8,
26
27 pub energy : f32,
30 pub x : f32,
31 pub y : f32,
32 pub z : f32,
33 pub has_coordinates : bool,
34 pub adc_pedestal : u16,
35}
36
37impl TrackerHit {
38 pub fn new() -> Self {
41 Self {
42 layer : 0,
43 row : 0,
44 module : 0,
45 channel : 0,
46 adc : 0,
47 oscillator : 0,
48 asic_event_code : 0,
49 energy : 0.0,
50 x : 0.0,
51 y : 0.0,
52 z : 0.0,
53 has_coordinates : false,
54 adc_pedestal : 0,
55 }
56 }
57
58 #[inline]
59 pub fn identity(&self) -> u64 {
60 ((self.layer as u64) << 40) |
62 ((self.row as u64) << 32) |
63 ((self.module as u64) << 24) |
64 ((self.channel as u64) << 16) |
65 (self.adc as u64)
66 }
67
68 pub fn get_stripid(&self) -> u32 {
70 crate::events::strip_id(self.layer ,
71 self.row ,
72 self.module ,
73 self.channel)
74 }
75
76 #[cfg(feature="database")]
77 pub fn set_coordinates(&mut self, strip_map : &HashMap<u32, TrackerStrip>) {
78 match strip_map.get(&self.get_stripid()) {
79 None => debug!("Can not get strip for strip id {}" , self.get_stripid()),
80 Some(strip) => {
81 self.x = strip.global_pos_x_l0;
82 self.y = strip.global_pos_y_l0;
83 self.z = strip.global_pos_z_l0;
84 self.has_coordinates = true
85 }
86 }
87 }
88}
89
90impl PartialEq for TrackerHit {
91 fn eq(&self, other: &TrackerHit) -> bool {
92 self.identity() == other.identity()
97 }
106}
107
108impl Eq for TrackerHit {
111}
112
113impl Ord for TrackerHit {
116 fn cmp(&self, other: &Self) -> Ordering {
117 other.identity().cmp(&self.identity())
118 }
119}
120
121impl PartialOrd for TrackerHit {
124 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
125 Some(self.cmp(other))
126 }
127}
128
129
130
131impl fmt::Display for TrackerHit {
132 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
133 let mut repr = String::from("<TrackerHit:");
134 repr += &(format!("\n Layer, Row, Module, Channel : {} {} {} {}" ,self.layer, self.row, self.module, self.channel));
135 repr += &(format!("\n ADC : {}" ,self.adc));
136 repr += &(format!("\n Oscillator : {}" ,self.oscillator));
137 repr += &(format!("\n ASIC Evt code : {}" ,self.asic_event_code));
138 if self.has_coordinates {
139 repr += &(format!("\n -- coordinates x : {} , y : {} , z {}", self.x, self.y, self.z));
140 } else {
141 repr += "\n -- [no coordinates set]";
142 }
143 repr += &(format!("\n Cali. energy : {}>", self.energy));
144 write!(f, "{}", repr)
145 }
146}
147
148#[cfg(feature="pybindings")]
149#[pymethods]
150impl TrackerHit {
151
152 fn __hash__(&self) -> isize {
154 let h = self.identity();
155 h as isize
158 }
159
160 fn subtract_pedestal(&mut self, pedestal : u16) {
163 self.adc -= pedestal;
164 }
165
166 #[getter]
167 fn get_strip_id(&self) -> u32 {
168 self.get_stripid()
169 }
170
171 #[getter]
172 fn get_layer(&self) -> u8 {
173 self.layer
174 }
175
176 #[getter]
177 fn get_row(&self) -> u8 {
178 self.row
179 }
180
181 #[getter]
182 fn get_module(&self) -> u8 {
183 self.module
184 }
185
186 #[getter]
187 fn get_channel(&self) -> u8 {
188 self.channel
189 }
190
191 #[getter]
192 fn get_adc(&self) -> u16 {
193 self.adc
194 }
195
196 #[getter]
197 fn get_oscillator(&self) -> u64 {
198 self.oscillator
199 }
200
201 #[getter]
202 fn get_asic_event_code(&self) -> u8 {
203 self.asic_event_code
204 }
205
206 #[getter]
207 fn get_energy(&self) -> f32 {
208 self.energy
209 }
210
211 #[getter]
212 fn get_x(&self) -> f32 {
213 self.x
214 }
215
216 #[getter]
217 fn get_y(&self) -> f32 {
218 self.y
219 }
220
221 #[getter]
222 fn get_z(&self) -> f32 {
223 self.z
224 }
225
226 fn __richcmp__(&self, other: &Self, op: CompareOp) -> PyResult<bool> {
228 match op {
229 CompareOp::Eq => Ok(self == other),
230 CompareOp::Ne => Ok(self != other),
231 _ => Ok(false), }
233 }
234}
235
236#[cfg(feature="random")]
237impl FromRandom for TrackerHit {
238 fn from_random() -> Self {
239 let mut rng = rand::rng();
240 Self {
241 layer : rng.random_range(0..9),
242 row : rng.random_range(0..6),
243 module : rng.random_range(0..6),
244 channel : rng.random_range(0..32),
245 adc : rng.random::<u16>() & 0x7ff,
246 oscillator : rng.random::<u64>(),
247 asic_event_code : rng.random_range(0..4),
248 energy : 0.0,
249 x : 0.0,
250 y : 0.0,
251 z : 0.0,
252 has_coordinates : false,
253 adc_pedestal : 0,
254 }
255 }
256}
257
258#[test]
259fn test_tracker_hit_equality() {
260 let hit_a = TrackerHit::from_random();
262 let hit_b = hit_a; assert_eq!(hit_a, hit_b, "Identical hits must be equal");
264
265 let mut hit_c = hit_a;
267 hit_c.channel = hit_a.channel.wrapping_add(1);
269 assert_ne!(hit_a, hit_c, "Hits with different channels must not be equal");
270
271 let mut hit_d = hit_a;
273 hit_d.adc = hit_a.adc.wrapping_add(1);
274 assert_ne!(hit_a, hit_d, "Hits with different ADC values must not be equal");
275}
276
277
278#[cfg(feature="pybindings")]
279pythonize!(TrackerHit);
280