From 573134c1af06eeff45bf469ffe123a1cad91a2e8 Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Mon, 27 Oct 2025 11:00:20 +0100 Subject: [PATCH 1/5] Allow for any barostat in SystemGenerator --- .../generators/system_generators.py | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/openmmforcefields/generators/system_generators.py b/openmmforcefields/generators/system_generators.py index 5183d5e6..47e349d7 100644 --- a/openmmforcefields/generators/system_generators.py +++ b/openmmforcefields/generators/system_generators.py @@ -91,9 +91,9 @@ def __init__( Small molecule force field to use. Must be supported by one of the registered template generators: [GAFFTemplateGenerator, SMIRNOFFTemplateGenerator] - Supported GAFF force fields include 'gaff-2.2.20', 'gaff-2.11', and others. + Supported GAFF force fields include: ['gaff-2.2.20', 'gaff-2.11', 'gaff-2.1', 'gaff-1.81', 'gaff-1.8', 'gaff-1.4'] (See ``GAFFTemplateGenerator.INSTALLED_FORCEFIELDS`` for a complete list.) - Supported SMIRNOFF force fields include all installed force fields from Parsley and Sage lines, such as 'openff-1.0.0' and 'openff-2.2.1'. + Supported SMIRNOFF force fields include: [`openff-1.0.0`, `smirnoff99Frosst-1.1.0`] (See ``SMIRNOFFTemplateGenerator.INSTALLED_FORCEFIELDS`` for a complete list.) forcefield_kwargs : dict, optional, default=None Keyword arguments to be passed to ``openmm.app.ForceField.createSystem()`` during ``System`` @@ -303,25 +303,16 @@ def _modify_forces(self, system): """ Add barostat and modify forces if requested. """ - # Add barostat if requested and the system uses periodic boundary conditions if (self.barostat is not None) and system.usesPeriodicBoundaryConditions(): import numpy as np import openmm + import copy MAXINT = np.iinfo(np.int32).max - # Determine pressure, temperature, and frequency - pressure = self.barostat.getDefaultPressure() - if hasattr(self.barostat, "getDefaultTemperature"): - temperature = self.barostat.getDefaultTemperature() - else: - temperature = self.barostat.getTemperature() - frequency = self.barostat.getFrequency() - - # Create the barostat - # TODO: Make sure we can support other kinds of barostats? - barostat = openmm.MonteCarloBarostat(pressure, temperature, frequency) + # Get the barostat + barostat = copy.deepcopy(self.barostat) seed = np.random.randint(MAXINT) barostat.setRandomNumberSeed(seed) system.addForce(barostat) From 960805cd275539327218035f1ed455b1acddb65d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 10:03:48 +0000 Subject: [PATCH 2/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- openmmforcefields/generators/system_generators.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openmmforcefields/generators/system_generators.py b/openmmforcefields/generators/system_generators.py index 47e349d7..5d25e80e 100644 --- a/openmmforcefields/generators/system_generators.py +++ b/openmmforcefields/generators/system_generators.py @@ -306,7 +306,6 @@ def _modify_forces(self, system): # Add barostat if requested and the system uses periodic boundary conditions if (self.barostat is not None) and system.usesPeriodicBoundaryConditions(): import numpy as np - import openmm import copy MAXINT = np.iinfo(np.int32).max From eb8ea54bf43fc5395daae947338b4692cc1df84c Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Wed, 29 Oct 2025 09:35:01 +0100 Subject: [PATCH 3/5] Fix doc strings --- openmmforcefields/generators/system_generators.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openmmforcefields/generators/system_generators.py b/openmmforcefields/generators/system_generators.py index 47e349d7..33415442 100644 --- a/openmmforcefields/generators/system_generators.py +++ b/openmmforcefields/generators/system_generators.py @@ -91,9 +91,9 @@ def __init__( Small molecule force field to use. Must be supported by one of the registered template generators: [GAFFTemplateGenerator, SMIRNOFFTemplateGenerator] - Supported GAFF force fields include: ['gaff-2.2.20', 'gaff-2.11', 'gaff-2.1', 'gaff-1.81', 'gaff-1.8', 'gaff-1.4'] + Supported GAFF force fields include 'gaff-2.2.20', 'gaff-2.11', and others. (See ``GAFFTemplateGenerator.INSTALLED_FORCEFIELDS`` for a complete list.) - Supported SMIRNOFF force fields include: [`openff-1.0.0`, `smirnoff99Frosst-1.1.0`] + Supported SMIRNOFF force fields include all installed force fields from Parsley and Sage lines, such as 'openff-1.0.0' and 'openff-2.2.1'. (See ``SMIRNOFFTemplateGenerator.INSTALLED_FORCEFIELDS`` for a complete list.) forcefield_kwargs : dict, optional, default=None Keyword arguments to be passed to ``openmm.app.ForceField.createSystem()`` during ``System`` From 18e021c528c59363f080c72ff5751ddcbe0dbb96 Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Fri, 31 Oct 2025 10:55:28 +0100 Subject: [PATCH 4/5] Add test for MonteCarloMembraneBarostat --- .../tests/test_system_generator.py | 70 +++++++++++++++---- 1 file changed, 55 insertions(+), 15 deletions(-) diff --git a/openmmforcefields/tests/test_system_generator.py b/openmmforcefields/tests/test_system_generator.py index a979fba1..2768d05e 100644 --- a/openmmforcefields/tests/test_system_generator.py +++ b/openmmforcefields/tests/test_system_generator.py @@ -7,6 +7,7 @@ import pytest from openff.toolkit.topology import Molecule from openmm.app import LJPME, PME, CutoffNonPeriodic, Modeller, PDBFile +from openmm import unit, MonteCarloBarostat, MonteCarloMembraneBarostat from openmmforcefields.generators import SystemGenerator from openmmforcefields.utils import Timer, get_data_filename @@ -139,21 +140,53 @@ def test_create(self): # Create an empty system generator SystemGenerator() - def test_barostat(self): - """Test that barostat addition works correctly""" + + @pytest.mark.parametrize( + "barostat_class, args", + [ + # MonteCarloBarostat + ( + MonteCarloBarostat, + [0.95 * unit.atmospheres, 301.0 * unit.kelvin, 23], + ), + # MonteCarloMembraneBarostat + ( + MonteCarloMembraneBarostat, + [ + 1.0 * unit.atmospheres, + 10.0 * unit.millinewton / unit.meter, + 301.0 * unit.kelvin, + MonteCarloMembraneBarostat.XYIsotropic, + MonteCarloMembraneBarostat.ZFree, + 23, + ], + ), + ], + ) + def test_barostat(self, barostat_class, args): + """Test that different barostats are correctly applied to the system""" # Create a protein SystemGenerator generator = SystemGenerator(forcefields=self.amber_forcefields) - # Create a template barostat - from openmm import MonteCarloBarostat, unit - - pressure = 0.95 * unit.atmospheres - temperature = 301.0 * unit.kelvin - frequency = 23 - generator.barostat = MonteCarloBarostat(pressure, temperature, frequency) + # Create the barostat + generator.barostat = barostat_class(*args) + + # Derive expected values based on barostat type + if barostat_class is MonteCarloBarostat: + expected = { + "pressure": args[0], + "temperature": args[1], + "frequency": args[2], + } + else: # MonteCarloMembraneBarostat + expected = { + "pressure": args[0], + "surface_tension": args[1], + "temperature": args[2], + "frequency": args[-1], + } # Load a PDB file - pdb_filename = get_data_filename(os.path.join("perses_jacs_systems", "mcl1", "MCL1_protein.pdb")) pdbfile = PDBFile(pdb_filename) @@ -176,13 +209,20 @@ def test_barostat(self): # Check barostat is present forces = {force.__class__.__name__: force for force in system.getForces()} - assert "MonteCarloBarostat" in forces.keys() + name = barostat_class.__name__ + assert name in forces, f"{name} not found in system forces" # Check barostat parameters - force = forces["MonteCarloBarostat"] - assert force.getDefaultPressure() == pressure - assert force.getDefaultTemperature() == temperature - assert force.getFrequency() == frequency + force = forces[name] + assert force.getDefaultTemperature() == expected["temperature"] + assert force.getDefaultPressure() == expected["pressure"] + assert force.getFrequency() == expected["frequency"] + + # Conditional check + if hasattr(force, "getDefaultSurfaceTension"): + assert force.getDefaultSurfaceTension() == expected["surface_tension"] + + @pytest.mark.parametrize( "small_molecule_forcefield", From 4d119361e1b4b331ebca13bf60af92ee02a66ef3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 31 Oct 2025 09:56:11 +0000 Subject: [PATCH 5/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- openmmforcefields/tests/test_system_generator.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/openmmforcefields/tests/test_system_generator.py b/openmmforcefields/tests/test_system_generator.py index 2768d05e..8edfc4d6 100644 --- a/openmmforcefields/tests/test_system_generator.py +++ b/openmmforcefields/tests/test_system_generator.py @@ -140,7 +140,6 @@ def test_create(self): # Create an empty system generator SystemGenerator() - @pytest.mark.parametrize( "barostat_class, args", [ @@ -222,8 +221,6 @@ def test_barostat(self, barostat_class, args): if hasattr(force, "getDefaultSurfaceTension"): assert force.getDefaultSurfaceTension() == expected["surface_tension"] - - @pytest.mark.parametrize( "small_molecule_forcefield", [