Metadata-Version: 2.4
Name: garnetff
Version: 1.0.0
Summary: Garnet biomolecular force field
Home-page: https://github.com/greener-group/garnet
Author: Joe G Greener
Author-email: jgreener@mrc-lmb.cam.ac.uk
License: MIT
Keywords: biomolecule force field graph neural network
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Classifier: Topic :: Scientific/Engineering :: Chemistry
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: torch
Requires-Dist: torch_geometric
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: keywords
Dynamic: license
Dynamic: license-file
Dynamic: requires-dist
Dynamic: summary

# Garnet force field

[![Build status](https://github.com/greener-group/garnet/actions/workflows/CI.yml/badge.svg)](https://github.com/greener-group/garnet/actions/workflows/CI.yml)
[![License](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/greener-group/garnet/blob/main/LICENSE.md)

If you use the force field, please cite the paper:

- A Blanco-González*, T K Schulze*, E Rovers, J G Greener. Training a force field for proteins and small molecules from scratch, [Chemical Science](https://doi.org/10.1039/d6sc02874h) (2026).

## Using the force field

The model was trained in Julia as described below.
To make it easier to parameterise molecules, it has been ported to PyTorch for inference.

### Installation

Example conda/mamba commands:
```bash
conda create -n garnet python=3.12
conda activate garnet
conda install -c conda-forge pip 'openff-toolkit-base>=0.18.0' rustworkx rdkit openmm pyxdg gemmi
pip install torch torch_geometric igraph
pip install git+https://github.com/openforcefield/openff-pablo.git@v0.2.0
pip install garnetff
```
Should you want to run the tests, you can run the following from this directory:
```bash
pip install pytest
pytest
```

### Assigning parameters

Garnet integrates with the [OpenFF](https://docs.openforcefield.org/en/latest) and [OpenMM](https://openmm.org) software ecosystem.
The recommended route to obtaining parameters for a system is to create an [OpenFF Toolkit](https://docs.openforcefield.org/projects/toolkit/en/stable) `Topology`, then call `topology_to_openmm_system` on it.
The `Topology` can come from a PDB file of the whole system, a SMILES string or a structure file.
In the first case, using [OpenFF Pablo](https://openff-pablo.readthedocs.io/en/stable) to read the PDB file can be more flexible than using `Topology.from_pdb` (for example, it supports nucleic acids and post-translational modifications).

```python
from garnetff import garnet
from openff.pablo import topology_from_pdb
from openmm.app import PME, HBonds
from openmm.unit import nanometer

pdb_fp = "data/gb3.pdb"
topology = topology_from_pdb(pdb_fp)

system, top_openmm = garnet.topology_to_openmm_system(
    topology,
    nonbondedMethod=PME,
    nonbondedCutoff=1*nanometer,
    constraints=HBonds,
    rigidWater=True,
)

# Run an OpenMM simulation
from openmm import LangevinMiddleIntegrator
from openmm.app import Simulation, PDBFile
from openmm.unit import picosecond, kelvin

temp = 300*kelvin
dt = 0.004*picosecond
integrator = LangevinMiddleIntegrator(temp, 1/picosecond, dt)
simulation = Simulation(top_openmm, system, integrator)
pdb = PDBFile(pdb_fp)
simulation.context.setPositions(pdb.positions)

simulation.minimizeEnergy()
simulation.context.setVelocitiesToTemperature(temp)
simulation.step(1000)
```
Disulfide bridges need to be explicitly given via `CONECT` records, unlike when reading in with OpenMM directly.

The `Topology` can also be written to an OpenMM force field XML file:
```python
garnet.topology_to_openmm_xml("gb3.xml", topology)
```
In this case each molecule is written out as a single residue.
The following gives a way to set up the above system using XML files:
```python
garnet.topology_to_openmm_xml("gb3.xml", topology, write_pdb="gb3_garnet.cif")

pdb = PDBxFile("gb3_garnet.cif")
forcefield = ForceField("gb3.xml")

system = forcefield.createSystem(
    pdb.topology,
    nonbondedMethod=PME,
    nonbondedCutoff=1*nanometer,
    constraints=HBonds,
    rigidWater=True,
)
```
However, currently only one force field XML can be loaded with `ForceField` from OpenMM [due to the way custom non-bonded forces work](https://github.com/openmm/openmm/issues/5154).

`topology_to_openmm_xml` has optional keyword arguments:
- `mol_names`: a list of strings to specify the name of each molecule.
- `prefix`: a string to give unique atom names and avoid clashes with other XML files.
- `write_top`: write an XML file of the bonding topology to the given file path.
- `write_pdb`: write a PDB or mmCIF file (determined by the extension) with molecules having a single residue name to the given file path.

From a SMILES string:
```python
from garnetff import garnet
from openff.toolkit.topology import Molecule, Topology

smiles = "[H]O[H]"
mol = Molecule.from_smiles(smiles, hydrogens_are_explicit=True)
topology = Topology.from_molecules(molecules=[mol])

system, top_openmm = garnet.topology_to_openmm_system(topology)
```

From a structure file (see [the OpenFF toolkit docs](https://docs.openforcefield.org/projects/toolkit/en/stable/api/generated/openff.toolkit.topology.Molecule.html#openff.toolkit.topology.Molecule.from_file) for available formats):
```python
from garnetff import garnet
from openff.toolkit.topology import Molecule, Topology

mol = Molecule.from_file("data/zw_l_alanine.sdf")
topology = Topology.from_molecules(molecules=[mol])

system, top_openmm = garnet.topology_to_openmm_system(topology)
```

The default options for `topology_to_openmm_system` are `nonbondedMethod=NoCutoff`, `nonbondedCutoff=1*nanometer`, `constraints=None` and `rigidWater=False`.
It is important to select these parameters carefully as described in the [the OpenMM documentation](https://docs.openmm.org/latest/userguide/application/02_running_sims.html#simulation-parameters).
Assigning parameters is usually fast (a few seconds), but for some molecules it can take a minute or so due to graph isomorphism checks.
Due to the custom non-bonded interaction, Garnet runs 15-20% slower than standard simulations with the Lennard-Jones potential in OpenMM.
If you want to use Garnet with simulation software other than OpenMM, you could try conversion software such as [ParmEd](https://parmed.github.io/ParmEd/html/index.html) or [OpenFF Interchange](https://docs.openforcefield.org/projects/interchange/en/stable).

### Binding free energy calculations

To run relative binding free energy calculations with Garnet using [OpenFE](https://github.com/OpenFreeEnergy/openfe), see the [validation/rbfe](/validation/rbfe/) directory.

## Training

See the [training](/training/) directory for instructions on how to train the force field from scratch.
Training made use of the [Molly.jl](https://juliamolsim.github.io/Molly.jl/stable) software.
Validation scripts are in the [validation](/validation/) directory.

## Feedback

We are interested in how people are using Garnet and in cases where it performs well or poorly.
Do let us know by opening an issue or [via email](https://www2.mrc-lmb.cam.ac.uk/groups/greener/#contact), user requests will inform future development.
