Changelog

All notable changes are collected here. Format loosely follows Keep a Changelog. Until vibe-qc cuts its first tagged release, every change lands on the main branch and is rolled up into the [Unreleased] block below.

[Unreleased]

Added

  • Phases 18 + 19 — atomic charges, bond orders, dipole moment. Every run_job .out file now appends a properties block with Mulliken and Löwdin atomic charges, Mayer bond orders (filtered to pairs with B_AB 0.10 for compactness), and the molecular dipole moment in both atomic units (e·bohr) and Debye, with the centre of mass as the default origin. Public Python API: :func:vibeqc.mulliken_charges, :func:vibeqc.loewdin_charges, :func:vibeqc.mayer_bond_orders, :func:vibeqc.dipole_moment (returning :class:vibeqc.DipoleMoment), :func:vibeqc.center_of_mass, and the lower-level :func:vibeqc.compute_dipole / :class:vibeqc.DipoleIntegrals. format_scf_trace grows basis= and include_properties= keywords. Verified against PySCF: Mulliken charges and dipole-moment components on H₂O / 6-31G* agree to better than 1e-6. 17 new tests; full suite 381 passing.

  • Phase P1.1 — gradient parallelism + thread-count control + timing reports. All five shell-quartet loops in cpp/src/gradient.cpp (overlap, kinetic, nuclear, two-electron RHF, two-electron UHF) now run under OpenMP via the thread-local-gradient-with-post-reduce pattern — closing the remaining P1 gap so analytic gradients scale on multi-core hardware. New public API: :func:vibeqc.get_num_threads, :func:vibeqc.set_num_threads (with n <= 0 meaning “restore default” — either OMP_NUM_THREADS or the hardware core count). run_job grows a num_threads= keyword; every .out file records the actual thread count used plus a wall-clock timing block summarising SCF total, per-iteration average, geometry-optimisation time (if any), and job total. 7 new tests cover the thread API and timing.

  • Phase 12e-c-2 — erfc-screened ERIs for the short-range Ewald J/K. build_jk_gamma_molecular_limit and build_fock_2e_real_space grow an optional omega parameter (default 0.0). When positive, the builders swap libint’s Operator::coulomb for Operator::erfc_coulomb with screening parameter ω, producing the short-range piece of the Ewald split for 3D bulk. Matching long-range piece (reciprocal-space Hartree, FFTW-accelerated) lands in 12e-c-3. 10 new tests cover the ω → 0 / ω → ∞ limits, monotone decrease in ω, and the J(0) = J_short(ω) + J_long(ω) decomposition consistency.

  • Phase 12e-c-1 — Gaussian-charge Ewald for V(g) via grid integration. First sub-phase of the full 3D Ewald stack. New public API: :func:vibeqc.ewald_point_charge_potential (Ewald-summed Coulomb potential of a periodic lattice of point charges, with optional short/long-range decomposition), :func:vibeqc.ewald_nuclear_potential (convenience wrapper for electronic attraction), and :func:vibeqc.compute_nuclear_lattice_ewald (full V_μν(g) via analytical erfc short-range (libint’s erfc_nuclear, Phase 12e-b) plus numerical grid integration of the smooth erf long-range part). α-invariant to ~1e-4 Ha across the working range of α. Not yet dispatched by compute_nuclear_lattice; callers that want the Ewald V must invoke it directly. Full EWALD_3D dispatch with the ERI Coulomb (J-term) Ewald, Saunders–Dovesi multipolar splitting, and FFTW3 acceleration follow in 12e-c-2 and 12e-c-3.

  • Phase P2 — memory estimator + pre-flight abort. Every compute-heavy driver now surfaces an upper-bound peak-memory estimate before the SCF starts, printed to the run log as

    vibeqc estimates this calculation will require ~12.4 GB of memory:
        ERI tensor       11.6 GB
        ...
    Available on this machine: 119.8 GB. Proceeding.
    

    When the estimate exceeds available RAM, run_job aborts with :class:vibeqc.InsufficientMemoryError; users can set memory_override=True on the run_job call to proceed anyway (the block then shows Proceeding (override)). New public API: :class:vibeqc.MemoryEstimate, :class:vibeqc.InsufficientMemoryError, :func:vibeqc.estimate_memory, :func:vibeqc.check_memory, :func:vibeqc.available_memory_bytes, :func:vibeqc.format_memory_report. Estimators cover RHF / UHF / RKS / UKS / MP2 / UMP2; the available_memory_bytes probe tries psutil first (optional dep), then falls back to /proc/meminfo (Linux) and os.sysconf (macOS). 22 new tests.

  • Phase P1 — OpenMP shared-memory parallelism. Single-node multithreading lands on every compute-heavy kernel: molecular 1e and 2e integrals (compute_overlap, compute_kinetic, compute_nuclear, compute_eri), the molecular Fock builder (build_fock_g, build_coulomb, build_exchange), periodic one-electron lattice sums (compute_overlap_lattice, compute_kinetic_lattice, compute_nuclear_lattice, compute_nuclear_erfc_lattice), the Γ-only and multi-k periodic Fock builds (build_jk_gamma_molecular_limit, build_fock_2e_real_space), the Ewald real-space and reciprocal-space loops, and AO evaluation on DFT grids (evaluate_ao, evaluate_ao_with_gradient, evaluate_ao_with_hessian). Thread-safe via a one-engine-per-thread pool in cpp/include/vibeqc/thread_pool.hpp. Controlled by OMP_NUM_THREADS; no API change, all 320 regression tests pass unchanged. Benchmark harness in scripts/bench.py reports scaling across a sweep of thread counts. Analytic gradients and the SAD initial guess remain single-threaded for now — a follow-on P1.1 pass.

  • Phase 12e-a — classical Ewald for point-charge Madelung energies. New public API: vibeqc.EwaldOptions, vibeqc.ewald_point_charge_energy, vibeqc.ewald_nuclear_repulsion. CoulombMethod.EWALD_3D dispatches nuclear_repulsion_per_cell through the Ewald engine. Validated against literature Madelung constants for NaCl (1e-8), CsCl (1e-6), ZnS (1e-4), and simple-cubic jellium (1e-6); α-invariance holds to 1e-9 across α ∈ {0.2, 0.3, 0.5, 1.0}. See docs/user_guide/ewald.md.

  • Phase 12e-b — erfc-screened nuclear-attraction lattice sum as an Ewald building block. New public API: vibeqc.compute_nuclear_erfc_lattice(basis, system, omega, options). Wraps libint’s Operator::erfc_nuclear; exponentially convergent real-space sum for any ω > 0. Used by Phase 12e-c to assemble the full EWALD_3D dispatch of compute_nuclear_lattice.

  • Documentation — new docs/user_guide/ewald.md with math, references, and usage examples; API index updated with the new symbols and the Version & banner section added; roadmap and feature matrix reflect 12e-a/b shipped and the 12e-c / 12f / v0.3.0+ work ahead.

Limitations

  • EWALD_3D on the SCF-facing nuclear-attraction V(g) and the ERI Coulomb term J is not yet wired. Bulk 3D HF / DFT results remain cutoff-dependent until Phase 12e-c lands the reciprocal-space pieces and the Saunders–Dovesi multipolar splitting.

[0.1.0] — 2026-04-18

First tagged release. All subsequent releases will follow semantic versioning (pre-1.0: any minor bump may break API; 0.2.0, 0.3.0, … mark milestone achievements).

Added

  • Runtime banner printed at the top of SCF-trace output — shows vibe-qc version, MPL 2.0 attribution, and linked library versions (libint, libxc, spglib). Exposed as vibeqc.banner(), vibeqc.print_banner(), vibeqc.library_versions().

  • Documentation site (Sphinx + Furo + MyST) with installation guide, tutorial, feature matrix, roadmap, and autogenerated API reference.

  • MPL 2.0 license at the repository root.

  • CRYSTAL-format basis-set parser and NWChem/.g94 emitter (python/vibeqc/basis_crystal.py) for per-element CRYSTAL basis files.

  • Bredow-group pob- basis sets* fetched into basis_library/custom/: pob-TZVP (H–Br), pob-TZVP-rev2 (H–Br), pob-DZVP-rev2 (subset).

  • Phase 12d — multi-k periodic Kohn-Sham DFT (run_rks_periodic), LDA and pure GGA. Validated against molecular RKS in the molecular limit across dim ∈ {1, 2, 3} × {LDA, PBE, BLYP}.

  • Phase 12c — multi-k periodic RHF (run_rhf_periodic) with real-space density matrix and the general three-lattice-index direct-SCF Fock build.

  • Phase 12b — Γ-only periodic RHF (run_rhf_periodic_gamma) in the molecular-limit regime.

  • Phase 12a — periodic one-electron infrastructure: PeriodicSystem, lattice-summed S/T/V integrals, Bloch sums, Monkhorst-Pack k-mesh, IBZ reduction via spglib.

  • spglib integration (vibeqc.Crystal, analyze_symmetry, to_primitive) + minimal VASP 5 POSCAR I/O.

  • UMP2 — open-shell MP2 on a UHF reference, three spin channels.

  • RMP2 — closed-shell MP2 on an RHF reference.

Known limitations (being addressed)

  • 3D bulk Coulomb lattice sum is currently direct-truncated (conditional convergence). Proper Ewald splitting lands in Phase 12e.

  • Periodic DFT uses the molecular Becke weight partition; image-atom Voronoi cells may intrude on the reference unit cell for tight crystals. Proper periodic Becke partition lands in Phase 12f.

  • ECP basis sets (pob-* for Rb–I, Cs–Po, La–Lu) parse but cannot be used: applying them needs libecpint integration.

  • Hybrid periodic DFT implemented in the code path (via exchange_scale) but not yet validated end-to-end.

  • Periodic UKS not yet available.