ak_core/utils/
atom_info.rs1use once_cell::sync::Lazy;
2use std::num::{ParseFloatError, ParseIntError};
3
4use crate::AtomicNumber;
5
6const DATA: &str = include_str!("atom_info.csv");
7
8pub struct AtomInfo {
9 pub number: AtomicNumber,
10 pub symbol: String,
11 pub covalent_radius: f64,
12 pub vdw_radius: f64,
13}
14
15pub struct PeriodicTable {
16 info_arr: [AtomInfo; 110],
17}
18
19impl PeriodicTable {
20 pub fn from_data() -> Result<Self, String> {
21 let mut info = Vec::new();
22
23 for (i, line) in DATA.lines().enumerate() {
24 if i == 0 || line.trim().is_empty() {
25 continue; }
27 let parts: Vec<&str> = line.split(',').collect();
28 if parts.len() != 4 {
29 return Err(format!("bad row {}: {}", i + 1, line));
30 }
31 let number_u8: u8 = parts[0]
32 .parse::<u8>()
33 .map_err(|e: ParseIntError| e.to_string())?;
34 let number: AtomicNumber = AtomicNumber::new(number_u8).expect("Invalid atomic number");
35 let symbol = parts[1].to_string();
36 let covalent_radius: f64 = parts[2]
37 .parse()
38 .map_err(|e: ParseFloatError| e.to_string())?;
39 let vdw_radius: f64 = parts[3]
40 .parse()
41 .map_err(|e: ParseFloatError| e.to_string())?;
42
43 info.push(AtomInfo {
44 number,
45 symbol,
46 covalent_radius,
47 vdw_radius,
48 });
49 }
50
51 let info_arr: [AtomInfo; 110] = info
52 .try_into()
53 .map_err(|v: Vec<AtomInfo>| format!("expected 110 rows, got {}", v.len()))?;
54
55 Ok(Self { info_arr })
56 }
57
58 pub fn get(&self, z: AtomicNumber) -> &AtomInfo {
59 self.info_arr
60 .get((z.get() - 1) as usize)
61 .expect("Mismatched index due")
62 }
63
64 pub fn get_by_symbol(&self, symbol: &str) -> &AtomInfo {
65 self.info_arr
66 .iter()
67 .find(|f| f.symbol == symbol)
68 .expect("Unknown element symbol")
69 }
70}
71
72pub static PERIODIC_TABLE: Lazy<PeriodicTable> =
73 Lazy::new(|| PeriodicTable::from_data().expect("Failed to build periodic table"));
74
75#[cfg(test)]
76mod test {
77
78 use crate::AtomicNumber;
79 use crate::utils::atom_info::PERIODIC_TABLE;
80
81 #[test]
82 fn get_from_table() {
83 let hydrogen_data = PERIODIC_TABLE.get(AtomicNumber::new(1).unwrap());
84 assert_eq!(hydrogen_data.number.get(), 1);
85 assert_eq!(hydrogen_data.symbol, String::from("H"));
86 }
87
88 #[test]
89 fn get_by_symbol() {
90 let hydrogen_data = PERIODIC_TABLE.get_by_symbol("H");
91 assert_eq!(hydrogen_data.number.get(), 1);
92 assert_eq!(hydrogen_data.symbol, String::from("H"));
93 }
94}