castep_param_io/param/basis_set/
mod.rs1use castep_param_derive::ParamDisplay;
2use derive_builder::Builder;
3use serde::{Deserialize, Serialize};
4
5mod basis_de_dloge;
6mod basis_precision;
7mod cut_off_energy;
8mod fine_gmax;
9mod fine_grid_scale;
10mod finite_basis_corr;
11mod finite_basis_npoints;
12mod finite_basis_spacing;
13mod fixed_npw;
14mod grid_scale;
15
16pub use basis_de_dloge::BasisDeDloge;
17pub use basis_precision::BasisPrecision;
18pub use cut_off_energy::CutoffEnergy;
19pub use fine_gmax::FineGMax;
20pub use fine_grid_scale::FineGridScale;
21pub use finite_basis_corr::FiniteBasisCorr;
22pub use finite_basis_npoints::FiniteBasisNPoints;
23pub use finite_basis_spacing::FiniteBasisSpacing;
24pub use fixed_npw::FixedNPW;
25pub use grid_scale::GridScale;
26
27use super::KeywordDisplay;
28
29#[derive(
30 Debug,
31 Clone,
32 Copy,
33 Serialize,
34 Deserialize,
35 Default,
36 Builder,
37 ParamDisplay,
38 PartialEq,
39 PartialOrd,
40)]
41#[builder(
42 setter(into, strip_option),
43 default,
44 build_fn(validate = "Self::validate")
45)]
46pub struct BasisSet {
47 pub basis_de_dloge: Option<BasisDeDloge>,
48 pub basis_precision: Option<BasisPrecision>,
49 pub cut_off_energy: Option<CutoffEnergy>,
50 pub fine_gmax: Option<FineGMax>,
51 pub fine_grid_scale: Option<FineGridScale>,
52 pub finite_basis_corr: Option<FiniteBasisCorr>,
53 pub finite_basis_npoints: Option<FiniteBasisNPoints>,
54 pub finite_basis_spacing: Option<FiniteBasisSpacing>,
55 pub fixed_npw: Option<FixedNPW>,
56 pub grid_scale: Option<GridScale>,
57}
58
59impl BasisSetBuilder {
60 fn validate(builder: &BasisSetBuilder) -> Result<(), String> {
61 if let Some(Some(FiniteBasisCorr::Manual)) = builder.finite_basis_corr {
63 match builder.basis_de_dloge {
64 Some(Some(_)) => (),
65 _ => return Err("BASIS_DE_DLOGE is required when FINITE_BASIS_CORR=1".to_string()),
66 }
67 }
68 if let Some(Some(_)) = builder.basis_precision {
70 if let Some(Some(_)) = builder.cut_off_energy {
71 return Err(
72 "BASIS_PRECISION and CUT_OFF_ENERGY cannot be both specified".to_string(),
73 );
74 }
75 } else if let Some(Some(_)) = builder.cut_off_energy {
76 if let Some(Some(_)) = builder.basis_precision {
77 return Err(
78 "BASIS_PRECISION and CUT_OFF_ENERGY cannot be both specified".to_string(),
79 );
80 }
81 }
82 if let Some(Some(_)) = builder.fixed_npw {
84 match builder.finite_basis_corr {
85 Some(Some(FiniteBasisCorr::NoCorrection)) => (),
86 _ => {
87 return Err(
88 "If use `FixedNPW`, `FiniteBasisCorr` must be 0 (NoCorrection)".to_string(),
89 )
90 }
91 }
92 }
93 Ok(())
94 }
95}
96
97#[cfg(test)]
98mod test {
99 use crate::param::basis_set::{BasisPrecision, FiniteBasisCorr};
100
101 use super::BasisSetBuilder;
102
103 #[test]
104 fn basis_set() {
105 let b = BasisSetBuilder::default().build();
106 assert!(b.is_ok());
107 let b = BasisSetBuilder::default().fixed_npw(true).build();
108 assert!(b.is_err());
109 let b = BasisSetBuilder::default()
110 .fixed_npw(true)
111 .finite_basis_corr(FiniteBasisCorr::NoCorrection)
112 .build();
113 assert!(b.is_ok());
114 println!("{}", b.unwrap());
115 let b = BasisSetBuilder::default()
116 .cut_off_energy(340.0)
117 .fine_grid_scale(1.5)
118 .build();
119 assert!(b.is_ok());
120 println!("{}", b.unwrap());
121 let b = BasisSetBuilder::default()
122 .basis_precision(BasisPrecision::Coarse)
123 .build();
124 assert!(b.is_ok());
125 let b = BasisSetBuilder::default()
126 .basis_precision(BasisPrecision::Coarse)
127 .cut_off_energy(320.0)
128 .build();
129 assert!(b.is_err());
130 dbg!(b.err());
131 let b = BasisSetBuilder::default().basis_de_dloge(-1.2345).build();
132 assert!(b.is_ok());
133 println!("{}", b.unwrap());
134 let b = BasisSetBuilder::default()
135 .finite_basis_corr(FiniteBasisCorr::Manual)
136 .build();
137 assert!(b.is_err());
138 dbg!(b.err());
139 let b = BasisSetBuilder::default()
140 .finite_basis_corr(FiniteBasisCorr::Manual)
141 .basis_de_dloge(2.0)
142 .build();
143 assert!(b.is_ok());
144 println!("{}", b.unwrap());
145 }
146}