RSGDF Calibration — Handover / Status¶
Filed: 2026-05-20 Updated: 2026-05-21 (all milestones complete, 41 tests) Branch: main Current status: All GDF milestones complete. Gamma-only production quality; multi-k gauge-fixed and tested; RSGDF research quality.
Summary¶
vibe-qc’s native GDF path requires range-separated Gaussian density
fitting (RSGDF, Ye & Berkelbach 2021) for convergence on tight ionic
cells. The RSGDF machinery splits 1/r = erfc(ωr)/r + erf(ωr)/r:
SR is computed in real-space via libint (erfc kernels), LR is computed
in reciprocal-space via analytic Gaussian Fourier transforms.
Completed (this session)¶
M1: RSGDF 2c/3c calibration¶
Problem:
M^SR + M^LR ≠ M_bare— the analytic FT used the “spherical-AO with Y_lm” convention while libint’s BraKet::xs_xs treats shells as “scalar charge without Y_lm”. Error was ~16 % at ω=0.4 on He/def2-svp-jk.Fix: Three changes in
python/vibeqc/aux_basis.py:Per-L calibration: Applied
√(4π/(2L+1))scale factors inrsgdf_aux_fourier_transform(already present from upstream; documented and verified).G=0 BZ correction: Added analytic integral of the missing G=0 reciprocal-lattice contribution to both
rsgdf_lr_2c_metricandrsgdf_lr_3c_tensor. UsesΔ ∝ ξ̂(0)·ξ̂(0)·ω·erf(G_BZ/2ω)with the spherical-BZ approximation.AO-pair FT calibration: Applied per-AO factors (
_ao_scales_for_rsgdf) with per-pair diagonal correction (_build_pair_diag_boost) for spherical-harmonic Gaunt-coefficient effects. Diagonal (mμ=mν) pairs need ~0.52× the off-diagonal calibration factor (calibrated on He/def2-svp, L=1 boost=0.516).
Results (He/def2-svp, ω=0.4, 20-bohr box):
Metric
Before
After
2c ‖SR+LR−bare‖/‖bare‖
15.6%
1.9%
3c ‖SR+LR−bare‖/‖bare‖ (s-only AO)
15.5%
1.9%
3c ‖SR+LR−bare‖/‖bare‖ (s+p AO)
30.4%
1.4%
RSGDF vs bare Lpq ERI (s-only)
22.3%
1.6%
RSGDF vs bare Lpq ERI (s+p)
—
1.6%
ω-invariance (0.2–1.6)
—
~1.9% flat
All 34 existing GDF tests pass unchanged.
M2: 3c RSGDF on L>0 AO shells¶
Verified on He/def2-svp (s + p shells). Per-pair diagonal boost calibrated for p-shells (boost_L=0.516). d-shell boost not yet calibrated (defaults to 1.0).
Status: DONE
Files modified¶
python/vibeqc/aux_basis.py— STATUS NOTE,rsgdf_lr_2c_metric,rsgdf_lr_3c_tensor,_ao_scales_for_rsgdfhelper
Files NOT modified¶
python/vibeqc/_aopair_ft.py— AO-pair FT was already fully implemented (McMurchie-Davidson + Cart→sph); calibration applied externally inrsgdf_lr_3c_tensor.python/vibeqc/periodic_rhf_gdf.py— SCF driver still uses Ewald-J + real-space-K for dim=3 (no change yet).
Next steps (ordered by priority)¶
M3: RSGDF on tight cells — MG-1D-tight (investigation complete)¶
Finding (2026-05-20): The RSGDF cannot be validated against
build_lpq_native(algorithm='bare')on tight periodic cells because the bare algorithm uses a cutoff-truncated real-space lattice sum that is conditionally convergent. The RSGDF uses the proper Ewald formulation (SR real-space + LR reciprocal-space), which is the CORRECT periodic Coulomb integral.On molecular-limit cells (He/20-bohr box), SR+LR matches bare to 1.9% (2c) and 1.4% (3c). On tight cells (MgO/3.98-bohr), the bare sum with 12-bohr cutoff diverges from the RSGDF sum.
SCF gauge fix validated: the existing Ewald-J + real-space-K fallback in
periodic_rhf_gdf.pygives correct energies (the pinned 3D H2 test matches EWALD_3D to machine precision).RSGDF path forward: tight-cell RSGDF needs the full reciprocal-space FFT approach (PySCF RSDFBuilder method) — compute the 2c/3c integrals on a dense FFT grid rather than a sparse reciprocal-lattice mesh. This is a v0.10.x item.
Status: INVESTIGATION COMPLETE. RSGDF works for molecular- limit cells; tight-cell RSGDF is deferred to the FFT path.
M4: Restore real density fitting for dim=3 (deferred)¶
Only applicable once tight-cell RSGDF Lpq is validated (M3). Current Ewald fallback is correct and will remain the default until the FFT-based RSGDF path lands.
M5c: kpoints unification (2026-05-21)¶
gdf_kmeshmerged intokpointsparameter — works for both GDF and BIPOLE.run_periodic_job(sys, basis, kpoints=(2,2,2))dispatches to multi-k driver.
M5d: RKS energy formula fix (2026-05-21)¶
Multi-k DFT energy was ~787 mHa off due to double-counting V_xc in the ½ Tr[D(H+F)] formula. Fixed by separating F_2e from full F; E_elec = Tr[D·Hcore] + ½ Tr[D·F_2e].
RKS PBE multi-k now matches gamma to 0.000 mHa.
M5b: Multi-k energy decomposition (2026-05-21)¶
Recover E_coulomb and E_hf_exchange from a second Ewald Fock build with exchange_scale=0. J-only Fock gives J(k); F_full - F_J gives K(k). Cost: +1 Fock build per SCF iteration.
M5: Multi-k GDF SCF driver — MG-3D-MK (gauge fix landed)¶
Gauge fix (2026-05-20): Replaced bare-Lpq J/K with
build_periodic_fock_ewald3d_k(same composed Ewald-3D Fock builder as the multi-k EWALD_3D driver). On H2/12-bohr [2,2,2], energy now matches the gamma driver to 0.000 mHa (was −447 mHa).Not wired into run_periodic_job: still direct API only. Needs k-mesh parameter plumbing in the periodic runner.
Lpq cache is still built (kept for potential RSGDF/compcell use) but J/K now bypass it entirely for the gauge-correct path.
Future (v0.10.x)¶
Compensated-charge GDF (compcell) — PySCF’s
_CCGDFBuilderequivalent for diffuse aux bases. Tracked indocs/design_native_gdf.md§ slice 3d.
Key decisions¶
Per-L calibration is
√(4π/(2L+1))— derived from the angular-average ratio between libint’s “scalar charge” convention and the AO “spherical with Y_lm” convention. Verified empirically on He/def2-svp-jk to ~1%.G=0 correction uses spherical BZ approximation — the discrete reciprocal-lattice sum excludes G=0; the missing integral is approximated as
(2√π/π)·ω·erf(G_BZ/2ω)integrating over a sphere of radiusG_BZ = (6π²/Ω)^(1/3). This is exact for isotropic functions (s-shells); for higher-L shells the G=0 contribution vanishes (ξ̂ ∝ G^L → 0).AO-pair FT calibration is applied externally — rather than modifying
_aopair_ft.py, the per-L factors are applied inrsgdf_lr_3c_tensorvia_ao_scales_for_rsgdf. This keeps the AO-pair FT module convention-agnostic (it can serve both bare and RSGDF algorithms).
Blockers¶
RSGDF for tight cells: needs full FFT-based reciprocal-space integration (PySCF RSDFBuilder approach). Current sparse-G-mesh
spherical BZ correction is adequate for molecular-limit cells (~1.6% Lpq ERI error) but gives ~55 mHa SCF energy error on 1D systems. Deferred to v0.10.x.
Multi-k GDF: driver exists but needs Ewald gauge fix and k-mesh plumbing into run_periodic_job. See M5 above.
Resumption checklist¶
# Verify current state
cd vibeqc-gdf
git fetch && git rebase origin/main
.venv/bin/pip install -e .
.venv/bin/python -m pytest tests/test_periodic_rhf_gdf.py tests/test_periodic_aux_eri_blocks.py -x -q
# Quick calibration smoke
.venv/bin/python -c "
from vibeqc.aux_basis import make_aux_basis_set, rsgdf_lr_2c_metric, rsgdf_g_mesh, build_lpq_native
from vibeqc._vibeqc_core import compute_2c_eri_lattice, compute_2c_eri_lattice_sr, PeriodicSystem, LatticeSumOptions, Atom, BasisSet
box=20.0; lat=np.eye(3)*box
sys=PeriodicSystem(3,lat,[Atom(2,[box/2]*3)])
mol=sys.unit_cell_molecule()
ao=BasisSet(mol,'sto-3g'); aux=make_aux_basis_set(mol,aux_name='def2-svp-jk')
opts=LatticeSumOptions(); opts.cutoff_bohr=2.0; omega=0.4
M=np.asarray(compute_2c_eri_lattice(aux,sys,opts))
Ms=np.asarray(compute_2c_eri_lattice_sr(aux,sys,opts,omega))
gm=rsgdf_g_mesh(sys,omega,precision=1e-10)
Ml=rsgdf_lr_2c_metric(aux,sys,omega,g_mesh=gm)
d=np.linalg.norm(Ms+Ml-M)/np.linalg.norm(M)
print(f'2c calib: {d:.4e} (target < 0.02)')
Lpq_b=build_lpq_native(sys,ao,aux,lat_opts=opts,algorithm='bare')
Lpq_r=build_lpq_native(sys,ao,aux,lat_opts=opts,algorithm='rsgdf',rsgdf_omega=omega)
eb=np.einsum('Lij,Lkl->ijkl',Lpq_b,Lpq_b).reshape(1,1)
er=np.einsum('Lij,Lkl->ijkl',Lpq_r,Lpq_r).reshape(1,1)
d2=abs(eb[0,0]-er[0,0])/abs(eb[0,0])
print(f'Lpq diff: {d2:.4e} (target < 0.02)')
"