Periodic-method requirements from basissetdev

Audience: the periodic-methods main development chat. Authors: basissetdev, M. F. Peintinger. Date: 2026-05-08; last refresh 2026-05-13. Status: living document; rebased onto main as features land.

2026-05-13 refresh. Since the initial audit on 2c7c7df, Codex landed the native GDF backend (periodic_rhf_gdf.py, periodic_k_gdf.py, periodic_gdf_blocks.py) — replacing the retired in-process PySCF periodic backend, which CLAUDE.md § 10 now formally forbids. CRYSTAL-style FMIXING (previous-Fock mixing) and Fermi-Dirac smearing are wired through the GDF and Ewald multi-k paths. Shared SCF mixing helpers (validate_fraction_01, mix_fock_matrices) live in cpp/include/vibeqc/scf_mixing.hppnew basissetdev work must reuse these, never duplicate (manifest rule). See per-requirement status notes below.

This is the punch list of periodic capabilities basissetdev needs in order to reproduce the published pob-paper test sets in vibe-qc. The papers in scope are:

  • M. F. Peintinger, D. Vilela Oliveira, T. Bredow, J. Comput. Chem. 34, 451 (2013). [pob-TZVP, PT2013]

  • D. Vilela Oliveira, J. Laun, M. F. Peintinger, T. Bredow, J. Comput. Chem. 40, 2364 (2019). [pob-TZVP-rev2 + pob-DZVP-rev2, VO2019]

Together they enumerate roughly 70 binary and ternary ionic / semiconducting / TM-oxide / metallic systems plus a 9-compound subset of the X23 molecular crystals. Each requirement here is tagged with the table(s) it gates and the count of compounds that become runnable when it lands.

Conventions

  • P0: hard blocker for ≥10 compounds in the test set.

  • P1: blocker for 1-10 compounds, or for cross-method validation.

  • P2: nice-to-have / faithful reproduction of CRYSTAL workflow.

  • vibe-qc state originally audited on commit 2c7c7df of basissetdev; refreshed 2026-05-13 on commit 1bf32cc.

  • Feature counts below are conservative — orthorhombic is the most permissive cell shape vibe-qc currently handles.

Test-set overview

Source

Table

Cell shape

Compounds

Listed

PT2013

T4

cubic

12

LiCl, NaCl, LiF, NaF, KF, CaF₂, K₂O, MgO, CaO, LiH, NaH, KH

PT2013

T5

hexagonal

10

BeF₂, ScCl₃, MgBr₂, BeO, α-SiO₂, B₂O₃, Al₂O₃, NaNO₃, MgCO₃, FePO₄

PT2013

T6

orthorhombic

5

BeBr₂, NaNO₂, CaH₂, CrCl₂, GeSe

PT2013

T8

cubic semiconductor

22

C(diamond), Si, Ge, AlP, AlN, Na₂Se, GaAs, GaP, ZnS, MnSe, ZnSe, β-BN, β-SiC, TiC, Cu₃N, VC, VN, TiN, CrN, K₂S, MnS

PT2013

T9

hexagonal semicond.

9

NiAs, α-SiC, α-BN, B₄C, ScB₂, CoS, CuS, GaF₃, GeO₂

PT2013

T10

cubic TM oxide

7

Sc₂O₃, MnO, FeO, CoO, NiO, Cu₂O, ZnCr₂O₄

PT2013

T11

hexagonal/tetragonal TM oxide

4

V₂O₃, Cr₂O₃, ZnO, TiO₂(rutile)

PT2013

T12

cubic metal

11

Li, Na, K, Ca, Sc, V, Cr, Fe, Ni, Cu, Al, Ni₃Al

PT2013

T14

HF cubic ionic

12 (subset of T4 + K₂S)

LiCl, NaCl, LiF, NaF, KF, CaF₂, K₂O, MgO, CaO, LiH, NaH, KH

VO2019

T2

cubic ionic

14

+ KBr, SiF₄

VO2019

T3

hexagonal ionic

10

(overlap with PT2013 T5)

VO2019

T4

orthorhombic ionic

4

NaNO₂, CaH₂, CrCl₂, GeSe

VO2019

T6

cubic semicond.

14

(subset of PT2013 T8)

VO2019

T7

hex semicond.

9

(subset of PT2013 T9)

VO2019

T9

cubic TM oxide

7

(overlap with PT2013 T10)

VO2019

T10

hex/tet TM oxide

5

+ TiO₂(anatase)

VO2019

T14

molecular crystal

9

from X23 — dispersion-dominated

VO2019

Figs 2–7

molecular hydride dimer

~30

H_n A–AH_n at 1.4–5 Å, A=Li–Br

Total unique compounds: ≈75. Counted by cell shape: roughly 40 cubic, 20 hexagonal, 10 orthorhombic/tetragonal, plus the molecular-crystal subset.

Hard requirements

R1 — Non-orthorhombic Ewald [P0]

The current ewald_j / periodic_*_ewald family rejects any cell that is not strictly orthorhombic, because the FFT Poisson solver indexes the real-space grid by Cartesian (a×b×c) box dimensions. Hexagonal, trigonal, and tetragonal cells with non-orthogonal a/b or a/c are refused at SCF entry with:

“system lattice must be orthorhombic (FFT Poisson solver does not yet support triclinic cells).”

The test-set fraction that requires non-orthorhombic Ewald:

  • Hexagonal: PT2013 T5 (10), PT2013 T9 (9), PT2013 T11 (3), VO2019 T3 (10), VO2019 T7 (9), VO2019 T10 (4) — ≈32 unique compounds blocked.

  • Tetragonal: TiO₂(rutile), TiO₂(anatase) — 2 compounds.

Acceptance: run_rhf_periodic_multi_k_ewald3d accepts hexagonal (a, b=a, c, α=β=90°, γ=120°) cells; total energy on α-Al₂O₃ (R-3c) at experimental geometry agrees with PySCF.pbc.GDF to 100 µHa per formula unit. Tetragonal (P4/mmm and P4₂/mnm spacegroups) covered by the same fix.

Note for kpoints.py: the hexagonal/trigonal Γ-centring guard is already in place; the work is on the Poisson side. No changes to the k-mesh API required.

R2 — Multi-k MP-grid SCF on production basis sizes [P0]

Status as of 2026-05-13: partially landed.

Native GDF backend live: periodic_rhf_gdf.py (Γ-only), periodic_k_gdf.py (multi-k), periodic_gdf_blocks.py (Bloch assembly from lattice blocks). The in-process PySCF periodic backend was retired (commits 545db04 / 7ab9384) — manifest § 10 now forbids importing PySCF inside vibe-qc; parity testing against PySCF happens out-of-process via examples/regression/ runner_pyscf.py. The CaF₂ pob-TZVP RKS-PBE CRYSTAL14 regression fixture (e46211c) is the first cubic-ionic parity test exercising basissetdev’s .d12 sidecar pipeline (Phase 14h).

Already landed in the multi-k path:

  • smearing_temperature Fermi-Dirac occupations (periodic_rhf_multi_k_ewald.py lines 33-34, 156, 445; periodic_k_gdf.py line 76). Unit-bearing strings (“0.01 Ha”, “300 K”) accepted via the GDF gamma path (7eacfd3). Free energy with E - T·S correction surfaced in the result bundle (periodic_rhf_gdf.py line 548).

  • fock_mixing (CRYSTAL FMIXING-equivalent) wired through both Γ-GDF and multi-k. Validation against MgO PBE/POB-TZVP CRYSTAL14 totals via examples/regression (commit 7c02666).

  • Low-dimensional MP meshes (1D / 2D systems) accepted by the legacy path (f4d95f9).

  • Periodic dimensionality is logged in GDF jobs (56fd2e7).

Still open:

  • Validation against CRYSTAL k-mesh density at production sizes. PT2013 / VO2019 use Pack-Monkhorst grids around 8×8×8 for rocksalt ionics, 4×4×4 for the larger sesquioxides. vibe-qc tests have so far focused on small (2×2×2 to 4×4×4) grids; the linear-system size at full pob-TZVP × 8×8×8 is unmeasured. The Phase-14h .d12 sidecars now make this measurable: same compound, same basis, same k-mesh, on both codes via vq. Bench needed.

  • Smoke test on metallic Cu (FCC, T12). Smearing is in; the metal-specific SCF flow at production size hasn’t been benchmarked. T12 metals (Li, Na, K, Ca, Sc, V, Cr, Fe, Ni, Cu, Al, Ni₃Al) inherit any remaining issues.

Acceptance: MgO total energy at Γ + 8×8×8 Pack-Monkhorst with pob-TZVP/PW1PW agrees with PT2013 SI Table 1 (E = −275.477 595 Ha per cell) to 1 mHa. Metallic Cu (FCC) converges with smearing σ = 0.01 Ha and reproduces the 2013 Table 12 lattice constant (3.506 Å) to 0.01 Å.

Reuse, don’t duplicate. Shared mixing helpers (validate_fraction_01, mix_fock_matrices) in cpp/include/vibeqc/scf_mixing.hpp are the canonical implementation across molecular + periodic, per manifest § 10. Any new basissetdev SCF-control work plugs into this header.

R3 — Stable open-shell UKS / UHF for transition-metal oxides [P0]

Status as of 2026-05-13: still blocked. No change since the 2026-05-08 audit; the broken-symmetry initial guess for AFM ground states has not landed. Basissetdev’s Goal 3 ships the 6 AFM-II compounds (MnO, FeO, CoO, NiO, α-MnS, α-MnSe) as BLOCKED ON: R3 stubs — their .py inputs are wired so the moment R3 lands, only the initial-guess hook needs filling in. The .d12 sidecars (Phase 14h) skip emission for AFM compounds since the CRYSTAL ATOMSPIN block requires the same magnetic- ordering decision; both emit when R3 + ATOMSPIN-aware generator support land together.

The multi-k UKS (periodic_uks_multi_k_ewald.py) and UHF (periodic_uhf_multi_k_ewald.py) modules exist. The blocker is not the kernel but the initial-guess strategy for antiferromagnetic ordering. Currently both default to Hcore → identical α/β densities → SCF converges to the closed-shell solution by symmetry. This is the wrong basin for AFM systems.

Compounds blocked (counted once across PT2013 + VO2019): MnO, FeO, CoO, NiO (T10/T9), Cr₂O₃, V₂O₃ (T11/T10), CrCl₂ (T6/T4), CrN, MnS, MnSe (T8/T6) — 10 transition-metal compounds.

Acceptance: broken-symmetry initial guess (Mulliken-localised single-atom UKS densities tiled into the AFM unit cell, optionally with a small spin-symmetry-breaking field on the magnetic sublattice). NiO total energy with pob-TZVP/PW1PW reproduces PT2013 SI Table 1 (−3167.495 768 Ha per cell, two formula units in the AFM-II unit cell) to 1 mHa.

R4 — PW1PW hybrid functional [P0]

PW1PW is the workhorse functional for PT2013 and VO2019. It is the 1-parameter global hybrid of Bredow & Gerson (T. Bredow, A. R. Gerson, Phys. Rev. B 61, 5194 (2000), DOI 10.1103/PhysRevB.61.5194), originally introduced as the “HF+PWGGA hybrid approach” in §III.D of that paper. The mixing α = 0.20 was empirically optimised on MgO / NiO / CoO bulk properties and coincidentally matched the B3LYP exchange-mixing fraction. The “PW1PW” name came into use in subsequent CRYSTAL-community papers (Peintinger 2013 onward).

Definition:

  • E_x = 0.20 · E_x^HF + 0.80 · E_x^PW91

  • E_c = E_c^PW91

Where PW91 = Perdew-Wang 91 GGA (libxc IDs XC_GGA_X_PW91 = 109 and XC_GGA_C_PW91 = 134). The hf_exchange_fraction mechanism in periodic_rks_multi_k_ewald.py already supports α = 0.20 mixing; what’s missing is the named entry in vibe-qc’s functional registry that resolves "PW1PW" to this triplet. Status 2026-05-13: still missing — no registry alias landed since the audit. The 33 .d12 parity sidecars in Phase 14h currently emit the no-DFT (HF) form; once PW1PW resolves, the generator just flips method="pw1pw" and CRYSTAL’s PW1PW keyword does the matching parity run.

Note: PW1PW is distinct from PBE0 (PBE-based hybrid, α = 0.25), B3LYP (three-parameter Becke88 + LYP + VWN5), and plain PW91 (no HF mixing). Do not silently substitute any of these for PW1PW in benchmarks against the pob SI tables.

Acceptance: functional="PW1PW" resolves to the Bredow-Gerson hybrid with α = 0.20 and PWGGA (X + C) DFT components. RKS total energy on MgO with pob-TZVP at converged k-mesh equals PT2013 SI Table 1 (E = −275.477 595 Ha per cell) to 1 mHa. (Without R1+R2 this is testable only for cubic ionics and TM oxides.)

The Bredow-Gerson 2000 paper additionally benchmarks HF+LYP, HF alone, B3LYP, BLYP, PBE, and plain PWGGA on MgO / NiO / CoO. If the periodic chat wants a smaller cross-validation acceptance target, the seven-functional comparison from that paper’s Tables I–IV is a clean test fixture: ≈30 (compound × functional) data points at known geometry. PDF reference: /private/tmp/bredow2000.pdf on the user’s machine; user-shipped 2026-05-08.

R5 — Geometry optimisation in periodic [P0]

Status as of 2026-05-13: still blocked. Gradients are present and have been extended (RKS gradients, periodic_gradient_rks.py; open-shell gradients, periodic_gradient_open_shell.py; multi-k gradients, periodic_gradient_multi_k.py), but no atom-or-lattice relaxation driver. Phase 14h .d12 sidecars fix the lattice at the experimental value so the parity test isn’t also gated on this requirement.

The molecular path has _optimize_geometry (runner.py); the periodic path has gradients (periodic_gradient*.py) but no relaxation driver. Every line of every pob-paper table is a relaxed geometry: lattice parameters and atomic positions are optimised against the basis. Without relaxation, comparison to the paper tables is impossible.

Two flavours needed:

  1. Atomic-position-only relax at fixed lattice. Required for T5/T6/T9/T10/T11/T8 (anything with internal coordinates), ≈40 compounds.

  2. Lattice + atomic-position simultaneous relax. Required for every cell in the test set, ≈75 compounds.

Acceptance: wrap the existing periodic-gradient drivers behind an ASE BFGS / FIRE optimiser that updates both atomic positions and the lattice tensor. NaCl (Fm-3m) with pob-TZVP/PW1PW relaxes from 5.5 Å starting cell to 5.609 ± 0.005 Å (PT2013 Table 4), atomic positions stay at (0, 0, 0) and (½, ½, ½) by symmetry.

For the lattice-tensor side, the stress tensor is the natural primitive but is currently not in vibe-qc (memory: deferred to v0.8). A first cut can use finite-difference lattice gradient (perturb each lattice parameter by ε, recompute total energy, divide) and feed that to the BFGS optimiser. Slower than analytical stress but unblocks the test set.

R6 — Counterpoise / BSSE for periodic crystals [P1]

VO2019’s central novelty is the BSSE-aware re-optimisation. They use CRYSTAL’s ATOMBSSE to compute the per-atom counterpoise correction in a periodic crystal (ghost-atom basis on the heavy atom, no nuclei, no electrons, in the otherwise-real lattice).

vibe-qc has no equivalent yet. To reproduce VO2019 numbers, needed; to use the rev2 basis sets, not strictly needed (the basis already incorporates the BSSE-aware exponent shift).

For Goal 4 of basissetdev (re-running the rev2 optimisation in vibe-qc), counterpoise IS required as part of the objective function. Hence P1 not P0.

Acceptance: ghost_atoms=[(symbol, position), …] parameter on PeriodicSystem that places basis functions but no nuclei / no electrons. NaH ATOMBSSE matches CRYSTAL within 1 mHa.

Cross-method validations

R7 — Functional zoo: PBE, PBE0, B3LYP, BLYP, HSE [P1]

PT2013 and VO2019 cite cross-validation against B3LYP and PBE0 in side notes. vibe-qc’s libxc-based functional registry should already accept these strings (the runner advertises them). What’s missing is end-to-end verification at converged k-mesh + multi-k SCF for the cubic ionic subset (which is the easy 12-compound benchmark). Listing here so the periodic chat doesn’t deprioritise.

Acceptance: the 12 cubic ionics from PT2013 T4 run with PBE, PBE0, B3LYP, BLYP, HSE06 (each), in addition to PW1PW.

R8 — Wu-Cohen GGA (WC) [P2]

WC (XC_GGA_X_WC = 118; correlation typically PBE) is used in PT2013 for the metallic systems (preliminary basis-set optimisation). Easy to add — libxc has it; the question is the registry alias.

Acceptance: functional="WC" resolves to WC-X + PBE-C.

Numerics & screening

R9 — TOLINTEG-equivalent screening control [P1]

linear_dependence.py and eigs_preflight.py already point at LatticeSumOptions.schwarz_threshold as the TOLINTEG-equivalent knob. PT2013 explicitly mentions ITOL5 = 27 (vs default 14) for ionic SCF convergence — i.e. extremely tight Coulomb-tail screening. Need to verify schwarz_threshold covers ITOL4 (Schwarz two-electron) AND ITOL5 (penetration / overlap-based truncation distance). If they’re conflated in vibe-qc, surface separately.

Acceptance: running the sulfide subset (ZnS, MnS, K₂S, CoS, CuS) with default screening converges; bumping the equivalent of ITOL5 to 27 closes any residual SCF oscillation.

R10 — Atomic-reference HF energies for cohesive / atomization [P1]

PT2013 Table 13 reports atomization enthalpies. To compute these you need (a) the periodic total energy and (b) the isolated-atom total energy in the same basis. The molecular path handles (b) at the symmetry-broken UHF level; the question is exposing a single-atom reference path that accepts a Mulliken-style fractional- occupation specification (atoms in PT2013 are computed with “neutral atomic configurations from our website” — the .single files in the Bredow archive).

Acceptance: vq.atomic_reference_energy(symbol, basis, configuration="neutral") returns the SCF energy for the open-shell atom with the published occupation, for every element in pob-TZVP.

Lower-priority polish

R11 — D3(BJ) for periodic [P2]

dispersion.py exists in molecular path. VO2019 Table 14 applies D3(BJ) on top of pob-TZVP / pob-TZVP-rev2 for the X23-subset molecular crystals; the deltas drive ≈2-3 % lattice-constant improvements. Periodic D3 is an additive post-SCF step on the relaxed geometry — needs lattice summation of the C₆/C₈ pairs but no SCF intrusion.

Acceptance: ZnO + D3(BJ) with pob-TZVP-rev2 reproduces VO2019 Table 14 D3-corrected c to 0.01 Å.

R12 — ATOMBSSE for the molecular hydride dimers [P2]

The 2019 BSSE-correction recipe uses molecular counterpoise on H_n A–AH_n dimers (computed in ORCA 3.0 with MP2). vibe-qc’s molecular DF MP2 was wired in v0.7.3. A native vibe-qc version of this step is needed for Goal 4 (re-running the rev2 optimisation without external ORCA dependencies).

Acceptance: counterpoise(H₂O)₂ at 2.5 Å with vibe-qc/MP2 matches ORCA 3.0 MP2 to 1 mHa.

Out of scope here (other chats / future versions)

  • Periodic stress tensor. Memory: reserved for vibe-qc v0.8. Once landed, R5 lattice opt becomes analytical instead of FD.

  • Slab / surface support. Same: v0.8 deliverable.

  • AutoAux periodic aux basis. Owned by the DF dev chat (memory: feedback_aux_basis_routing.md).

  • CCM / cyclic-cluster method. Memory: deferred to a later vibe-qc version.

Suggested implementation order

The order that unblocks the most of the test set per landed feature:

  1. R5 atomic-position relax + R4 PW1PW + R7 functional verification → unlocks 12 cubic ionics from PT2013 T4 + 12 cubic ionics from VO2019 T2 (overlap) + 22 cubic semiconductors from PT2013 T8 + 7 cubic TM oxides from PT2013 T10 = ≈40 compounds runnable.

  2. R3 broken-symmetry UKS guess → unlocks the 10 TM oxide / chloride / nitride compounds.

  3. R1 non-orthorhombic Ewald → unlocks the 32 hexagonal/ tetragonal compounds. Big single-feature payoff.

  4. R5b lattice relax (FD lattice gradient) → enables the actual lattice-constant comparison vs. paper tables for everything above.

  5. R2 metallic k-mesh smearing → unlocks the 12 cubic metals.

  6. R6 ATOMBSSE periodic + R12 molecular counterpoise → unlocks the rev2 re-optimisation pipeline for Goal 4.

Status table (as of refresh on 1bf32cc, 2026-05-13)

Req

Title

State

R1

Non-orthorhombic Ewald

MISSING

R2

Multi-k MP-grid SCF

partial — native GDF + smearing + FMIXING landed; production-size CRYSTAL14 parity bench outstanding

R3

Open-shell UKS for AFM TM oxides

partial — kernels exist, BS guess still missing

R4

PW1PW hybrid functional

partial — hf_exchange_fraction exists, registry alias still missing

R5

Periodic geometry / lattice optimisation

MISSING — gradients exist (RKS / open-shell / multi-k), no relax driver

R6

Counterpoise / BSSE periodic

MISSING

R7

PBE/PBE0/B3LYP/BLYP/HSE verification

partial — registry exists, end-to-end untested at production size

R8

WC GGA functional

partial — libxc has it, registry alias TBD

R9

TOLINTEG-equivalent screening control

partial — schwarz_threshold exists, ITOL4/5 conflation TBD

R10

Atomic-reference HF for atomisation

partial — molecular UHF works, fractional-occ wrapper missing

R11

D3(BJ) for periodic

partial — molecular path exists, periodic glue missing

R12

ATOMBSSE molecular dimer

partial — molecular MP2 works, counterpoise glue missing

Shared infrastructure now in main (basissetdev reuses, never duplicates)

Header / module

Provides

Notes

cpp/include/vibeqc/scf_mixing.hpp

validate_fraction_01, mix_fock_matrices

Canonical Fock-mixing primitives; molecular UHF/UKS + periodic GDF/Ewald all dispatch here.

python/vibeqc/periodic_rhf_gdf.py

Γ-only RHF GDF backend

Native; no PySCF runtime dependency.

python/vibeqc/periodic_k_gdf.py

Multi-k GDF

Cubic / orthorhombic / low-dim lattice families covered.

python/vibeqc/periodic_gdf_blocks.py

Bloch assembly from lattice blocks

Underpins both Γ and multi-k.

examples/regression/runner_pyscf.py

Out-of-process PySCF parity

Manifest § 10: PySCF is external; vibe-qc never imports it.

examples/basisset_dev/inputs/*.d12 (Phase 14h)

CRYSTAL14 parity sidecars

33 cubic ionic / semiconductor / TM-compound .d12 decks; runs out-of-process via vq submit + run-crystal.sh (memory: reference_crystal14_via_vq.md).

Hand-off note

This document is the deliverable from basissetdev to the periodic-methods chat. It does not prescribe how each requirement is implemented; that is the periodic chat’s call. When a requirement lands, mark it ✅ here and update PLAN.md Goal 2 status. basissetdev rebases onto main after each landing.