castep_cell_io/cell_document/
mod.rs1#[allow(unused_imports)]
2mod chemrust_impl;
3pub mod params;
4pub mod sections;
5pub mod units;
6
7use std::fs::read_to_string;
8use std::path::PathBuf;
9use std::{fmt::Display, fs, io::Error, path::Path};
10
11use castep_periodic_table::data::ELEMENT_TABLE;
12use castep_periodic_table::element::{ElementSymbol, LookupElement};
13use chemrust_core::data::atom::CoreAtomData;
14use chemrust_core::data::lattice::{CrystalModel, UnitCellParameters};
15use chemrust_core::data::symmetry::SymmetryInfo;
16
17pub use sections::constraints::{FixAllCell, FixCom, IonicConstraintsBlock};
18pub use sections::external_fields::{ExtEFieldBlock, ExtPressureBlock};
19pub use sections::ionic_positions::{IonicPosition, IonicPositionBlock, Mixture};
20pub use sections::kpoint_settings::*;
21pub use sections::lattice_parameters::{LatticeABC, LatticeCart, LatticeParam, LatticeParamBlock};
22pub use sections::species_characters::{
23 LCAOBasis, SpeciesLCAOStatesBlock, SpeciesMass, SpeciesMassBlock, SpeciesPot, SpeciesPotBlock,
24};
25
26pub use chemrust_impl::to_cell_document;
27pub use sections::CellEntries;
28pub use sections::CellEssentials;
29
30use crate::{CellParseError, CellParser};
31
32#[derive(Debug, Clone)]
34pub struct CellDocument {
35 model_description: CellEssentials,
36 other_entries: Option<Vec<CellEntries>>,
37}
38
39impl CrystalModel for CellDocument {
40 fn get_cell_parameters(&self) -> &impl UnitCellParameters {
41 self.model_description().lattice_block()
42 }
43
44 fn get_atom_data(&self) -> &impl CoreAtomData {
45 self.model_description().ionic_pos_block()
46 }
47
48 fn get_cell_parameters_mut(&mut self) -> &mut impl UnitCellParameters {
49 self.model_description_mut().lattice_block_mut()
50 }
51
52 fn get_atom_data_mut(&mut self) -> &mut impl CoreAtomData {
53 self.model_description_mut().ionic_pos_block_mut()
54 }
55}
56
57impl SymmetryInfo for CellDocument {
58 fn get_space_group_it_num(&self) -> u8 {
59 if matches!(
60 self.other_entries().and_then(|entries| {
61 entries
62 .iter()
63 .find(|entry| matches!(entry, CellEntries::SymmetryOps(_)))
64 }),
65 Some(CellEntries::SymmetryOps(..))
66 ) {
67 todo!()
68 } else {
69 1_u8
70 }
71 }
72
73 fn make_symmetry(&self) -> bool {
74 matches!(
75 self.other_entries().and_then(|entries| {
76 entries
77 .iter()
78 .find(|entry| matches!(entry, CellEntries::SymmetryOps(_)))
79 }),
80 Some(CellEntries::SymmetryOps(..))
81 )
82 }
83}
84
85impl CellDocument {
86 pub fn new(model_description: CellEssentials) -> Self {
87 Self {
88 model_description,
89 other_entries: None,
90 }
91 }
92
93 pub fn parse_from_file<P: AsRef<Path>>(&self, file_path: P) -> Result<Self, CellParseError> {
94 let content = read_to_string(file_path).map_err(|_| CellParseError::FileReadingFailure)?;
95 CellParser::from(&content).parse()
96 }
97
98 pub fn write_out<P: AsRef<Path>>(&self, path: P) -> Result<(), Error> {
99 fs::write(path, self.to_string())
100 }
101
102 pub fn other_entries(&self) -> Option<&Vec<CellEntries>> {
103 self.other_entries.as_ref()
104 }
105
106 pub fn other_entries_mut(&mut self) -> &mut Option<Vec<CellEntries>> {
107 &mut self.other_entries
108 }
109
110 pub fn set_entries(&mut self, entries: Option<Vec<CellEntries>>) {
111 self.other_entries = entries;
112 }
113 pub fn get_elements(&self) -> Vec<ElementSymbol> {
114 let mut symbols: Vec<ElementSymbol> = self
115 .model_description()
116 .ionic_pos_block()
117 .positions()
118 .iter()
119 .map(|pos| pos.symbol())
120 .collect();
121 symbols.sort();
122 symbols.dedup();
123 symbols
124 }
125
126 pub fn total_spin(&self) -> u32 {
129 self.model_description()
130 .ionic_pos_block()
131 .positions()
132 .iter()
133 .map(|&pos| ELEMENT_TABLE.get_by_symbol(pos.symbol()).spin() as u32)
134 .sum::<u32>()
135 }
136
137 pub fn model_description(&self) -> &CellEssentials {
138 &self.model_description
139 }
140
141 pub fn model_description_mut(&mut self) -> &mut CellEssentials {
142 &mut self.model_description
143 }
144
145 pub fn set_model_description(&mut self, model_description: CellEssentials) {
146 self.model_description = model_description;
147 }
148
149 pub fn get_potential_paths<P: AsRef<Path>>(&self, potentials_loc: P) -> Vec<PathBuf> {
150 self.get_elements()
151 .iter()
152 .map(|&elm| {
153 let potential_file = ELEMENT_TABLE.get_by_symbol(elm).potential();
154 potentials_loc.as_ref().join(potential_file)
155 })
156 .collect()
157 }
158}
159
160impl Display for CellDocument {
161 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
162 let entries = self
163 .other_entries()
164 .map(|e| {
165 e.iter()
166 .map(|item| format!("{}", item))
167 .collect::<Vec<String>>()
168 .join("\n")
169 })
170 .unwrap_or_default();
171 let content = [
172 format!("{}", self.model_description().lattice_block()),
173 format!("{}", self.model_description().ionic_pos_block()),
174 entries,
175 ]
176 .concat();
177 write!(f, "{}", content)
178 }
179}