castep_param_io/param/xc_correlation/
xc_definition.rs1use std::fmt::Display;
2
3use castep_param_derive::KeywordDisplay;
4use derive_builder::Builder;
5use serde::{Deserialize, Serialize};
6
7use crate::param::KeywordDisplay;
8
9#[derive(Debug, Clone, Serialize, Deserialize, Builder, PartialEq, PartialOrd)]
10#[builder(setter(into, strip_option), default)]
11pub struct XCDefinition {
12 functional_weight: Vec<FunctionalWeight>,
13 nlxc_screening_length: Option<f64>,
15 nlxc_screening_function: Option<NLXC_ScreeningFunction>,
17 nlxc_divergence_corr: Option<NLXC_DivergenceCorr>,
19 nlxc_ppd_int: Option<NLXC_PPD_Int>,
20}
21
22#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, PartialOrd)]
23#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
24pub enum FunctionalWeight {
25 LDA(f64), LDA_X(f64), LDA_C(f64), PW91(f64), PBE(f64), PBE_X(f64), PBE_C(f64), RPBE(f64), WC(f64), PBESOL(f64), PBESOL_X(f64), PBESOL_C(f64), B88_X(f64), LYP_C(f64), HF(f64), HF_LDA(f64), SX(f64), SX_LDA(f64), PBE0(f64), B3LYP(f64), HSE03(f64), HSE06(f64), }
48
49#[derive(
50 Debug,
51 Clone,
52 Copy,
53 PartialEq,
54 Eq,
55 PartialOrd,
56 Ord,
57 Hash,
58 Deserialize,
59 Serialize,
60 Default,
61 KeywordDisplay,
62)]
63#[allow(non_camel_case_types)]
64#[keyword_display(field = "NLXC_SCREENING_FUNCTION", direct_display = false)]
65pub enum NLXC_ScreeningFunction {
66 #[default]
67 ThomasFermi,
68 ErrorFunction,
69}
70
71#[derive(
72 Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize, KeywordDisplay,
73)]
74#[allow(non_camel_case_types)]
75#[keyword_display(field = "NLXC_PPD_INT")]
76pub enum NLXC_PPD_Int {
77 On,
78 Off,
79}
80
81#[derive(
82 Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize, KeywordDisplay,
83)]
84#[allow(non_camel_case_types)]
85#[keyword_display(field = "NLXC_DIVERGENCE_CORR")]
86pub enum NLXC_DivergenceCorr {
87 On,
88 Off,
89}
90
91impl Display for FunctionalWeight {
92 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93 match self {
94 FunctionalWeight::LDA(w)
95 | FunctionalWeight::LDA_X(w)
96 | FunctionalWeight::LDA_C(w)
97 | FunctionalWeight::PW91(w)
98 | FunctionalWeight::PBE(w)
99 | FunctionalWeight::PBE_X(w)
100 | FunctionalWeight::PBE_C(w)
101 | FunctionalWeight::RPBE(w)
102 | FunctionalWeight::WC(w)
103 | FunctionalWeight::PBESOL(w)
104 | FunctionalWeight::PBESOL_X(w)
105 | FunctionalWeight::PBESOL_C(w)
106 | FunctionalWeight::B88_X(w)
107 | FunctionalWeight::LYP_C(w)
108 | FunctionalWeight::HF(w)
109 | FunctionalWeight::HF_LDA(w)
110 | FunctionalWeight::SX(w)
111 | FunctionalWeight::SX_LDA(w)
112 | FunctionalWeight::PBE0(w)
113 | FunctionalWeight::B3LYP(w)
114 | FunctionalWeight::HSE03(w)
115 | FunctionalWeight::HSE06(w) => write!(f, "{w}"),
116 }
117 }
118}
119
120impl KeywordDisplay for FunctionalWeight {
121 fn field(&self) -> String {
122 match self {
123 FunctionalWeight::LDA(_) => "LDA".to_string(),
124 FunctionalWeight::LDA_X(_) => "LDA-X".to_string(),
125 FunctionalWeight::LDA_C(_) => "LDA-C".to_string(),
126 FunctionalWeight::PW91(_) => "PW91".to_string(),
127 FunctionalWeight::PBE(_) => "PBE".to_string(),
128 FunctionalWeight::PBE_X(_) => "PBE_X".to_string(),
129 FunctionalWeight::PBE_C(_) => "PBE_C".to_string(),
130 FunctionalWeight::RPBE(_) => "RPBE".to_string(),
131 FunctionalWeight::WC(_) => "WC".to_string(),
132 FunctionalWeight::PBESOL(_) => "PBESOL".to_string(),
133 FunctionalWeight::PBESOL_X(_) => "PBESOL_X".to_string(),
134 FunctionalWeight::PBESOL_C(_) => "PBESOL_C".to_string(),
135 FunctionalWeight::B88_X(_) => "B88_X".to_string(),
136 FunctionalWeight::LYP_C(_) => "LYP_C".to_string(),
137 FunctionalWeight::HF(_) => "HF".to_string(),
138 FunctionalWeight::HF_LDA(_) => "HF_LDA".to_string(),
139 FunctionalWeight::SX(_) => "SX".to_string(),
140 FunctionalWeight::SX_LDA(_) => "SX-LDA".to_string(),
141 FunctionalWeight::PBE0(_) => "PBE0".to_string(),
142 FunctionalWeight::B3LYP(_) => "B3LYP".to_string(),
143 FunctionalWeight::HSE03(_) => "HSE03".to_string(),
144 FunctionalWeight::HSE06(_) => "HSE06".to_string(),
145 }
146 }
147}
148
149impl Display for NLXC_ScreeningFunction {
150 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151 match self {
152 NLXC_ScreeningFunction::ThomasFermi => f.write_str("THOMAS-FERMI"),
153 NLXC_ScreeningFunction::ErrorFunction => f.write_str("ERRORFUNCTION"),
154 }
155 }
156}
157
158impl Default for XCDefinition {
159 fn default() -> Self {
160 Self {
161 functional_weight: vec![FunctionalWeight::HF(1.0)],
162 nlxc_screening_length: None,
163 nlxc_screening_function: None,
164 nlxc_divergence_corr: None,
165 nlxc_ppd_int: None,
166 }
167 }
168}
169
170impl Display for XCDefinition {
171 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
172 let output = [
173 Some("%BLOCK xc_definition".to_string()),
174 Some(
175 self.functional_weight
176 .iter()
177 .map(|f| f.output())
178 .collect::<Vec<String>>()
179 .join("\n"),
180 ),
181 self.nlxc_screening_length
182 .map(|v| format!("NLXC_SCREENING_LENGTH {v}")),
183 self.nlxc_screening_function.map(|v| v.output()),
184 self.nlxc_ppd_int.map(|v| v.output()),
185 self.nlxc_divergence_corr.map(|v| v.output()),
186 Some("%ENDBLOCK xc_definition".to_string()),
187 ]
188 .into_iter()
189 .flatten()
190 .collect::<Vec<String>>()
191 .join("\n");
192 write!(f, "{}", output)
193 }
194}