Skip to main content

castep_cell_io/param/general/
task.rs

1use castep_cell_fmt::{Cell, CellValue, ToCell, ToCellValue};
2use castep_cell_fmt::parse::{FromCellValue, FromKeyValue};
3use castep_cell_fmt::{CResult, Error};
4use castep_cell_fmt::query::value_as_str;
5use serde::{Deserialize, Serialize};
6
7/// Defines the type of calculation to perform.
8///
9/// Keyword type: String
10///
11/// Default: Task::SinglePoint
12///
13/// Example:
14/// TASK : optics
15#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)]
16#[serde(rename = "TASK")]
17#[derive(Default)]
18pub enum Task {
19    /// Performs a single-point energy calculation.
20    #[serde(alias = "SINGLEPOINT", alias = "singlepoint")]
21    #[default]
22    SinglePoint,
23    /// Calculates band structure properties.
24    #[serde(alias = "BANDSTRUCTURE", alias = "bandstructure")]
25    BandStructure,
26    /// Searches for a minimum energy structure.
27    #[serde(alias = "GEOMETRYOPTIMIZATION", alias = "geometryoptimization")]
28    GeometryOptimization,
29    /// Performs a molecular dynamics calculation.
30    #[serde(alias = "MOLECULARDYNAMICS", alias = "moleculardynamics")]
31    MolecularDynamics,
32    /// Calculates optical properties.
33    #[serde(alias = "OPTICS", alias = "optics")]
34    Optics,
35    /// Performs a linear response calculation to determine phonon frequencies and eigenvectors.
36    #[serde(alias = "PHONON", alias = "phonon")]
37    Phonon,
38    /// Performs an electric field linear response calculation.
39    #[serde(alias = "EFIELD", alias = "efield")]
40    Efield,
41    /// Performs both Phonon and Efield calculations.
42    #[serde(alias = "PHONON+EFIELD", alias = "phonon+efield")]
43    PhononPlusEfield,
44    /// Performs a transition-state search.
45    #[serde(alias = "TRANSITIONSTATESEARCH", alias = "transitionstatesearch")]
46    TransitionStateSearch,
47    /// Performs an NMR calculation.
48    #[serde(alias = "MAGRES", alias = "magres")]
49    MagRes,
50    /// Performs core level spectroscopy calculation.
51    #[serde(alias = "ELNES", alias = "elnes")]
52    Elnes,
53    /// Performs electronic spectroscopy calculation.
54    #[serde(alias = "ELECTRONICSPECTROSCOPY", alias = "electronicspectroscopy")]
55    ElectronicSpectroscopy,
56    /// Performs a free energy of solvation calculation.
57    #[serde(alias = "AUTOSOLVATION", alias = "autosolvation")]
58    Autosolvation,
59}
60
61
62impl FromCellValue for Task {
63    fn from_cell_value(value: &CellValue<'_>) -> CResult<Self> {
64        match value_as_str(value)?.to_ascii_lowercase().as_str() {
65            "singlepoint" => Ok(Self::SinglePoint),
66            "bandstructure" => Ok(Self::BandStructure),
67            "geometryoptimization" => Ok(Self::GeometryOptimization),
68            "moleculardynamics" => Ok(Self::MolecularDynamics),
69            "optics" => Ok(Self::Optics),
70            "phonon" => Ok(Self::Phonon),
71            "efield" => Ok(Self::Efield),
72            "phonon+efield" => Ok(Self::PhononPlusEfield),
73            "transitionstatesearch" => Ok(Self::TransitionStateSearch),
74            "magres" => Ok(Self::MagRes),
75            "elnes" => Ok(Self::Elnes),
76            "electronicspectroscopy" => Ok(Self::ElectronicSpectroscopy),
77            "autosolvation" => Ok(Self::Autosolvation),
78            other => Err(Error::Message(format!("unknown Task: {other}"))),
79        }
80    }
81}
82
83impl FromKeyValue for Task {
84    const KEY_NAME: &'static str = "TASK";
85
86    fn from_cell_value_kv(value: &CellValue<'_>) -> CResult<Self> {
87        Self::from_cell_value(value)
88    }
89}
90
91impl ToCell for Task {
92    fn to_cell(&self) -> Cell<'_> {
93        Cell::KeyValue("TASK", self.to_cell_value())
94    }
95}
96
97impl ToCellValue for Task {
98    fn to_cell_value(&self) -> CellValue<'_> {
99        CellValue::String(
100            match self {
101                Task::SinglePoint => "SinglePoint",
102                Task::BandStructure => "BandStructure",
103                Task::GeometryOptimization => "GeometryOptimization",
104                Task::MolecularDynamics => "MolecularDynamics",
105                Task::Optics => "Optics",
106                Task::Phonon => "Phonon",
107                Task::Efield => "Efield",
108                Task::PhononPlusEfield => "Phonon+Efield",
109                Task::TransitionStateSearch => "TransitionStateSearch",
110                Task::MagRes => "MagRes",
111                Task::Elnes => "Elnes",
112                Task::ElectronicSpectroscopy => "ElectronicSpectroscopy",
113                Task::Autosolvation => "Autosolvation",
114            }
115            .to_string(),
116        )
117    }
118}
119
120#[cfg(test)]
121mod tests {
122    use super::*;
123    use castep_cell_fmt::CellValue;
124
125    #[test]
126    fn test_case_insensitive_parsing() {
127        let val = CellValue::Str("singlepoint");
128        assert_eq!(Task::from_cell_value(&val).unwrap(), Task::SinglePoint);
129
130        let val = CellValue::Str("SINGLEPOINT");
131        assert_eq!(Task::from_cell_value(&val).unwrap(), Task::SinglePoint);
132
133        let val = CellValue::Str("SinglePoint");
134        assert_eq!(Task::from_cell_value(&val).unwrap(), Task::SinglePoint);
135    }
136
137    #[test]
138    fn test_all_variants() {
139        assert_eq!(Task::from_cell_value(&CellValue::Str("bandstructure")).unwrap(), Task::BandStructure);
140        assert_eq!(Task::from_cell_value(&CellValue::Str("geometryoptimization")).unwrap(), Task::GeometryOptimization);
141        assert_eq!(Task::from_cell_value(&CellValue::Str("moleculardynamics")).unwrap(), Task::MolecularDynamics);
142        assert_eq!(Task::from_cell_value(&CellValue::Str("optics")).unwrap(), Task::Optics);
143        assert_eq!(Task::from_cell_value(&CellValue::Str("phonon")).unwrap(), Task::Phonon);
144        assert_eq!(Task::from_cell_value(&CellValue::Str("efield")).unwrap(), Task::Efield);
145        assert_eq!(Task::from_cell_value(&CellValue::Str("phonon+efield")).unwrap(), Task::PhononPlusEfield);
146        assert_eq!(Task::from_cell_value(&CellValue::Str("transitionstatesearch")).unwrap(), Task::TransitionStateSearch);
147        assert_eq!(Task::from_cell_value(&CellValue::Str("magres")).unwrap(), Task::MagRes);
148        assert_eq!(Task::from_cell_value(&CellValue::Str("elnes")).unwrap(), Task::Elnes);
149        assert_eq!(Task::from_cell_value(&CellValue::Str("electronicspectroscopy")).unwrap(), Task::ElectronicSpectroscopy);
150        assert_eq!(Task::from_cell_value(&CellValue::Str("autosolvation")).unwrap(), Task::Autosolvation);
151    }
152
153    #[test]
154    fn test_invalid_variant() {
155        let val = CellValue::Str("invalid");
156        assert!(Task::from_cell_value(&val).is_err());
157    }
158
159    #[test]
160    fn test_key_name() {
161        assert_eq!(Task::KEY_NAME, "TASK");
162    }
163}
164