Skip to content

Can't reuse GAFFTemplateGenerator for more than one force field #369

Description

@epretti

Reproducing example:

from openff.toolkit.topology import Molecule
from openmm.app import ForceField
from openmmforcefields.generators import GAFFTemplateGenerator

molecule = Molecule.from_smiles("c1ccccc1") # benzene
generator = GAFFTemplateGenerator(molecules=molecule)

for repeat in range(2):
    print(repeat)
    forcefield = ForceField()
    forcefield.registerTemplateGenerator(generator.generator)
    system = forcefield.createSystem(molecule.to_topology().to_openmm())

Output:

0
1
Traceback (most recent call last):
...
KeyError: 'ca'

I believe that the cause is an attempt to keep track of which atom types have been output so as not to output any duplicates:

# We need to make sure we don't duplicate atom types we have already told
# OpenMM about. To do this we will keep track of atom types we have already
# seen and ensure we only record new atom types in the xml.
# iterate over a copy of the atom types
for atom_type in params.atom_types.copy().keys():
if atom_type not in self._gaff_atom_types_observed:
self._gaff_atom_types_observed.add(atom_type)
_logger.debug(f"added {atom_type} to set of seen types")
# if we have seen the atom type, delete it from the OG params,
# not the copy!
else:
del params.atom_types[atom_type]
_logger.debug(f"{atom_type} already recorded")

But this is tracked on a per-generator basis, so when the generator is applied to the second force field, it doesn't tell it about any atom types, which of course fails. This should have been caught by the test suite, specifically
def test_multiple_registration(self):
"""Test registering the template generator with multiple force fields"""

which was designed to test exactly this, but unfortunately all the GAFF tests were disabled in commit b685637 when GAFF was temporarily removed, and they were never reactivated in commit 051cbcb when GAFF was re-enabled (and the code leading to this problem was introduced).

@mikemhenry, @mattwthompson, or @peastman: For OpenMM >= 8.1.2, since duplicate registration of atom types is now allowed as long as they are identical thanks to openmm/openmm#4531, this logic should be unnecessary, right? But if we want to continue supporting older versions of OpenMM, or there's some other important reason for this logic, then something more complicated will have to be done.

Activity

  1. mattwthompson commented on Mar 21, 2025

    @mattwthompson
    Collaborator

    I'm in favor of just ripping this out; bending over backwards to support a corner case like this (re-using a generator for multiple ForceFields on an older version of OpenMM) is a bad trade-off

    GAFF tests do need to be turned back on, though

  2. epretti commented on Mar 21, 2025

    @epretti
    MemberAuthor

    Agreed. Peter likewise suggested it would be OK to not support older versions of OpenMM that don't have the fix required to make duplicate atom types work. I was not entirely convinced that the present logic would work in all situations anyway, as there is a subtlety in that the FFXML generated here might or might not get cached later. PR coming momentarily with this removed and GAFF tests switched over to be conditionally enabled based on the --rungaff flag used elsewhere, instead of being skipped.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions