qsym2/target/tensor/
axialvector_transformation.rs

1//! Implementation of symmetry transformation for axial vectors.
2
3use nalgebra::Vector3;
4use ndarray::{Array1, Array2, Axis, LinalgScalar, ScalarOperand};
5use ndarray_linalg::solve::Determinant;
6use ndarray_linalg::types::Lapack;
7use num_complex::{Complex, ComplexFloat};
8
9use crate::permutation::Permutation;
10use crate::symmetry::symmetry_element::SymmetryOperation;
11use crate::symmetry::symmetry_transformation::{
12    ComplexConjugationTransformable, SpatialUnitaryTransformable, SpinUnitaryTransformable,
13    SymmetryTransformable, TimeReversalTransformable, TransformationError,
14};
15use crate::target::tensor::axialvector::{AxialVector3, TimeParity};
16
17// ---------------------------
18// SpatialUnitaryTransformable
19// ---------------------------
20impl<T> SpatialUnitaryTransformable for AxialVector3<T>
21where
22    T: ComplexFloat + LinalgScalar + ScalarOperand + Copy + Lapack,
23    f64: Into<T>,
24{
25    fn transform_spatial_mut(
26        &mut self,
27        rmat: &Array2<f64>,
28        _perm: Option<&Permutation<usize>>,
29    ) -> Result<&mut Self, TransformationError> {
30        // rmat is in (y, z, x) order. We must first reorder into (x, y, z) order.
31        let rmat_xyz = rmat.select(Axis(0), &[2, 0, 1]).select(Axis(1), &[2, 0, 1]);
32        let det = rmat_xyz
33            .det()
34            .expect("Unable to obtain the determinant of the transformation matrix.");
35        let old_components = Array1::from_iter(self.components.iter().cloned());
36        let new_components = rmat_xyz.mapv(|x| (det * x).into()).dot(&old_components);
37        self.components = Vector3::from_iterator(new_components.into_iter());
38        Ok(self)
39    }
40}
41
42// ------------------------
43// SpinUnitaryTransformable
44// ------------------------
45
46impl<T> SpinUnitaryTransformable for AxialVector3<T>
47where
48    T: ComplexFloat + Lapack,
49{
50    /// Axial vectors are spatial quantities, therefore spin transformations have no effects on
51    /// them.
52    fn transform_spin_mut(
53        &mut self,
54        _dmat: &Array2<Complex<f64>>,
55    ) -> Result<&mut Self, TransformationError> {
56        Ok(self)
57    }
58}
59
60// -------------------------------
61// ComplexConjugationTransformable
62// -------------------------------
63
64impl<T> ComplexConjugationTransformable for AxialVector3<T>
65where
66    T: ComplexFloat + Lapack,
67{
68    fn transform_cc_mut(&mut self) -> Result<&mut Self, TransformationError> {
69        self.components = self.components.map(|x| x.conj());
70        Ok(self)
71    }
72}
73
74// -------------------------
75// TimeReversalTransformable
76// -------------------------
77
78impl<T> TimeReversalTransformable for AxialVector3<T>
79where
80    T: ComplexFloat + Lapack,
81{
82    /// Provides a custom implementation of time reversal where the axial vector is kept invariant
83    /// or inverted based on its time-parity. The components of the vector are also
84    /// complex-conjugated to respect the antiunitarity of time reversal.
85    fn transform_timerev_mut(&mut self) -> Result<&mut Self, TransformationError> {
86        self.transform_cc_mut()?;
87        match self.time_parity {
88            TimeParity::Even => {}
89            TimeParity::Odd => self.components = -self.components,
90        }
91        Ok(self)
92    }
93}
94
95// ---------------------
96// SymmetryTransformable
97// ---------------------
98impl<T> SymmetryTransformable for AxialVector3<T>
99where
100    T: ComplexFloat + Lapack,
101    AxialVector3<T>: SpatialUnitaryTransformable + TimeReversalTransformable,
102{
103    fn sym_permute_sites_spatial(
104        &self,
105        _symop: &SymmetryOperation,
106    ) -> Result<Permutation<usize>, TransformationError> {
107        Permutation::from_image(vec![0]).map_err(|err| TransformationError(err.to_string()))
108    }
109}