Skip to content

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 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 molecule
from atomli.calculators.xtb import XTB
from atomli.optimize import BFGS
atoms = molecule("H2O")
atoms.calc = XTB(method="gfn2")
energy = atoms.get_potential_energy() # eV
BFGS(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:

Water relaxed with GFN2-xTB: O-H 0.9592 A, H-O-H 107.22 degrees.
QuantityGFN2-xTBExperimentError
O-H length0.9592 Å0.9572 Å+0.0020 Å
H-O-H angle107.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.

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 np
from atomli.build import bulk
from 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:

CellAtomsOne energy
conventional cubic823 ms
2×2×2 supercell64798 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 molecule
from 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.

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() > 0

On 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.

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.

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.

  • 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.

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.

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.