use castep_cell_fmt::{Cell, CellValue, ToCell, ToCellValue};
use castep_cell_fmt::parse::{FromCellValue, FromKeyValue};
use castep_cell_fmt::{CResult, Error};
use castep_cell_fmt::query::value_as_str;
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
#[derive(Default)]
pub enum OpticXcFunctional {
#[default]
Lda,
Pw91,
Pbe,
Rpbe,
Wc,
Pbesol,
Blyp,
Hf,
HfLda,
SX,
SXlda,
Pbe0,
B3lyp,
Hse03,
Hse06,
Rscan,
}
impl FromCellValue for OpticXcFunctional {
fn from_cell_value(value: &CellValue<'_>) -> CResult<Self> {
match value_as_str(value)?.to_ascii_lowercase().as_str() {
"lda" => Ok(Self::Lda),
"pw91" => Ok(Self::Pw91),
"pbe" => Ok(Self::Pbe),
"rpbe" => Ok(Self::Rpbe),
"wc" => Ok(Self::Wc),
"pbesol" => Ok(Self::Pbesol),
"blyp" => Ok(Self::Blyp),
"hf" => Ok(Self::Hf),
"hf-lda" => Ok(Self::HfLda),
"sx" => Ok(Self::SX),
"sx-lda" => Ok(Self::SXlda),
"pbe0" => Ok(Self::Pbe0),
"b3lyp" => Ok(Self::B3lyp),
"hse03" => Ok(Self::Hse03),
"hse06" => Ok(Self::Hse06),
"rscan" => Ok(Self::Rscan),
other => Err(Error::Message(format!("unknown OpticXcFunctional: {other}"))),
}
}
}
impl FromKeyValue for OpticXcFunctional {
const KEY_NAME: &'static str = "OPTICS_XC_FUNCTIONAL";
fn from_cell_value_kv(value: &CellValue<'_>) -> CResult<Self> {
Self::from_cell_value(value)
}
}
impl ToCell for OpticXcFunctional {
fn to_cell(&self) -> Cell<'_> {
Cell::KeyValue("OPTICS_XC_FUNCTIONAL", self.to_cell_value())
}
}
impl ToCellValue for OpticXcFunctional {
fn to_cell_value(&self) -> CellValue<'_> {
CellValue::String(
match self {
OpticXcFunctional::Lda => "LDA",
OpticXcFunctional::Pw91 => "PW91",
OpticXcFunctional::Pbe => "PBE",
OpticXcFunctional::Rpbe => "RPBE",
OpticXcFunctional::Wc => "WC",
OpticXcFunctional::Pbesol => "PBESOL",
OpticXcFunctional::Blyp => "BLYP",
OpticXcFunctional::Hf => "HF",
OpticXcFunctional::HfLda => "HF-LDA",
OpticXcFunctional::SX => "SX",
OpticXcFunctional::SXlda => "SX-LDA",
OpticXcFunctional::Pbe0 => "PBE0",
OpticXcFunctional::B3lyp => "B3LYP",
OpticXcFunctional::Hse03 => "HSE03",
OpticXcFunctional::Hse06 => "HSE06",
OpticXcFunctional::Rscan => "RSCAN",
}
.to_string(),
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use castep_cell_fmt::CellValue;
#[test]
fn test_case_insensitive_parsing() {
let val = CellValue::Str("lda");
assert_eq!(OpticXcFunctional::from_cell_value(&val).unwrap(), OpticXcFunctional::Lda);
let val = CellValue::Str("LDA");
assert_eq!(OpticXcFunctional::from_cell_value(&val).unwrap(), OpticXcFunctional::Lda);
let val = CellValue::Str("pbe");
assert_eq!(OpticXcFunctional::from_cell_value(&val).unwrap(), OpticXcFunctional::Pbe);
let val = CellValue::Str("PBE");
assert_eq!(OpticXcFunctional::from_cell_value(&val).unwrap(), OpticXcFunctional::Pbe);
}
#[test]
fn test_all_variants() {
assert_eq!(OpticXcFunctional::from_cell_value(&CellValue::Str("pw91")).unwrap(), OpticXcFunctional::Pw91);
assert_eq!(OpticXcFunctional::from_cell_value(&CellValue::Str("rpbe")).unwrap(), OpticXcFunctional::Rpbe);
assert_eq!(OpticXcFunctional::from_cell_value(&CellValue::Str("wc")).unwrap(), OpticXcFunctional::Wc);
assert_eq!(OpticXcFunctional::from_cell_value(&CellValue::Str("pbesol")).unwrap(), OpticXcFunctional::Pbesol);
assert_eq!(OpticXcFunctional::from_cell_value(&CellValue::Str("blyp")).unwrap(), OpticXcFunctional::Blyp);
assert_eq!(OpticXcFunctional::from_cell_value(&CellValue::Str("hf")).unwrap(), OpticXcFunctional::Hf);
assert_eq!(OpticXcFunctional::from_cell_value(&CellValue::Str("hf-lda")).unwrap(), OpticXcFunctional::HfLda);
assert_eq!(OpticXcFunctional::from_cell_value(&CellValue::Str("sx")).unwrap(), OpticXcFunctional::SX);
assert_eq!(OpticXcFunctional::from_cell_value(&CellValue::Str("sx-lda")).unwrap(), OpticXcFunctional::SXlda);
assert_eq!(OpticXcFunctional::from_cell_value(&CellValue::Str("pbe0")).unwrap(), OpticXcFunctional::Pbe0);
assert_eq!(OpticXcFunctional::from_cell_value(&CellValue::Str("b3lyp")).unwrap(), OpticXcFunctional::B3lyp);
assert_eq!(OpticXcFunctional::from_cell_value(&CellValue::Str("hse03")).unwrap(), OpticXcFunctional::Hse03);
assert_eq!(OpticXcFunctional::from_cell_value(&CellValue::Str("hse06")).unwrap(), OpticXcFunctional::Hse06);
assert_eq!(OpticXcFunctional::from_cell_value(&CellValue::Str("rscan")).unwrap(), OpticXcFunctional::Rscan);
}
#[test]
fn test_invalid() {
assert!(OpticXcFunctional::from_cell_value(&CellValue::Str("invalid")).is_err());
}
#[test]
fn test_key_name() {
assert_eq!(OpticXcFunctional::KEY_NAME, "OPTICS_XC_FUNCTIONAL");
}
#[test]
fn test_default() {
assert_eq!(OpticXcFunctional::default(), OpticXcFunctional::Lda);
}
#[test]
fn test_to_cell_value() {
assert_eq!(
OpticXcFunctional::Lda.to_cell_value(),
CellValue::String("LDA".to_string())
);
assert_eq!(
OpticXcFunctional::Pw91.to_cell_value(),
CellValue::String("PW91".to_string())
);
}
#[test]
fn test_to_cell() {
let cell = OpticXcFunctional::Lda.to_cell();
match cell {
Cell::KeyValue(key, _) => assert_eq!(key, "OPTICS_XC_FUNCTIONAL"),
_ => panic!("Expected KeyValue cell"),
}
}
}