castep_seeding/seed/
seed_setup.rs1use castep_cell_io::{
2 cell_document::{
3 BSKpointPathSpacing, CellDocument, CellEntries, ExtEFieldBlock, ExtPressureBlock,
4 FixAllCell, FixCom, IonicConstraintsBlock, KpointMPSpacing, KpointSettings,
5 NCKpointSettings, SpeciesLCAOStatesBlock, SpeciesMassBlock, SpeciesPotBlock,
6 },
7 CastepTask, EnergyCutoff, EnergyCutoffError, InvLengthUnit,
8};
9
10use castep_periodic_table::data::ELEMENT_TABLE;
11use castep_periodic_table::element::LookupElement;
12use std::path::Path;
13
14use crate::SeedingErrors;
15use castep_param_io::param::CastepParam;
16
17pub trait CellBuilding {
18 fn geom_opt_cell_template(template_cell: &CellDocument) -> CellDocument {
19 let elements = template_cell.get_elements();
20 let entries = vec![
21 CellEntries::KpointSettings(KpointSettings::MPSpacing(KpointMPSpacing::default())),
22 CellEntries::FixAllCell(FixAllCell::new(true)),
23 CellEntries::FixCom(FixCom::new(false)),
24 CellEntries::IonicConstraints(IonicConstraintsBlock::default()),
25 CellEntries::ExtEfield(ExtEFieldBlock::default()),
26 CellEntries::ExtPressure(ExtPressureBlock::default()),
27 CellEntries::SpeciesMass(SpeciesMassBlock::from_elements(&elements)),
28 CellEntries::SpeciesPot(SpeciesPotBlock::from_elements(&elements)),
29 CellEntries::SpeciesLCAOStates(SpeciesLCAOStatesBlock::from_elememts(&elements)),
30 ];
31 let mut geom_cell = template_cell.clone();
32 geom_cell.set_entries(Some(entries));
33 geom_cell
34 }
35
36 #[cfg(feature = "template")]
37 fn bs_cell_template(template_cell: &CellDocument) -> CellDocument {
38 let mut bs_cell = template_cell.clone();
39 let elements = template_cell.get_elements();
40 let entries = vec![
41 CellEntries::KpointSettings(KpointSettings::MPSpacing(KpointMPSpacing::default())),
42 CellEntries::NCKpointSettings(NCKpointSettings::PathSpacing(BSKpointPathSpacing::new(
43 InvLengthUnit::Ang,
44 0.07,
45 ))),
46 CellEntries::FixAllCell(FixAllCell::new(true)),
47 CellEntries::FixCom(FixCom::new(false)),
48 CellEntries::IonicConstraints(IonicConstraintsBlock::default()),
49 CellEntries::ExtEfield(ExtEFieldBlock::default()),
50 CellEntries::ExtPressure(ExtPressureBlock::default()),
51 CellEntries::SpeciesMass(SpeciesMassBlock::from_elements(&elements)),
52 CellEntries::SpeciesPot(SpeciesPotBlock::from_elements(&elements)),
53 CellEntries::SpeciesLCAOStates(SpeciesLCAOStatesBlock::from_elememts(&elements)),
54 ];
55 bs_cell.set_entries(Some(entries));
56 bs_cell
57 }
58
59 fn build_cell_for_task(
60 &self,
61 template_cell: &CellDocument,
62 castep_task: CastepTask,
63 ) -> CellDocument {
64 #[cfg(feature = "template")]
65 match castep_task {
66 CastepTask::BandStructure => Self::bs_cell_template(template_cell),
67 CastepTask::GeometryOptimization => Self::geom_opt_cell_template(template_cell),
68 }
69 }
70}
71
72pub trait ParamBuilding {
73 fn cutoff_energy<P: AsRef<Path>>(
74 &self,
75 template_cell: &CellDocument,
76 energy_cutoff: EnergyCutoff,
77 potentials_loc: P,
78 ) -> Result<f64, EnergyCutoffError> {
79 let cutoff_energies = template_cell
80 .get_elements()
81 .iter()
82 .map(|&elm| {
83 let potential_name = ELEMENT_TABLE.get_by_symbol(elm).potential();
84 let potential_file = Path::new(potentials_loc.as_ref()).join(potential_name);
85 energy_cutoff.get_cutoff_energy_from_pot(potential_file)
86 })
87 .collect::<Result<Vec<f64>, EnergyCutoffError>>()?;
88 Ok(cutoff_energies
89 .into_iter()
90 .reduce(|prev, next| if next > prev { next } else { prev })
91 .expect("Error in comparing the largest cutoff energy"))
92 }
93 fn build_param_for_task(
94 &self,
95 template_cell: &CellDocument,
96 castep_task: CastepTask,
97 ) -> Result<CastepParam, SeedingErrors>;
98
99 #[cfg(feature = "template")]
100 fn geom_opt_param_template<P: AsRef<Path>>(
101 &self,
102 template_cell: &CellDocument,
103 energy_cutoff: EnergyCutoff,
104 use_edft: bool,
105 potentials_loc: P,
106 ) -> Result<castep_param_io::param::CastepParam, crate::SeedingErrors> {
107 use castep_periodic_table::element::ElementFamily;
108
109 use castep_param_io::param::{CastepParam, MetalsMethod, NumOccCycles};
110
111 {
112 let use_edft = if use_edft {
113 template_cell.get_elements().iter().any(|elm| {
114 matches!(
115 elm.family(),
116 ElementFamily::RareEarthLa | ElementFamily::RareEarthAc
117 )
118 })
119 } else {
120 false
121 };
122 let mut param = CastepParam::geom_opt_param_template(
123 self.cutoff_energy(template_cell, energy_cutoff, potentials_loc)?,
124 template_cell.total_spin().into(),
125 )?;
126 if use_edft {
127 if let Some(electro_min) = param.electro_min.as_mut() {
128 electro_min.metals_method = Some(MetalsMethod::EDFT);
129 electro_min.num_occ_cycles = Some(NumOccCycles::from(6));
130 }
131 }
132 Ok(param)
133 }
134 }
135
136 #[cfg(feature = "template")]
137 fn dos_param_template<P: AsRef<Path>>(
138 &self,
139 template_cell: &CellDocument,
140 energy_cutoff: EnergyCutoff,
141 use_edft: bool,
142 potentials_loc: P,
143 ) -> Result<castep_param_io::param::CastepParam, crate::SeedingErrors> {
144 use castep_periodic_table::element::ElementFamily;
145
146 use castep_param_io::param::{CastepParam, MetalsMethod, NumOccCycles};
147
148 let use_edft = if use_edft {
149 template_cell.get_elements().iter().any(|elm| {
150 matches!(
151 elm.family(),
152 ElementFamily::RareEarthLa | ElementFamily::RareEarthAc
153 )
154 })
155 } else {
156 false
157 };
158
159 let mut param = CastepParam::dos_opt_param_template(
160 self.cutoff_energy(template_cell, energy_cutoff, potentials_loc)?,
161 template_cell.total_spin().into(),
162 )?;
163 if use_edft {
164 if let Some(electro_min) = param.electro_min.as_mut() {
165 electro_min.metals_method = Some(MetalsMethod::EDFT);
166 electro_min.num_occ_cycles = Some(NumOccCycles::from(6));
167 }
168 }
169 Ok(param)
170 }
171}