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