Skip to main content

sci_form/xtb/
params.rs

1//! GFN0-xTB element parameters.
2//!
3//! Simplified tight-binding parameters covering main-group and transition-metal
4//! elements. Values are calibrated to reproduce GFN0-xTB level-0 band structures.
5// Some `eta` (chemical hardness) values coincidentally resemble float constants.
6#![allow(clippy::approx_constant)]
7
8use serde::{Deserialize, Serialize};
9
10/// Per-element tight-binding parameters.
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct XtbParams {
13    /// Atomic number.
14    pub z: u8,
15    /// Element symbol.
16    pub symbol: &'static str,
17    /// Number of valence electrons.
18    pub n_valence: u8,
19    /// s-orbital level energy (eV).
20    pub h_s: f64,
21    /// p-orbital level energy (eV), 0.0 if not applicable.
22    pub h_p: f64,
23    /// d-orbital level energy (eV), 0.0 if not applicable.
24    pub h_d: f64,
25    /// Slater exponent for s shell.
26    pub zeta_s: f64,
27    /// Slater exponent for p shell (0.0 if not applicable).
28    pub zeta_p: f64,
29    /// Slater exponent for d shell (0.0 if not applicable).
30    pub zeta_d: f64,
31    /// Chemical hardness (eV) — used in charge self-consistency.
32    pub eta: f64,
33    /// Electronegativity (eV) — diagonal Hamiltonian shift.
34    pub en: f64,
35    /// Covalent radius (Å) — for repulsive potential.
36    pub r_cov: f64,
37    /// Coordination number reference — for CN-dependent corrections.
38    pub cn_ref: f64,
39}
40
41/// GFN0-xTB-level parameters for supported elements.
42///
43/// Parameters are drawn from GFN0-xTB and Grimme's element-specific tables.
44static XTB_PARAMS: &[(u8, XtbParams)] = &[
45    (
46        1,
47        XtbParams {
48            z: 1,
49            symbol: "H",
50            n_valence: 1,
51            h_s: -10.707,
52            h_p: 0.0,
53            h_d: 0.0,
54            zeta_s: 1.230,
55            zeta_p: 0.0,
56            zeta_d: 0.0,
57            eta: 7.461,
58            en: 2.20,
59            r_cov: 0.32,
60            cn_ref: 1.0,
61        },
62    ),
63    (
64        5,
65        XtbParams {
66            z: 5,
67            symbol: "B",
68            n_valence: 3,
69            h_s: -13.170,
70            h_p: -6.480,
71            h_d: 0.0,
72            zeta_s: 1.596,
73            zeta_p: 1.307,
74            zeta_d: 0.0,
75            eta: 4.010,
76            en: 2.04,
77            r_cov: 0.85,
78            cn_ref: 3.0,
79        },
80    ),
81    (
82        6,
83        XtbParams {
84            z: 6,
85            symbol: "C",
86            n_valence: 4,
87            h_s: -13.970,
88            h_p: -5.195,
89            h_d: 0.0,
90            zeta_s: 1.739,
91            zeta_p: 1.419,
92            zeta_d: 0.0,
93            eta: 5.343,
94            en: 2.55,
95            r_cov: 0.77,
96            cn_ref: 3.0,
97        },
98    ),
99    (
100        7,
101        XtbParams {
102            z: 7,
103            symbol: "N",
104            n_valence: 5,
105            h_s: -14.120,
106            h_p: -5.320,
107            h_d: 0.0,
108            zeta_s: 1.950,
109            zeta_p: 1.590,
110            zeta_d: 0.0,
111            eta: 6.899,
112            en: 3.04,
113            r_cov: 0.71,
114            cn_ref: 3.0,
115        },
116    ),
117    (
118        8,
119        XtbParams {
120            z: 8,
121            symbol: "O",
122            n_valence: 6,
123            h_s: -17.280,
124            h_p: -8.590,
125            h_d: 0.0,
126            zeta_s: 2.227,
127            zeta_p: 1.856,
128            zeta_d: 0.0,
129            eta: 8.210,
130            en: 3.44,
131            r_cov: 0.66,
132            cn_ref: 2.0,
133        },
134    ),
135    (
136        9,
137        XtbParams {
138            z: 9,
139            symbol: "F",
140            n_valence: 7,
141            h_s: -20.010,
142            h_p: -11.470,
143            h_d: 0.0,
144            zeta_s: 2.490,
145            zeta_p: 2.100,
146            zeta_d: 0.0,
147            eta: 10.874,
148            en: 3.98,
149            r_cov: 0.64,
150            cn_ref: 1.0,
151        },
152    ),
153    (
154        14,
155        XtbParams {
156            z: 14,
157            symbol: "Si",
158            n_valence: 4,
159            h_s: -10.320,
160            h_p: -4.105,
161            h_d: 0.0,
162            zeta_s: 1.634,
163            zeta_p: 1.288,
164            zeta_d: 0.0,
165            eta: 3.380,
166            en: 1.90,
167            r_cov: 1.17,
168            cn_ref: 4.0,
169        },
170    ),
171    (
172        15,
173        XtbParams {
174            z: 15,
175            symbol: "P",
176            n_valence: 5,
177            h_s: -12.550,
178            h_p: -5.060,
179            h_d: 0.0,
180            zeta_s: 1.880,
181            zeta_p: 1.490,
182            zeta_d: 0.0,
183            eta: 4.880,
184            en: 2.19,
185            r_cov: 1.10,
186            cn_ref: 3.0,
187        },
188    ),
189    (
190        16,
191        XtbParams {
192            z: 16,
193            symbol: "S",
194            n_valence: 6,
195            h_s: -13.300,
196            h_p: -6.890,
197            h_d: 0.0,
198            zeta_s: 2.020,
199            zeta_p: 1.670,
200            zeta_d: 0.0,
201            eta: 4.563,
202            en: 2.58,
203            r_cov: 1.04,
204            cn_ref: 2.0,
205        },
206    ),
207    (
208        17,
209        XtbParams {
210            z: 17,
211            symbol: "Cl",
212            n_valence: 7,
213            h_s: -15.030,
214            h_p: -8.110,
215            h_d: 0.0,
216            zeta_s: 2.180,
217            zeta_p: 1.850,
218            zeta_d: 0.0,
219            eta: 5.852,
220            en: 3.16,
221            r_cov: 0.99,
222            cn_ref: 1.0,
223        },
224    ),
225    (
226        35,
227        XtbParams {
228            z: 35,
229            symbol: "Br",
230            n_valence: 7,
231            h_s: -13.100,
232            h_p: -7.380,
233            h_d: 0.0,
234            zeta_s: 2.440,
235            zeta_p: 2.010,
236            zeta_d: 0.0,
237            eta: 5.012,
238            en: 2.96,
239            r_cov: 1.14,
240            cn_ref: 1.0,
241        },
242    ),
243    (
244        53,
245        XtbParams {
246            z: 53,
247            symbol: "I",
248            n_valence: 7,
249            h_s: -11.480,
250            h_p: -6.250,
251            h_d: 0.0,
252            zeta_s: 2.680,
253            zeta_p: 2.190,
254            zeta_d: 0.0,
255            eta: 4.180,
256            en: 2.66,
257            r_cov: 1.33,
258            cn_ref: 1.0,
259        },
260    ),
261    // Transition metals (first row)
262    (
263        22,
264        XtbParams {
265            z: 22,
266            symbol: "Ti",
267            n_valence: 4,
268            h_s: -8.970,
269            h_p: -5.440,
270            h_d: -10.810,
271            zeta_s: 1.075,
272            zeta_p: 1.075,
273            zeta_d: 4.550,
274            eta: 3.400,
275            en: 1.54,
276            r_cov: 1.36,
277            cn_ref: 6.0,
278        },
279    ),
280    (
281        24,
282        XtbParams {
283            z: 24,
284            symbol: "Cr",
285            n_valence: 6,
286            h_s: -8.660,
287            h_p: -5.240,
288            h_d: -11.220,
289            zeta_s: 1.700,
290            zeta_p: 1.700,
291            zeta_d: 4.950,
292            eta: 3.720,
293            en: 1.66,
294            r_cov: 1.27,
295            cn_ref: 6.0,
296        },
297    ),
298    (
299        25,
300        XtbParams {
301            z: 25,
302            symbol: "Mn",
303            n_valence: 7,
304            h_s: -9.750,
305            h_p: -5.890,
306            h_d: -11.670,
307            zeta_s: 1.800,
308            zeta_p: 1.800,
309            zeta_d: 5.150,
310            eta: 3.720,
311            en: 1.55,
312            r_cov: 1.39,
313            cn_ref: 6.0,
314        },
315    ),
316    (
317        26,
318        XtbParams {
319            z: 26,
320            symbol: "Fe",
321            n_valence: 8,
322            h_s: -9.100,
323            h_p: -5.320,
324            h_d: -12.600,
325            zeta_s: 1.900,
326            zeta_p: 1.900,
327            zeta_d: 5.350,
328            eta: 3.960,
329            en: 1.83,
330            r_cov: 1.25,
331            cn_ref: 6.0,
332        },
333    ),
334    (
335        27,
336        XtbParams {
337            z: 27,
338            symbol: "Co",
339            n_valence: 9,
340            h_s: -9.210,
341            h_p: -5.290,
342            h_d: -13.180,
343            zeta_s: 2.000,
344            zeta_p: 2.000,
345            zeta_d: 5.550,
346            eta: 4.105,
347            en: 1.88,
348            r_cov: 1.26,
349            cn_ref: 6.0,
350        },
351    ),
352    (
353        28,
354        XtbParams {
355            z: 28,
356            symbol: "Ni",
357            n_valence: 10,
358            h_s: -10.950,
359            h_p: -6.270,
360            h_d: -13.490,
361            zeta_s: 2.100,
362            zeta_p: 2.100,
363            zeta_d: 5.750,
364            eta: 4.295,
365            en: 1.91,
366            r_cov: 1.21,
367            cn_ref: 4.0,
368        },
369    ),
370    (
371        29,
372        XtbParams {
373            z: 29,
374            symbol: "Cu",
375            n_valence: 11,
376            h_s: -11.400,
377            h_p: -6.060,
378            h_d: -14.000,
379            zeta_s: 2.200,
380            zeta_p: 2.200,
381            zeta_d: 5.950,
382            eta: 4.200,
383            en: 1.90,
384            r_cov: 1.38,
385            cn_ref: 4.0,
386        },
387    ),
388    (
389        30,
390        XtbParams {
391            z: 30,
392            symbol: "Zn",
393            n_valence: 12,
394            h_s: -12.410,
395            h_p: -6.530,
396            h_d: -17.990,
397            zeta_s: 2.010,
398            zeta_p: 2.010,
399            zeta_d: 6.150,
400            eta: 4.870,
401            en: 1.65,
402            r_cov: 1.31,
403            cn_ref: 4.0,
404        },
405    ),
406    // Transition metals (second row selection)
407    (
408        44,
409        XtbParams {
410            z: 44,
411            symbol: "Ru",
412            n_valence: 8,
413            h_s: -10.400,
414            h_p: -6.870,
415            h_d: -14.900,
416            zeta_s: 1.900,
417            zeta_p: 1.900,
418            zeta_d: 5.380,
419            eta: 3.500,
420            en: 2.20,
421            r_cov: 1.26,
422            cn_ref: 6.0,
423        },
424    ),
425    (
426        46,
427        XtbParams {
428            z: 46,
429            symbol: "Pd",
430            n_valence: 10,
431            h_s: -7.320,
432            h_p: -3.750,
433            h_d: -12.020,
434            zeta_s: 2.190,
435            zeta_p: 2.190,
436            zeta_d: 5.983,
437            eta: 3.890,
438            en: 2.20,
439            r_cov: 1.31,
440            cn_ref: 4.0,
441        },
442    ),
443    (
444        47,
445        XtbParams {
446            z: 47,
447            symbol: "Ag",
448            n_valence: 11,
449            h_s: -6.270,
450            h_p: -3.970,
451            h_d: -14.580,
452            zeta_s: 2.242,
453            zeta_p: 2.242,
454            zeta_d: 6.070,
455            eta: 3.140,
456            en: 1.93,
457            r_cov: 1.53,
458            cn_ref: 4.0,
459        },
460    ),
461    // Third-row TM selection
462    (
463        78,
464        XtbParams {
465            z: 78,
466            symbol: "Pt",
467            n_valence: 10,
468            h_s: -9.077,
469            h_p: -5.475,
470            h_d: -12.590,
471            zeta_s: 2.550,
472            zeta_p: 2.550,
473            zeta_d: 6.013,
474            eta: 4.360,
475            en: 2.28,
476            r_cov: 1.28,
477            cn_ref: 4.0,
478        },
479    ),
480    (
481        79,
482        XtbParams {
483            z: 79,
484            symbol: "Au",
485            n_valence: 11,
486            h_s: -10.920,
487            h_p: -5.550,
488            h_d: -15.070,
489            zeta_s: 2.600,
490            zeta_p: 2.600,
491            zeta_d: 6.163,
492            eta: 5.010,
493            en: 2.54,
494            r_cov: 1.44,
495            cn_ref: 4.0,
496        },
497    ),
498];
499
500/// Look up xTB parameters by atomic number.
501pub fn get_xtb_params(z: u8) -> Option<&'static XtbParams> {
502    XTB_PARAMS
503        .iter()
504        .find(|(elem, _)| *elem == z)
505        .map(|(_, p)| p)
506}
507
508/// Check if an element is supported by the xTB solver.
509pub fn is_xtb_supported(z: u8) -> bool {
510    get_xtb_params(z).is_some()
511}
512
513/// Count total valence electrons for an xTB calculation.
514pub fn count_xtb_electrons(elements: &[u8]) -> usize {
515    elements
516        .iter()
517        .map(|&z| get_xtb_params(z).map_or(0, |p| p.n_valence as usize))
518        .sum()
519}
520
521/// Count basis functions: 1 (s-only for H), 4 (s+p), or 9 (s+p+d for TM).
522pub fn num_xtb_basis_functions(z: u8) -> usize {
523    match get_xtb_params(z) {
524        None => 0,
525        Some(p) => {
526            let mut n = 1; // s
527            if p.zeta_p > 0.0 {
528                n += 3;
529            } // p
530            if p.zeta_d > 0.0 {
531                n += 5;
532            } // d
533            n
534        }
535    }
536}
537
538#[cfg(test)]
539mod tests {
540    use super::*;
541
542    #[test]
543    fn test_xtb_params_exist() {
544        assert!(get_xtb_params(1).is_some());
545        assert!(get_xtb_params(6).is_some());
546        assert!(get_xtb_params(26).is_some());
547        assert!(get_xtb_params(78).is_some());
548        assert!(get_xtb_params(92).is_none()); // uranium not supported
549    }
550
551    #[test]
552    fn test_xtb_electron_count() {
553        assert_eq!(count_xtb_electrons(&[8, 1, 1]), 8); // water
554        assert_eq!(count_xtb_electrons(&[6, 1, 1, 1, 1]), 8); // CH4
555    }
556
557    #[test]
558    fn test_xtb_basis_count() {
559        assert_eq!(num_xtb_basis_functions(1), 1); // H: s only
560        assert_eq!(num_xtb_basis_functions(6), 4); // C: s+p
561        assert_eq!(num_xtb_basis_functions(26), 9); // Fe: s+p+d
562    }
563}