castep_param_io/param/electronic/bands_option/mod.rs
1use castep_param_derive::ParamDisplay;
2use derive_builder::Builder;
3pub use extra_bands::ExtraBands;
4pub use nbands::Nbands;
5use serde::{Deserialize, Serialize};
6
7use crate::param::KeywordDisplay;
8
9mod extra_bands;
10/// This keyword determines the maximum number of bands at any k-point and spin.
11/// There are three ways in which you can specify the maximum number of bands at any k-point and spin:
12/// Directly, using `NBANDS`.
13/// Indirectly, by specifying the number of extra bands in addition to the number of occupied bands using `NEXTRA_BANDS`.
14/// This is the method used in the CASTEP interface.
15/// Indirectly, by specifying the number of extra bands in addition to the number of occupied bands as a percentage of the latter value using `PERC_EXTRA_BANDS`.
16/// It is not possible to have both the `NBANDS` keyword and either the `NEXTRA_BANDS` or `PERC_EXTRA_BANDS` keywords present in the same input file.
17#[derive(
18 Debug,
19 Clone,
20 Copy,
21 PartialEq,
22 PartialOrd,
23 Serialize,
24 Deserialize,
25 Builder,
26 Default,
27 ParamDisplay,
28)]
29#[builder(setter(into, strip_option), default)]
30pub struct BandsOption {
31 nbands: Option<Nbands>,
32 extra_bands: Option<ExtraBands>,
33}
34
35mod nbands {
36
37 use castep_param_derive::KeywordDisplay;
38 use serde::{Deserialize, Serialize};
39
40 use crate::param::{ElectronicParam, SpinPolarised};
41
42 use super::extra_bands::ExtraBands;
43
44 #[derive(
45 Debug,
46 Clone,
47 Copy,
48 PartialEq,
49 Eq,
50 PartialOrd,
51 Ord,
52 Hash,
53 Serialize,
54 Deserialize,
55 KeywordDisplay,
56 )]
57 #[keyword_display(field = "NBANDS", from = u32, value=u32)]
58 pub struct Nbands(u32);
59
60 impl Nbands {
61 /// If NEXTRA_BANDS is specified and SPIN_POLARIZED : FALSE:
62 /// NBANDS : (NELECTRONS/2) + NEXTRA_BANDS
63 /// Or, if SPIN_POLARIZED : TRUE:
64 /// NBANDS : max(NUP, NDOWN) + NEXTRA_BANDS.
65 /// If PERC_EXTRA_BANDS is specified and SPIN_POLARIZED : FALSE:
66 /// NBANDS : (NELECTRONS/2) × [ 1 + (PERC_EXTRA_BANDS/100)]
67 /// Or, if SPIN_POLARIZED : TRUE:
68 /// NBANDS : max(NUP, NDOWN) × [ 1 + (PERC_EXTRA_BANDS/100)]
69 /// If NBANDS, NEXTRA_BANDS and PERC_EXTRA_BANDS are not specified and FIX_OCCUPANCY : TRUE, then, if SPIN_POLARIZED : FALSE:
70 /// NBANDS : NELECTRONS/2.
71 /// Or, if SPIN_POLARIZED : TRUE:
72 /// NBANDS : max(NUP, NDOWN)
73 /// If FIX_OCCUPANCY : FALSE, these default values of NBANDS will be multiplied by 1.2.
74 pub fn default_value(
75 electronic_param: ElectronicParam,
76 spin_polarised: SpinPolarised,
77 extra_bands: Option<ExtraBands>,
78 // fix_occupancy: FixOccupancy,
79 ) -> Self {
80 if let (Some(ExtraBands::NextraBands(nextra)), SpinPolarised::False) =
81 (extra_bands, spin_polarised)
82 {
83 let nelectrons = electronic_param
84 .nelectrons
85 .expect("Number of electrons of the system is not determined!");
86 return Self(nelectrons.value() as u32 / 2 + nextra);
87 }
88 if let (Some(ExtraBands::NextraBands(nextra)), SpinPolarised::True) =
89 (extra_bands, spin_polarised)
90 {
91 let nup = electronic_param
92 .nup
93 .expect("NUP of the system is not determined!");
94 let ndown = electronic_param
95 .ndown
96 .expect("NDOWN of the system is not determined!");
97 let max = if nup.value() > ndown.value() {
98 nup.value()
99 } else {
100 ndown.value()
101 };
102 return Self(max as u32 + nextra);
103 }
104 todo!()
105 }
106 }
107}