gchemol_core/
element.rs

1// [[file:../gchemol-core.note::*imports][imports:1]]
2use serde::*;
3// imports:1 ends here
4
5// [[file:../gchemol-core.note::cab264f1][cab264f1]]
6const ELEMENT_DATA: [(&str, &str); 118] = [
7    ("H", "Hydrogen"),
8    ("He", "Helium"),
9    ("Li", "Lithium"),
10    ("Be", "Beryllium"),
11    ("B", "Boron"),
12    ("C", "Carbon"),
13    ("N", "Nitrogen"),
14    ("O", "Oxygen"),
15    ("F", "Fluorine"),
16    ("Ne", "Neon"),
17    ("Na", "Sodium"),
18    ("Mg", "Magnesium"),
19    ("Al", "Aluminum"),
20    ("Si", "Silicon"),
21    ("P", "Phosphorus"),
22    ("S", "Sulfur"),
23    ("Cl", "Chlorine"),
24    ("Ar", "Argon"),
25    ("K", "Potassium"),
26    ("Ca", "Calcium"),
27    ("Sc", "Scandium"),
28    ("Ti", "Titanium"),
29    ("V", "Vanadium"),
30    ("Cr", "Chromium"),
31    ("Mn", "Manganese"),
32    ("Fe", "Iron"),
33    ("Co", "Cobalt"),
34    ("Ni", "Nickel"),
35    ("Cu", "Copper"),
36    ("Zn", "Zinc"),
37    ("Ga", "Gallium"),
38    ("Ge", "Germanium"),
39    ("As", "Arsenic"),
40    ("Se", "Selenium"),
41    ("Br", "Bromine"),
42    ("Kr", "Krypton"),
43    ("Rb", "Rubidium"),
44    ("Sr", "Strontium"),
45    ("Y", "Yttrium"),
46    ("Zr", "Zirconium"),
47    ("Nb", "Niobium"),
48    ("Mo", "Molybdenum"),
49    ("Tc", "Technetium"),
50    ("Ru", "Ruthenium"),
51    ("Rh", "Rhodium"),
52    ("Pd", "Palladium"),
53    ("Ag", "Silver"),
54    ("Cd", "Cadmium"),
55    ("In", "Indium"),
56    ("Sn", "Tin"),
57    ("Sb", "Antimony"),
58    ("Te", "Tellurium"),
59    ("I", "Iodine"),
60    ("Xe", "Xenon"),
61    ("Cs", "Cesium"),
62    ("Ba", "Barium"),
63    ("La", "Lanthanum"),
64    ("Ce", "Cerium"),
65    ("Pr", "Praesodymium"),
66    ("Nd", "Neodymium"),
67    ("Pm", "Promethium"),
68    ("Sm", "Samarium"),
69    ("Eu", "Europium"),
70    ("Gd", "Gadolinium"),
71    ("Tb", "Terbium"),
72    ("Dy", "Dyprosium"),
73    ("Ho", "Holmium"),
74    ("Er", "Erbium"),
75    ("Tm", "Thulium"),
76    ("Yb", "Ytterbium"),
77    ("Lu", "Lutetium"),
78    ("Hf", "Hafnium"),
79    ("Ta", "Tantalium"),
80    ("W", "Wolfram"),
81    ("Re", "Rhenium"),
82    ("Os", "Osmium"),
83    ("Ir", "Iridium"),
84    ("Pt", "Platinum"),
85    ("Au", "Gold"),
86    ("Hg", "Mercury"),
87    ("Tl", "Thallium"),
88    ("Pb", "Lead"),
89    ("Bi", "Bismuth"),
90    ("Po", "Polonium"),
91    ("At", "Astatine"),
92    ("Rn", "Radon"),
93    ("Fr", "Francium"),
94    ("Ra", "Radium"),
95    ("Ac", "Actinium"),
96    ("Th", "Thorium"),
97    ("Pa", "Protactinium"),
98    ("U", "Uranium"),
99    ("Np", "Neptunium"),
100    ("Pu", "Plutonium"),
101    ("Am", "Americium"),
102    ("Cm", "Curium"),
103    ("Bk", "Berkelium"),
104    ("Cf", "Californium"),
105    ("Es", "Einsteinium"),
106    ("Fm", "Fermium"),
107    ("Mv", "Mendelevium"),
108    ("No", "Nobelium"),
109    ("Lr", "Lawrencium"),
110    ("Rf", "Rutherfordium"),
111    ("Db", "Dubnium"),
112    ("Sg", "Seaborgium"),
113    ("Bh", "Bohrium"),
114    ("Hs", "Hassium"),
115    ("Mt", "Meitnerium"),
116    ("Uun", "Ununnilium"),
117    ("Uuu", "Unununium"),
118    ("Uub", "Ununbium"),
119    ("Uut", "Ununtrium"),
120    ("Uuq", "Ununquadium"),
121    ("Uup", "Ununpentium"),
122    ("Uuh", "Ununhexium"),
123    ("Uus", "Ununseptium"),
124    ("Uuo", "Ununoctium"),
125];
126// cab264f1 ends here
127
128// [[file:../gchemol-core.note::*base][base:1]]
129/// Represents different kind of atom, such as cheimcial element, dummy atom,
130/// etc.
131#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
132pub enum AtomKind {
133    /// Chemical element.
134    Element(usize),
135
136    /// Dummy atom for special purpose.
137    Dummy(String),
138}
139
140use self::AtomKind::{Dummy, Element};
141
142impl AtomKind {
143    /// Element symbol.
144    pub fn symbol(&self) -> &str {
145        match &self {
146            Element(num) => ELEMENT_DATA[num - 1].0,
147            Dummy(sym) => sym,
148        }
149    }
150
151    /// Atomic number.
152    pub fn number(&self) -> usize {
153        match &self {
154            Element(num) => *num,
155            Dummy(_) => 0,
156        }
157    }
158
159    /// Element name.
160    pub fn name(&self) -> &str {
161        match &self {
162            Element(num) => ELEMENT_DATA[num - 1].1,
163            Dummy(sym) => sym,
164        }
165    }
166}
167// base:1 ends here
168
169// [[file:../gchemol-core.note::3ffd6c5d][3ffd6c5d]]
170gut::config::lazy_static! {
171    /// Global cache for quick get element number from symbol
172    pub static ref ELEMENTS: std::collections::HashMap<&'static str, usize> = {
173        ELEMENT_DATA.iter().zip(1..).map(|((s, _), i)| (*s, i)).collect()
174    };
175}
176
177impl std::fmt::Display for AtomKind {
178    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
179        write!(f, "{:}", self.symbol())
180    }
181}
182
183impl std::convert::From<usize> for AtomKind {
184    fn from(value: usize) -> Self {
185        match value {
186            0 => Dummy("dummy".into()),
187            _ => Element(value),
188        }
189    }
190}
191
192impl std::convert::From<&str> for AtomKind {
193    fn from(label: &str) -> Self {
194        // from element symbol
195        if let Some(&n) = ELEMENTS.get(label) {
196            return Element(n);
197        }
198
199        // element specified in number
200        if let Ok(x) = label.parse::<usize>() {
201            return Element(x);
202        }
203
204        // element specified in symbol or long name
205        let sym = label.to_uppercase();
206        for (i, &(s, n)) in ELEMENT_DATA.iter().enumerate() {
207            if s.to_uppercase() == sym || n.to_uppercase() == sym {
208                return Element(i + 1);
209            }
210        }
211
212        // set as dummy atom as the last resort
213        Dummy(label.into())
214    }
215}
216
217impl std::convert::From<String> for AtomKind {
218    fn from(label: String) -> Self {
219        Self::from(label.as_str())
220    }
221}
222
223impl std::convert::From<&String> for AtomKind {
224    fn from(label: &String) -> Self {
225        Self::from(label.as_str())
226    }
227}
228// 3ffd6c5d ends here
229
230// [[file:../gchemol-core.note::*test][test:1]]
231#[test]
232fn test_element() {
233    let h1: AtomKind = 1.into();
234    let h2: AtomKind = "H".into();
235    let h3: AtomKind = "h".into();
236    let h4: AtomKind = "1".into();
237
238    assert_eq!(h1, h2);
239    assert_eq!(h1, h3);
240    assert_eq!(h1, h4);
241
242    let si: AtomKind = "SI".into();
243    assert_eq!(si.number(), 14);
244    assert_eq!(si.to_string(), "Si");
245    assert_eq!(si.name(), "Silicon");
246
247    // dummy atom
248    let x: AtomKind = "X".into();
249    assert_eq!(x.symbol(), "X");
250    assert_eq!(x.number(), 0);
251
252    let s = String::from("Fe");
253    let fe: AtomKind = s.into();
254    assert_eq!(fe.symbol(), "Fe");
255}
256// test:1 ends here