Skip to main content

endf_mat/
elements.rs

1//! Element symbol and name lookup by atomic number.
2//!
3//! Complete periodic table data for Z=0 (neutron) through Z=118 (Oganesson).
4
5/// Element symbol from atomic number Z.
6///
7/// Returns `Some("H")` for Z=1, `Some("U")` for Z=92, etc.
8/// Returns `Some("n")` for Z=0 (neutron).
9/// Returns `None` for Z > 118.
10pub fn element_symbol(z: u32) -> Option<&'static str> {
11    ELEMENT_SYMBOLS.get(z as usize).copied()
12}
13
14/// Element name from atomic number Z.
15///
16/// Returns `Some("Hydrogen")` for Z=1, `Some("Uranium")` for Z=92, etc.
17/// Returns `None` for Z > 118.
18pub fn element_name(z: u32) -> Option<&'static str> {
19    ELEMENT_NAMES.get(z as usize).copied()
20}
21
22/// Atomic number Z from element symbol (case-insensitive for elements Z≥1).
23///
24/// Accepts "U", "u", "Fe", "fe", etc.
25///
26/// **Neutron special case**: the neutron symbol `"n"` (Z=0) is matched
27/// case-sensitively. Passing `"N"` returns `Some(7)` (Nitrogen), not Z=0.
28pub fn symbol_to_z(symbol: &str) -> Option<u32> {
29    // Neutron "n" is exact-match only to avoid shadowing Nitrogen "N"
30    if symbol == "n" {
31        return Some(0);
32    }
33    let lower = symbol.to_lowercase();
34    for (z, &sym) in ELEMENT_SYMBOLS.iter().enumerate().skip(1) {
35        if sym.to_lowercase() == lower {
36            return Some(z as u32);
37        }
38    }
39    None
40}
41
42// Element symbols indexed by Z. Z=0 is the neutron.
43#[rustfmt::skip]
44static ELEMENT_SYMBOLS: &[&str] = &[
45    "n",  "H",  "He", "Li", "Be", "B",  "C",  "N",  "O",  "F",  // 0-9
46    "Ne", "Na", "Mg", "Al", "Si", "P",  "S",  "Cl", "Ar", "K",  // 10-19
47    "Ca", "Sc", "Ti", "V",  "Cr", "Mn", "Fe", "Co", "Ni", "Cu", // 20-29
48    "Zn", "Ga", "Ge", "As", "Se", "Br", "Kr", "Rb", "Sr", "Y",  // 30-39
49    "Zr", "Nb", "Mo", "Tc", "Ru", "Rh", "Pd", "Ag", "Cd", "In", // 40-49
50    "Sn", "Sb", "Te", "I",  "Xe", "Cs", "Ba", "La", "Ce", "Pr", // 50-59
51    "Nd", "Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm", // 60-69
52    "Yb", "Lu", "Hf", "Ta", "W",  "Re", "Os", "Ir", "Pt", "Au", // 70-79
53    "Hg", "Tl", "Pb", "Bi", "Po", "At", "Rn", "Fr", "Ra", "Ac", // 80-89
54    "Th", "Pa", "U",  "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es", // 90-99
55    "Fm", "Md", "No", "Lr", "Rf", "Db", "Sg", "Bh", "Hs", "Mt", // 100-109
56    "Ds", "Rg", "Cn", "Nh", "Fl", "Mc", "Lv", "Ts", "Og",       // 110-118
57];
58
59#[rustfmt::skip]
60static ELEMENT_NAMES: &[&str] = &[
61    "neutron",     "Hydrogen",    "Helium",      "Lithium",     "Beryllium",
62    "Boron",       "Carbon",      "Nitrogen",    "Oxygen",      "Fluorine",
63    "Neon",        "Sodium",      "Magnesium",   "Aluminum",    "Silicon",
64    "Phosphorus",  "Sulfur",      "Chlorine",    "Argon",       "Potassium",
65    "Calcium",     "Scandium",    "Titanium",    "Vanadium",    "Chromium",
66    "Manganese",   "Iron",        "Cobalt",      "Nickel",      "Copper",
67    "Zinc",        "Gallium",     "Germanium",   "Arsenic",     "Selenium",
68    "Bromine",     "Krypton",     "Rubidium",    "Strontium",   "Yttrium",
69    "Zirconium",   "Niobium",     "Molybdenum",  "Technetium",  "Ruthenium",
70    "Rhodium",     "Palladium",   "Silver",      "Cadmium",     "Indium",
71    "Tin",         "Antimony",    "Tellurium",   "Iodine",      "Xenon",
72    "Cesium",      "Barium",      "Lanthanum",   "Cerium",      "Praseodymium",
73    "Neodymium",   "Promethium",  "Samarium",    "Europium",    "Gadolinium",
74    "Terbium",     "Dysprosium",  "Holmium",     "Erbium",      "Thulium",
75    "Ytterbium",   "Lutetium",    "Hafnium",     "Tantalum",    "Tungsten",
76    "Rhenium",     "Osmium",      "Iridium",     "Platinum",    "Gold",
77    "Mercury",     "Thallium",    "Lead",        "Bismuth",     "Polonium",
78    "Astatine",    "Radon",       "Francium",    "Radium",      "Actinium",
79    "Thorium",     "Protactinium","Uranium",     "Neptunium",   "Plutonium",
80    "Americium",   "Curium",      "Berkelium",   "Californium", "Einsteinium",
81    "Fermium",     "Mendelevium", "Nobelium",    "Lawrencium",  "Rutherfordium",
82    "Dubnium",     "Seaborgium",  "Bohrium",     "Hassium",     "Meitnerium",
83    "Darmstadtium","Roentgenium", "Copernicium", "Nihonium",    "Flerovium",
84    "Moscovium",   "Livermorium", "Tennessine",  "Oganesson",
85];
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90
91    #[test]
92    fn test_element_symbol() {
93        assert_eq!(element_symbol(0), Some("n"));
94        assert_eq!(element_symbol(1), Some("H"));
95        assert_eq!(element_symbol(26), Some("Fe"));
96        assert_eq!(element_symbol(92), Some("U"));
97        assert_eq!(element_symbol(118), Some("Og"));
98        assert_eq!(element_symbol(119), None);
99    }
100
101    #[test]
102    fn test_element_name() {
103        assert_eq!(element_name(1), Some("Hydrogen"));
104        assert_eq!(element_name(92), Some("Uranium"));
105        assert_eq!(element_name(26), Some("Iron"));
106        assert_eq!(element_name(119), None);
107    }
108
109    #[test]
110    fn test_symbol_to_z() {
111        assert_eq!(symbol_to_z("H"), Some(1));
112        assert_eq!(symbol_to_z("Fe"), Some(26));
113        assert_eq!(symbol_to_z("U"), Some(92));
114        assert_eq!(symbol_to_z("fe"), Some(26)); // case-insensitive
115        assert_eq!(symbol_to_z("Xx"), None);
116        // Neutron: exact lowercase match only
117        assert_eq!(symbol_to_z("n"), Some(0));
118        assert_eq!(symbol_to_z("N"), Some(7)); // "N" is Nitrogen, not neutron
119    }
120
121    #[test]
122    fn test_symbol_roundtrip() {
123        for z in 1..=118 {
124            let sym = element_symbol(z).unwrap();
125            assert_eq!(symbol_to_z(sym), Some(z));
126        }
127    }
128
129    #[test]
130    fn test_table_sizes() {
131        assert_eq!(ELEMENT_SYMBOLS.len(), 119); // Z=0..118
132        assert_eq!(ELEMENT_NAMES.len(), 119);
133    }
134}