1use core::{
2 fmt::{Display, Formatter},
3 ops::RangeInclusive,
4};
5
6use super::Element;
7
8#[cfg(feature = "ranges")]
9pub const ATOMIC_WEIGHT_RANGE: RangeInclusive<f64> = 1.008..=294.0;
21
22#[derive(Clone, Debug, PartialEq)]
23#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
24pub enum AtomicWeight {
26 Interval {
28 range: RangeInclusive<f64>,
30 conventional: f64,
32 },
33 Uncertainty {
35 weight: f64,
37 uncertainty: f64,
39 },
40 MassNumber {
42 number: u64,
44 },
45}
46
47impl PartialOrd for AtomicWeight {
48 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
49 f64::from(self).partial_cmp(&f64::from(other))
50 }
51}
52
53impl From<AtomicWeight> for f64 {
54 fn from(weight: AtomicWeight) -> Self {
55 weight.get_value()
56 }
57}
58
59impl From<&AtomicWeight> for f64 {
60 fn from(weight: &AtomicWeight) -> Self {
61 weight.get_value()
62 }
63}
64
65impl AtomicWeight {
66 const fn get_value(&self) -> f64 {
67 match self {
68 AtomicWeight::Interval {
69 range: _,
70 conventional,
71 } => *conventional,
72 AtomicWeight::Uncertainty {
73 weight,
74 uncertainty: _,
75 } => *weight,
76 AtomicWeight::MassNumber { number } => *number as f64,
77 }
78 }
79}
80
81impl Display for AtomicWeight {
82 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
83 fn get_precision(uncertainty: f64) -> (usize, u8) {
84 let mut digit = uncertainty;
85 let mut precision = 0u8;
86 while digit < 1.0 && precision < 15 {
87 digit *= 10.0;
88 precision = precision.saturating_add(1);
89 }
90 (precision as usize, digit as u8)
91 }
92 match self {
93 AtomicWeight::Interval {
94 range: _,
95 conventional,
96 } => f.write_fmt(format_args!("{}", conventional)),
97 AtomicWeight::Uncertainty {
98 weight,
99 uncertainty,
100 } => {
101 let (precision, digit) = get_precision(*uncertainty);
102 f.write_fmt(format_args!(
103 "{w:.prec$}({u})",
104 w = weight,
105 prec = precision,
106 u = digit
107 ))
108 }
109 AtomicWeight::MassNumber { number } => f.write_fmt(format_args!("[{}]", number)),
110 }
111 }
112}
113
114const fn bounds(range: RangeInclusive<f64>, conventional: f64) -> AtomicWeight {
115 AtomicWeight::Interval {
116 range,
117 conventional,
118 }
119}
120
121const fn unc(weight: f64, uncertainty: f64) -> AtomicWeight {
122 AtomicWeight::Uncertainty {
123 weight,
124 uncertainty,
125 }
126}
127const fn mn(number: u64) -> AtomicWeight {
128 AtomicWeight::MassNumber { number }
129}
130
131impl Element {
132 pub const fn atomic_weight(&self) -> AtomicWeight {
143 match self {
144 Element::H => bounds(1.0078..=1.0082, 1.008),
145 Element::He => unc(4.002602, 0.000002),
146 Element::Li => bounds(6.938..=6.997, 6.94),
147 Element::Be => unc(9.0121831, 0.0000005),
148 Element::B => bounds(10.806..=10.821, 10.81),
149 Element::C => bounds(12.009..=12.012, 12.011),
150 Element::N => bounds(14.006..=14.008, 14.007),
151 Element::O => bounds(15.999..=16.000, 15.999),
152 Element::F => unc(18.998403163, 0.000000006),
153 Element::Ne => unc(20.1797, 0.0006),
154 Element::Na => unc(22.98976928, 0.00000002),
155 Element::Mg => bounds(24.304..=24.307, 24.305),
156 Element::Al => unc(26.9815385, 0.0000007),
157 Element::Si => bounds(28.084..=28.086, 28.085),
158 Element::P => unc(30.973761998, 0.000000005),
159 Element::S => bounds(32.059..=32.076, 32.06),
160 Element::Cl => bounds(35.446..=35.457, 35.45),
161 Element::Ar => unc(39.948, 0.001),
162 Element::K => unc(39.0983, 0.0001),
163 Element::Ca => unc(40.078, 0.004),
164 Element::Sc => unc(44.955908, 0.000005),
165 Element::Ti => unc(47.867, 0.001),
166 Element::V => unc(50.9415, 0.0001),
167 Element::Cr => unc(51.9961, 0.0006),
168 Element::Mn => unc(54.938044, 0.000003),
169 Element::Fe => unc(55.845, 0.002),
170 Element::Co => unc(58.933194, 0.000004),
171 Element::Ni => unc(58.6934, 0.0004),
172 Element::Cu => unc(63.546, 0.003),
173 Element::Zn => unc(65.38, 0.02),
174 Element::Ga => unc(69.723, 0.001),
175 Element::Ge => unc(72.63, 0.008),
176 Element::As => unc(74.921595, 0.000006),
177 Element::Se => unc(78.971, 0.008),
178 Element::Br => bounds(79.901..=79.907, 79.904),
179 Element::Kr => unc(83.798, 0.002),
180 Element::Rb => unc(85.4678, 0.0003),
181 Element::Sr => unc(87.62, 0.01),
182 Element::Y => unc(88.90584, 0.00002),
183 Element::Zr => unc(91.224, 0.002),
184 Element::Nb => unc(92.90637, 0.00002),
185 Element::Mo => unc(95.95, 0.01),
186 Element::Tc => unc(97.90721, 0.00003),
187 Element::Ru => unc(101.07, 0.02),
188 Element::Rh => unc(102.9055, 0.00002),
189 Element::Pd => unc(106.42, 0.01),
190 Element::Ag => unc(107.8682, 0.0002),
191 Element::Cd => unc(112.414, 0.004),
192 Element::In => unc(114.818, 0.001),
193 Element::Sn => unc(118.71, 0.007),
194 Element::Sb => unc(121.76, 0.001),
195 Element::Te => unc(127.6, 0.03),
196 Element::I => unc(126.90447, 0.00003),
197 Element::Xe => unc(131.293, 0.006),
198 Element::Cs => unc(132.90545196, 0.00000006),
199 Element::Ba => unc(137.327, 0.007),
200 Element::La => unc(138.90547, 0.00007),
201 Element::Ce => unc(140.116, 0.001),
202 Element::Pr => unc(140.90766, 0.00002),
203 Element::Nd => unc(144.242, 0.003),
204 Element::Pm => unc(144.91276, 0.00002),
205 Element::Sm => unc(150.36, 0.02),
206 Element::Eu => unc(151.964, 0.001),
207 Element::Gd => unc(157.25, 0.03),
208 Element::Tb => unc(158.92535, 0.00002),
209 Element::Dy => unc(162.5, 0.001),
210 Element::Ho => unc(164.93033, 0.00002),
211 Element::Er => unc(167.259, 0.003),
212 Element::Tm => unc(168.93422, 0.00002),
213 Element::Yb => unc(173.045, 0.01),
214 Element::Lu => unc(174.9668, 0.0001),
215 Element::Hf => unc(178.49, 0.02),
216 Element::Ta => unc(180.94788, 0.00002),
217 Element::W => unc(183.84, 0.01),
218 Element::Re => unc(186.207, 0.001),
219 Element::Os => unc(190.23, 0.03),
220 Element::Ir => unc(192.217, 0.003),
221 Element::Pt => unc(195.084, 0.009),
222 Element::Au => unc(196.966569, 0.000005),
223 Element::Hg => unc(200.592, 0.003),
224 Element::Tl => bounds(204.38..=204.39, 204.38),
225 Element::Pb => unc(207.2, 0.1),
226 Element::Bi => unc(208.9804, 0.00001),
227 Element::Po => mn(209),
228 Element::At => mn(210),
229 Element::Rn => mn(222),
230 Element::Fr => mn(223),
231 Element::Ra => mn(226),
232 Element::Ac => mn(227),
233 Element::Th => unc(232.0377, 0.0004),
234 Element::Pa => unc(231.03588, 0.00002),
235 Element::U => unc(238.02891, 0.00003),
236 Element::Np => mn(237),
237 Element::Pu => mn(244),
238 Element::Am => mn(243),
239 Element::Cm => mn(247),
240 Element::Bk => mn(247),
241 Element::Cf => mn(251),
242 Element::Es => mn(252),
243 Element::Fm => mn(257),
244 Element::Md => mn(258),
245 Element::No => mn(259),
246 Element::Lr => mn(262),
247 Element::Rf => mn(267),
248 Element::Db => mn(268),
249 Element::Sg => mn(271),
250 Element::Bh => mn(274),
251 Element::Hs => mn(269),
252 Element::Mt => mn(276),
253 Element::Ds => mn(281),
254 Element::Rg => mn(281),
255 Element::Cn => mn(285),
256 Element::Nh => mn(286),
257 Element::Fl => mn(289),
258 Element::Mc => mn(288),
259 Element::Lv => mn(293),
260 Element::Ts => mn(294),
261 Element::Og => mn(294),
262 }
263 }
264}