Basis-set library
Two Gaussian basis-set sources back the Basis column of
data/IBM_VQE_Test_Benchmark.csv (and any future VQE benchmark scenario):
the real Basis Set Exchange (BSE) for
the six standard fixed bases, and Grimme group’s
q-vSZP for the charge-adaptive one
— both real and independently usable without ORCA. Typed Pydantic
schemas live in src/qpubench/schemas/catalogs/basis_sets.py; the loaders live in
src/qpubench/hamiltonian_sources/basis_set_exchange.py and
src/qpubench/hamiltonian_sources/qvszp.py — same
core-never-imports-a-quantum-library boundary as hamiltonian_library.py
vs. hamiltonian_sources/hamlib.py.
Installation
pip install 'qpubench[bse]' # Basis Set Exchange
pip install 'qpubench[qvszp]' # q-vSZP downloader (just `requests`)
basis_set_exchange bundles its own basis-set data in the wheel — no
network access needed at runtime. qvszp downloads directly from
github.com/grimme-lab/qvSZP and caches locally (same pattern as
hamlib.py).
Basis Set Exchange — real, verified
from qpubench.hamiltonian_sources.basis_set_exchange import (
count_basis_functions, get_basis_set_entry, list_available_elements,
)
entry = get_basis_set_entry("cc-pvdz") # confirms it's real via bse.get_metadata()
elements = list_available_elements("sto-3g") # ['H', 'He', 'Li', ...]
n = count_basis_functions("def2-tzvp", "O") # 31 — spatial AO functions
count_basis_functions() computes real spherical-harmonic AO counts from
BSE’s own shell data and was cross-checked in this session against real
pyscf.gto.M(...).nao for every (element, basis) pair in
data/IBM_VQE_Test_Benchmark.csv — exact match in all 18 cases (H, Li, O
× sto-3g/6-31g/cc-pvdz/cc-pvtz/def2-svp/def2-tzvp), see
tests/test_basis_sets.py. Two real BSE shell shapes are handled
correctly, not just the simple case: general-contraction shells (one l,
several contracted columns — e.g. cc-pVDZ’s 3 s-type contractions on O)
and combined SP/SPD shells (several ls, one column each — e.g. 6-31G’s
combined SP shell on Li).
BASIS_SET_CATALOG covers the six standard bases currently in the
benchmark CSV:
| Name | Family | Cardinality | Polarization |
|---|---|---|---|
sto-3g |
minimal | 1 | no |
6-31g |
Pople | 2 | no |
cc-pvdz |
Dunning correlation-consistent | 2 | yes |
cc-pvtz |
Dunning correlation-consistent | 3 | yes |
def2-svp |
Karlsruhe def2 | 2 | yes |
def2-tzvp |
Karlsruhe def2 | 3 | yes |
q-vSZP — real, verified via its own data files (ORCA NOT required)
Correction (2026-07-09): an earlier version of this doc claimed q-vSZP
had no offline representation at all, and that ORCA + the Fortran CLI
were required just to know its composition. That was wrong — caught by
actually downloading and parsing the real files in
q-vSZP_basis/
rather than only reading the top-level README.
What’s actually there — five real, plain-text files, no ORCA/Fortran needed to read any of them:
| File | QvSZPVariant |
What it is |
|---|---|---|
basisq |
FULL |
Complete q-vSZP basis, Z=1-103 |
basisq_lesspolfunc |
NO_POLARIZATION |
Polarization shell dropped |
basisq_gxtb |
GXTB |
Smaller basis matched to the g-xTB charge model |
ecpq |
— | Effective core potentials, Z=3-103 (ncore=2, i.e. the 1s core) |
basis_qvSZP_CP2K_format |
— | The FULL basis, pre-converted, directly usable as a CP2K BASIS_SET file |
The key fact that makes this usable offline: each primitive row carries two coefficient columns — a charge-independent base value and a linear-in-charge slope for the same function, not two separate functions. Only the coefficient values are charge-dependent; the number of shells/functions per element is fixed. This is confirmed directly by the CP2K file’s own header comment:
“The source basis carries charge/environment-dependent coefficient columns. CP2K BASIS_SET files are static, so this file uses the first contraction coefficient column.”
i.e. CP2K’s own maintainers already treat q-vSZP this way — a static,
q=0-reference basis, no per-molecule regeneration step, no ORCA.
from qpubench.hamiltonian_sources.qvszp import (
count_basis_functions, ecp_core_electrons, get_cp2k_format_text,
)
from qpubench.schemas.catalogs.basis_sets import QvSZPVariant
count_basis_functions("Li") # 9 (1s + 1p + 1d)
count_basis_functions("H", QvSZPVariant.GXTB) # 1 (s only)
ecp_core_electrons("Li") # 2 (1s core replaced)
ecp_core_electrons("H") # None (all-electron)
cp2k_basis = get_cp2k_format_text() # ready to drop into a CP2K &BASIS_SET
count_basis_functions() is verified in this session against a live
download+parse of the real basisq file, cross-checked against the
independently-generated CP2K file (identical shell composition), and
against ecpq’s real element coverage — see tests/test_qvszp.py.
Real per-element function counts, FULL variant:
| Element | Shells | Functions | ECP core |
|---|---|---|---|
| H | 1s + 1p | 4 | none (all-electron) |
| Li | 1s + 1p + 1d | 9 | 2 (1s) |
| O | 1s + 1p + 1d | 9 | 2 (1s) |
This also corrected a real error in the original benchmark CSV draft: its
qvSZP/Li2 qubit count was 34, which is impossible for a homonuclear
diatomic (34 spin-orbitals implies 17 spatial orbitals total, an odd
number that can’t split evenly across two chemically-equivalent Li
atoms). The real value, from the data above, is 2 x 9 x 2 = 36.
What’s still genuinely CLI/tool-only
Producing the true, molecule-specific charge-adapted coefficients (the
actual q-vSZP method, not the static q=0 reference used above) — and
writing ORCA-ready .basisq/.ecpq files for a specific molecule — still
needs either the real Fortran CLI (build from source via FPM; no PyPI
package) or a from-scratch GFN2-xTB charge calculation via tblite
(pip-installable, ORCA-independent) plus reimplementing the
charge-interpolation formula. That specific step remains schema-only here
(QvSZPRunConfig/QvSZPBasisResult), same “container, not solver”
boundary as pyscf.ProjectionEmbeddingConfig/DMETConfig
(PsiEmbed/libDMET):
from qpubench.schemas.catalogs.basis_sets import QvSZPRunConfig, QvSZPVariant
config = QvSZPRunConfig(
structure_file="h2o.xyz",
variant=QvSZPVariant.FULL, # or NO_POLARIZATION / GXTB
)
# write your own adapter around the real `qvSZP` CLI (or a real tblite
# GFN2-xTB charge calculation) to produce a real QvSZPBasisResult with
# molecule-adapted coefficients — nothing here calls either for real.
But basis-function/qubit counts, element coverage, and a usable static
basis (including for CP2K directly) do not need any of that — use
hamiltonian_sources.qvszp instead.
Why not just PySCF’s built-in basis strings?
pyscf.gto.M(basis=...) already accepts any of the six BSE names directly
(and is what hamiltonian_sources/ab_initio.py uses) — this module isn’t
a replacement for that. It exists for what PySCF’s string argument doesn’t
give you: a catalogue you can enumerate/validate a Basis CSV column
against, element coverage per basis, and real q-vSZP support (which PySCF
has no built-in knowledge of at all).