1use serde::Serialize;
7
8#[derive(Debug, Clone, Serialize)]
10pub struct Pm3Params {
11 pub z: u8,
12 pub symbol: &'static str,
13 pub uss: f64,
15 pub upp: f64,
17 pub beta_s: f64,
19 pub beta_p: f64,
21 pub zeta_s: f64,
23 pub zeta_p: f64,
25 pub gss: f64,
27 pub gsp: f64,
29 pub gpp: f64,
31 pub gp2: f64,
33 pub hsp: f64,
35 pub core_charge: f64,
37 pub heat_of_atomization: f64,
39 pub alpha: f64,
41}
42
43pub fn is_pm3_supported(z: u8) -> bool {
45 get_pm3_params(z).is_some()
46}
47
48pub fn get_pm3_params(z: u8) -> Option<&'static Pm3Params> {
50 ALL_PM3_PARAMS.iter().find(|p| p.z == z)
51}
52
53static ALL_PM3_PARAMS: &[Pm3Params] = &[
55 Pm3Params {
57 z: 1,
58 symbol: "H",
59 uss: -13.073321,
60 upp: 0.0,
61 beta_s: -5.626512,
62 beta_p: 0.0,
63 zeta_s: 0.967807,
64 zeta_p: 0.0,
65 gss: 14.794208,
66 gsp: 0.0,
67 gpp: 0.0,
68 gp2: 0.0,
69 hsp: 0.0,
70 core_charge: 1.0,
71 heat_of_atomization: 52.102,
72 alpha: 3.356386,
73 },
74 Pm3Params {
76 z: 6,
77 symbol: "C",
78 uss: -47.270320,
79 upp: -36.266918,
80 beta_s: -11.910015,
81 beta_p: -9.802755,
82 zeta_s: 1.565085,
83 zeta_p: 1.842345,
84 gss: 11.200708,
85 gsp: 10.265027,
86 gpp: 10.796292,
87 gp2: 9.044175,
88 hsp: 1.582725,
89 core_charge: 4.0,
90 heat_of_atomization: 170.89,
91 alpha: 2.707807,
92 },
93 Pm3Params {
95 z: 7,
96 symbol: "N",
97 uss: -49.335672,
98 upp: -47.509736,
99 beta_s: -14.062521,
100 beta_p: -20.043848,
101 zeta_s: 2.028094,
102 zeta_p: 2.313728,
103 gss: 11.904787,
104 gsp: 7.348565,
105 gpp: 11.754672,
106 gp2: 10.807277,
107 hsp: 1.136713,
108 core_charge: 5.0,
109 heat_of_atomization: 113.00,
110 alpha: 2.830545,
111 },
112 Pm3Params {
114 z: 8,
115 symbol: "O",
116 uss: -86.993002,
117 upp: -71.879580,
118 beta_s: -45.202651,
119 beta_p: -24.752515,
120 zeta_s: 3.796544,
121 zeta_p: 2.389402,
122 gss: 15.755760,
123 gsp: 10.621160,
124 gpp: 13.654016,
125 gp2: 12.406095,
126 hsp: 0.593883,
127 core_charge: 6.0,
128 heat_of_atomization: 59.559,
129 alpha: 3.217102,
130 },
131 Pm3Params {
133 z: 9,
134 symbol: "F",
135 uss: -110.435303,
136 upp: -105.685047,
137 beta_s: -48.405230,
138 beta_p: -27.744660,
139 zeta_s: 4.708555,
140 zeta_p: 2.491178,
141 gss: 10.496667,
142 gsp: 16.073689,
143 gpp: 14.817856,
144 gp2: 14.418393,
145 hsp: 0.727763,
146 core_charge: 7.0,
147 heat_of_atomization: 18.86,
148 alpha: 3.358921,
149 },
150 Pm3Params {
152 z: 15,
153 symbol: "P",
154 uss: -40.441400,
155 upp: -29.593012,
156 beta_s: -6.753700,
157 beta_p: -6.753700,
158 zeta_s: 1.998195,
159 zeta_p: 1.907535,
160 gss: 7.800000,
161 gsp: 5.100000,
162 gpp: 7.300000,
163 gp2: 6.500000,
164 hsp: 1.300000,
165 core_charge: 5.0,
166 heat_of_atomization: 75.57,
167 alpha: 1.943950,
168 },
169 Pm3Params {
171 z: 16,
172 symbol: "S",
173 uss: -49.895371,
174 upp: -44.392583,
175 beta_s: -8.827465,
176 beta_p: -8.091415,
177 zeta_s: 1.891185,
178 zeta_p: 1.658972,
179 gss: 8.964667,
180 gsp: 6.785500,
181 gpp: 9.961066,
182 gp2: 7.391876,
183 hsp: 2.532137,
184 core_charge: 6.0,
185 heat_of_atomization: 66.40,
186 alpha: 2.267302,
187 },
188 Pm3Params {
190 z: 17,
191 symbol: "Cl",
192 uss: -100.227166,
193 upp: -53.614396,
194 beta_s: -27.528560,
195 beta_p: -11.593922,
196 zeta_s: 2.246210,
197 zeta_p: 2.151010,
198 gss: 16.013810,
199 gsp: 8.013055,
200 gpp: 7.522215,
201 gp2: 7.166017,
202 hsp: 3.481968,
203 core_charge: 7.0,
204 heat_of_atomization: 28.99,
205 alpha: 2.542201,
206 },
207 Pm3Params {
209 z: 35,
210 symbol: "Br",
211 uss: -116.618200,
212 upp: -74.228400,
213 beta_s: -31.171400,
214 beta_p: -6.315200,
215 zeta_s: 5.348457,
216 zeta_p: 2.131271,
217 gss: 15.036050,
218 gsp: 9.906850,
219 gpp: 7.862200,
220 gp2: 7.399000,
221 hsp: 0.549000,
222 core_charge: 7.0,
223 heat_of_atomization: 28.18,
224 alpha: 2.455000,
225 },
226 Pm3Params {
228 z: 53,
229 symbol: "I",
230 uss: -103.553600,
231 upp: -74.430400,
232 beta_s: -14.409600,
233 beta_p: -5.889600,
234 zeta_s: 7.001013,
235 zeta_p: 2.454354,
236 gss: 13.613200,
237 gsp: 9.929800,
238 gpp: 6.874100,
239 gp2: 6.131100,
240 hsp: 0.551300,
241 core_charge: 7.0,
242 heat_of_atomization: 25.52,
243 alpha: 2.144000,
244 },
245];
246
247pub fn num_pm3_basis_functions(z: u8) -> usize {
249 match z {
250 1 => 1, _ if is_pm3_supported(z) => 4, _ => 0,
253 }
254}
255
256pub fn count_pm3_electrons(elements: &[u8]) -> usize {
258 elements
259 .iter()
260 .map(|&z| get_pm3_params(z).map_or(0, |p| p.core_charge as usize))
261 .sum()
262}
263
264#[cfg(test)]
265mod tests {
266 use super::*;
267
268 #[test]
269 fn test_pm3_params_exist() {
270 for z in [1, 6, 7, 8, 9, 15, 16, 17, 35, 53] {
271 assert!(is_pm3_supported(z), "Missing PM3 params for Z={}", z);
272 }
273 }
274
275 #[test]
276 fn test_pm3_unsupported() {
277 assert!(!is_pm3_supported(26)); assert!(!is_pm3_supported(78)); }
280
281 #[test]
282 fn test_pm3_electron_count() {
283 assert_eq!(count_pm3_electrons(&[8, 1, 1]), 8);
285 assert_eq!(count_pm3_electrons(&[6, 1, 1, 1, 1]), 8);
287 }
288
289 #[test]
290 fn test_pm3_basis_count() {
291 assert_eq!(num_pm3_basis_functions(1), 1);
292 assert_eq!(num_pm3_basis_functions(6), 4);
293 assert_eq!(num_pm3_basis_functions(26), 0);
294 }
295}