1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
//! Map from raw spin densities / gradients to libxc reduced variables, plus the
//! spin-scaling helpers shared by exchange/correlation energies.
//! Provenance: ported-from-libxc (MPL-2.0), `maple/util.mpl`.
//!
//! Spin factors are taken as the cancellation-free `opz = 1 + z = 2·n_a/n` (and
//! `omz = 1 − z = 2·n_b/n`) rather than reconstructed as `1 ± z` from `z`, which
//! would lose precision near full spin polarization (z → ±1).
use DualNum;
use ;
/// Wigner–Seitz radius `rs = (3/(4π n))^(1/3) = RS_FACTOR / n^(1/3)`.
pub
/// Relative spin polarization `z = (n_a − n_b)/(n_a + n_b)`.
///
/// Provided for completeness with the libxc reduced-variable vocabulary; the
/// family harnesses derive ζ via the cancellation-free `opz`/`omz` helpers
/// rather than this direct difference form, so this is currently unused.
pub
/// Squared reduced density gradient `x² = σ / n^(8/3) = (|∇n|/n^(4/3))²`,
/// computed **directly from σ and n — never via `√σ`**. This is the only reduced
/// gradient the GGA harness seeds into a differentiated energy, for **both** the
/// total gradient `x_t²` and the per-spin gradients `x_{s0}²`/`x_{s1}²`
/// (`σ_aa/n_a^(8/3)`, `σ_bb/n_b^(8/3)`).
///
/// Provenance / rationale (sqrt-free): `√σ`'s derivatives diverge as `σ → 0`
/// (`d√σ ∝ σ^(-1/2)`, `d²√σ ∝ σ^(-3/2)`). For the **total** gradient the σ_ab
/// clamp can drive `σ_tot` to **exactly 0**, where `d√σ = ∞` and squaring back
/// gives `0·∞ = NaN` in `vxc`. For the **per-spin** gradients σ is floored `> 0`,
/// so `vxc` is finite — but the *second* derivative still loses the finite-limit
/// cancellation in f64 as σ approaches the floor (`fxc`'s `v2sigma2` error grows
/// `~ ε·σ^(-3/2)`, reaching ~1e21 at the floor; the crossover past the 1e-10
/// golden tol is `σ ≲ 1e-6`). Working in the squared form `σ/n^(8/3)` (linear in
/// σ, smooth at 0) avoids both: enhancements consume `x²` directly, reintroducing
/// `√` only where a genuine magnitude is needed and only far from 0 (B88's
/// `x·asinh x`, switched to a power series in `x²` near 0). Provenance:
/// ported-from-libxc (MPL-2.0), `maple/util.mpl` (the reduced gradient); the
/// sqrt-free organization is xcx's, for AD-safety (see `docs/api-convention.md` §8).
pub
/// Per-spin dimensionless kinetic-energy density `t_σ = τ_σ / n_σ^(5/3)`,
/// computed **directly from τ and n — never via any √**. This is the meta-GGA
/// analogue of [`reduced_grad_sq`]: τ enters the differentiated path linearly,
/// so forward-AD's first and second derivatives stay finite as τ → 0 (τ is
/// floored `> 0` by the harness, but keeping it sqrt-free avoids reintroducing the
/// `σ → 0`-style cancellation at second order). Provenance: ported-from-libxc
/// (MPL-2.0), `maple/util.mpl` (`t_total` per-spin term `τ_σ/n_σ^(5/3)`).
pub
/// The dimensionless meta-GGA iso-orbital indicator
/// `α = (τ_σ − τ_W,σ)/τ_unif,σ = (t_σ − x_σ²/8)/K_FACTOR_C`, taking the **squared**
/// reduced gradient `x_σ²` (sqrt-free) and the reduced kinetic-energy density
/// `t_σ` ([`reduced_tau`]). This is libxc's `tpss_alpha` (util.mpl `K_FACTOR_C`),
/// the central switch variable of the SCAN/TPSS family.
///
/// **AD-hazard (CLAUDE.md §3, the τ-ratio class).** `α` has 0/0 structure as the
/// density → uniform: at `α ≈ 0` (`τ → τ_W`, the single-orbital / von Weizsäcker
/// edge) and at `σ → 0` (`τ_W → 0`); the SCAN-family switch functions `f(α)` have
/// near-singular derivatives at `α ≈ 1`. The form here is cancellation-free in
/// the *energy* — `t_σ − x_σ²/8` is a plain difference of two finite reduced
/// variables — and consumers must keep `f(α)` AD-safe across the `α ≈ 1` seam
/// (factor out, don't subtract close-to-equal terms). Densify golden+fuzz around
/// `α = 0`, `α = 1`, `σ → 0`, and the `τ = τ_W` edge.
pub
/// `(1 + z)^p` with libxc's clamp, taking the cancellation-free `opz = 1 + z`.
/// When `opz ≤ zeta_threshold`, returns `zeta_threshold^p` (keeps the value and
/// its derivative defined at full polarization). Provenance: util.mpl `opz_pow_n`.
pub
/// libxc per-channel density screen: `true` when the (floored) spin density is at
/// or below `dens_threshold`. Uses the spin density directly — matching libxc's
/// `my_rho[spin] ≤ dens_threshold` — so borderline decisions at full
/// polarization agree exactly (reconstructing `n_spin` from `rs`/`opz` would
/// round across the threshold). The predicate is on the real part, so forward-AD
/// follows the chosen branch. Provenance: util.mpl `screen_dens` / `n_spin`.
pub
/// 3D LDA exchange energy per particle for one spin channel, given the
/// cancellation-free `opz = 1 + z`:
/// `LDA_X_FACTOR · opz^(4/3) · 2^(-4/3) · n^(1/3)`, with `n^(1/3) = RS_FACTOR/rs`.
/// Provenance: util.mpl `lda_x_spin`.
pub
/// `(1+z)^p − 1`, libxc's exact form `expm1(p·log1p(z))`, clamped to
/// `zeta_threshold^p − 1` when `1 + z ≤ zeta_threshold`. The `−1` is built in (so
/// `f(0)=0` is exact), but `log1p(z)` is taken on `z` itself — matching libxc's
/// arithmetic, including its cancellation near `z = −1`. This is required for
/// correlation `f(ζ)` to agree with libxc bit-for-bit; exchange uses the
/// cancellation-free `opz` form above (which is what libxc's exchange does).
/// Provenance: util.mpl `opz_pow_n_m1`.
pub
/// `x^(5/3)` matching libxc's C `pow`: `0` at `x ≤ 0` (where `pow(0, 5/3) = 0`
/// and the symbolic derivative `(5/3)·pow(0, 2/3) = 0`), else the real `powf`. The
/// guard is essential at full polarization: when the floored minority density is
/// lost in the f64 sum `n_a + n_b`, a base of exactly `0` reaches `^(5/3)`, where
/// num-dual's `powf(0, 5/3)` would yield `NaN` whereas the true `0·∞ → 0` weight
/// (and libxc's `pow`) give `0`. Shared by [`t_total`] (the meta-GGA spin combiner,
/// used by TPSS-c and r2SCAN-c). Provenance: util.mpl `t_total` (`pow` semantics).
pub
/// libxc `t_total(z, a, b) = a·((1+z)/2)^(5/3) + b·((1−z)/2)^(5/3)`: the spin
/// combiner that turns per-spin reduced quantities into the total. The bases
/// `(1±z)/2 = n_{a,b}/n ∈ [0, 1]`; the `^(5/3)` is taken via [`pow_5_3`] so the
/// `z = ±1` (single-channel) edge is finite. With `a = b = 1` it returns the
/// uniform-gas KE spin factor `((1+z)/2)^(5/3) + ((1−z)/2)^(5/3)`. Shared by the
/// meta-GGA correlations (TPSS-c, r2SCAN-c). Provenance: util.mpl `t_total`.
pub
/// `1 − z^12` in libxc's cancellation-free factored form
/// `(1−z)(1+z)(1 + z² + z⁴ + z⁶ + z⁸ + z^10)` (util.mpl `one_minus_z_pow_n` for
/// the even case `n = 12`). Takes the **raw** `z` (correlation convention); the
/// `(1−z)(1+z)` factor keeps both `z = ±1` boundaries cancellation-free, and the
/// factor vanishes there. Used by r2SCAN-c's `scan_Gc`. Provenance: util.mpl
/// `one_minus_z_pow_n`.
pub
/// PW92/VWN spin-scaling function
/// `f(z) = [(1+z)^(4/3) + (1−z)^(4/3) − 2] / (2^(4/3) − 2)`, via the `_m1`
/// primitive (so `f(0)=0` exactly) in libxc's exact form. Provenance: util.mpl
/// `f_zeta`.
pub
/// `1 − z²` in libxc's factored form `(1−z)(1+z)` (util.mpl `one_minus_z_pow_n`
/// for n = 2). Takes the **raw** `z` (correlation's z-based convention, see
/// docs/api-convention.md §8, divergence A); the `(1−z)(1+z)` factorisation keeps both
/// boundaries cancellation-free. **Unclamped** — distinct from the
/// `zeta_threshold`-clamped `(1±z)²` you get from [`opz_pow`]. Used by LYP
/// correlation. Provenance: util.mpl `one_minus_z_pow_n`.
pub
/// `1 − z⁴` in libxc's cancellation-free factored form `(1−z)(1+z)(1+z²)`
/// (util.mpl `one_minus_z_pow_n` for n = 4). Like `f_zeta`, this takes the **raw**
/// `z` rather than the cancellation-free `opz`/`omz` — correlation must reproduce
/// libxc's z-based arithmetic to match it (see docs/api-convention.md §8,
/// divergence A). The factor vanishes as `z → ±1`, so the choice is numerically
/// immaterial there.
/// Provenance: util.mpl `one_minus_z_pow_n`.
pub
/// PBE/PW91 spin-scaling `φ(ζ) = [(1+ζ)^(2/3) + (1−ζ)^(2/3)]/2`, built from the
/// cancellation-free `opz_pow_m1` primitive so `φ(0)=1` is exact and `ζ → ±1` is
/// clamped at `zeta_threshold` (`(1±ζ)^(2/3)` stays defined). z-based, the
/// correlation convention. Provenance: util.mpl `mphi`.
pub
/// Squared PBE correlation reduced gradient `t² = x_t²/((4·2^(1/3))²·φ(ζ)²·rs)`
/// (util.mpl `tt`, squared), taking the squared total reduced gradient `xt2`
/// (`reduced_grad_sq`). Working in `t²` (not `t`) keeps forward-AD finite when the
/// total gradient vanishes: PBE-C's `H` depends on `t` only through `t²`/`t⁴`, so
/// the maple's intermediate `√σ_tot` (whose derivative blows up at σ_tot = 0,
/// reachable via the σ_ab clamp) is unnecessary. Takes `φ(ζ)` precomputed (PBE-C
/// reuses it in the `A`/`H` terms). Provenance: util.mpl `tt`.
pub