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::{QSym2Output, log_subtitle, qsym2_output};
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
67pub(crate) fn log_bao(bao: &BasisAngularOrder, index: Option<usize>) {
80 if let Some(i) = index {
81 log_subtitle(&format!("Basis angular order (explicit component {i})"));
82 } else {
83 log_subtitle("Basis angular order (uniform across all explicit components)");
84 }
85 qsym2_output!("");
86 "The basis angular order information dictates how basis functions in each basis shell are transformed.\n\
87 It is important to check that this is consistent with the basis set being used, otherwise incorrect\n\
88 symmetry results will be obtained.".log_output_display();
89 bao.log_output_display();
90 qsym2_output!("");
91}
92
93pub(crate) fn log_cc_transversal<G>(group: &G)
99where
100 G: ClassPropertiesSummary,
101 G::GroupElement: fmt::Display,
102{
103 log_subtitle("Conjugacy class transversal");
104 qsym2_output!("");
105 group.class_transversal_to_string().log_output_display();
106 qsym2_output!("");
107}
108
109macro_rules! fn_construct_unitary_group {
114 ( $(#[$meta:meta])* $vis:vis $func:ident ) => {
115 $(#[$meta])*
116 $vis fn $func(&self) -> Result<UnitaryRepresentedSymmetryGroup, anyhow::Error> {
117 let params = self.parameters;
118 let sym = match params.use_magnetic_group {
119 Some(MagneticSymmetryAnalysisKind::Representation) => self.symmetry_group
120 .magnetic_symmetry
121 .as_ref()
122 .ok_or_else(|| {
123 format_err!(
124 "Magnetic symmetry requested for analysis, but no magnetic symmetry found."
125 )
126 })?,
127 Some(MagneticSymmetryAnalysisKind::Corepresentation) => bail!("Magnetic corepresentations requested, but unitary-represented group is being constructed."),
128 None => &self.symmetry_group.unitary_symmetry
129 };
130 let group = if params.use_double_group {
131 UnitaryRepresentedGroup::from_molecular_symmetry(sym, params.infinite_order_to_finite)?
132 .to_double_group()?
133 } else {
134 UnitaryRepresentedGroup::from_molecular_symmetry(sym, params.infinite_order_to_finite)?
135 };
136
137 qsym2_output!(
138 "Unitary-represented group for representation analysis: {}",
139 group.name()
140 );
141 qsym2_output!("");
142 if let Some(chartab_display) = params.write_character_table.as_ref() {
143 log_subtitle("Character table of irreducible representations");
144 qsym2_output!("");
145 match chartab_display {
146 CharacterTableDisplay::Symbolic => {
147 group.character_table().log_output_debug();
148 "Any `En` in a character value denotes the first primitive n-th root of unity:\n \
149 En = exp(2πi/n)".log_output_display();
150 }
151 CharacterTableDisplay::Numerical => group.character_table().log_output_display(),
152 }
153 qsym2_output!("");
154 qsym2_output!("The symbol `◈` indicates the principal class of the group.");
155 qsym2_output!("");
156 "Note 1: `FS` contains the classification of the irreps using the Frobenius--Schur indicator:\n \
157 `r` = real: the irrep and its complex-conjugate partner are real and identical,\n \
158 `c` = complex: the irrep and its complex-conjugate partner are complex and inequivalent,\n \
159 `q` = quaternion: the irrep and its complex-conjugate partner are complex and equivalent.\n\n\
160 Note 2: The conjugacy classes are sorted according to the following order:\n \
161 E -> C_n (n descending) -> C2 -> i -> S_n (n decending) -> σ\n \
162 Within each order and power, elements with axes close to Cartesian axes are put first.\n \
163 Within each equi-inclination from Cartesian axes, z-inclined axes are put first, then y, then x.\n\n\
164 Note 3: The Mulliken labels generated for the irreps in the table above are internally consistent.\n \
165 However, certain labels might differ from those tabulated elsewhere using other conventions.\n \
166 If need be, please check with other literature to ensure external consistency.".log_output_display();
167 qsym2_output!("");
168 }
169 Ok(group)
170 }
171 }
172}
173
174macro_rules! fn_construct_magnetic_group {
175 ( $(#[$meta:meta])* $vis:vis $func:ident ) => {
176 $(#[$meta])*
177 $vis fn $func(&self) -> Result<MagneticRepresentedSymmetryGroup, anyhow::Error> {
178 let params = self.parameters;
179 let sym = match params.use_magnetic_group {
180 Some(MagneticSymmetryAnalysisKind::Corepresentation) => self.symmetry_group
181 .magnetic_symmetry
182 .as_ref()
183 .ok_or_else(|| {
184 format_err!(
185 "Magnetic symmetry requested for analysis, but no magnetic symmetry found."
186 )
187 })?,
188 Some(MagneticSymmetryAnalysisKind::Representation) => bail!("Unitary representations requested, but magnetic-represented group is being constructed."),
189 None => &self.symmetry_group.unitary_symmetry
190 };
191 let group = if params.use_double_group {
192 MagneticRepresentedGroup::from_molecular_symmetry(sym, params.infinite_order_to_finite)?
193 .to_double_group()?
194 } else {
195 MagneticRepresentedGroup::from_molecular_symmetry(sym, params.infinite_order_to_finite)?
196 };
197
198 qsym2_output!(
199 "Magnetic-represented group for corepresentation analysis: {}",
200 group.name()
201 );
202 qsym2_output!("");
203
204 if let Some(chartab_display) = params.write_character_table.as_ref() {
205 log_subtitle("Character table of irreducible corepresentations");
206 qsym2_output!("");
207 match chartab_display {
208 CharacterTableDisplay::Symbolic => {
209 group.character_table().log_output_debug();
210 "Any `En` in a character value denotes the first primitive n-th root of unity:\n \
211 En = exp(2πi/n)".log_output_display();
212 }
213 CharacterTableDisplay::Numerical => group.character_table().log_output_display(),
214 }
215 qsym2_output!("");
216 qsym2_output!("The symbol `◈` indicates the principal class of the group.");
217 qsym2_output!("");
218 "Note 1: The ircorep notation `D[Δ]` means that this ircorep is induced by the representation Δ\n \
219 of the unitary halving subgroup. The exact nature of Δ determines the kind of D[Δ].\n\n\
220 Note 2: `IN` shows the intertwining numbers of the ircoreps which classify them into three kinds:\n \
221 `1` = 1st kind: the ircorep is induced by a single irrep of the unitary halving subgroup once,\n \
222 `4` = 2nd kind: the ircorep is induced by a single irrep of the unitary halving subgroup twice,\n \
223 `2` = 3rd kind: the ircorep is induced by an irrep of the unitary halving subgroup and its Wigner conjugate.\n\n\
224 Note 3: Only unitary-represented elements are shown in the character table, as characters of\n \
225 antiunitary-represented elements are not invariant under a change of basis.\n\n\
226 Refs:\n \
227 Newmarch, J. D. & Golding, R. M. J. Math. Phys. 23, 695–704 (1982)\n \
228 Bradley, C. J. & Davies, B. L. Rev. Mod. Phys. 40, 359–379 (1968)\n \
229 Newmarch, J. D. J. Math. Phys. 24, 742–756 (1983)".log_output_display();
230 qsym2_output!("");
231 }
232
233 Ok(group)
234 }
235 }
236}
237
238pub(crate) use fn_construct_magnetic_group;
239pub(crate) use fn_construct_unitary_group;