qsym2/drivers/representation_analysis/
mod.rs1use std::fmt;
4
5#[cfg(feature = "python")]
6use pyo3::prelude::*;
7use serde::{Deserialize, Serialize};
8
9use crate::basis::ao::BasisAngularOrder;
10use crate::group::class::ClassPropertiesSummary;
11use crate::io::format::{log_subtitle, qsym2_output, QSym2Output};
12
13pub mod angular_function;
14pub mod density;
15pub mod multideterminant;
16pub mod slater_determinant;
17pub mod vibrational_coordinate;
18
19#[derive(Clone, Debug, Deserialize, Serialize)]
25pub enum CharacterTableDisplay {
26 Symbolic,
28
29 Numerical,
31}
32
33impl fmt::Display for CharacterTableDisplay {
34 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
35 match self {
36 CharacterTableDisplay::Symbolic => write!(f, "Symbolic"),
37 CharacterTableDisplay::Numerical => write!(f, "Numerical"),
38 }
39 }
40}
41
42#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
45#[cfg_attr(feature = "python", pyclass(eq, eq_int))]
46pub enum MagneticSymmetryAnalysisKind {
47 Representation,
50
51 Corepresentation,
54}
55
56impl fmt::Display for MagneticSymmetryAnalysisKind {
57 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
58 match self {
59 MagneticSymmetryAnalysisKind::Representation => write!(f, "Unitary representations"),
60 MagneticSymmetryAnalysisKind::Corepresentation => {
61 write!(f, "Magnetic corepresentations")
62 }
63 }
64 }
65}
66
67fn log_bao(bao: &BasisAngularOrder) {
77 log_subtitle("Basis angular order");
78 qsym2_output!("");
79 "The basis angular order information dictates how basis functions in each basis shell are transformed.\n\
80 It is important to check that this is consistent with the basis set being used, otherwise incorrect\n\
81 symmetry results will be obtained.".log_output_display();
82 bao.log_output_display();
83 qsym2_output!("");
84}
85
86pub(crate) fn log_cc_transversal<G>(group: &G)
92where
93 G: ClassPropertiesSummary,
94 G::GroupElement: fmt::Display,
95{
96 log_subtitle("Conjugacy class transversal");
97 qsym2_output!("");
98 group.class_transversal_to_string().log_output_display();
99 qsym2_output!("");
100}
101
102macro_rules! fn_construct_unitary_group {
107 ( $(#[$meta:meta])* $vis:vis $func:ident ) => {
108 $(#[$meta])*
109 $vis fn $func(&self) -> Result<UnitaryRepresentedSymmetryGroup, anyhow::Error> {
110 let params = self.parameters;
111 let sym = match params.use_magnetic_group {
112 Some(MagneticSymmetryAnalysisKind::Representation) => self.symmetry_group
113 .magnetic_symmetry
114 .as_ref()
115 .ok_or_else(|| {
116 format_err!(
117 "Magnetic symmetry requested for analysis, but no magnetic symmetry found."
118 )
119 })?,
120 Some(MagneticSymmetryAnalysisKind::Corepresentation) => bail!("Magnetic corepresentations requested, but unitary-represented group is being constructed."),
121 None => &self.symmetry_group.unitary_symmetry
122 };
123 let group = if params.use_double_group {
124 UnitaryRepresentedGroup::from_molecular_symmetry(sym, params.infinite_order_to_finite)?
125 .to_double_group()?
126 } else {
127 UnitaryRepresentedGroup::from_molecular_symmetry(sym, params.infinite_order_to_finite)?
128 };
129
130 qsym2_output!(
131 "Unitary-represented group for representation analysis: {}",
132 group.name()
133 );
134 qsym2_output!("");
135 if let Some(chartab_display) = params.write_character_table.as_ref() {
136 log_subtitle("Character table of irreducible representations");
137 qsym2_output!("");
138 match chartab_display {
139 CharacterTableDisplay::Symbolic => {
140 group.character_table().log_output_debug();
141 "Any `En` in a character value denotes the first primitive n-th root of unity:\n \
142 En = exp(2πi/n)".log_output_display();
143 }
144 CharacterTableDisplay::Numerical => group.character_table().log_output_display(),
145 }
146 qsym2_output!("");
147 qsym2_output!("The symbol `◈` indicates the principal class of the group.");
148 qsym2_output!("");
149 "Note 1: `FS` contains the classification of the irreps using the Frobenius--Schur indicator:\n \
150 `r` = real: the irrep and its complex-conjugate partner are real and identical,\n \
151 `c` = complex: the irrep and its complex-conjugate partner are complex and inequivalent,\n \
152 `q` = quaternion: the irrep and its complex-conjugate partner are complex and equivalent.\n\n\
153 Note 2: The conjugacy classes are sorted according to the following order:\n \
154 E -> C_n (n descending) -> C2 -> i -> S_n (n decending) -> σ\n \
155 Within each order and power, elements with axes close to Cartesian axes are put first.\n \
156 Within each equi-inclination from Cartesian axes, z-inclined axes are put first, then y, then x.\n\n\
157 Note 3: The Mulliken labels generated for the irreps in the table above are internally consistent.\n \
158 However, certain labels might differ from those tabulated elsewhere using other conventions.\n \
159 If need be, please check with other literature to ensure external consistency.".log_output_display();
160 qsym2_output!("");
161 }
162 Ok(group)
163 }
164 }
165}
166
167macro_rules! fn_construct_magnetic_group {
168 ( $(#[$meta:meta])* $vis:vis $func:ident ) => {
169 $(#[$meta])*
170 $vis fn $func(&self) -> Result<MagneticRepresentedSymmetryGroup, anyhow::Error> {
171 let params = self.parameters;
172 let sym = match params.use_magnetic_group {
173 Some(MagneticSymmetryAnalysisKind::Corepresentation) => self.symmetry_group
174 .magnetic_symmetry
175 .as_ref()
176 .ok_or_else(|| {
177 format_err!(
178 "Magnetic symmetry requested for analysis, but no magnetic symmetry found."
179 )
180 })?,
181 Some(MagneticSymmetryAnalysisKind::Representation) => bail!("Unitary representations requested, but magnetic-represented group is being constructed."),
182 None => &self.symmetry_group.unitary_symmetry
183 };
184 let group = if params.use_double_group {
185 MagneticRepresentedGroup::from_molecular_symmetry(sym, params.infinite_order_to_finite)?
186 .to_double_group()?
187 } else {
188 MagneticRepresentedGroup::from_molecular_symmetry(sym, params.infinite_order_to_finite)?
189 };
190
191 qsym2_output!(
192 "Magnetic-represented group for corepresentation analysis: {}",
193 group.name()
194 );
195 qsym2_output!("");
196
197 if let Some(chartab_display) = params.write_character_table.as_ref() {
198 log_subtitle("Character table of irreducible corepresentations");
199 qsym2_output!("");
200 match chartab_display {
201 CharacterTableDisplay::Symbolic => {
202 group.character_table().log_output_debug();
203 "Any `En` in a character value denotes the first primitive n-th root of unity:\n \
204 En = exp(2πi/n)".log_output_display();
205 }
206 CharacterTableDisplay::Numerical => group.character_table().log_output_display(),
207 }
208 qsym2_output!("");
209 qsym2_output!("The symbol `◈` indicates the principal class of the group.");
210 qsym2_output!("");
211 "Note 1: The ircorep notation `D[Δ]` means that this ircorep is induced by the representation Δ\n \
212 of the unitary halving subgroup. The exact nature of Δ determines the kind of D[Δ].\n\n\
213 Note 2: `IN` shows the intertwining numbers of the ircoreps which classify them into three kinds:\n \
214 `1` = 1st kind: the ircorep is induced by a single irrep of the unitary halving subgroup once,\n \
215 `4` = 2nd kind: the ircorep is induced by a single irrep of the unitary halving subgroup twice,\n \
216 `2` = 3rd kind: the ircorep is induced by an irrep of the unitary halving subgroup and its Wigner conjugate.\n\n\
217 Note 3: Only unitary-represented elements are shown in the character table, as characters of\n \
218 antiunitary-represented elements are not invariant under a change of basis.\n\n\
219 Refs:\n \
220 Newmarch, J. D. & Golding, R. M. J. Math. Phys. 23, 695–704 (1982)\n \
221 Bradley, C. J. & Davies, B. L. Rev. Mod. Phys. 40, 359–379 (1968)\n \
222 Newmarch, J. D. J. Math. Phys. 24, 742–756 (1983)".log_output_display();
223 qsym2_output!("");
224 }
225
226 Ok(group)
227 }
228 }
229}
230
231pub(crate) use fn_construct_magnetic_group;
232pub(crate) use fn_construct_unitary_group;