qsym2/interfaces/binaries/
mod.rs1use std::path::PathBuf;
4
5use anyhow::{format_err, Context};
6use byteorder::{BigEndian, LittleEndian};
7use derive_builder::Builder;
8use ndarray::{Array1, Array2, Array4, ShapeBuilder};
9use serde::{Deserialize, Serialize};
10
11use crate::angmom::spinor_rotation_3d::SpinConstraint;
12use crate::drivers::representation_analysis::angular_function::AngularFunctionRepAnalysisParams;
13use crate::drivers::representation_analysis::slater_determinant::{
14 SlaterDeterminantRepAnalysisDriver, SlaterDeterminantRepAnalysisParams,
15};
16use crate::drivers::representation_analysis::MagneticSymmetryAnalysisKind;
17use crate::drivers::symmetry_group_detection::SymmetryGroupDetectionDriver;
18use crate::drivers::QSym2Driver;
19use crate::interfaces::input::analysis::SlaterDeterminantSourceHandle;
20use crate::interfaces::input::ao_basis::InputBasisAngularOrder;
21use crate::interfaces::input::SymmetryGroupDetectionInputKind;
22use crate::io::numeric::NumericReader;
23use crate::io::{read_qsym2_binary, QSym2FileType};
24use crate::symmetry::symmetry_group::{
25 MagneticRepresentedSymmetryGroup, UnitaryRepresentedSymmetryGroup,
26};
27use crate::target::determinant::SlaterDeterminant;
28
29#[cfg(test)]
30#[path = "binaries_tests.rs"]
31mod binaries_tests;
32
33#[derive(Clone, Builder, Serialize, Deserialize)]
40pub struct BinariesSlaterDeterminantSource {
41 pub xyz: PathBuf,
43
44 pub sao: PathBuf,
46
47 #[builder(default = "None")]
50 pub sao_4c: Option<PathBuf>,
51
52 pub coefficients: Vec<PathBuf>,
55
56 pub occupations: Vec<PathBuf>,
58
59 pub bao: InputBasisAngularOrder,
61
62 pub spin_constraint: SpinConstraint,
64
65 pub matrix_order: MatrixOrder,
67
68 pub byte_order: ByteOrder,
70}
71
72impl BinariesSlaterDeterminantSource {
73 fn builder() -> BinariesSlaterDeterminantSourceBuilder {
76 BinariesSlaterDeterminantSourceBuilder::default()
77 }
78}
79
80impl Default for BinariesSlaterDeterminantSource {
81 fn default() -> Self {
82 BinariesSlaterDeterminantSource {
83 xyz: PathBuf::from("path/to/xyz"),
84 sao: PathBuf::from("path/to/2c/ao/overlap/matrix"),
85 sao_4c: None,
86 coefficients: vec![
87 PathBuf::from("path/to/alpha/coeffs"),
88 PathBuf::from("path/to/beta/coeffs"),
89 ],
90 occupations: vec![
91 PathBuf::from("path/to/alpha/occupations"),
92 PathBuf::from("path/to/beta/occupations"),
93 ],
94 bao: InputBasisAngularOrder::default(),
95 spin_constraint: SpinConstraint::Unrestricted(2, false),
96 matrix_order: MatrixOrder::default(),
97 byte_order: ByteOrder::default(),
98 }
99 }
100}
101
102impl SlaterDeterminantSourceHandle for BinariesSlaterDeterminantSource {
103 type Outcome = (String, String);
104
105 fn sd_source_handle(
106 &self,
107 pd_params_inp: &SymmetryGroupDetectionInputKind,
108 afa_params: &AngularFunctionRepAnalysisParams,
109 sda_params: &SlaterDeterminantRepAnalysisParams<f64>,
110 ) -> Result<Self::Outcome, anyhow::Error> {
111 let pd_res = match pd_params_inp {
112 SymmetryGroupDetectionInputKind::Parameters(pd_params) => {
113 let mut pd_driver = SymmetryGroupDetectionDriver::builder()
114 .parameters(pd_params)
115 .xyz(Some(self.xyz.clone()))
116 .build()
117 .with_context(|| "Unable to construct a symmetry-group detection driver when handling custom Slater determinant source")?;
118 pd_driver.run().with_context(|| {
119 "Unable to run the symmetry-group detection driver successfully when handling custom Slater determinant source"
120 })?;
121 pd_driver
122 .result()
123 .with_context(|| "Unable to retrieve the symmetry-group detection result when handling custom Slater determinant source")?
124 .clone()
125 }
126 SymmetryGroupDetectionInputKind::FromFile(pd_res_file) => {
127 read_qsym2_binary(pd_res_file, QSym2FileType::Sym).with_context(|| {
128 format!(
129 "Unable to read `{}.qsym2.sym` when handling custom Slater determinant source",
130 pd_res_file.display()
131 )
132 })?
133 }
134 };
135 let mol = &pd_res.pre_symmetry.recentred_molecule;
136 let bao = self.bao.to_basis_angular_order(mol)
137 .with_context(|| "Unable to digest the input basis angular order information when handling custom Slater determinant source")?;
138 let n_spatial = bao.n_funcs();
139
140 let sao_v = match self.byte_order {
141 ByteOrder::LittleEndian => {
142 NumericReader::<_, LittleEndian, f64>::from_file(&self.sao)
143 .with_context(|| {
144 "Unable to read the specified two-centre SAO file when handling custom Slater determinant source"
145 })?.collect::<Vec<_>>()
146 }
147 ByteOrder::BigEndian => {
148 NumericReader::<_, BigEndian, f64>::from_file(&self.sao)
149 .with_context(|| {
150 "Unable to read the specified two-centre SAO file when handling custom Slater determinant source"
151 })?.collect::<Vec<_>>()
152 }
153 };
154 let sao = match self.matrix_order {
155 MatrixOrder::RowMajor => Array2::from_shape_vec((n_spatial, n_spatial), sao_v)
156 .with_context(|| {
157 "Unable to construct an AO overlap matrix from the read-in row-major binary file when handling custom Slater determinant source"
158 })?,
159 MatrixOrder::ColMajor => Array2::from_shape_vec((n_spatial, n_spatial).f(), sao_v)
160 .with_context(|| {
161 "Unable to construct an AO overlap matrix from the read-in column-major binary file when handling custom Slater determinant source"
162 })?,
163 };
164
165 let sao_4c = if let Some(sao_4c_path) = self.sao_4c.as_ref() {
166 let sao_4c_v = match self.byte_order {
167 ByteOrder::LittleEndian => {
168 NumericReader::<_, LittleEndian, f64>::from_file(sao_4c_path)
169 .with_context(|| {
170 "Unable to read the specified four-centre SAO file when handling custom Slater determinant source"
171 })?.collect::<Vec<_>>()
172 }
173 ByteOrder::BigEndian => {
174 NumericReader::<_, BigEndian, f64>::from_file(sao_4c_path)
175 .with_context(|| {
176 "Unable to read the specified four-centre SAO file when handling custom Slater determinant source"
177 })?.collect::<Vec<_>>()
178 }
179 };
180 let sao_4c = match self.matrix_order {
181 MatrixOrder::RowMajor => Array4::from_shape_vec((n_spatial, n_spatial, n_spatial, n_spatial), sao_4c_v)
182 .with_context(|| {
183 "Unable to construct a four-centre AO overlap matrix from the read-in row-major binary file when handling custom Slater determinant source"
184 })?,
185 MatrixOrder::ColMajor => Array4::from_shape_vec((n_spatial, n_spatial, n_spatial, n_spatial).f(), sao_4c_v)
186 .with_context(|| {
187 "Unable to construct a four-centre AO overlap matrix from the read-in column-major binary file when handling custom Slater determinant source"
188 })?,
189 };
190 Some(sao_4c)
191 } else {
192 None
193 };
194
195 let cs_v = match self.byte_order {
196 ByteOrder::LittleEndian => self
197 .coefficients
198 .iter()
199 .map(|c_path| {
200 NumericReader::<_, LittleEndian, f64>::from_file(c_path)
201 .map(|r| r.collect::<Vec<_>>())
202 })
203 .collect::<Result<Vec<_>, _>>()
204 .with_context(|| {
205 "Unable to read the specified coefficient binary file(s) when handling custom Slater determinant source"
206 })?,
207 ByteOrder::BigEndian => self
208 .coefficients
209 .iter()
210 .map(|c_path| {
211 NumericReader::<_, BigEndian, f64>::from_file(c_path)
212 .map(|r| r.collect::<Vec<_>>())
213 })
214 .collect::<Result<Vec<_>, _>>()
215 .with_context(|| {
216 "Unable to read the specified coefficient binary file(s) when handling custom Slater determinant source"
217 })?,
218 };
219 let cs = match self.matrix_order {
220 MatrixOrder::RowMajor => cs_v
221 .into_iter()
222 .map(|c_v| {
223 let nmo = c_v.len().div_euclid(n_spatial);
224 Array2::from_shape_vec((n_spatial, nmo), c_v)
225 })
226 .collect::<Result<Vec<_>, _>>()
227 .with_context(|| {
228 "Unable to construct coefficient matrix (matrices) from the read-in row-major binary file(s) when handling custom Slater determinant source"
229 })?,
230
231 MatrixOrder::ColMajor => cs_v
232 .into_iter()
233 .map(|c_v| {
234 let nmo = c_v.len().div_euclid(n_spatial);
235 Array2::from_shape_vec((n_spatial, nmo).f(), c_v)
236 })
237 .collect::<Result<Vec<_>, _>>()
238 .with_context(|| {
239 "Unable to construct coefficient matrix (matrices) from the read-in column-major binary file(s) when handling custom Slater determinant source"
240 })?,
241 };
242
243 let occs = match self.byte_order {
244 ByteOrder::LittleEndian => self
245 .occupations
246 .iter()
247 .map(|occ_path| {
248 Ok::<_, anyhow::Error>(Array1::from_vec(
249 NumericReader::<_, LittleEndian, f64>::from_file(occ_path)
250 .map(|r| r.collect::<Vec<f64>>())?,
251 ))
252 })
253 .collect::<Result<Vec<_>, _>>()
254 .with_context(|| {
255 "Unable to read the specified occupation binary file(s) when handling custom Slater determinant source"
256 })?,
257 ByteOrder::BigEndian => self
258 .occupations
259 .iter()
260 .map(|occ_path| {
261 Ok::<_, anyhow::Error>(Array1::from_vec(
262 NumericReader::<_, BigEndian, f64>::from_file(occ_path)
263 .map(|r| r.collect::<Vec<f64>>())?,
264 ))
265 })
266 .collect::<Result<Vec<_>, _>>()
267 .with_context(|| {
268 "Unable to read occupation binary file(s) when handling custom Slater determinant source"
269 })?,
270 };
271
272 let det = SlaterDeterminant::<f64, SpinConstraint>::builder()
273 .coefficients(&cs)
274 .occupations(&occs)
275 .bao(&bao)
276 .mol(mol)
277 .structure_constraint(self.spin_constraint.clone())
278 .complex_symmetric(false)
279 .threshold(sda_params.linear_independence_threshold)
280 .build()
281 .with_context(|| "Failed to construct a Slater determinant when handling custom Slater determinant source")?;
282
283 match &sda_params.use_magnetic_group {
284 Some(MagneticSymmetryAnalysisKind::Corepresentation) => {
285 let mut sda_driver = SlaterDeterminantRepAnalysisDriver::<
286 MagneticRepresentedSymmetryGroup,
287 f64,
288 SpinConstraint,
289 >::builder()
290 .parameters(sda_params)
291 .angular_function_parameters(afa_params)
292 .determinant(&det)
293 .sao(&sao)
294 .sao_spatial_4c(sao_4c.as_ref())
295 .symmetry_group(&pd_res)
296 .build()
297 .with_context(|| {
298 "Failed to construct a Slater determinant corepresentation analysis driver when handling custom Slater determinant source"
299 })?;
300 sda_driver
301 .run()
302 .with_context(|| {
303 "Failed to execute the Slater determinant corepresentation analysis driver successfully when handling custom Slater determinant source"
304 })?;
305 let group_name = pd_res
306 .magnetic_symmetry
307 .as_ref()
308 .and_then(|magsym| magsym.group_name.clone())
309 .ok_or(format_err!("Magnetic group name not found when handling custom Slater determinant source."))?;
310 let sym = sda_driver
311 .result()
312 .with_context(|| {
313 "Failed to obtain corepresentation analysis result when handling custom Slater determinant source"
314 })?
315 .determinant_symmetry()
316 .as_ref()
317 .map_err(|err| format_err!(err.clone()))
318 .with_context(|| {
319 "Failed to obtain determinant symmetry from corepresentation analysis result when handling custom Slater determinant source"
320 })?
321 .to_string();
322 Ok((group_name, sym))
323 }
324 Some(MagneticSymmetryAnalysisKind::Representation) | None => {
325 let mut sda_driver = SlaterDeterminantRepAnalysisDriver::<
326 UnitaryRepresentedSymmetryGroup,
327 f64,
328 SpinConstraint,
329 >::builder()
330 .parameters(sda_params)
331 .angular_function_parameters(afa_params)
332 .determinant(&det)
333 .sao(&sao)
334 .sao_spatial_4c(sao_4c.as_ref())
335 .symmetry_group(&pd_res)
336 .build()
337 .with_context(|| {
338 "Failed to construct a Slater determinant representation analysis driver when handling custom Slater determinant source"
339 })?;
340 sda_driver
341 .run()
342 .with_context(|| {
343 "Failed to execute the Slater determinant representation analysis driver successfully when handling custom Slater determinant source"
344 })?;
345 let group_name = if sda_params.use_magnetic_group.is_none() {
346 pd_res
347 .unitary_symmetry
348 .group_name
349 .as_ref()
350 .ok_or(format_err!("Unitary group name not found when handling custom Slater determinant source."))?.clone()
351 } else {
352 pd_res
353 .magnetic_symmetry
354 .as_ref()
355 .and_then(|magsym| magsym.group_name.clone())
356 .ok_or(format_err!("Magnetic group name not found when handling custom Slater determinant source."))?
357 };
358 let sym = sda_driver
359 .result()
360 .with_context(|| {
361 "Failed to obtain representation analysis result when handling custom Slater determinant source"
362 })?
363 .determinant_symmetry()
364 .as_ref()
365 .map_err(|err| format_err!(err.clone()))
366 .with_context(|| {
367 "Failed to obtain determinant symmetry from representation analysis result when handling custom Slater determinant source"
368 })?
369 .to_string();
370 Ok((group_name, sym))
371 }
372 }
373 }
374}
375
376#[derive(Clone, Serialize, Deserialize)]
379pub enum MatrixOrder {
380 RowMajor,
381 ColMajor,
382}
383
384impl Default for MatrixOrder {
385 fn default() -> Self {
386 MatrixOrder::RowMajor
387 }
388}
389
390#[derive(Clone, Serialize, Deserialize)]
392pub enum ByteOrder {
393 LittleEndian,
394 BigEndian,
395}
396
397impl Default for ByteOrder {
398 fn default() -> Self {
399 ByteOrder::LittleEndian
400 }
401}