Band structure and density of states¶
For periodic systems vibe-qc can sample a real-space Fock matrix on a
user-specified k-path (band structure) or on a Monkhorst–Pack mesh
(density of states), and the matching plotters in vibeqc.plot give
you publication-style figures with one call.
What you need¶
A real-space lattice Fock matrix F_real and overlap S_real
(vibeqc.LatticeMatrixSet). For non-interacting bands
(Hcore = T + V) helper functions build these for you, so the minimal
recipe is two lines:
import vibeqc as vq
system = vq.PeriodicSystem(
1, # 1D
[[6.0, 0, 0], [0, 30, 0], [0, 0, 30]], # lattice (bohr)
[vq.Atom(1, [0, 0, 0]), vq.Atom(1, [1.4, 0, 0])], # H2 per cell
)
basis = vq.BasisSet(system.unit_cell_molecule(), "sto-3g")
kpath = vq.kpath_from_segments(
system,
[((0.0, 0, 0), "Γ", (0.5, 0, 0), "X")],
points_per_segment=40,
)
bands = vq.band_structure_hcore(system, basis, kpath, n_electrons_per_cell=2)
dos = vq.density_of_states_hcore(system, basis, [80, 1, 1],
sigma=0.02, n_electrons_per_cell=2)
bands.energies is a (n_kpoints, n_bands) numpy array; dos.dos is
a 1D array on the auto-chosen energy grid dos.energies. Both objects
remember their Fermi level for the convenience of plotters.
Plotting¶
vibeqc.plot is a thin matplotlib layer (lazy import — vibe-qc itself
doesn’t depend on matplotlib):
from vibeqc.plot import bands_dos_figure
fig = bands_dos_figure(bands, dos, title="H2 chain (STO-3G)")
fig.savefig("h-chain.png", dpi=150)
You can also call band_structure_figure(bands) and dos_figure(dos)
on their own. All plotters accept units="eV" (default) or
"Hartree", and shift_to_fermi=True (default) puts E_F at zero.
Interacting bands from a converged SCF¶
band_structure_hcore only knows about T + V. For a self-consistent
Fock matrix you’d build F_real = T + V + J(D) − ½K(D) + V_xc(D)
yourself (vibe-qc doesn’t yet persist the converged real-space Fock on
PeriodicRHFResult/PeriodicKSResult) and pass it to
band_structure(F_real, S_real, kpath, …). Saving the converged Fock
is on the roadmap.
What’s exposed¶
vq.kpath_from_segments(system, segments, points_per_segment=30)
vq.band_structure(F_real, S_real, kpath, *, n_electrons_per_cell=None)
vq.band_structure_hcore(system, basis, kpath, *, n_electrons_per_cell=None)
vq.density_of_states(F_real, S_real, kmesh, *, sigma=0.01,
energy_grid=None, n_grid=401, pad=5.0,
n_electrons_per_cell=None)
vq.density_of_states_hcore(system, basis, mesh, *, sigma=0.01,
n_electrons_per_cell=None, …)
vq.BandStructure # dataclass: kpath, energies, e_fermi, …
vq.DensityOfStates # dataclass: energies, dos, sigma, e_fermi
vq.KPath # dataclass: kpoints_cart/frac, distances, labels
vq.plot.band_structure_figure(bs, …)
vq.plot.dos_figure(dos, …)
vq.plot.bands_dos_figure(bs, dos, …)
A complete worked example is in
examples/input-h-chain-bands.py.
Validation¶
tests/test_bands.py checks that:
the DOS integrates to
n_bands(each Gaussian has unit area, weights sum to one),band_structurereturns sorted eigenvalues at every k,the k-path tracks correct cumulative distances and that segments joined at shared endpoints don’t double-count points,
e_fermiis set only for closed-shell electron counts (open-shell band-structure interpretation requires α/β channels and is deferred).