castep_seeding/seed/
seed_folder.rs1use std::{
2 fs::{create_dir, File},
3 io::{BufWriter, Write},
4 path::{Path, PathBuf},
5};
6
7use crate::{error::SeedingErrors, CellBuilding, ParamBuilding};
8use castep_cell_io::{cell_document::CellDocument, CastepTask};
9use castep_periodic_table::{data::ELEMENT_TABLE, element::LookupElement};
10
11pub trait SeedFolder {
14 fn seed_name(&self) -> &str;
15 fn root_dir(&self) -> impl AsRef<Path>;
16 fn cell_template(&self) -> &CellDocument;
17 fn seed_dir(&self) -> impl AsRef<Path> {
20 self.root_dir().as_ref().join(self.seed_name())
21 }
22 fn create_seed_dir(&self) -> Result<PathBuf, SeedingErrors> {
23 let seed_dir = self.seed_dir();
24 if seed_dir.as_ref().exists() {
25 return Ok(seed_dir.as_ref().into());
26 }
27 create_dir(&seed_dir).map_err(SeedingErrors::CreateSeedDir)?;
28 Ok(seed_dir.as_ref().into())
29 }
30 fn soft_link_potentials<P: AsRef<Path>>(&self, potential_src: P) -> Result<(), SeedingErrors> {
31 self.cell_template()
32 .get_elements()
33 .iter()
34 .try_for_each(|&elm| {
35 let potential_file = ELEMENT_TABLE.get_by_symbol(elm).potential();
36 let src_path = potential_src.as_ref().join(potential_file);
37 let dst_path = self.seed_dir().as_ref().join(potential_file);
38 if dst_path.is_symlink() || dst_path.exists() {
39 Ok(())
40 } else {
41 #[cfg(target_os = "windows")]
42 {
43 std::os::windows::fs::symlink_file(src_path, dst_path)
44 .map_err(SeedingErrors::SoftlinkError)
45 }
46 #[cfg(not(target_os = "windows"))]
47 std::os::unix::fs::symlink(src_path, dst_path)
48 .map_err(SeedingErrors::SoftlinkError)
49 }
50 })
51 }
52 fn create_seed_file<P: AsRef<Path>, F: AsRef<[u8]>>(
53 &self,
54 filename: P,
55 file_content: F,
56 ) -> Result<(), SeedingErrors> {
57 let seed_dir = self.seed_dir();
58 let file_path = seed_dir.as_ref().join(filename);
59 let file = File::create(file_path).map_err(SeedingErrors::WriteError)?;
60 let mut f = BufWriter::new(file);
61 f.write_all(file_content.as_ref())
62 .map_err(SeedingErrors::WriteError)?;
63 Ok(())
64 }
65 fn write_files(
68 &self,
69 cell_builder: &impl CellBuilding,
70 param_builder: &impl ParamBuilding,
71 ) -> Result<(), SeedingErrors> {
72 [
73 (
74 format!("{}.param", self.seed_name()),
75 param_builder
76 .build_param_for_task(self.cell_template(), CastepTask::GeometryOptimization)?
77 .to_string(),
78 ),
79 (
80 format!("{}_DOS.param", self.seed_name()),
81 param_builder
82 .build_param_for_task(self.cell_template(), CastepTask::BandStructure)?
83 .to_string(),
84 ),
85 (
86 format!("{}.cell", self.seed_name()),
87 cell_builder
88 .build_cell_for_task(self.cell_template(), CastepTask::GeometryOptimization)
89 .to_string(),
90 ),
91 (
92 format!("{}_DOS.cell", self.seed_name()),
93 cell_builder
94 .build_cell_for_task(self.cell_template(), CastepTask::BandStructure)
95 .to_string(),
96 ),
97 ]
98 .iter()
99 .try_for_each(|(filename, file_content)| self.create_seed_file(filename, file_content))?;
100 Ok(())
101 }
102 fn actions<P: AsRef<Path>>(
104 &self,
105 cell_builder: &impl CellBuilding,
106 param_builder: &impl ParamBuilding,
107 potential_src: P,
108 ) -> Result<(), SeedingErrors> {
109 self.create_seed_dir()?;
110 self.write_files(cell_builder, param_builder)?;
111 self.soft_link_potentials(potential_src)
112 }
113}