README.md

March 30, 2026 · View on GitHub

GFN-FF

A general force field for elements Z = 1–103

build status License: LGPL v3

This repository provides a standalone library implementation of the GFN-FF method by S.Spicher and S.Grimme, adapted from the xtb code (most recently at commit 6d44803 and validated against that version's results). The primary purpose is to serve as a linkable dependency for other Fortran, C, and C++ projects. From this point forward, development may diverge from the upstream xtb implementation.


Method

GFN-FF (Geometries, Frequencies, Non-covalent interactions Force-Field) is a completely automated, topology-based force field for fast structure optimisations and non-covalent interaction energies across the periodic table (Z = 1–103). The topology and parametrisation are derived entirely from the input geometry, without user-defined atom types or connectivity.

The following features are available and documented in the associated publications:

  • Molecular GFN-FF — a generic, partially polarisable force field covering organic, organometallic, and biochemical systems (S. Spicher, S. Grimme, Angew. Chem. Int. Ed. 2020, 59, 15665. doi:10.1002/anie.202004239)

  • Periodic boundary conditions / molecular crystals — adjusted non-covalent interactions for lattice energy predictions and unit-cell optimisations of molecular crystals (S. Grimme, T. Rose, Z. Naturforsch. B 2024, 79, 191. doi:10.1515/znb-2023-0088)

  • Lanthanide and actinide extension — reparametrised f-element treatment enabling MD simulations and geometry optimisations for large lanthanide- and actinide-containing systems (T. Rose, M. Bursch, J.-M. Mewes, S. Grimme, Inorg. Chem. 2024. doi:10.1021/acs.inorgchem.4c03215)


Building from source

The library requires a Fortran and C compiler (e.g. gfortran/gcc), LAPACK/BLAS (e.g. OpenBLAS), and optionally OpenMP. Both CMake (≥ 3.21) and Meson (≥ 0.59) build systems are supported.

CMake Meson
cmake -B _build
cmake --build _build

To run the test suite:

cmake -B _build -DWITH_TESTS=ON
cmake --build _build
ctest --test-dir _build
meson setup _build
ninja -C _build

To run the test suite:

meson setup _build -Dtests=true
ninja -C _build test

The compiled library (libgfnff.a by default) is placed in the build directory and can be linked into any downstream project.


Library usage

The interface is exposed through the gfnff_interface Fortran module and the gfnff_interface_c.h C header (located in include/). Two steps are required: initialise the calculator (topology setup) and call the singlepoint routine. The initialisation is typically the more expensive step; once complete, singlepoint evaluations can be called repeatedly on the same calculator object.

Fortran
use iso_fortran_env, only: real64
use gfnff_interface

type(gfnff_data) :: calc
integer  :: nat, ichrg, io
integer,  allocatable :: at(:)
real(real64), allocatable :: xyz(:,:), gradient(:,:)
real(real64) :: energy, sigma(3,3)

! ... populate nat, at, xyz, ichrg ...

call calc%init(nat, at, xyz, ichrg=ichrg, iostat=io)

call calc%singlepoint(nat, at, xyz, energy, gradient, iostat=io, sigma=sigma)

call calc%deallocate()

All coordinates are in Bohr; the energy is in Hartree, the gradient in Eh/Bohr, and sigma (3×3) is the stress tensor in Hartree (zero for non-periodic systems). Full working example: app/main.F90.

C
#include "gfnff_interface_c.h"

double sigma[3][3];   /* stress tensor (Hartree); zero for non-PBC */

c_gfnff_calculator calc =
    c_gfnff_calculator_init(nat, at, xyz, ichrg, printlevel, solvent);

c_gfnff_calculator_singlepoint(&calc, nat, at, xyz, &energy, gradient,
                               sigma, &iostat);

c_gfnff_calculator_deallocate(&calc);

Full working example: test/main.c.

C++
#include "gfnff_interface_c.h"

double sigma[3][3];   // stress tensor (Hartree); zero for non-PBC

c_gfnff_calculator calc =
    c_gfnff_calculator_init(nat, at, xyz, ichrg, printlevel, solvent);

c_gfnff_calculator_singlepoint(&calc, nat, at, xyz, &energy, gradient,
                               sigma, &iostat);

c_gfnff_calculator_deallocate(&calc);

Full working example: test/main.cpp.

Integrating as a CMake subproject

Add the repository as a subdirectory and link against the exported target:

add_subdirectory(gfnff)
target_link_libraries(my_target PRIVATE gfnff)
Integrating as a Meson subproject

Place the repository under subprojects/gfnff/ and wrap it:

gfnff_dep = dependency('gfnff', fallback: ['gfnff', 'gfnff_dep'])

Periodic boundary conditions

PBC support is available via c_gfnff_calculator_init_pbc on the C/C++ side and via an optional lattice argument to calc%init in Fortran. See the PBC sections in test/main.c and test/main.cpp for worked examples.


Python bindings

Python bindings are provided through a ctypes-based interface. The shared library is bundled into a binary wheel, so no Fortran or C compiler is needed at install time.

Installation

Binary wheels for Linux (x86_64) and macOS (x86_64 / arm64) are published on PyPI:

pip install gfnff          # library only
pip install "gfnff[ase]"   # + ASE (enables the CLI and the ASE calculator)

Building from source

The source build compiles the Fortran library on your machine. The following system packages must be present before running pip:

DependencyExample (Debian/Ubuntu)Example (Fedora/RHEL)Example (macOS)
Fortran compilerapt install gfortrandnf install gcc-gfortranbrew install gcc
LAPACK + BLASapt install libopenblas-devdnf install openblas-develbrew install openblas
CMake ≥ 3.21installed by pip automatically

Once those are in place:

pip install ".[ase]"           # from a checkout
pip install "gfnff[ase]" --no-binary gfnff   # force source build from PyPI

Command-line interface

Installing gfnff[ase] places a gfnff executable on your PATH.

gfnff <input> [options]

The input file is read by ASE, so any format it supports works (xyz, extxyz, POSCAR, cif, …).

Singlepoint (default):

gfnff molecule.xyz
gfnff molecule.xyz --chrg -1
gfnff molecule.xyz --alpb h2o        # implicit solvation (--solv is an alias)

Geometry optimisation (L-BFGS via ASE, cell fixed, writes gfnff.log.extxyz):

gfnff molecule.xyz --opt
gfnff molecule.xyz --opt --fmax 0.05          # looser convergence, eV/Å
gfnff molecule.xyz --opt --outfile path.xyz   # custom trajectory file
gfnff molecule.xyz --opt --alpb acetone       # optimise in solvent

Variable-cell optimisation (L-BFGS + ExpCellFilter, periodic systems only):

gfnff crystal.cif --optcell
gfnff crystal.cif --optcell --fmax 0.01

Full option list: gfnff --help

The trajectory file (gfnff.log.extxyz) stores energy and forces in each frame header, compatible with ASE's ase gui.


Low-level API (GFNFFCalculator)

GFNFFCalculator mirrors the C API one-to-one. All quantities use the same units as the library itself: Bohr for coordinates and lattice, Hartree for energy, Eh/Bohr for gradients, and Hartree for the stress tensor.

import numpy as np
from gfnff import GFNFFCalculator

# Atomic numbers and coordinates in Bohr
numbers = np.array([6, 8, 1, 1], dtype=np.int32)   # CO + 2 H
positions = np.array([[0, 0, 0], [2.1, 0, 0],
                      [-1.0, 0, 0], [3.1, 0, 0]], dtype=np.float64)

with GFNFFCalculator(numbers, positions, charge=0, printlevel=0) as calc:
    energy, gradient, sigma = calc.singlepoint(numbers, positions)
    print(f"Energy: {energy:.6f} Eh")
    print(f"Gradient shape: {gradient.shape}")  # (nat, 3)
    print(f"Stress tensor:\n{sigma}")            # (3, 3), Hartree; zero for non-PBC

Periodic systems use a separate initialiser:

calc = GFNFFCalculator(
    numbers, positions,
    lattice=lattice_bohr,   # shape (3, 3), rows are lattice vectors
    npbc=3,
)

ASE Calculator (GFNFF)

GFNFF is a fully compatible ASE Calculator. It handles unit conversion automatically (Å ↔ Bohr, eV ↔ Hartree). Implemented properties: energy, forces, stress.

from ase.build import molecule
from gfnff import GFNFF

atoms = molecule("caffeine")
atoms.calc = GFNFF()

energy = atoms.get_potential_energy()   # eV
forces = atoms.get_forces()             # eV / Å, shape (nat, 3)
stress = atoms.get_stress()             # eV / ų, Voigt [xx,yy,zz,yz,xz,xy]; zero for non-PBC

Periodic systems work the same way — provide an atoms object with cell and pbc set:

from ase.io import read
from gfnff import GFNFF

atoms = read("quartz.cif")
atoms.calc = GFNFF()
print(atoms.get_potential_energy())  # eV / unit cell
print(atoms.get_stress())            # eV / ų, Voigt

Variable-cell relaxation via ASE's ExpCellFilter:

from ase.filters import ExpCellFilter
from ase.optimize import LBFGS

opt = LBFGS(ExpCellFilter(atoms))
opt.run(fmax=0.01)

Additional options:

ParameterDefaultDescription
charge0Total charge. Also reads atoms.info["charge"] (takes precedence).
solvent""Implicit solvent name: "h2o", "acetone", "chcl3", … (molecular systems only)
printlevel0Fortran output verbosity (0 = silent, 3 = verbose).

Running the tests

pip install "gfnff[test]"
pytest python/tests/

License

This project is licensed (as the original xtb code) under the GNU Lesser General Public License v3 or later. See LICENSE for details.