BIPOLE multi-k chat — session handover (2026-05-19)

This is a session handover for the bipole-multik chat (the chat that picked up item #1 of docs/handover_bipole_v0_8_2026_05_18.md — “Multi-k F_J^LR(k) proper”).

For the current BIPOLE driver state, read docs/handover_bipole_2026_05_20.md instead — it is the canonical, up-to-date handover. This file only records what this chat session delivered and how it was absorbed, so the thread can be picked up if needed without re-deriving context.

What this chat delivered

Commit 602c315 bipole: per-k F_J^LR(k) closes Γ→k-mesh shift (v0.9.0 multi-k) — the first working multi-k Ewald-J-split path.

The deliverable closed the n_k != 1 NotImplementedError guard in run_pbc_bipole_rhf(use_ewald_j_split=True) by implementing:

  1. Shifted-ν Gaussian-product AO-pair FT (_aopair_ft.ao_pair_fourier_transform_shifted_ket, ..._at_cells, ..._bloch) — closed-form FT_μν(K; R_g) = φ_μ(r) φ_ν(r-R_g) e^{-iK·r} dr with the non-linear Gaussian-product-centre shift P_g = P_0 + (α_ν/γ)·R_g. Replaced the bra-pair-at-home phase approximation FT_μν(K; 0)·e^{-iK·R_g} that is only exact for D(g=0).

  2. k-space ρ̂(K) (bipole_fock_ewald.compute_rho_hat_from_k_density) — ρ̂(K) = Σ_k w_k Σ_λσ D(k)_λσ · FT^{(+k)}_λσ(K). This is the proper Bloch-formalism form; the real-space form Σ_g D_real(g)·FT(K; R_g) over-counts when n_cells n_k because real_space_density_from_kpoints takes Re[exp(-ik·R_g)·D(k)] and the resulting D(g) does not round-trip to D(k) under a cutoff-truncated lattice.

  3. Per-k compute_J_long_range_at_k + a JLongRangeCache holding the invariant K-vectors / kernel / shifted-ν FT stack.

Tests: tests/test_pbc_bipole_multik_ewald_split.py (+9 unit tests: shifted-ν FT identities, Hermiticity of F_J^LR(k), cache reuse, SHRINK 2 2 smoke). tests/test_pbc_bipole_ewald_split_integration.py flipped ..._multik_raises..._multik_runs.

Empirical at the time of 602c315 (MgO STO-3G):

Config

E_total (Ha)

Δ vs CRYSTAL SHRINK 8 8

SHRINK 2 2 cutoff=8

-269.377

+1.84 Ha (PASS)

This closed the multi-k guard and improved on Γ-only’s +2.17 Ha, but was not yet dense-k parity.

How it was absorbed / superseded

602c315 was the foundation; six subsequent BIPOLE commits on main built straight on top of it and took the driver all the way to dense-k sub-mHa CRYSTAL14 parity:

  • f3d3dcc Implement CRYSTAL-gauge periodic BIPOLE SCF — analytic 3D Ewald V_ne, native build_jk_2e_real_space, real-space J_LR(g) blocks for TOTENY-style energy accounting.

  • b8db49f / 5ada267 — dense-k parity scripts; CRYSTAL gauge made the 3D default (use_ewald_j_split=None).

  • 83a5da8 / 8c1d3ee — ODA support on the Ewald-J path.

  • a947934 Expand IBZ meshes for BIPOLE Ewald-J — the use_symmetry=False constraint this chat documented is now handled automatically: IBZ-reduced meshes carrying ir_mapping metadata are expanded internally to the full uniform mesh.

Final dense-k sign-off (from handover_bipole_2026_05_20.md):

Demo

vibe-qc E_total

CRYSTAL14

Δ

MgO

-271.2177749

-271.2181437

+0.37 mHa

diamond

-74.8771394

-74.8769944

-0.15 mHa

silicon

-571.3214716

-571.3208122

-0.66 mHa

So this chat’s headline target (close the +0.4–2.5 Ha Γ-vs-SHRINK residuals → sub-mHa CRYSTAL parity on MgO/diamond/Si STO-3G) is done — completed by the dense-k sign-off chat building on this chat’s multi-k foundation.

Branch / sync state at handover

  • Worktree: .claude/worktrees/trusting-yalow-8d19ec, branch claude/trusting-yalow-8d19ec.

  • HEAD == origin/main at e48ce06 after fast-forwarding 40 commits. Working tree clean.

  • No uncommitted work from this chat; 602c315 is its only commit and is in main history.

If picking up this thread

The multi-k correctness milestone is closed. What remains (all already enumerated in handover_bipole_2026_05_20.md §”Recommended next phase” and §”Known limitations”):

  1. NiO UHF parityrun_pbc_bipole_uhf scaffold exists; NiO unsigned against CRYSTAL.

  2. True IBZ acceleration — IBZ meshes are currently expanded to full meshes internally (correctness bridge, no perf win). The k-space ρ̂(K) formula from 602c315 would need orbit-expanded operator/density construction to keep reduced meshes reduced.

  3. Native C++ SDR far-pair branch — the Python Ewald-J path is a CRYSTAL-gauge parity scaffold, not the production Saunders-Dovesi-Roetti multipole dispatch.

  4. EXT EL-SPHEROPOLE (handover-v0.8 item #2) — a partial s-s impl landed separately (ab5fef8); its contribution is effectively captured by the reciprocal-space construction for the dense-k cases, but a line-for-line CRYSTAL decomposition is still open.

Memory file ~/.claude/projects/-Users-mpei-gitlab-vibeqc-bipole/memory/reference_bipole_multik_v0_9_0_landed_2026-05-18.md has this chat’s full implementation notes + the two-compounding-bugs analysis.