XTB
XTB calculates energies and forces with GFN2-xTB or g-xTB.
One constructor argument selects the method, and the name is strict. The
Python calculator accepts gfn2 (also spelled GFN2-xTB, as the ASE
community xtb calculator spells it) and gxtb. It does not silently
substitute GFN1 or IPEA1. Both methods publish the same properties and accept
the same charge and spin inputs.
GFN2-xTB
Section titled “GFN2-xTB”GFN2-xTB is a self-consistent extended tight-binding method from the Grimme group. It is parametrized for geometries, frequencies, and noncovalent interactions. Choose it for rapid relaxation, conformer and structure screening, and molecular dynamics when DFT is too expensive.
from atomli.build import moleculefrom atomli.calculators.xtb import XTBfrom atomli.optimize import BFGS
atoms = molecule("H2O")atoms.calc = XTB(method="gfn2")
energy = atoms.get_potential_energy() # eVBFGS(atoms).run(fmax=1e-4)That relaxation starts 0.75 eV/Å from the minimum and finishes at 9.0e-5 eV/Å in 0.93 ms. Here is where it lands, against the spectroscopic geometry of gas-phase water:
| Quantity | GFN2-xTB | Experiment | Error |
|---|---|---|---|
| O-H length | 0.9592 Å | 0.9572 Å | +0.0020 Å |
| H-O-H angle | 107.22° | 104.52° | +2.70° |
The bond length is within
2 milliangstrom.
The angle is 2.7° too wide,
which is a real limitation of the parametrization rather than a convergence
problem: tightening fmax further does not move it. Reference values are from
Benedict, Gailar and Plyler, J. Chem. Phys. 24, 1139 (1956).
For the same molecule’s vibrational frequencies, and where GFN2 does worse, see vibrational analysis.
Periodic cells
Section titled “Periodic cells”A GFN2 energy scan over the lattice constant of diamond silicon locates the minimum at 5.423 Å, against an experimental 5.431 Å, an error of -0.14%. That is 31 single points in 0.25 s.
import numpy as npfrom atomli.build import bulkfrom atomli.calculators.xtb import XTB
energies = []for a in np.arange(5.30, 5.601, 0.01): cell = bulk("Si", "diamond", a=a) cell.calc = XTB(method="gfn2") energies.append(cell.get_potential_energy() / len(cell))Cost grows quickly with cell size, so size the cell before committing to a trajectory:
| Cell | Atoms | One energy |
|---|---|---|
| conventional cubic | 8 | 23 ms |
| 2×2×2 supercell | 64 | 798 ms |
Those cells are sampled at the gamma point only, so their energies per atom are not comparable with each other and are not quoted here. The 34× jump for an 8× cell is the self-consistent diagonalization, and it is the thing that decides whether a periodic xTB workflow is practical.
g-xTB is the newer general-purpose tight-binding method from the Grimme group. It targets higher accuracy than GFN2-xTB at comparable cost. Choose it when GFN2-xTB energetics are not accurate enough but a full QC calculation remains too expensive.
from atomli.build import moleculefrom atomli.calculators.xtb import XTB
atoms = molecule("H2O")atoms.calc = XTB(method="gxtb")
energy = atoms.get_potential_energy()forces = atoms.get_forces()For g-xTB, omitting device uses Atomli’s process default, which is CPU unless
atomli.set_default_device(...) has selected a GPU. Explicit device="gpu"
(or the "wgpu" compatibility alias) requires the native-f32 WebGPU path;
unsupported GPU execution is reported as an error rather than silently falling
back to CPU. The resident session is kept with the calculator across compatible
geometry updates, so optimization and MD reuse its device resources. Device
selection is g-xTB-specific; GFN2-xTB stays on its CPU implementation when no
explicit device is supplied.
The cost is comparable: 0.87 ms on that water against 0.73 ms for GFN2-xTB. The total energies are not. g-xTB returns -2079.97 eV where GFN2-xTB returns -137.97 eV, because the two parametrizations put different amounts of the atomic reference energy into the total. Total energies from different tight-binding methods are never comparable with each other; only differences within one method are.
Supported properties
Section titled “Supported properties”Both methods publish energy, forces, and stress.
stress = periodic_atoms.get_stress()Atomli returns the full 3 × 3 stress tensor. Stress is meaningful for a structure with a cell. The native backend supports nonperiodic, one-dimensional, two-dimensional, and three-dimensional periodicity when the periodic axes use the supported leading-axis masks. Periodic structures require a cell, and stress enables cell-relaxation workflows.
Check a stress before you relax a cell against it. The test is free: compress the cell to somewhere the energy is demonstrably not at its minimum, and the hydrostatic stress must be nonzero, because stress is the volume derivative of that same energy.
import numpy as np
tight = bulk("Si", "diamond", a=5.20)tight.calc = XTB(method="gfn2")assert np.abs(tight.get_stress()).max() > 0On this build that assertion fails. Diamond silicon at 5.20 Šsits 354 meV above the GFN2 minimum, so its stress cannot be zero, and the returned tensor is 8e-16 eV/ų, which is zero to floating-point noise. Cell relaxation against that stress will report success and move nothing. Energies and forces from the same periodic calculation are unaffected, and the lattice scan above is built from energies for exactly this reason.
Charge and unpaired electrons
Section titled “Charge and unpaired electrons”Atomli passes total charge and spin state into tb.rs. Both gfn2 and gxtb
accept these inputs:
ion = Atoms( "OH", positions=[[0, 0, 0], [0, 0, 0.97]], charge=1, unpaired=0,)ion.calc = XTB(method="gfn2")When an Atomli calculator is attached to ase.Atoms, total initial charges are
summed and atoms.info["unpaired"] supplies the unpaired-electron count.
State reuse
Section titled “State reuse”The Rust calculator is constructed once and retained across evaluations. It caches the converged wavefunction, electronic matrices, spectra, and compatible calculation results. Optimizers can therefore request energy and forces without rebuilding the entire tight-binding state for each property call.
Python features
Section titled “Python features”- GFN2-xTB and g-xTB
- Energy, forces, and stress
- Molecular and periodic structures
- Cell optimization through stress
- Total charge and unpaired-electron input
- g-xTB
device="cpu" | "auto" | "wgpu"execution selection - Direct attachment to Atomli or ASE atoms
The current Python class does not expose solvation configuration, SCF controls, charges, dipoles, spectra, or excited-state analysis.
Native-only features
Section titled “Native-only features”The tb.rs-backed native adapter already supports more:
- atomic charges, molecular dipoles, and atom-resolved magnetic moments;
- ALPB, GBSA, C-PCM, CDS, and shift solvation paths for GFN2-xTB;
- electronic temperature, temperature annealing, mixer settings, initial guesses, progress callbacks, and reusable SCF convergence recipes;
- optional D4 control and shell-localization U terms;
- retained overlap and Hamiltonian matrices, orbital populations, eigenvalue spectra, DOS, projected DOS, and real-space density or orbital grids;
- sTDA-xTB and sTDA/g-xTB excitation spectra;
- independent finite-displacement evaluations that restore a converged reference wavefunction between displacements.
These capabilities exist in the native engine but are not yet methods on the
public XTB Python class.
Use cases
Section titled “Use cases”Choose XTB when QC is too expensive but an electronic method is still useful, especially for rapid relaxation, charged systems, and periodic cells. Choose MLIP for much larger model-covered simulations, or QC when functional and basis control are essential.