castep_param_io/param/xc_correlation/
xc_definition.rs

1use 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    /// The NLXC_SCREENING_LENGTH parameter can be used to set the screening length value in Bohr-1. Default value is 1.437 Å-1 = 0.76 Bohr-1.
14    nlxc_screening_length: Option<f64>,
15    /// NLXC_SCREENING_FUNCTION values can be set to either THOMAS-FERMI (default) or ERRORFUNCTION.
16    nlxc_screening_function: Option<NLXC_ScreeningFunction>,
17    /// NLXC_DIVERGENCE_CORR can be set to either ON or OFF. Divergence correction is ON by default when using unscreened Hartree-Fock (HF) exchange, including such functionals as B3LYP or PBE0; and OFF by default when using screened HF exchange (functionals like SX-LDA, HSE03, HSE06).
18    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),      // Local Density Approximation
26    LDA_X(f64),    // Local Density Approximation, exchange only
27    LDA_C(f64),    // Local Density Approximation, correlation only
28    PW91(f64),     // Perdew Wang '91 GGA
29    PBE(f64),      // Perdew Burke Ernzerhof GGA functional
30    PBE_X(f64),    // Perdew Burke Ernzerhof GGA functional, exchange only
31    PBE_C(f64),    // Perdew Burke Ernzerhof GGA functional, correlation only
32    RPBE(f64),     // Revised Perdew Burke Ernzerhof GGA functional
33    WC(f64),       // Wu-Cohen GGA functional
34    PBESOL(f64),   // PBEsol, PBE functional for solids
35    PBESOL_X(f64), // PBEsol, PBE functional for solids, exchange only
36    PBESOL_C(f64), // PBEsol, PBE functional for solids, correlation only
37    B88_X(f64),    // Becke (1988) GGA functional , exchange only
38    LYP_C(f64),    // Lee-Yang-Parr (1988) GGA functional, correlation only
39    HF(f64),       // exact exchange, no correlation
40    HF_LDA(f64),   // exact exchange, LDA correlation
41    SX(f64),       // screened exchange, no correlation
42    SX_LDA(f64),   // screened exchange, LDA correlation
43    PBE0(f64),     // PBE0 hybrid functional
44    B3LYP(f64),    // B3LYP hybrid functional
45    HSE03(f64),    // HSE03 hybrid functional
46    HSE06(f64),    // HSE06 hybrid functional
47}
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}