castep_cell_io/parsing/
cell_parser.rs

1use crate::{
2    cell_document::{CellDocument, CellEntries, CellEssentials},
3    keywords::{
4        DocumentSections, KPointKeywords, KeywordType, LatticeBlockType, PositionsKeywords,
5        SpeciesKeywords,
6    },
7    parsing::helpers::{
8        current_sections, get_block_data, get_field_data, parse_bs_kpoint_list,
9        parse_ionic_positions, parse_kpoint_list, parse_lattice_param, parse_species_mass_block,
10        parse_species_pot_block,
11    },
12    CellParseError, CellParser,
13};
14
15use super::helpers::{
16    parse_bs_kpoint_path, parse_kpoint_mp_grid_field, parse_kpoint_mp_spacing_field,
17    parse_species_lcao_block,
18};
19
20impl<'a, S: AsRef<str>> From<&'a S> for CellParser<'a> {
21    fn from(value: &'a S) -> Self {
22        Self {
23            input: value.as_ref(),
24            lattice_param: None,
25            ionic_positions: None,
26            other_entries: Vec::new(),
27        }
28    }
29}
30
31impl CellParser<'_> {
32    pub fn parse(&mut self) -> Result<CellDocument, CellParseError> {
33        while let Ok(section) = current_sections(&mut self.input) {
34            match section {
35                DocumentSections::CellLatticeVectors(lat_keyword) => {
36                    self.parse_lattice_param_section(lat_keyword)?;
37                }
38                DocumentSections::IonicPositions(pos_keyword) => {
39                    self.parse_ionic_pos_section(pos_keyword)?;
40                }
41                DocumentSections::KPoint(kpt_keyword) => {
42                    let kpt_setting = self.parse_kpt_section(kpt_keyword)?;
43                    self.other_entries.push(kpt_setting);
44                }
45                DocumentSections::Species(spec_keyword) => {
46                    let entry = self.parse_species_section(spec_keyword)?;
47                    self.other_entries.push(entry);
48                }
49                DocumentSections::Misc(ref misc_keyword) => match misc_keyword {
50                    KeywordType::Block(_) => {
51                        get_block_data(&mut self.input)
52                            .map_err(|_| CellParseError::GetBlockDataFailure)?;
53                        #[cfg(debug_assertions)]
54                        dbg!(&self.input);
55                    }
56                    KeywordType::Field(field_kw) => {
57                        let field_data = get_field_data(&mut self.input)
58                            .map_err(|_| CellParseError::GetBlockDataFailure)?;
59                        #[cfg(debug_assertions)]
60                        {
61                            dbg!((field_kw, field_data));
62                        }
63                    }
64                },
65                DocumentSections::End => {
66                    break;
67                }
68                _ => {
69                    #[cfg(debug_assertions)]
70                    println!("{:?}", section)
71                }
72            }
73        }
74        if self.lattice_param.is_some() && self.ionic_positions.is_some() {
75            let model_description = CellEssentials::new(
76                self.lattice_param.unwrap(),
77                self.ionic_positions.as_ref().unwrap().to_owned(),
78            );
79            let mut cell_doc = CellDocument::new(model_description);
80            cell_doc.set_entries(Some(self.other_entries.clone()));
81            // Default to true whether `SPIN` is found in parsing or not.
82            cell_doc
83                .model_description_mut()
84                .ionic_pos_block_mut()
85                .set_spin_polarised(true);
86            Ok(cell_doc)
87        } else {
88            Err(CellParseError::RequiredSectionMissing)
89        }
90    }
91    fn parse_lattice_param_section(
92        &mut self,
93        lat_keyword: LatticeBlockType,
94    ) -> Result<(), CellParseError> {
95        let param = parse_lattice_param(&mut self.input, lat_keyword)?;
96        self.lattice_param = Some(param);
97        Ok(())
98    }
99    fn parse_ionic_pos_section(
100        &mut self,
101        pos_keyword: PositionsKeywords,
102    ) -> Result<(), CellParseError> {
103        let positions = parse_ionic_positions(&mut self.input, pos_keyword)?;
104        self.ionic_positions = Some(positions);
105        Ok(())
106    }
107    fn parse_species_section(
108        &mut self,
109        species_keyword: SpeciesKeywords,
110    ) -> Result<CellEntries, CellParseError> {
111        match species_keyword {
112            SpeciesKeywords::SPECIES_LCAO_STATES => Ok(CellEntries::SpeciesLCAOStates(
113                parse_species_lcao_block(&mut self.input)?,
114            )),
115            SpeciesKeywords::SPECIES_MASS => Ok(CellEntries::SpeciesMass(
116                parse_species_mass_block(&mut self.input)?,
117            )),
118            SpeciesKeywords::SPECIES_POT => Ok(CellEntries::SpeciesPot(parse_species_pot_block(
119                &mut self.input,
120            )?)),
121        }
122    }
123    fn parse_kpt_section(
124        &mut self,
125        kpt_keyword: KPointKeywords,
126    ) -> Result<CellEntries, CellParseError> {
127        match kpt_keyword {
128            KPointKeywords::KPOINT_LIST => Ok(CellEntries::KpointSettings(parse_kpoint_list(
129                &mut self.input,
130            )?)),
131            KPointKeywords::KPOINT_MP_GRID => Ok(CellEntries::KpointSettings(
132                parse_kpoint_mp_grid_field(&mut self.input)?,
133            )),
134            KPointKeywords::KPOINT_MP_SPACING => Ok(CellEntries::KpointSettings(
135                parse_kpoint_mp_spacing_field(&mut self.input)?,
136            )),
137            KPointKeywords::KPOINT_MP_OFFSET => todo!(),
138            KPointKeywords::SPECTRAL_KPOINT_LIST => Ok(CellEntries::NCKpointSettings(
139                parse_bs_kpoint_list(&mut self.input)?,
140            )),
141            KPointKeywords::SPECTRAL_KPOINT_PATH => Ok(CellEntries::NCKpointSettings(
142                parse_bs_kpoint_path(&mut self.input)?,
143            )),
144            KPointKeywords::SPECTRAL_KPOINT_PATH_SPACING => todo!(),
145        }
146    }
147}