Skip to main content

sci_form/xtb/
gfn2_params.rs

1//! GFN2-xTB parameters from the official parametrization.
2//!
3//! Values extracted from tblite (Bannwarth, Ehlert, Grimme, JCTC 2019, 15, 1652).
4//! All self-energies are in eV, Slater exponents in bohr⁻¹,
5//! Hubbard parameters in Hartree, repulsion parameters dimensionless.
6
7/// Per-element GFN2-xTB parameter set.
8#[derive(Debug, Clone, Copy)]
9pub struct Gfn2ElementParams {
10    pub z: u8,
11    /// Number of shells in the basis.
12    pub nshell: usize,
13    /// Angular momentum per shell: 0=s, 1=p, 2=d.
14    pub ang_shell: [u8; 3],
15    /// Self-energy / atomic level per shell (eV).
16    pub selfenergy: [f64; 3],
17    /// Slater exponent per shell (bohr⁻¹).
18    pub slater: [f64; 3],
19    /// Reference occupation per shell.
20    pub ref_occ: [f64; 3],
21    /// Hubbard parameter (Hartree).
22    pub hubbard: f64,
23    /// Shell-resolved Hubbard scaling: 1 + shell_hubbard[l].
24    pub shell_hubbard: [f64; 3],
25    /// Repulsion exponent α.
26    pub rep_alpha: f64,
27    /// Repulsion effective nuclear charge Z_eff.
28    pub rep_zeff: f64,
29    /// Number of valence electrons.
30    pub n_valence: u8,
31    /// Principal quantum number per shell.
32    pub pqn: [u8; 3],
33    /// Number of Gaussian primitives per shell for STO-nG.
34    pub ngauss: [u8; 3],
35    /// Shell polynomial coefficients (per shell, already ×0.01 scaled).
36    /// Indexed by shell index (matching ang_shell ordering).
37    pub shpoly: [f64; 3],
38    /// CN-dependent self-energy shift per shell (eV).
39    /// SE_eff = SE - kCN * CN.
40    pub kcn: [f64; 3],
41    /// Third-order Hubbard derivative (already ×0.1 scaled, Hartree).
42    pub gam3: f64,
43    /// Atomic radius (bohr) for shell polynomial distance scaling.
44    pub atomic_rad: f64,
45    /// Pauling electronegativity.
46    pub pauling_en: f64,
47    /// Element kind (1=main group, 2=transition metal) for gam3shell lookup.
48    pub kind: u8,
49    /// Multipole dipole XC kernel (already scaled by 0.01).
50    pub dkernel: f64,
51    /// Multipole quadrupole XC kernel (already scaled by 0.01).
52    pub qkernel: f64,
53    /// Multipole damping radius (bohr).
54    pub mp_rad: f64,
55    /// Valence CN for multipole radii.
56    pub mp_vcn: f64,
57}
58
59/// Conversion factor: 1 eV → Hartree.
60pub const EV_TO_HARTREE: f64 = 1.0 / 27.21138505;
61/// Repulsion exponent for heavy-atom pairs.
62pub const REP_KEXP: f64 = 1.5;
63/// Repulsion exponent for light-atom pairs (involving H or He).
64pub const REP_KEXP_LIGHT: f64 = 1.0;
65/// Repulsion R exponent.
66pub const REP_REXP: f64 = 1.0;
67
68/// Global GFN2-xTB Hamiltonian scaling parameters.
69/// Off-diagonal K factor by angular momentum pair: kdiag[l].
70pub const KDIAG: [f64; 5] = [1.85, 2.23, 2.23, 2.23, 2.23];
71/// Electronegativity scaling of off-diagonal elements.
72pub const ENSCALE: f64 = 2.0e-2;
73/// Exponent for Slater-ratio scaling of off-diagonal elements.
74pub const WEXP: f64 = 0.5;
75
76/// Ångström to bohr conversion factor.
77pub const AATOAU: f64 = 1.8897259886;
78
79/// Third-order shell-resolved scaling factors.
80/// gam3shell(kind, l): kind=1 (main group), kind=2 (TM).
81/// Indexed as [s, p, d, f] = [[1.0, 1.0], [0.5, 0.5], [0.25, 0.25], [0.25, 0.25]].
82pub const GAM3_SHELL: [[f64; 2]; 4] = [
83    [1.0, 1.0],   // s
84    [0.5, 0.5],   // p
85    [0.25, 0.25], // d
86    [0.25, 0.25], // f
87];
88
89/// Gamma function exponent (alphaj in xtb).
90pub const GAMMA_EXP: f64 = 2.0;
91
92/// Multipole damping exponents.
93pub const MP_DMP3: f64 = 3.0;
94pub const MP_DMP5: f64 = 4.0;
95/// Multipole CN-dependent radius shift.
96pub const MP_SHIFT: f64 = 1.2;
97/// Multipole radius sigmoid exponent.
98pub const MP_KEXP_MULTI: f64 = 4.0;
99/// Multipole maximum radius (bohr).
100pub const MP_RMAX: f64 = 5.0;
101
102/// D4 dispersion parameters for GFN2-xTB.
103pub const D4_S6: f64 = 1.0;
104pub const D4_S8: f64 = 2.7;
105pub const D4_A1: f64 = 0.52;
106pub const D4_A2: f64 = 5.0;
107pub const D4_S9: f64 = 5.0;
108
109// ---- GFN2-xTB element parameters ----
110// Source: tblite/tblite gfn2.f90 (official GFN2-xTB parametrization)
111
112static GFN2_PARAMS: &[Gfn2ElementParams] = &[
113    // Z=1, H
114    Gfn2ElementParams {
115        z: 1,
116        nshell: 1,
117        ang_shell: [0, 0, 0],
118        selfenergy: [-10.707211, 0.0, 0.0],
119        slater: [1.230000, 0.0, 0.0],
120        ref_occ: [1.0, 0.0, 0.0],
121        hubbard: 0.405771,
122        shell_hubbard: [1.0, 1.0, 1.0],
123        rep_alpha: 2.213717,
124        rep_zeff: 1.105388,
125        n_valence: 1,
126        pqn: [1, 0, 0],
127        ngauss: [3, 0, 0],
128        shpoly: [-0.00953618, 0.0, 0.0],
129        kcn: [-0.0500000, 0.0, 0.0],
130        gam3: 0.0800000,
131        atomic_rad: 0.32 * AATOAU,
132        pauling_en: 2.20,
133        kind: 1,
134        dkernel: 0.05563889,
135        qkernel: 0.00027431,
136        mp_rad: 1.4,
137        mp_vcn: 1.0,
138    },
139    // Z=5, B
140    Gfn2ElementParams {
141        z: 5,
142        nshell: 2,
143        ang_shell: [0, 1, 0],
144        selfenergy: [-9.224376, -7.419002, 0.0],
145        slater: [1.479444, 1.479805, 0.0],
146        ref_occ: [2.0, 1.0, 0.0],
147        hubbard: 0.513556,
148        shell_hubbard: [1.0, 1.3994080, 1.0],
149        rep_alpha: 1.373856,
150        rep_zeff: 7.192431,
151        n_valence: 3,
152        pqn: [2, 2, 0],
153        ngauss: [4, 4, 0],
154        shpoly: [-0.05183150, -0.02453322, 0.0],
155        kcn: [0.0120462, -0.0141086, 0.0],
156        gam3: 0.0946104,
157        atomic_rad: 0.84 * AATOAU,
158        pauling_en: 2.04,
159        kind: 1,
160        dkernel: -0.00481186,
161        qkernel: -0.00058228,
162        mp_rad: 5.0,
163        mp_vcn: 3.0,
164    },
165    // Z=6, C
166    Gfn2ElementParams {
167        z: 6,
168        nshell: 2,
169        ang_shell: [0, 1, 0],
170        selfenergy: [-13.970922, -10.063292, 0.0],
171        slater: [2.096432, 1.800000, 0.0],
172        ref_occ: [1.0, 3.0, 0.0],
173        hubbard: 0.538015,
174        shell_hubbard: [1.0, 1.1056358, 1.0],
175        rep_alpha: 1.247655,
176        rep_zeff: 4.231078,
177        n_valence: 4,
178        pqn: [2, 2, 0],
179        ngauss: [4, 4, 0],
180        shpoly: [-0.02294321, -0.00271102, 0.0],
181        kcn: [-0.0102144, 0.0161657, 0.0],
182        gam3: 0.1500000,
183        atomic_rad: 0.75 * AATOAU,
184        pauling_en: 2.55,
185        kind: 1,
186        dkernel: -0.00411674,
187        qkernel: 0.00213583,
188        mp_rad: 3.0,
189        mp_vcn: 3.0,
190    },
191    // Z=7, N
192    Gfn2ElementParams {
193        z: 7,
194        nshell: 2,
195        ang_shell: [0, 1, 0],
196        selfenergy: [-16.686243, -12.523956, 0.0],
197        slater: [2.339881, 2.014332, 0.0],
198        ref_occ: [1.5, 3.5, 0.0],
199        hubbard: 0.461493,
200        shell_hubbard: [1.0, 1.1164892, 1.0],
201        rep_alpha: 1.682689,
202        rep_zeff: 5.242592,
203        n_valence: 5,
204        pqn: [2, 2, 0],
205        ngauss: [4, 4, 0],
206        shpoly: [-0.08506003, -0.02504201, 0.0],
207        kcn: [-0.1955336, 0.0561076, 0.0],
208        gam3: -0.0639780,
209        atomic_rad: 0.71 * AATOAU,
210        pauling_en: 3.04,
211        kind: 1,
212        dkernel: 0.03521273,
213        qkernel: 0.02026786,
214        mp_rad: 1.9,
215        mp_vcn: 3.0,
216    },
217    // Z=8, O
218    Gfn2ElementParams {
219        z: 8,
220        nshell: 2,
221        ang_shell: [0, 1, 0],
222        selfenergy: [-20.229985, -15.503117, 0.0],
223        slater: [2.439742, 2.137023, 0.0],
224        ref_occ: [2.0, 4.0, 0.0],
225        hubbard: 0.451896,
226        shell_hubbard: [1.0, 1.1497020, 1.0],
227        rep_alpha: 2.165712,
228        rep_zeff: 5.784415,
229        n_valence: 6,
230        pqn: [2, 2, 0],
231        ngauss: [4, 4, 0],
232        shpoly: [-0.14955291, -0.03350819, 0.0],
233        kcn: [0.0117826, -0.0145102, 0.0],
234        gam3: -0.0517134,
235        atomic_rad: 0.64 * AATOAU,
236        pauling_en: 3.44,
237        kind: 1,
238        dkernel: -0.04935670,
239        qkernel: -0.00310828,
240        mp_rad: 1.8,
241        mp_vcn: 2.0,
242    },
243    // Z=9, F
244    Gfn2ElementParams {
245        z: 9,
246        nshell: 2,
247        ang_shell: [0, 1, 0],
248        selfenergy: [-23.458179, -15.746583, 0.0],
249        slater: [2.416361, 2.308399, 0.0],
250        ref_occ: [2.0, 5.0, 0.0],
251        hubbard: 0.531518,
252        shell_hubbard: [1.0, 1.1677376, 1.0],
253        rep_alpha: 2.421394,
254        rep_zeff: 7.021486,
255        n_valence: 7,
256        pqn: [2, 2, 0],
257        ngauss: [4, 4, 0],
258        shpoly: [-0.13011924, -0.12300828, 0.0],
259        kcn: [0.0394362, -0.0538373, 0.0],
260        gam3: 0.1426212,
261        atomic_rad: 0.60 * AATOAU,
262        pauling_en: 3.98,
263        kind: 1,
264        dkernel: -0.08339183,
265        qkernel: -0.00245955,
266        mp_rad: 2.4,
267        mp_vcn: 1.0,
268    },
269    // Z=14, Si
270    Gfn2ElementParams {
271        z: 14,
272        nshell: 3,
273        ang_shell: [0, 1, 2],
274        selfenergy: [-14.360932, -6.915131, -1.825036],
275        slater: [1.773917, 1.718996, 1.250000],
276        ref_occ: [1.5, 2.5, 0.0],
277        hubbard: 0.720000,
278        shell_hubbard: [1.0000000, 0.4419958, 0.7700000],
279        rep_alpha: 1.187323,
280        rep_zeff: 40.001111,
281        n_valence: 4,
282        pqn: [3, 3, 3],
283        ngauss: [4, 4, 3],
284        shpoly: [0.02358522, -0.07900406, 0.11366185],
285        kcn: [0.1858479, -0.1383073, -0.1935494],
286        gam3: 0.1936289,
287        atomic_rad: 1.14 * AATOAU,
288        pauling_en: 1.90,
289        kind: 1,
290        dkernel: -0.00025750,
291        qkernel: -0.00080000,
292        mp_rad: 3.9,
293        mp_vcn: 3.0,
294    },
295    // Z=15, P
296    Gfn2ElementParams {
297        z: 15,
298        nshell: 3,
299        ang_shell: [0, 1, 2],
300        selfenergy: [-17.518756, -9.842286, -0.444893],
301        slater: [1.816945, 1.903247, 1.167533],
302        ref_occ: [1.5, 3.5, 0.0],
303        hubbard: 0.297739,
304        shell_hubbard: [1.0000000, 0.8441940, 0.6500000],
305        rep_alpha: 1.143343,
306        rep_zeff: 19.683502,
307        n_valence: 5,
308        pqn: [3, 3, 3],
309        ngauss: [4, 4, 3],
310        shpoly: [-0.19831771, -0.05515577, 0.26397535],
311        kcn: [0.0547610, -0.0489930, 0.2429507],
312        gam3: 0.0711291,
313        atomic_rad: 1.09 * AATOAU,
314        pauling_en: 2.19,
315        kind: 1,
316        dkernel: 0.02110225,
317        qkernel: 0.00028679,
318        mp_rad: 2.1,
319        mp_vcn: 3.0,
320    },
321    // Z=16, S
322    Gfn2ElementParams {
323        z: 16,
324        nshell: 3,
325        ang_shell: [0, 1, 2],
326        selfenergy: [-20.029654, -11.377694, -0.420282],
327        slater: [1.981333, 2.025643, 1.702555],
328        ref_occ: [2.0, 4.0, 0.0],
329        hubbard: 0.339971,
330        shell_hubbard: [1.0000000, 0.8914134, 0.7500000],
331        rep_alpha: 1.214553,
332        rep_zeff: 14.995090,
333        n_valence: 6,
334        pqn: [3, 3, 3],
335        ngauss: [4, 4, 3],
336        shpoly: [-0.25855520, -0.08048064, 0.25993857],
337        kcn: [-0.0256951, -0.0098465, 0.2007690],
338        gam3: -0.0501722,
339        atomic_rad: 1.04 * AATOAU,
340        pauling_en: 2.58,
341        kind: 1,
342        dkernel: -0.00151117,
343        qkernel: 0.00442859,
344        mp_rad: 3.1,
345        mp_vcn: 3.0,
346    },
347    // Z=17, Cl
348    Gfn2ElementParams {
349        z: 17,
350        nshell: 3,
351        ang_shell: [0, 1, 2],
352        selfenergy: [-29.278781, -12.673758, -0.240338],
353        slater: [2.485265, 2.199650, 2.476089],
354        ref_occ: [2.0, 5.0, 0.0],
355        hubbard: 0.248514,
356        shell_hubbard: [1.0000000, 1.4989400, 1.5000000],
357        rep_alpha: 1.577144,
358        rep_zeff: 17.353134,
359        n_valence: 7,
360        pqn: [3, 3, 3],
361        ngauss: [4, 4, 3],
362        shpoly: [-0.16562004, -0.06986430, 0.38045622],
363        kcn: [0.0617972, -0.0181618, 0.1672768],
364        gam3: 0.1495483,
365        atomic_rad: 1.00 * AATOAU,
366        pauling_en: 3.16,
367        kind: 1,
368        dkernel: -0.02536958,
369        qkernel: 0.00122783,
370        mp_rad: 2.5,
371        mp_vcn: 1.0,
372    },
373    // Z=35, Br
374    Gfn2ElementParams {
375        z: 35,
376        nshell: 3,
377        ang_shell: [0, 1, 2],
378        selfenergy: [-23.583718, -12.588824, 0.047980],
379        slater: [2.077587, 2.263120, 1.845038],
380        ref_occ: [2.0, 5.0, 0.0],
381        hubbard: 0.261253,
382        shell_hubbard: [1.0, 1.5203002, 1.4],
383        rep_alpha: 1.296174,
384        rep_zeff: 32.845361,
385        n_valence: 7,
386        pqn: [4, 4, 4],
387        ngauss: [4, 4, 3],
388        shpoly: [-0.25005079, -0.14520078, 0.36614038],
389        kcn: [0.0006150, -0.0058347, 0.2250180],
390        gam3: 0.1300000,
391        atomic_rad: 1.17 * AATOAU,
392        pauling_en: 2.96,
393        kind: 1,
394        dkernel: -0.01088586,
395        qkernel: 0.00216935,
396        mp_rad: 3.9,
397        mp_vcn: 1.0,
398    },
399    // Z=53, I
400    Gfn2ElementParams {
401        z: 53,
402        nshell: 3,
403        ang_shell: [0, 1, 2],
404        selfenergy: [-20.949407, -12.180159, -0.266596],
405        slater: [2.159500, 2.308379, 1.691185],
406        ref_occ: [2.0, 5.0, 0.0],
407        hubbard: 0.383124,
408        shell_hubbard: [1.0000000, 0.9661265, 1.3000000],
409        rep_alpha: 1.017946,
410        rep_zeff: 63.319176,
411        n_valence: 7,
412        pqn: [5, 5, 5],
413        ngauss: [4, 4, 3],
414        shpoly: [-0.26957547, -0.14183312, 0.28211905],
415        kcn: [-0.0506150, 0.0084766, 0.3077127],
416        gam3: 0.1200000,
417        atomic_rad: 1.33 * AATOAU,
418        pauling_en: 2.66,
419        kind: 1,
420        dkernel: -0.00603648,
421        qkernel: 0.00069660,
422        mp_rad: 5.0,
423        mp_vcn: 1.0,
424    },
425    // ---- Transition metals (3d) ----
426    // Z=22, Ti  (shell order: d=0, s=1, p=2)
427    Gfn2ElementParams {
428        z: 22,
429        nshell: 3,
430        ang_shell: [2, 0, 1],
431        selfenergy: [-7.234331, -10.900000, -1.928783],
432        slater: [1.849994, 1.469983, 0.957410],
433        ref_occ: [1.0, 1.0, 1.0],
434        hubbard: 0.513586,
435        shell_hubbard: [0.5078886, 1.0000000, 0.6200000],
436        rep_alpha: 0.723104,
437        rep_zeff: 12.036336,
438        n_valence: 4,
439        pqn: [3, 4, 4],
440        ngauss: [3, 4, 4],
441        shpoly: [-0.27724389, 0.04561234, 0.51801626],
442        kcn: [0.1028188, 0.1007021, -0.0237074],
443        gam3: 0.1767268,
444        atomic_rad: 1.36 * AATOAU,
445        pauling_en: 1.54,
446        kind: 2,
447        dkernel: -0.00434506,
448        qkernel: 0.00059660,
449        mp_rad: 5.0,
450        mp_vcn: 4.0,
451    },
452    // Z=24, Cr
453    Gfn2ElementParams {
454        z: 24,
455        nshell: 3,
456        ang_shell: [2, 0, 1],
457        selfenergy: [-7.209794, -9.201304, -0.696957],
458        slater: [1.568211, 1.395427, 1.080270],
459        ref_occ: [1.0, 1.0, 4.0],
460        hubbard: 0.396299,
461        shell_hubbard: [1.7405872, 1.0000000, 0.5300000],
462        rep_alpha: 0.966993,
463        rep_zeff: 19.517914,
464        n_valence: 6,
465        pqn: [3, 4, 4],
466        ngauss: [3, 4, 4],
467        shpoly: [-0.27971622, 0.13376234, 0.48092152],
468        kcn: [0.0289291, -0.0232087, -0.0188919],
469        gam3: 0.0300000,
470        atomic_rad: 1.22 * AATOAU,
471        pauling_en: 1.66,
472        kind: 2,
473        dkernel: 0.00149669,
474        qkernel: 0.00137744,
475        mp_rad: 5.0,
476        mp_vcn: 6.0,
477    },
478    // Z=25, Mn
479    Gfn2ElementParams {
480        z: 25,
481        nshell: 3,
482        ang_shell: [2, 0, 1],
483        selfenergy: [-10.120933, -5.617346, -4.198724],
484        slater: [1.839250, 1.222190, 1.240215],
485        ref_occ: [1.0, 1.0, 5.0],
486        hubbard: 0.346651,
487        shell_hubbard: [1.0545811, 1.0000000, 0.4000000],
488        rep_alpha: 1.071100,
489        rep_zeff: 18.760605,
490        n_valence: 7,
491        pqn: [3, 4, 4],
492        ngauss: [3, 4, 4],
493        shpoly: [-0.31255885, 0.28519691, 0.26346555],
494        kcn: [-0.0195827, -0.0275000, -0.0015839],
495        gam3: 0.0600000,
496        atomic_rad: 1.19 * AATOAU,
497        pauling_en: 1.55,
498        kind: 2,
499        dkernel: -0.00759168,
500        qkernel: 0.00229903,
501        mp_rad: 5.0,
502        mp_vcn: 6.0,
503    },
504    // Z=26, Fe
505    Gfn2ElementParams {
506        z: 26,
507        nshell: 3,
508        ang_shell: [2, 0, 1],
509        selfenergy: [-10.035473, -5.402911, -3.308988],
510        slater: [1.911049, 1.022393, 1.294467],
511        ref_occ: [1.0, 1.0, 6.0],
512        hubbard: 0.271594,
513        shell_hubbard: [1.4046615, 1.0000000, 0.3500000],
514        rep_alpha: 1.113422,
515        rep_zeff: 20.360089,
516        n_valence: 8,
517        pqn: [3, 4, 4],
518        ngauss: [3, 4, 4],
519        shpoly: [-0.28614961, 0.11527794, 0.39459890],
520        kcn: [-0.0274654, -0.4049876, -0.0756480],
521        gam3: -0.0500000,
522        atomic_rad: 1.16 * AATOAU,
523        pauling_en: 1.83,
524        kind: 2,
525        dkernel: 0.00412929,
526        qkernel: 0.00267734,
527        mp_rad: 5.0,
528        mp_vcn: 6.0,
529    },
530    // Z=27, Co
531    Gfn2ElementParams {
532        z: 27,
533        nshell: 3,
534        ang_shell: [2, 0, 1],
535        selfenergy: [-10.580430, -8.596723, -2.585753],
536        slater: [2.326507, 1.464221, 1.298678],
537        ref_occ: [1.0, 1.0, 7.0],
538        hubbard: 0.477760,
539        shell_hubbard: [0.7581507, 1.0000000, 0.3500000],
540        rep_alpha: 1.241717,
541        rep_zeff: 27.127744,
542        n_valence: 9,
543        pqn: [3, 4, 4],
544        ngauss: [3, 4, 4],
545        shpoly: [-0.22355636, 0.09168460, 0.25424719],
546        kcn: [0.0121980, -0.0227872, 0.0076513],
547        gam3: 0.0300000,
548        atomic_rad: 1.11 * AATOAU,
549        pauling_en: 1.88,
550        kind: 2,
551        dkernel: -0.00247938,
552        qkernel: 0.00048237,
553        mp_rad: 5.0,
554        mp_vcn: 6.0,
555    },
556    // Z=28, Ni
557    Gfn2ElementParams {
558        z: 28,
559        nshell: 3,
560        ang_shell: [2, 0, 1],
561        selfenergy: [-12.712236, -8.524281, -2.878873],
562        slater: [2.430756, 1.469945, 1.317046],
563        ref_occ: [1.0, 1.0, 8.0],
564        hubbard: 0.344970,
565        shell_hubbard: [0.9388812, 1.0000000, 0.4000000],
566        rep_alpha: 1.077516,
567        rep_zeff: 10.533269,
568        n_valence: 10,
569        pqn: [3, 4, 4],
570        ngauss: [3, 4, 4],
571        shpoly: [-0.25385640, 0.20839550, 0.30886445],
572        kcn: [-0.0066417, 0.0310301, 0.0226796],
573        gam3: -0.0200000,
574        atomic_rad: 1.10 * AATOAU,
575        pauling_en: 1.91,
576        kind: 2,
577        dkernel: -0.01261887,
578        qkernel: -0.00080000,
579        mp_rad: 5.0,
580        mp_vcn: 4.0,
581    },
582    // Z=29, Cu
583    Gfn2ElementParams {
584        z: 29,
585        nshell: 3,
586        ang_shell: [2, 0, 1],
587        selfenergy: [-9.506548, -6.922958, -2.267723],
588        slater: [2.375425, 1.550837, 1.984703],
589        ref_occ: [1.0, 0.0, 10.0],
590        hubbard: 0.202969,
591        shell_hubbard: [2.3333066, 1.0000000, 1.0700000],
592        rep_alpha: 0.998768,
593        rep_zeff: 9.913846,
594        n_valence: 11,
595        pqn: [3, 4, 4],
596        ngauss: [3, 4, 4],
597        shpoly: [-0.26508943, 0.17798264, 0.14977818],
598        kcn: [-0.0173684, 0.3349047, -0.2619446],
599        gam3: 0.0500000,
600        atomic_rad: 1.12 * AATOAU,
601        pauling_en: 1.90,
602        kind: 2,
603        dkernel: -0.00700000,
604        qkernel: -0.00345631,
605        mp_rad: 5.0,
606        mp_vcn: 4.0,
607    },
608    // Z=30, Zn
609    Gfn2ElementParams {
610        z: 30,
611        nshell: 3,
612        ang_shell: [2, 0, 1],
613        selfenergy: [-7.177294, -0.991895, 0.000000],
614        slater: [1.664847, 1.176434, 0.000000],
615        ref_occ: [2.0, 0.0, 10.0],
616        hubbard: 0.564152,
617        shell_hubbard: [1.0000000, 1.0000000, 1.0684343],
618        rep_alpha: 1.160262,
619        rep_zeff: 22.099503,
620        n_valence: 12,
621        pqn: [3, 4, 4],
622        ngauss: [3, 4, 4],
623        shpoly: [0.00000000, -0.09240315, 0.22271839],
624        kcn: [0.0000000, 0.2011910, -0.0055135],
625        gam3: 0.2312896,
626        atomic_rad: 1.18 * AATOAU,
627        pauling_en: 1.65,
628        kind: 2,
629        dkernel: -0.00100000,
630        qkernel: 0.00007658,
631        mp_rad: 5.0,
632        mp_vcn: 2.0,
633    },
634    // ---- Second-row TM ----
635    // Z=44, Ru
636    Gfn2ElementParams {
637        z: 44,
638        nshell: 3,
639        ang_shell: [2, 0, 1],
640        selfenergy: [-10.285405, -5.332608, -3.307153],
641        slater: [2.102697, 1.749643, 1.348322],
642        ref_occ: [1.0, 1.0, 6.0],
643        hubbard: 0.711205,
644        shell_hubbard: [0.6947695, 1.0000000, 0.3500000],
645        rep_alpha: 1.031669,
646        rep_zeff: 28.070247,
647        n_valence: 8,
648        pqn: [4, 5, 5],
649        ngauss: [4, 4, 3],
650        shpoly: [-0.27583213, 0.10106270, 0.34028722],
651        kcn: [-0.0263914, 0.4471162, -0.0034723],
652        gam3: -0.0500000,
653        atomic_rad: 1.25 * AATOAU,
654        pauling_en: 2.20,
655        kind: 2,
656        dkernel: -0.00081922,
657        qkernel: 0.00359228,
658        mp_rad: 5.0,
659        mp_vcn: 6.0,
660    },
661    // Z=46, Pd
662    Gfn2ElementParams {
663        z: 46,
664        nshell: 3,
665        ang_shell: [2, 0, 1],
666        selfenergy: [-11.963518, -9.714059, -2.035281],
667        slater: [2.353691, 1.828354, 1.333352],
668        ref_occ: [1.0, 0.0, 10.0],
669        hubbard: 0.273310,
670        shell_hubbard: [1.0931707, 1.0000000, 0.4000000],
671        rep_alpha: 1.092745,
672        rep_zeff: 28.674700,
673        n_valence: 10,
674        pqn: [4, 5, 5],
675        ngauss: [4, 4, 3],
676        shpoly: [-0.27173113, 0.06200145, 0.45341322],
677        kcn: [0.0060285, 0.0266820, 0.0503075],
678        gam3: 0.0800000,
679        atomic_rad: 1.20 * AATOAU,
680        pauling_en: 2.20,
681        kind: 2,
682        dkernel: -0.00310361,
683        qkernel: -0.00040485,
684        mp_rad: 5.0,
685        mp_vcn: 4.0,
686    },
687    // Z=47, Ag
688    Gfn2ElementParams {
689        z: 47,
690        nshell: 3,
691        ang_shell: [2, 0, 1],
692        selfenergy: [-9.591083, -8.083960, -2.934333],
693        slater: [2.843549, 1.798462, 1.266649],
694        ref_occ: [2.0, 0.0, 10.0],
695        hubbard: 0.263740,
696        shell_hubbard: [1.8024848, 1.0000000, 0.9700000],
697        rep_alpha: 0.678344,
698        rep_zeff: 6.493286,
699        n_valence: 11,
700        pqn: [4, 5, 5],
701        ngauss: [4, 4, 3],
702        shpoly: [-0.16490742, 0.01091490, 0.11561444],
703        kcn: [-0.0062719, -0.0065794, 0.1677171],
704        gam3: 0.0200000,
705        atomic_rad: 1.28 * AATOAU,
706        pauling_en: 1.93,
707        kind: 2,
708        dkernel: -0.00800314,
709        qkernel: -0.00020810,
710        mp_rad: 5.0,
711        mp_vcn: 4.0,
712    },
713    // ---- Third-row TM ----
714    // Z=78, Pt
715    Gfn2ElementParams {
716        z: 78,
717        nshell: 3,
718        ang_shell: [2, 0, 1],
719        selfenergy: [-12.047728, -10.482306, -3.778297],
720        slater: [2.704492, 2.329136, 1.623286],
721        ref_occ: [1.0, 1.0, 8.0],
722        hubbard: 0.353574,
723        shell_hubbard: [0.9796788, 1.0000000, 0.4000000],
724        rep_alpha: 1.204081,
725        rep_zeff: 53.881425,
726        n_valence: 10,
727        pqn: [5, 6, 6],
728        ngauss: [3, 6, 6],
729        shpoly: [-0.27243898, 0.06737556, 0.19259455],
730        kcn: [-0.0204828, 0.1139530, 0.1408029],
731        gam3: 0.0600000,
732        atomic_rad: 1.23 * AATOAU,
733        pauling_en: 2.28,
734        kind: 2,
735        dkernel: -0.00423684,
736        qkernel: 0.00098019,
737        mp_rad: 5.0,
738        mp_vcn: 4.0,
739    },
740    // Z=79, Au
741    Gfn2ElementParams {
742        z: 79,
743        nshell: 3,
744        ang_shell: [2, 0, 1],
745        selfenergy: [-9.578599, -7.688552, 0.883399],
746        slater: [3.241287, 2.183171, 2.084484],
747        ref_occ: [2.0, 0.0, 10.0],
748        hubbard: 0.438997,
749        shell_hubbard: [1.0614126, 1.0000000, 0.4000000],
750        rep_alpha: 0.919210,
751        rep_zeff: 14.711475,
752        n_valence: 11,
753        pqn: [5, 6, 6],
754        ngauss: [3, 6, 6],
755        shpoly: [-0.06410815, 0.04691539, 0.25250274],
756        kcn: [-0.0154462, 0.1479337, 0.1048065],
757        gam3: 0.0850000,
758        atomic_rad: 1.24 * AATOAU,
759        pauling_en: 2.54,
760        kind: 2,
761        dkernel: 0.00393418,
762        qkernel: -0.00020320,
763        mp_rad: 5.0,
764        mp_vcn: 4.0,
765    },
766];
767
768/// Look up GFN2-xTB parameters by atomic number.
769pub fn get_gfn2_params(z: u8) -> Option<&'static Gfn2ElementParams> {
770    GFN2_PARAMS.iter().find(|p| p.z == z)
771}
772
773/// Check if an element is supported by GFN2-xTB.
774pub fn is_gfn2_supported(z: u8) -> bool {
775    get_gfn2_params(z).is_some()
776}
777
778/// Compute effective Hubbard parameter (Hartree) as occupation-weighted average
779/// across shells: η_eff = Σ_sh(n_sh × η × shell_hubbard_sh) / Σ_sh(n_sh).
780/// This approximates shell-resolved SCC with an atom-level gamma.
781pub fn effective_hubbard(p: &Gfn2ElementParams) -> f64 {
782    let mut num = 0.0;
783    let mut den = 0.0;
784    for sh in 0..p.nshell {
785        let n = p.ref_occ[sh];
786        num += n * p.hubbard * p.shell_hubbard[sh];
787        den += n;
788    }
789    if den > 0.0 {
790        num / den
791    } else {
792        p.hubbard
793    }
794}
795
796/// Count basis functions for GFN2-xTB: s=1, p=3, d=5.
797pub fn gfn2_basis_size(z: u8) -> usize {
798    match get_gfn2_params(z) {
799        None => 0,
800        Some(p) => {
801            let mut n = 0;
802            for i in 0..p.nshell {
803                n += match p.ang_shell[i] {
804                    0 => 1,
805                    1 => 3,
806                    2 => 5,
807                    _ => 0,
808                };
809            }
810            n
811        }
812    }
813}
814
815/// Count total valence electrons.
816pub fn gfn2_electron_count(elements: &[u8]) -> usize {
817    elements
818        .iter()
819        .map(|&z| get_gfn2_params(z).map_or(0, |p| p.n_valence as usize))
820        .sum()
821}
822
823/// Compute kshell factor for off-diagonal H0 scaling.
824/// GFN2 uses: kshell(k, l) = merge(2.0, (kdiag[l]+kdiag[k])/2, ...)
825pub fn kshell_factor(l_a: u8, l_b: u8) -> f64 {
826    let la = l_a as usize;
827    let lb = l_b as usize;
828    // sp/ps and sd/ds pairs use k=2.0 (from tblite kshell function)
829    if (la == 2 && (lb == 0 || lb == 1)) || (lb == 2 && (la == 0 || la == 1)) {
830        2.0
831    } else {
832        (KDIAG[la] + KDIAG[lb]) / 2.0
833    }
834}
835
836#[cfg(test)]
837mod tests {
838    use super::*;
839
840    #[test]
841    fn test_gfn2_params_hydrogen() {
842        let p = get_gfn2_params(1).unwrap();
843        assert_eq!(p.nshell, 1);
844        assert!((p.selfenergy[0] - (-10.707211)).abs() < 1e-4);
845        assert!((p.slater[0] - 1.23).abs() < 1e-4);
846        assert_eq!(p.n_valence, 1);
847    }
848
849    #[test]
850    fn test_gfn2_params_carbon() {
851        let p = get_gfn2_params(6).unwrap();
852        assert_eq!(p.nshell, 2);
853        assert!((p.selfenergy[0] - (-13.970922)).abs() < 1e-4);
854        assert!((p.selfenergy[1] - (-10.063292)).abs() < 1e-4);
855        assert_eq!(p.n_valence, 4);
856    }
857
858    #[test]
859    fn test_gfn2_basis_size() {
860        assert_eq!(gfn2_basis_size(1), 1); // H: s
861        assert_eq!(gfn2_basis_size(6), 4); // C: s+p
862        assert_eq!(gfn2_basis_size(26), 9); // Fe: d+s+p
863    }
864
865    #[test]
866    fn test_gfn2_electron_count() {
867        assert_eq!(gfn2_electron_count(&[8, 1, 1]), 8); // H2O
868        assert_eq!(gfn2_electron_count(&[6, 1, 1, 1, 1]), 8); // CH4
869    }
870}