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