qsym2/sandbox/bindings/python/representation_analysis/
real_space_function.rs1use std::path::PathBuf;
4
5use duplicate::duplicate_item;
6use nalgebra::Point3;
7use num::Complex;
8use numpy::{PyArray1, PyArray2, PyArrayMethods};
9use pyo3::exceptions::{PyIOError, PyRuntimeError};
10use pyo3::prelude::*;
11use pyo3::types::PyFunction;
12
13use crate::analysis::EigenvalueComparisonMode;
14use crate::drivers::representation_analysis::angular_function::AngularFunctionRepAnalysisParams;
15use crate::drivers::representation_analysis::{
16 CharacterTableDisplay, MagneticSymmetryAnalysisKind,
17};
18use crate::drivers::symmetry_group_detection::SymmetryGroupDetectionResult;
19use crate::drivers::QSym2Driver;
20use crate::io::format::qsym2_output;
21use crate::io::{read_qsym2_binary, QSym2FileType};
22use crate::sandbox::drivers::representation_analysis::real_space_function::{
23 RealSpaceFunctionRepAnalysisDriver, RealSpaceFunctionRepAnalysisParams,
24};
25use crate::sandbox::target::real_space_function::RealSpaceFunction;
26use crate::symmetry::symmetry_group::{
27 MagneticRepresentedSymmetryGroup, UnitaryRepresentedSymmetryGroup,
28};
29use crate::symmetry::symmetry_transformation::SymmetryTransformationKind;
30
31#[duplicate_item(
36 [
37 dtype_ [ f64 ]
38 doc_sub_ [ "Python-exposed function to perform representation symmetry analysis for real-valued real-space functions and log the result via the `qsym2-output` logger at the `INFO` level." ]
39 func_sub_ [ "* `function` - A Python function callable on three Cartesian coordinates to give a scalar value. Python type: `Callable[[float, float, float], float]`." ]
40 rep_analyse_real_space_function_ [ rep_analyse_real_space_function_real ]
41 ]
42 [
43 dtype_ [ Complex<f64> ]
44 doc_sub_ [ "Python-exposed function to perform representation symmetry analysis for complex-valued real-space functions and log the result via the `qsym2-output` logger at the `INFO` level." ]
45 func_sub_ [ "* `function` - A Python function callable on three Cartesian coordinates to give a scalar value. Python type: `Callable[[float, float, float], complex]`." ]
46 rep_analyse_real_space_function_ [ rep_analyse_real_space_function_complex ]
47 ]
48)]
49#[doc = doc_sub_]
50#[doc = func_sub_]
57#[allow(clippy::too_many_arguments)]
95#[pyfunction]
96#[pyo3(signature = (
97 inp_sym,
98 function,
99 integrality_threshold,
100 linear_independence_threshold,
101 use_magnetic_group,
102 use_double_group,
103 use_cayley_table,
104 symmetry_transformation_kind,
105 eigenvalue_comparison_mode,
106 grid_points,
107 weight,
108 write_overlap_eigenvalues=true,
109 write_character_table=true,
110 infinite_order_to_finite=None,
111 angular_function_integrality_threshold=1e-7,
112 angular_function_linear_independence_threshold=1e-7,
113 angular_function_max_angular_momentum=2
114))]
115pub fn rep_analyse_real_space_function_(
116 py: Python<'_>,
117 inp_sym: PathBuf,
118 function: Py<PyFunction>,
119 integrality_threshold: f64,
120 linear_independence_threshold: f64,
121 use_magnetic_group: Option<MagneticSymmetryAnalysisKind>,
122 use_double_group: bool,
123 use_cayley_table: bool,
124 symmetry_transformation_kind: SymmetryTransformationKind,
125 eigenvalue_comparison_mode: EigenvalueComparisonMode,
126 grid_points: Bound<'_, PyArray2<f64>>,
127 weight: Bound<'_, PyArray1<dtype_>>,
128 write_overlap_eigenvalues: bool,
129 write_character_table: bool,
130 infinite_order_to_finite: Option<u32>,
131 angular_function_integrality_threshold: f64,
132 angular_function_linear_independence_threshold: f64,
133 angular_function_max_angular_momentum: u32,
134) -> PyResult<()> {
135 let pd_res: SymmetryGroupDetectionResult =
136 read_qsym2_binary(inp_sym.clone(), QSym2FileType::Sym)
137 .map_err(|err| PyIOError::new_err(err.to_string()))?;
138
139 let mut file_name = inp_sym.to_path_buf();
140 file_name.set_extension(QSym2FileType::Sym.ext());
141 qsym2_output!(
142 "Symmetry-group detection results read in from {}.",
143 file_name.display(),
144 );
145 qsym2_output!("");
146
147 let afa_params = AngularFunctionRepAnalysisParams::builder()
148 .integrality_threshold(angular_function_integrality_threshold)
149 .linear_independence_threshold(angular_function_linear_independence_threshold)
150 .max_angular_momentum(angular_function_max_angular_momentum)
151 .build()
152 .map_err(|err| PyRuntimeError::new_err(err.to_string()))?;
153 let real_space_function_params = RealSpaceFunctionRepAnalysisParams::<f64>::builder()
154 .integrality_threshold(integrality_threshold)
155 .linear_independence_threshold(linear_independence_threshold)
156 .use_magnetic_group(use_magnetic_group.clone())
157 .use_double_group(use_double_group)
158 .use_cayley_table(use_cayley_table)
159 .symmetry_transformation_kind(symmetry_transformation_kind)
160 .eigenvalue_comparison_mode(eigenvalue_comparison_mode)
161 .write_overlap_eigenvalues(write_overlap_eigenvalues)
162 .write_character_table(if write_character_table {
163 Some(CharacterTableDisplay::Symbolic)
164 } else {
165 None
166 })
167 .infinite_order_to_finite(infinite_order_to_finite)
168 .build()
169 .map_err(|err| PyRuntimeError::new_err(err.to_string()))?;
170
171 let weight = weight.to_owned_array();
172 let grid_array = grid_points.to_owned_array();
173 if grid_array.shape()[0] != 3 {
174 return Err(PyRuntimeError::new_err(
175 "The grid point array does not have the expected dimensions of 3 × N.",
176 ));
177 }
178 let grid_points = grid_array
179 .columns()
180 .into_iter()
181 .map(|col| Point3::new(col[0], col[1], col[2]))
182 .collect::<Vec<_>>();
183
184 let real_space_function = RealSpaceFunction::<dtype_, _>::builder()
185 .function(|pt| {
186 Python::attach(|py_inner| {
187 let res = function.call1(py_inner, (pt.x, pt.y, pt.z)).expect(
188 "Unable to apply the real-space function on the specified coordinates.",
189 );
190 res.extract::<dtype_>(py_inner)
191 .expect("Unable to extract the result from the real-space function call.")
192 })
193 })
194 .grid_points(grid_points)
195 .build()
196 .map_err(|err| PyRuntimeError::new_err(err.to_string()))?;
197
198 match &use_magnetic_group {
199 Some(MagneticSymmetryAnalysisKind::Corepresentation) => {
200 let mut real_space_function_driver = RealSpaceFunctionRepAnalysisDriver::<
201 MagneticRepresentedSymmetryGroup,
202 dtype_,
203 _,
204 >::builder()
205 .parameters(&real_space_function_params)
206 .angular_function_parameters(&afa_params)
207 .real_space_function(&real_space_function)
208 .weight(&weight)
209 .symmetry_group(&pd_res)
210 .build()
211 .map_err(|err| PyRuntimeError::new_err(err.to_string()))?;
212 py.detach(|| {
213 real_space_function_driver
214 .run()
215 .map_err(|err| PyRuntimeError::new_err(err.to_string()))
216 })?
217 }
218 Some(MagneticSymmetryAnalysisKind::Representation) | None => {
219 let mut real_space_function_driver = RealSpaceFunctionRepAnalysisDriver::<
220 UnitaryRepresentedSymmetryGroup,
221 dtype_,
222 _,
223 >::builder()
224 .parameters(&real_space_function_params)
225 .angular_function_parameters(&afa_params)
226 .real_space_function(&real_space_function)
227 .weight(&weight)
228 .symmetry_group(&pd_res)
229 .build()
230 .map_err(|err| PyRuntimeError::new_err(err.to_string()))?;
231 py.detach(|| {
232 real_space_function_driver
233 .run()
234 .map_err(|err| PyRuntimeError::new_err(err.to_string()))
235 })?
236 }
237 };
238
239 Ok(())
240}