Turn ligands into a ready-to-use OpenMM force-field XML —
either the non-standard residues (ligands, cofactors, hetero molecules) found in
a PDB, or ligand files on their own. Parameters come from AmberTools
(antechamber + parmchk2) via ParmEd,
from OpenFF Sage or
Espaloma via
openmmforcefields, or — for
CHARMM — by converting the CGenFF stream file
ParamChem gave you.
The output is a plain ffxml file you load alongside the standard force fields:
ff = ForceField("amber14-all.xml", "amber14/tip3p.xml", "extras.xml")
system = ff.createSystem(pdb.topology)Two ways in, depending on whether you have a structure:
from forcefill import build_forcefield_xml, build_ligand_xml
# A complex: find what amber14 cannot match and parameterize it
build_forcefield_xml("complex.pdb", "extras.xml")
# Just the ligand, no structure anywhere
build_ligand_xml("benzamidinium.sdf", "ben.xml")- Identify —
ForceField.getUnmatchedResiduesfinds every residue the base force field (default:amber14-all.xml+amber14/tip3p.xml) has no template for. - Classify — only chemistry a stand-alone GAFF treatment is actually valid for gets parameterized; see What gets skipped, and why.
- Check — before anything expensive: the net charge is read from the ligand file, a supplied file is confirmed to be the same molecule as the residue, and the geometry is checked for the faults that produce NaN energies.
- Parameterize — each unique residue through
antechamber(GAFF2 atom types, AM1-BCC charges →.mol2) andparmchk2(missing parameters →.frcmod), through OpenFF withbackend="smirnoff", through the Espaloma graph network withbackend="espaloma", or from a CGenFF stream file withbackend="charmm". - Assemble — one XML per residue, plus one combined XML.
- Validate — an
openmm.Systemis built frombase force field + new XMLfor every parameterized residue on its own (and for the whole input when nothing was skipped), so a template that does not match its residue fails loudly here instead of at simulation time.minimize=Trueadditionally catches parameters that are unphysical rather than merely absent (see Checks).
Full documentation is at forcefill.readthedocs.io:
| Installation | conda-forge, and the two dependencies that are not ordinary ones |
| Quickstart | a complex in, an ffxml out, and simulating with it |
| What gets skipped, and why | the residues forcefill refuses, and what to do instead |
| Cleaning the structure | water, buffer ions and crystallization additives — and the metals it keeps |
| Ligand input | SDF, MOL2 or SMILES; LigandSpec; ligands with no structure at all |
| Four backends | GAFF, OpenFF Sage, Espaloma, CGenFF — and which mix |
| CHARMM and CGenFF | converting a ParamChem stream file, and the three ways doing it by hand goes wrong |
| Bespoke torsions | a BespokeFit OFFXML, and the checks that protect the QC you paid for |
| Checks | what runs before the expensive step, and what runs after |
| Things to get right | explicit hydrogens, net charge, virtual sites, the periodic box |
Relation to openmmforcefields |
which template generators forcefill uses, and why not GAFFTemplateGenerator |
| API reference | every public function, class and constant |
AmberTools is conda-only, so conda-forge is the recommended route:
conda env create -f environment.yml
conda activate forcefill
pip install -e . --no-depsOr into an existing environment:
conda install -c conda-forge openmm parmed ambertools
pip install forcefillRequires Python ≥ 3.12. Two things are not ordinary dependencies: AmberTools is
not a Python package (the antechamber and parmchk2 executables must be on
PATH for the gaff backend), and espaloma is optional because it pulls in
PyTorch. The full list, and the reason the openmmforcefields floor is 0.16, is
in the installation guide.
from forcefill import build_forcefield_xml
result = build_forcefield_xml(
"complex.pdb",
"extras.xml",
net_charges={"LIG": -1}, # essential for sensible AM1-BCC charges
clean_structure=True, # drop water, buffer ions and crystallization additives
)
print(result.parameterized) # ['LIG']
print(result.skipped) # {'ZN': 'monatomic species - ...'}then simulate with:
from openmm import app
pdb = app.PDBFile("complex.pdb")
ff = app.ForceField("amber14-all.xml", "amber14/tip3p.xml", "extras.xml")
system = ff.createSystem(pdb.topology)result also reports the per-residue XML files (result.residue_xmls), the
skip reasons (result.skipped), and the directory holding every intermediate
file (result.workdir) for inspection — pass cleanup=True to remove it on
success.
More, including per-ligand settings and the other three backends, in the guide.
conda env create -f environment.yml && conda activate forcefill
pip install -e . --no-deps
pytest -m "not integration and not smirnoff" # fast hermetic tests only
pytest # everything, including real antechamber and OpenFFStyle is enforced by ruff (pip install -e '.[dev]' && pre-commit install).
The docs build is pip-only and separate from the conda environment — see Contributing, which also has the release process.
Every release is described in CHANGELOG.md. The public API is
everything exported from forcefill/__init__.py, and it follows semantic
versioning from 1.0.0 on.
- A
forcefillcommand-line interface —build_ligand_xmlis the shape one wants. - Caching, so re-runs into the same workdir skip finished antechamber jobs —
and finished SMIRNOFF/Espaloma templates, which openmmforcefields' own
cache=cannot help with on the code path forcefill uses. - Covalently bound ligands. Still skipped, and deliberately: a stand-alone treatment of a polymer-linked residue is wrong whichever backend produces it.
MIT — see LICENSE.