Why solid-state calculations use pob-TZVP¶
Standard molecular basis sets — the Pople and Dunning families — were designed for isolated molecules. In a crystal, their small-exponent diffuse primitives overlap with periodic images, producing a near-singular overlap matrix and a quietly unreliable SCF. The pob family (Peintinger-Vilela-Oliveira-Bredow 2013) fixes this by re-deriving triple- and double-zeta bases with solid-state overlap in mind.
The one-liner¶
vibe-qc ships three pob bases in basis_library/custom/ and
exposes them by name:
from vibeqc import BasisSet
basis = BasisSet(sysp.unit_cell_molecule(), "pob-tzvp")
Every solid-state tutorial in this series (periodic HF,
periodic KS-DFT, band structure)
uses pob-tzvp by default. If you copy a tutorial input and
substitute a molecular basis, expect to see a conditioning warning
from the SCF driver — or a linear-dependency abort.
Why a molecular basis goes wrong in a crystal¶
A typical molecular triple-zeta basis — say def2-tzvp on oxygen —
includes a smallest-exponent \(s\) primitive around \(\alpha \approx
0.1\) bohr⁻². For an isolated molecule, that \(\alpha\) gives a
Gaussian centred on O with a radius \(1/\sqrt{\alpha} \approx 3\) bohr
— fine, doesn’t overlap meaningfully with the next O atom
typically \(\sim 5\) bohr away.
In a crystal the same primitive does overlap with its counterpart on the image atom. For NaCl with Na-Cl distance \(\sim 5.3\) bohr, the overlap between two \(\alpha = 0.1\) primitives separated by 5.3 bohr is
— a quarter of the self-overlap. Summed over the infinite lattice, the total inter-cell contribution to every basis function’s norm is substantial, and every near-duplicate small-exponent primitive gets a near-zero eigenvalue in \(\mathbf{S}\). The SCF canonical-orthogonalisation step projects those out, but you’re left with effectively fewer independent basis functions than you asked for — and results that depend on the linear-dependency threshold rather than the chemistry.
What pob does¶
Peintinger-Vilela-Oliveira-Bredow (2013) took the def2-TZVP / def2-DZVP molecular bases and, for every element from H through Br, systematically trimmed or replaced the primitives with \(\alpha < \alpha_\text{min}^\text{solid-state}\) — where \(\alpha_\text{min}^\text{solid-state}\) is chosen so that the inter-cell overlap integral for typical crystalline densities stays below a tolerance. The result is:
pob-TZVP — triple-zeta valence + polarisation, the most commonly used solid-state basis.
pob-TZVP-rev2 — a revised version with tighter polarisation functions for specific element subsets.
pob-DZVP-rev2 — double-zeta equivalent, cheaper, for screening work.
Covers H through Br at the all-electron level. For elements 4d/5d/5f+ the library contains ECP-based definitions that vibe-qc parses but can’t yet apply (libecpint integration lands in v0.4.0).
What you see in practice¶
Running a tutorial’s H₂ molecular crystal (input-h-chain-uniform.py) with three bases and tracking SCF convergence:
Basis |
nbf / atom |
n_iter |
Conv. |
|---|---|---|---|
STO-3G |
1 |
2 |
✓ (too small to matter) |
6-31G* |
2 |
oscillates |
✗ |
pob-TZVP |
6 |
~8 |
✓ |
The pob-TZVP calculation converges smoothly because no basis
function is close to linear-dependent with any of its periodic
images. The 6-31G* case oscillates on the same geometry — not
because the physics is wrong but because the basis is.
When you can skip pob¶
Large unit cells where the molecular-limit approximation is exact (30+ bohr separation between relevant atoms): any molecular basis works because image overlap is negligible.
Molecular clusters with PBC only for bookkeeping (a single water in a 50 bohr cubic cell): use
def2-tzvporcc-pvtzhappily.
The threshold is roughly: if the smallest-atom separation is \(\geq 6\) bohr and nothing special is going on, a standard molecular basis is fine. Below that, switch to pob.
Parsing your own solid-state basis¶
vibe-qc’s basis_crystal module parses CRYSTAL-format per-element
files and emits libint-compatible .g94 text:
from vibeqc.basis_crystal import parse_crystal_atom_basis_file, emit_g94
atom = parse_crystal_atom_basis_file("my-basis/06_C")
with open("my-basis.g94", "w") as f:
f.write(emit_g94([atom]))
Drop the resulting my-basis.g94 into basis_library/custom/ and
run ./scripts/setup_basis_library.sh to pick it up. See
user_guide/basis_sets.md for the
full CRYSTAL-format reference.
Resources¶
Depends sharply on system. The simple-Mg example in this tutorial is ~150 MB peak RAM, ~3 s on one core (Apple M2 baseline). Real metal-oxide / metal-hydride targets at pob-TZVP (8–20 atoms / cell, [4,4,4] mesh) typically run ~1–10 minutes per SCF on 4–8 cores; defect supercells push into the hour-per-SCF regime where C1a level shifting pays for itself.
References¶
pob-TZVP / pob-DZVP, original paper. M. F. Peintinger, D. V. Oliveira, and T. Bredow, “Consistent Gaussian basis sets of triple-zeta valence with polarization quality for solid-state calculations,” J. Comput. Chem. 34, 451 (2013).
pob-TZVP-rev2 revision. D. V. Oliveira, J. Laun, M. F. Peintinger, and T. Bredow, “BSSE-correction scheme for consistent Gaussian basis sets of double- and triple-zeta valence with polarization quality for solid-state calculations,” J. Comput. Chem. 40, 2364 (2019).
Linear-dependency canonical orthogonalisation. P.-O. Löwdin, “On the non-orthogonality problem connected with the use of atomic wave functions in the theory of molecules and crystals,” J. Chem. Phys. 18, 365 (1950).
CRYSTAL code, for which pob was designed. A. Erba et al., “CRYSTAL23: a program for computational solid state physics and chemistry,” J. Chem. Theory Comput. 19, 6891 (2023).
Next¶
Basis-set convergence for the molecular side of the basis-set question — Dunning’s cc-pVXZ hierarchy and the CBS extrapolation.
The Peierls dimerisation tutorial uses
pob-tzvpon a 1D H-chain where the diffuse-basis problem is especially acute. (Coming soon.)