Semiempirical Methods¶
vibe-qc ships a self-contained semiempirical platform covering four method families, DFTB, GFN-xTB, NDDO, and INDO, for molecules and periodic solids. The platform is vibe-qc’s own implementation, not a wrapper around external programs (External QC codes (ORCA / Psi4 / others)). The MACE machine-learning interatomic potential is documented separately because it is an external pre-trained model, not a semiempirical electronic-structure method (Machine-learning interatomic potentials (MACE)).
Warning
Production readiness varies by method. DFTB is intended for screening/preoptimization; GFN2-xTB is gated experimental; PM6, OM2 and OM3 are production for molecular work (PES shape pinned by regression, published-benchmark validation for OM2, see the status table); OM1 is experimental until its analytic core-valence ECP lands; MSINDO is reference-parity validated for its current molecular scope. See the status table and the comparative production brief in Semiempirical and MACE method comparison.
Method families¶
Family |
Methods |
Best for |
Cost |
|---|---|---|---|
DFTB |
DFTB0, SCC-DFTB, UDFTB0, USCC-DFTB |
Screening, preoptimization |
Fastest |
GFN-xTB |
GFN2-xTB |
Organic / main-group |
Fast |
NDDO |
PM6, OM1, OM2, OM3 |
Development benchmarking, pre-screening |
Fast |
INDO |
MSINDO |
Reference-parity molecular semiempirical runs inside the supported element/spin scope |
Fast |
Quick start¶
DFTB0, non-self-consistent tight-binding¶
from vibeqc.semiempirical import DFTB0Model
from vibeqc import Molecule, Atom
mol = Molecule([
Atom(8, [0.00, 0.00, 0.00]),
Atom(1, [1.55, 0.90, 0.00]),
Atom(1, [-1.55, 0.90, 0.00]),
])
model = DFTB0Model(mol)
print(f"Energy: {model.energy():.6f} Ha")
print(f"Gradient shape: {model.gradient().shape}") # (3, 3)
SCC-DFTB, self-consistent charges¶
from vibeqc.semiempirical import SCCDFTBModel
model = SCCDFTBModel(mol, charge_mixing=0.2)
print(f"Energy: {model.energy():.6f} Ha")
GFN2-xTB, published parameters (experimental)¶
from vibeqc.semiempirical import GFN2Model
from vibeqc.semiempirical.methods.gfn2_params import load_gfn2_params
params = load_gfn2_params() # auto-fetches 86-element Grimme parameter set
model = GFN2Model(mol, params=params, warn=False) # warn=False silences experimental gate
print(f"Energy: {model.energy():.6f} Ha")
Warning
GFN2-xTB is gated experimental. The H0/overlap deep-state
bug was fixed 2026-06-01, and molecular AES (dipole + quadrupole), the
GAM3 third-order term, and post-SCF native D4-style dispersion are now
implemented.
The remaining production gates are periodic AES image-cell multipole Ewald
terms, stricter periodic molecular-limit parity, difficult periodic/polar
fixtures, and a full external-parity matrix against xtb. See
Method status.
The post-SCF native D4 term is included for H, He, B, C, N, O, F, and Ne;
outside that reference-data set GFN2 returns zero D4 and emits
GFN2D4UnsupportedWarning.
PM6, NDDO with published parameters¶
from vibeqc.semiempirical import PM6Model
model = PM6Model(mol)
print(f"Energy: {model.energy():.6f} Ha")
OMx, orthogonalization-corrected NDDO¶
from vibeqc.semiempirical import OMxModel
model = OMxModel(mol, variant="om2") # "om1", "om2", or "om3"
print(f"Energy: {model.energy():.6f} Ha")
Through run_job¶
All seven methods are available via vibeqc.runner.run_job():
from vibeqc import run_job
run_job(mol, method="dftb0", optimize=True, output="h2o_dftb0")
run_job(mol, method="pm6", output="h2o_pm6")
run_job(mol, method="gfn2_xtb", output="h2o_gfn2") # emits experimental warning
Periodic systems¶
All families support Gamma-point periodic calculations with finite-difference gradients and stress.
DFTB periodic¶
from vibeqc._vibeqc_core import PeriodicSystem, Atom
from vibeqc._vibeqc_core import semiempirical as _se
import numpy as np
# 1D carbon chain
atoms = [Atom(6, [0.0, 0.0, 0.0])]
cell = np.diag([2.5, 30.0, 30.0])
system = PeriodicSystem(1, cell, atoms)
params = _se.SemiempiricalParameters.dftb0_default()
result = _se.run_dftb0_gamma(system, params)
print(f"Energy: {result.energy:.6f} Ha")
GFN2 periodic¶
from vibeqc._vibeqc_core.semiempirical import xtb as _xtb
from vibeqc.semiempirical.methods.gfn2_params import load_gfn2_params
params = load_gfn2_params()
result = _xtb.run_gfn2_xtb_gamma(system, params)
PM6 / OMx periodic¶
from vibeqc.semiempirical import PeriodicPM6Model, PeriodicOMxModel
pm6 = PeriodicPM6Model(system)
print(f"PM6: {pm6.energy():.6f} Ha")
omx = PeriodicOMxModel(system, variant="om2")
print(f"OM2: {omx.energy():.6f} Ha")
Preoptimization workflows¶
Use semiempirical methods for fast structure preoptimization before an expensive DFT calculation:
from vibeqc.semiempirical import preoptimize_periodic
# Preoptimize a periodic system with DFTB0, then run DFT
preoptimize_periodic(
system,
method="dftb0",
fmax=0.01,
)
For molecular systems, use optimize=True with run_job:
from vibeqc import run_job
# Preoptimize with DFTB0, then refine with DFT
run_job(mol, method="dftb0", optimize=True)
run_job(mol, method="rks", functional="PBE", basis="def2-svp", optimize=True)
Method status¶
Method |
Status |
Energy accuracy |
Gradient |
Periodic |
Open-shell |
Elements |
|---|---|---|---|---|---|---|
DFTB0 / UDFTB0 |
Screening/preopt |
In-house parameters, not DFTB+ parity |
Analytic |
Gamma + k |
yes |
91 in-house |
SCC-DFTB / USCC |
Screening/preopt |
In-house parameters, not DFTB+ parity |
Analytic |
Gamma + k |
yes |
91 in-house |
GFN2-xTB |
Gated experimental |
External xTB parity matrix still open |
Analytic (FD-consistent to <1e-5 Ha/bohr on H2O/CH4/NH3: full H0 shape + shell-ES + 3rd-order + AES derivatives; periodic Gamma is fixed-charge) |
Gamma + k, experimental |
yes |
86 fetched (LGPL) |
PM6 / UPM6 |
Production (molecular) |
Physical PES pinned by regression; spherical Klopman-Ohno fallback where MOPAC diatomic data is absent (wells ~0.1-0.3 bohr long) |
FD |
Gamma, experimental |
yes |
82 bundled MOPAC |
OM2 / OM3 |
Production (molecular) |
Published OMx Hamiltonian (Dral 2016); relative energetics match published benchmarks (H3- bend 0.1 kcal/mol, ethane barrier ±0.6); bond minima ~0.1-0.2 Å long (documented integral stand-ins) |
FD |
Gamma, legacy-model parity only |
yes (UHF) |
5 published (H,C,N,O,F) |
OM1 |
Experimental (warns) |
Analytic core-valence ECP (Kolb-Thiel 1993) not implemented; X-H bonds ~0.3 A short, close contacts can collapse |
FD |
Gamma, legacy-model parity only |
yes (UHF) |
5 published (H,C,N,O,F) |
MSINDO |
Production within scope |
Reference MSINDO parity ≤1 µHa (INDO + NDDO) |
FD and analytic molecular/CCM paths |
CCM 1-D/2-D/3-D + Ewald |
UHF s/p/d within validated fixtures |
H-Xe (Z=1-54); NDDO H,Li-F,Na-Cl |
The same implementation labels are available from Python through
vibeqc.semiempirical.semiempirical_route_status(route). Routes such as
msindo-cis, msindo-cis-gradient, msindo-ovgf, msindo-md, and
msindo-metadynamics are explicitly marked python-reference until their hot
loops move to native kernels or are declared intentionally orchestration-only.
periodic-pm6 and periodic-omx are marked mixed-native: Gamma energy uses
native NDDO kernels, while the current gradient, stress, and cell-optimization
helpers still rely on finite-difference Python orchestration. The lookup also
labels molecular pm6-gradient-fd and omx-gradient-fd as native-fd: their
displacement loops are C++-backed, but they remain finite-difference stopgaps
until analytic molecular NDDO gradients land. The lookup accepts public method
aliases such as dftb0, scc-dftb, gfn2xtb, om2, om2-gradient-fd,
gfn2, msindo, and ccm.
Direct run_semiempirical(...) results compute gradients lazily when
result.gradient() is called. DFTB0/SCC-DFTB, GFN2-xTB, PM6/UPM6, and OMx
expose their existing gradient surfaces through that adapter, while
closed-shell MSINDO INDO uses the native analytic-gradient route there.
MSINDO NDDO and open-shell MSINDO keep gradient() unset at the unified runner
layer until those gradient surfaces are promoted. Geometry-optimizer
SemiempiricalProvider calls the same unified runner, preserving the documented
MSINDO finite-difference force fallback when a MSINDO result is energy-only.
See also
Semiempirical and MACE method comparison for production guidance and
../semiempirical_acceptance_matrix.py for the living validation-gate
matrix.
Element coverage¶
DFTB, 91 elements (H-U except Po/Z=84), including 3d/4d/5d transition metals, lanthanides (La-Lu), and early actinides (Ac-U). All parameters are in-house estimates; DFT-fitted production repulsive potentials are deferred.
GFN2-xTB, 86 elements from the published Grimme-group parameter set. Parameters are fetched on demand at first use (LGPL-3.0 licensed, not bundled, see ADR-002).
PM6, 82 elements from the bundled MOPAC PM6 parameter cache (Apache-2.0 provenance in the TOML header), with the Stewart 2007 H/C/N/O/F subset still available. The public wrapper auto-selects the MOPAC-derived cache for elements outside H/C/N/O/F.
OMx, 5 elements (H, C, N, O, F) from Dral 2016 Tables 1-3.
# Check element coverage
from vibeqc.semiempirical import SemiempiricalParameters
params = SemiempiricalParameters.dftb0_default()
elements = [Z for Z in range(1, 93) if params.has_element(Z)]
print(f"DFTB covers {len(elements)} elements")
Parameter customisation¶
DFTB custom parameters¶
from vibeqc.semiempirical import SemiempiricalParameters
custom = SemiempiricalParameters()
custom.add_element(
Z=1, on_site=[-0.21], zeta=[1.24],
hubbard_u=0.42, valence_electrons=1,
)
custom.add_element(
Z=8, on_site=[-0.89, -0.33], zeta=[2.25, 2.25],
hubbard_u=0.45, valence_electrons=6,
)
# Set repulsive pair (R⁻¹² form)
custom.set_repulsive_pair_analytic(1, 1, A=5.0)
custom.set_repulsive_pair_analytic(1, 8, A=15.0)
custom.set_repulsive_pair_analytic(8, 8, A=40.0)
model = DFTB0Model(mol, params=custom)
GFN2 parameters¶
GFN2-xTB parameters are fetched automatically from the Grimme group’s GitHub repository. To force a refresh:
from vibeqc.semiempirical.methods.gfn2_params import load_gfn2_params
params = load_gfn2_params(force_refetch=True)
PM6 parameters¶
from vibeqc.semiempirical.methods.pm6_params import load_pm6_params
params = load_pm6_params()
model = PM6Model(mol, params=params)
Comparing against external programs¶
Reference energies from external programs can be obtained via out-of-process subprocess runners (External QC codes (ORCA / Psi4 / others)):
from examples.regression.core.runner_xtb import energy as xtb_energy
from examples.regression.core.runner_mopac import energy as mopac_energy
from examples.regression.core.runner_dftbp import energy as dftbp_energy
print(f"xTB GFN2 H2O: {xtb_energy('H2O'):.6f} Eh")
print(f"MOPAC PM6 H2O: {mopac_energy('H2O'):.6f} Ha")
print(f"DFTB+ H2O: {dftbp_energy('H2O'):.6f} Ha")
These runners require the external program to be installed on $PATH
(see each runner’s docstring for install instructions).
Performance tips¶
DFTB0 is 3-5× faster than SCC‑DFTB (no SCF loop). Use it for preoptimization where charge self-consistency is less important.
DFTB gradients (DFTB0 and SCC-DFTB) are analytic and match finite differences tightly; the SCC energy is variational in the density, so its fixed-charge gradient is exact at SCC convergence.
Periodic systems support Gamma-point for all methods; DFTB also supports k-point meshes. Increase the lattice cutoff (
cutoff_bohr) for tight cells.Memory is negligible, the basis is minimal (one function per valence shell).
Known limitations¶
DFTB repulsive potentials are in-house R−12 estimates; DFT-fitted production repulsives are deferred.
GFN2-xTB still lacks periodic AES image-cell multipole Ewald terms and a closed external
xtbparity matrix (Method status).PM6 reports a PM6-like total, not a MOPAC heat of formation; use MOPAC out-of-process when exact MOPAC convention parity is required.
OM2/OM3 are production molecular paths within their documented H/C/N/O/F scope; OM1 remains experimental until the analytic core-valence ECP lands.
Periodic GFN2/NDDO gradients are finite-difference only; analytic periodic NDDO gradients are deferred.
MSINDO molecular closed-shell analytic gradients and closed-shell CCM analytic / finite-difference gradients are available through the native route inside their documented scopes. NDDO, odd-electron analytic gradients, and excited-state/root-tracking gradients remain on their documented fallback or reference paths. See MSINDO (semiempirical INDO).