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 pub fn get_by_symbol_opt(&self, symbol: &str) -> Option<&AtomInfo> {
72 self.info_arr.iter().find(|f| f.symbol == symbol)
73 }
74}
75
76pub static PERIODIC_TABLE: Lazy<PeriodicTable> =
77 Lazy::new(|| PeriodicTable::from_data().expect("Failed to build periodic table"));
78
79#[cfg(test)]
80mod test {
81
82 use crate::AtomicNumber;
83 use crate::utils::atom_info::PERIODIC_TABLE;
84
85 #[test]
86 fn get_from_table() {
87 let hydrogen_data = PERIODIC_TABLE.get(AtomicNumber::new(1).unwrap());
88 assert_eq!(hydrogen_data.number.get(), 1);
89 assert_eq!(hydrogen_data.symbol, String::from("H"));
90 }
91
92 #[test]
93 fn get_by_symbol() {
94 let hydrogen_data = PERIODIC_TABLE.get_by_symbol("H");
95 assert_eq!(hydrogen_data.number.get(), 1);
96 assert_eq!(hydrogen_data.symbol, String::from("H"));
97 }
98}