1use crate::Field;
8use nalgebra::{Matrix4, Vector3, Vector4};
9use std::{
10 fmt::Display,
11 ops::{Add, Sub},
12};
13
14#[derive(Debug, Clone, PartialEq, Copy, Default)]
30pub struct FourMomentum<F: Field + 'static>(Vector4<F>);
31
32impl<F: Field> Eq for FourMomentum<F> {}
33
34impl<F: Field> Display for FourMomentum<F> {
35 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36 write!(
37 f,
38 "[{}, ({}, {}, {})]",
39 self.e(),
40 self.px(),
41 self.py(),
42 self.pz(),
43 )
44 }
45}
46
47impl<F: Field> FourMomentum<F> {
48 #[allow(clippy::missing_const_for_fn)]
49 pub fn new(e: F, px: F, py: F, pz: F) -> Self {
50 Self(Vector4::new(e, px, py, pz))
54 }
55
56 #[allow(clippy::missing_const_for_fn)]
58 pub fn e(&self) -> F {
59 self.0[0]
60 }
61 #[allow(clippy::missing_const_for_fn)]
63 pub fn px(&self) -> F {
64 self.0[1]
65 }
66 #[allow(clippy::missing_const_for_fn)]
68 pub fn py(&self) -> F {
69 self.0[2]
70 }
71 #[allow(clippy::missing_const_for_fn)]
73 pub fn pz(&self) -> F {
74 self.0[3]
75 }
76
77 pub fn set_e(&mut self, value: F) {
79 self.0[0] = value;
80 }
81 pub fn set_px(&mut self, value: F) {
83 self.0[1] = value;
84 }
85 pub fn set_py(&mut self, value: F) {
87 self.0[2] = value;
88 }
89 pub fn set_pz(&mut self, value: F) {
91 self.0[3] = value;
92 }
93
94 #[allow(clippy::suboptimal_flops)]
107 pub fn m2(&self) -> F {
108 F::powi(self.e(), 2) - F::powi(self.px(), 2) - F::powi(self.py(), 2) - F::powi(self.pz(), 2)
109 }
110
111 pub fn m(&self) -> F {
119 F::sqrt(self.m2())
120 }
121
122 pub fn boost_along(&self, other: &Self) -> Self {
138 let m_boost = other.boost_matrix();
139 (m_boost * self.0).into()
140 }
141 pub fn momentum(&self) -> Vector3<F> {
152 Vector3::new(self.px(), self.py(), self.pz())
153 }
154
155 pub fn costheta(&self) -> F {
157 let v = self.momentum();
158 let r = F::sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
159 v.z / r
160 }
161
162 pub fn theta_cos(&self) -> F {
166 self.costheta()
167 }
168
169 pub fn theta(&self) -> F {
171 F::acos(self.costheta())
172 }
173
174 pub fn phi(&self) -> F {
176 let v = self.momentum();
177 F::atan2(v.y, v.x)
178 }
179
180 pub fn beta3(&self) -> Vector3<F> {
184 self.momentum() / self.e()
185 }
186
187 pub fn direction(&self) -> Vector3<F> {
189 let v = self.momentum();
190 let mag = F::sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
191 v / mag
192 }
193
194 pub fn boost_matrix(&self) -> Matrix4<F> {
207 let b = self.beta3();
208 let b2 = b.dot(&b);
209 let g = F::one() / F::sqrt(F::one() - b2);
210 Matrix4::new(
211 g,
212 -g * b[0],
213 -g * b[1],
214 -g * b[2],
215 -g * b[0],
216 F::one() + (g - F::one()) * b[0] * b[0] / b2,
217 (g - F::one()) * b[0] * b[1] / b2,
218 (g - F::one()) * b[0] * b[2] / b2,
219 -g * b[1],
220 (g - F::one()) * b[1] * b[0] / b2,
221 F::one() + (g - F::one()) * b[1] * b[1] / b2,
222 (g - F::one()) * b[1] * b[2] / b2,
223 -g * b[2],
224 (g - F::one()) * b[2] * b[0] / b2,
225 (g - F::one()) * b[2] * b[1] / b2,
226 F::one() + (g - F::one()) * b[2] * b[2] / b2,
227 )
228 }
229}
230
231impl<F: Field> From<FourMomentum<F>> for Vector4<F> {
232 fn from(val: FourMomentum<F>) -> Self {
233 Self::new(val.e(), val.px(), val.py(), val.pz())
234 }
235}
236
237impl<F: Field> From<&FourMomentum<F>> for Vector4<F> {
238 fn from(val: &FourMomentum<F>) -> Self {
239 Self::new(val.e(), val.px(), val.py(), val.pz())
240 }
241}
242
243impl<F: Field> From<Vector4<F>> for FourMomentum<F> {
244 fn from(value: Vector4<F>) -> Self {
245 Self(value)
246 }
247}
248
249impl<F: Field> From<&Vector4<F>> for FourMomentum<F> {
250 fn from(value: &Vector4<F>) -> Self {
251 Self(*value)
252 }
253}
254
255impl<F: Field> From<Vec<F>> for FourMomentum<F> {
256 fn from(value: Vec<F>) -> Self {
257 Self::new(value[0], value[1], value[2], value[3])
258 }
259}
260
261impl<F: Field> From<&Vec<F>> for FourMomentum<F> {
262 fn from(value: &Vec<F>) -> Self {
263 Self::new(value[0], value[1], value[2], value[3])
264 }
265}
266
267impl<F: Field> Add for FourMomentum<F> {
268 type Output = Self;
269 fn add(self, rhs: Self) -> Self::Output {
270 Self(self.0 + rhs.0)
271 }
272}
273
274impl<F: Field> Add for &FourMomentum<F> {
275 type Output = <FourMomentum<F> as Add>::Output;
276 fn add(self, rhs: &FourMomentum<F>) -> Self::Output {
277 FourMomentum::add(*self, *rhs)
278 }
279}
280
281impl<F: Field> Sub for FourMomentum<F> {
282 type Output = Self;
283 fn sub(self, rhs: Self) -> Self::Output {
284 Self(self.0 - rhs.0)
285 }
286}
287
288impl<F: Field> Sub for &FourMomentum<F> {
289 type Output = <FourMomentum<F> as Sub>::Output;
290 fn sub(self, rhs: &FourMomentum<F>) -> Self::Output {
291 FourMomentum::sub(*self, *rhs)
292 }
293}
294
295impl<F: Field> std::iter::Sum<Self> for FourMomentum<F> {
296 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
297 iter.fold(Self::default(), |a, b| a + b)
298 }
299}
300
301#[cfg(test)]
302mod tests {
303 use super::*;
304 use crate::assert_is_close;
305 #[test]
306 fn test_set_components() {
307 let mut p = FourMomentum::<f64>::default();
308 p.set_e(1.0);
309 p.set_px(2.0);
310 p.set_py(3.0);
311 p.set_pz(4.0);
312 assert_is_close!(p.e(), 1.0, f64);
313 assert_is_close!(p.px(), 2.0, f64);
314 assert_is_close!(p.py(), 3.0, f64);
315 assert_is_close!(p.pz(), 4.0, f64);
316 }
317
318 #[test]
319 fn test_sum() {
320 let a = FourMomentum::new(0.1, 0.2, 0.3, 0.4);
321 let b = FourMomentum::new(1.0, 2.0, 3.0, 4.0);
322 let c = FourMomentum::new(10.0, 20.0, 30.0, 40.0);
323 let d: FourMomentum<f64> = [a, b, c].into_iter().sum();
324 assert_is_close!(d.e(), 11.1, f64);
325 assert_is_close!(d.px(), 22.2, f64);
326 assert_is_close!(d.py(), 33.3, f64);
327 assert_is_close!(d.pz(), 44.4, f64);
328 }
329
330 #[test]
331 fn test_ops() {
332 let a = FourMomentum::new(0.1, 0.2, 0.3, 0.4);
333 let b = FourMomentum::new(1.0, 2.0, 3.0, 4.0);
334 let c = a + b;
335 let d = b - a;
336 assert_is_close!(c.e(), 1.1, f64);
337 assert_is_close!(c.px(), 2.2, f64);
338 assert_is_close!(c.py(), 3.3, f64);
339 assert_is_close!(c.pz(), 4.4, f64);
340 assert_is_close!(d.e(), 0.9, f64);
341 assert_is_close!(d.px(), 1.8, f64);
342 assert_is_close!(d.py(), 2.7, f64);
343 assert_is_close!(d.pz(), 3.6, f64);
344 }
345}