qsym2/target/density/
density_transformation.rs1use ndarray::{concatenate, s, Array2, Axis, LinalgScalar, ScalarOperand};
4use ndarray_linalg::types::Lapack;
5use num_complex::{Complex, ComplexFloat};
6
7use crate::permutation::{IntoPermutation, PermutableCollection, Permutation};
8use crate::symmetry::symmetry_element::SymmetryOperation;
9use crate::symmetry::symmetry_transformation::{
10 assemble_sh_rotation_3d_matrices, permute_array_by_atoms, ComplexConjugationTransformable,
11 DefaultTimeReversalTransformable, SpatialUnitaryTransformable, SpinUnitaryTransformable,
12 SymmetryTransformable, TimeReversalTransformable, TransformationError,
13};
14use crate::target::density::Density;
15
16impl<'a, T> SpatialUnitaryTransformable for Density<'a, T>
20where
21 T: ComplexFloat + LinalgScalar + ScalarOperand + Copy + Lapack,
22 f64: Into<T>,
23{
24 fn transform_spatial_mut(
25 &mut self,
26 rmat: &Array2<f64>,
27 perm: Option<&Permutation<usize>>,
28 ) -> Result<&mut Self, TransformationError> {
29 let tmats: Vec<Array2<T>> = assemble_sh_rotation_3d_matrices(self.bao, rmat, perm)
30 .map_err(|err| TransformationError(err.to_string()))?
31 .iter()
32 .map(|tmat| tmat.map(|&x| x.into()))
33 .collect();
34 let pbao = if let Some(p) = perm {
35 self.bao
36 .permute(p)
37 .map_err(|err| TransformationError(err.to_string()))?
38 } else {
39 self.bao.clone()
40 };
41 let old_denmat = &self.density_matrix;
42 let p_coeff = if let Some(p) = perm {
43 permute_array_by_atoms(old_denmat, p, &[Axis(0), Axis(1)], self.bao)
44 } else {
45 old_denmat.clone()
46 };
47 let trow_p_blocks = pbao
48 .shell_boundary_indices()
49 .into_iter()
50 .zip(tmats.iter())
51 .map(|((shl_start, shl_end), tmat)| {
52 tmat.dot(&p_coeff.slice(s![shl_start..shl_end, ..]))
53 })
54 .collect::<Vec<_>>();
55 let trow_p_coeff = concatenate(
56 Axis(0),
57 &trow_p_blocks
58 .iter()
59 .map(|trow_p_block| trow_p_block.view())
60 .collect::<Vec<_>>(),
61 )
62 .expect("Unable to concatenate the transformed rows for the various shells.");
63
64 let tcol_trow_p_blocks = pbao
65 .shell_boundary_indices()
66 .into_iter()
67 .zip(tmats.iter())
68 .map(|((shl_start, shl_end), tmat)| {
69 trow_p_coeff
71 .slice(s![.., shl_start..shl_end])
72 .dot(&tmat.t())
73 })
74 .collect::<Vec<_>>();
75 let new_denmat = concatenate(
76 Axis(1),
77 &tcol_trow_p_blocks
78 .iter()
79 .map(|tcol_trow_p_block| tcol_trow_p_block.view())
80 .collect::<Vec<_>>(),
81 )
82 .expect("Unable to concatenate the transformed columns for the various shells.");
83 self.density_matrix = new_denmat;
84 Ok(self)
85 }
86}
87
88impl<'a, T> SpinUnitaryTransformable for Density<'a, T>
93where
94 T: ComplexFloat + Lapack,
95{
96 fn transform_spin_mut(
101 &mut self,
102 _: &Array2<Complex<f64>>,
103 ) -> Result<&mut Self, TransformationError> {
104 Ok(self)
105 }
106}
107
108impl<'a, T> ComplexConjugationTransformable for Density<'a, T>
113where
114 T: ComplexFloat + Lapack,
115{
116 fn transform_cc_mut(&mut self) -> Result<&mut Self, TransformationError> {
117 self.density_matrix.mapv_inplace(|x| x.conj());
118 self.complex_conjugated = !self.complex_conjugated;
119 Ok(self)
120 }
121}
122
123impl<'a, T> DefaultTimeReversalTransformable for Density<'a, T> where T: ComplexFloat + Lapack {}
127
128impl<'a, T> SymmetryTransformable for Density<'a, T>
132where
133 T: ComplexFloat + Lapack,
134 Density<'a, T>: SpatialUnitaryTransformable + TimeReversalTransformable,
135{
136 fn sym_permute_sites_spatial(
137 &self,
138 symop: &SymmetryOperation,
139 ) -> Result<Permutation<usize>, TransformationError> {
140 if (symop.generating_element.threshold().log10() - self.mol.threshold.log10()).abs() >= 3.0
141 {
142 log::warn!(
143 "Symmetry operation threshold ({:.3e}) and molecule threshold ({:.3e}) \
144 differ by more than three orders of magnitudes.",
145 symop.generating_element.threshold(),
146 self.mol.threshold
147 )
148 }
149 symop
150 .act_permute(&self.mol.molecule_ordinary_atoms())
151 .ok_or(TransformationError(format!(
152 "Unable to determine the atom permutation corresponding to the operation `{symop}`.",
153 )))
154 }
155}