castep_param_io/param/basis_set/
mod.rs

1use 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        // 1. basis_de_dloge required if finite_basis_corr=Manual (1)
62        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        // 2. Basis_precision and cut_off_energy is mutually exclusive. Only one of them is permitted
69        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        // 3. If use `FixedNPW`, `FiniteBasisCorr` must be 0 (NoCorrection)
83        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}