qsym2/target/density/
density_projection.rs1use anyhow::{self, format_err};
4use ndarray::Array2;
5use num::{Complex, ToPrimitive};
6
7use super::density_analysis::DensitySymmetryOrbit;
8use crate::analysis::Orbit;
9use crate::chartab::chartab_symbols::LinearSpaceSymbol;
10use crate::projection::Projectable;
11use crate::symmetry::symmetry_group::SymmetryGroupProperties;
12use crate::target::density::Density;
13
14impl<'a, G> Projectable<G, Density<'a, f64>> for DensitySymmetryOrbit<'a, G, f64>
15where
16 G: SymmetryGroupProperties,
17{
18 type Projected<'p>
19 = Result<Density<'p, f64>, anyhow::Error>
20 where
21 Self: 'p;
22
23 fn project_onto(&self, row: &G::RowSymbol) -> Self::Projected<'_> {
24 let group_order = self
25 .group()
26 .order()
27 .to_f64()
28 .ok_or_else(|| format_err!("Unable to convert the group order to `f64`."))?;
29 let dim_f64 = row
30 .dimensionality()
31 .to_f64()
32 .ok_or_else(|| format_err!("Unable to convert the degeneracy to `f64`."))?;
33 let denmat_res = self.generate_orbit_algebra_terms(row).fold(
34 Ok(Array2::<f64>::zeros(self.origin().density_matrix().raw_dim())),
35 |acc_res, item_res| acc_res.and_then(|acc| item_res.and_then(|(chr, den)| {
36 let chr_complex = chr.complex_conjugate().complex_value();
37 if chr_complex.im > self.origin().threshold() {
38 Err(format_err!("Complex characters encountered. Density projection fails over the reals."))
39 } else {
40 Ok(acc + dim_f64 * chr_complex.re / group_order * den.density_matrix())
41 }
42 })),
43 );
44 denmat_res.and_then(|denmat| {
45 Density::builder()
46 .bao(self.origin().bao)
47 .complex_symmetric(self.origin().complex_symmetric)
48 .complex_conjugated(self.origin().complex_conjugated)
49 .mol(self.origin().mol)
50 .density_matrix(denmat)
51 .threshold(self.origin().threshold)
52 .build()
53 .map_err(|err| format_err!(err))
54 })
55 }
56}
57
58impl<'a, G> Projectable<G, Density<'a, Complex<f64>>> for DensitySymmetryOrbit<'a, G, Complex<f64>>
59where
60 G: SymmetryGroupProperties,
61{
62 type Projected<'p>
63 = Result<Density<'p, Complex<f64>>, anyhow::Error>
64 where
65 Self: 'p;
66
67 fn project_onto(&self, row: &G::RowSymbol) -> Self::Projected<'_> {
68 let group_order = Complex::from(
69 self.group()
70 .order()
71 .to_f64()
72 .ok_or_else(|| format_err!("Unable to convert the group order to `f64`."))?,
73 );
74 let dim_f64 = row
75 .dimensionality()
76 .to_f64()
77 .ok_or_else(|| format_err!("Unable to convert the degeneracy to `f64`."))?;
78 let denmat_res = self.generate_orbit_algebra_terms(row).fold(
79 Ok(Array2::<Complex<f64>>::zeros(
80 self.origin().density_matrix().raw_dim(),
81 )),
82 |acc_res, item_res| {
83 acc_res.and_then(|acc| {
84 item_res.and_then(|(chr, den)| {
85 let chr_complex = chr.complex_conjugate().complex_value();
86 Ok(acc + dim_f64 * chr_complex / group_order * den.density_matrix())
87 })
88 })
89 },
90 );
91 denmat_res.and_then(|denmat| {
92 Density::builder()
93 .bao(self.origin().bao)
94 .complex_symmetric(self.origin().complex_symmetric)
95 .complex_conjugated(self.origin().complex_conjugated)
96 .mol(self.origin().mol)
97 .density_matrix(denmat)
98 .threshold(self.origin().threshold)
99 .build()
100 .map_err(|err| format_err!(err))
101 })
102 }
103}