qsym2/target/tensor/
axialvector.rs

1//! Axial vectors.
2
3use std::fmt;
4
5use approx;
6use derive_builder::Builder;
7use nalgebra::Vector3;
8use ndarray_linalg::types::Lapack;
9use num_complex::{Complex, ComplexFloat};
10use num_traits::float::{Float, FloatConst};
11
12#[cfg(test)]
13#[path = "axialvector_tests.rs"]
14mod axialvector_tests;
15
16#[path = "axialvector_analysis.rs"]
17pub mod axialvector_analysis;
18#[path = "axialvector_transformation.rs"]
19mod axialvector_transformation;
20
21/// Enumerated type to handle the two possible time parities.
22#[derive(Debug, PartialEq, Eq, Clone)]
23pub enum TimeParity {
24    /// Variant for time-even.
25    Even,
26
27    /// Variant for time-odd.
28    Odd,
29}
30
31// -------
32// Display
33// -------
34impl fmt::Display for TimeParity {
35    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36        match self {
37            TimeParity::Even => write!(f, "time-even"),
38            TimeParity::Odd => write!(f, "time-odd"),
39        }
40    }
41}
42
43// ==================
44// Struct definitions
45// ==================
46
47/// Structure to manage axial vectors in three dimensions.
48#[derive(Builder, Clone)]
49pub struct AxialVector3<T>
50where
51    T: ComplexFloat + Lapack,
52{
53    /// The $`(x, y, z)`$ components of this axial vector.
54    components: Vector3<T>,
55
56    /// The time parity of this axial vector.
57    time_parity: TimeParity,
58
59    /// The threshold for comparing determinants.
60    threshold: <T as ComplexFloat>::Real,
61}
62
63impl<T> AxialVector3<T>
64where
65    T: ComplexFloat + Clone + Lapack,
66{
67    /// Returns a builder to construct a new [`AxialVector3`].
68    pub fn builder() -> AxialVector3Builder<T> {
69        AxialVector3Builder::default()
70    }
71
72    /// Returns a shared reference to the components of the axial vector.
73    pub fn components(&self) -> &Vector3<T> {
74        &self.components
75    }
76
77    /// Returns a shared reference to the time parity.
78    pub fn time_parity(&self) -> &TimeParity {
79        &self.time_parity
80    }
81
82    /// Returns the threshold with which axial vectors are compared.
83    pub fn threshold(&self) -> <T as ComplexFloat>::Real {
84        self.threshold
85    }
86}
87
88// =====================
89// Trait implementations
90// =====================
91
92// ----
93// From
94// ----
95impl<T> From<AxialVector3<T>> for AxialVector3<Complex<T>>
96where
97    T: Float + FloatConst + Lapack,
98    Complex<T>: Lapack,
99{
100    fn from(value: AxialVector3<T>) -> Self {
101        AxialVector3::<Complex<T>>::builder()
102            .components(value.components.map(Complex::from))
103            .time_parity(value.time_parity.clone())
104            .threshold(value.threshold)
105            .build()
106            .expect("Unable to construct a complex axial vector in three dimensions.")
107    }
108}
109
110// ---------
111// PartialEq
112// ---------
113impl<T> PartialEq for AxialVector3<T>
114where
115    T: ComplexFloat<Real = f64> + Lapack,
116{
117    fn eq(&self, other: &Self) -> bool {
118        let thresh = (self.threshold * other.threshold).sqrt();
119        let components_eq = approx::relative_eq!(
120            (&self.components - &other.components)
121                .map(|x| ComplexFloat::abs(x).powi(2))
122                .sum()
123                .sqrt(),
124            0.0,
125            epsilon = thresh,
126            max_relative = thresh,
127        );
128        self.time_parity == other.time_parity && components_eq
129    }
130}
131
132// --
133// Eq
134// --
135impl<T> Eq for AxialVector3<T> where T: ComplexFloat<Real = f64> + Lapack {}
136
137// -----
138// Debug
139// -----
140impl<T> fmt::Debug for AxialVector3<T>
141where
142    T: fmt::Debug + ComplexFloat + Lapack,
143{
144    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145        write!(
146            f,
147            "AxialVector3({})({:+.7}, {:+.7}, {:+.7})",
148            self.time_parity, self.components[0], self.components[1], self.components[2],
149        )
150    }
151}
152
153// -------
154// Display
155// -------
156impl<T> fmt::Display for AxialVector3<T>
157where
158    T: fmt::Display + ComplexFloat + Lapack,
159{
160    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161        write!(
162            f,
163            "AxialVector3({})({:+.3}, {:+.3}, {:+.3})",
164            self.time_parity, self.components[0], self.components[1], self.components[2],
165        )
166    }
167}