From 9c8827876f0df8001132b503b9a8b3464415f9bd Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Wed, 25 Sep 2024 11:32:37 +0200 Subject: [PATCH 01/36] Move interchange creation to utils --- .../protocols/gromacs_md/md_methods.py | 153 +----------------- .../gromacs_utils/system_creation.py | 148 +++++++++++++++++ 2 files changed, 152 insertions(+), 149 deletions(-) create mode 100644 openfe_gromacs/protocols/gromacs_utils/system_creation.py diff --git a/openfe_gromacs/protocols/gromacs_md/md_methods.py b/openfe_gromacs/protocols/gromacs_md/md_methods.py index 99b6b61..5edd4fe 100644 --- a/openfe_gromacs/protocols/gromacs_md/md_methods.py +++ b/openfe_gromacs/protocols/gromacs_md/md_methods.py @@ -15,28 +15,18 @@ import pathlib import subprocess import uuid -import warnings from collections import defaultdict from collections.abc import Iterable from typing import Any -import gmxapi as gmx import gufe import pint from gufe import ChemicalSystem, SmallMoleculeComponent, settings from openfe.protocols.openmm_utils import ( - charge_generation, - settings_validation, - system_creation, system_validation, ) -from openfe.protocols.openmm_utils.omm_settings import BasePartialChargeSettings -from openfe.utils import log_system_probe, without_oechem_backend -from openff.interchange import Interchange -from openff.toolkit.topology import Molecule as OFFMolecule +from openfe.utils import log_system_probe from openff.units import unit -from openff.units.openmm import from_openmm, to_openmm -from openmmtools import forces from openfe_gromacs.protocols.gromacs_md.md_settings import ( EMOutputSettings, @@ -52,6 +42,7 @@ OpenMMEngineSettings, OpenMMSolvationSettings, ) +from openfe_gromacs.protocols.gromacs_utils import system_creation logger = logging.getLogger(__name__) @@ -662,31 +653,6 @@ def __init__( generation=generation, ) - @staticmethod - def _assign_partial_charges( - charge_settings: OpenFFPartialChargeSettings, - smc_components: dict[SmallMoleculeComponent, OFFMolecule], - ) -> None: - """ - Assign partial charges to SMCs. - - Parameters - ---------- - charge_settings : OpenFFPartialChargeSettings - Settings for controlling how the partial charges are assigned. - smc_components : dict[SmallMoleculeComponent, openff.toolkit.Molecule] - Dictionary of OpenFF Molecules to add, keyed by - SmallMoleculeComponent. - """ - for mol in smc_components.values(): - charge_generation.assign_offmol_partial_charges( - offmol=mol, - overwrite=False, - method=charge_settings.partial_charge_method, - toolkit_backend=charge_settings.off_toolkit_backend, - generate_n_conformers=charge_settings.number_of_conformers, - nagl_model=charge_settings.nagl_model, - ) def _handle_settings(self) -> dict[str, gufe.settings.SettingsBaseModel]: """ @@ -775,112 +741,6 @@ def _write_mdp_files(self, settings: dict, shared_basepath): return mdps - def _create_interchange(self, settings, components, shared_basepath): - """ - Creates the Interchange object for the system. - - Parameters - ---------- - settings: dict - Dictionary of all the settings - components: dict - Dictionary of the components of the settings, solvent, protein, and - small molecules - shared_basepath : Pathlike, optional - Where to run the calculation, defaults to current working directory - - Returns - ------- - stateA_interchange: Interchange object - The interchange object of the system. - """ - # Set the environment variable for using the experimental interchange - # functionality `from_openmm` and raise a warning - os.environ["INTERCHANGE_EXPERIMENTAL"] = "1" - war = ( - "Environment variable INTERCHANGE_EXPERIMENTAL=1 is set for using " - "the interchange functionality 'from_openmm' which is not well " - "tested yet." - ) - warnings.warn(war) - # Create the stateA system - # Create a dictionary of OFFMol for each SMC for bookkeeping - smc_components: dict[SmallMoleculeComponent, OFFMolecule] - - # ToDo: Make this more general, check if there is a smc_component, - # allow ProteinComponents, ... - smc_components = {i: i.to_openff() for i in components["small_mols"]} - - # a. assign partial charges to smcs - self._assign_partial_charges(settings["charge_settings"], smc_components) - - # b. get a system generator - if settings["output_settings_em"].forcefield_cache is not None: - ffcache = shared_basepath / settings["output_settings_em"].forcefield_cache - else: - ffcache = None - - # Note: we block out the oechem backend for all systemgenerator - # linked operations to avoid any smiles operations that can - # go wrong when doing rdkit->OEchem roundtripping - with without_oechem_backend(): - system_generator = system_creation.get_system_generator( - forcefield_settings=settings["forcefield_settings"], - integrator_settings=settings["integrator_settings"], - thermo_settings=settings["thermo_settings"], - cache=ffcache, - has_solvent=components["solvent_comp"] is not None, - ) - - # Force creation of smc templates so we can solvate later - for mol in smc_components.values(): - system_generator.create_system( - mol.to_topology().to_openmm(), molecules=[mol] - ) - - # c. get OpenMM Modeller + a resids dictionary for each component - stateA_modeller, comp_resids = system_creation.get_omm_modeller( - protein_comp=components["protein_comp"], - solvent_comp=components["solvent_comp"], - small_mols=smc_components, - omm_forcefield=system_generator.forcefield, - solvent_settings=settings["solvation_settings"], - ) - - # d. get topology & positions - # Note: roundtrip positions to remove vec3 issues - stateA_topology = stateA_modeller.getTopology() - stateA_positions = to_openmm(from_openmm(stateA_modeller.getPositions())) - - # e. create the stateA System - stateA_system = system_generator.create_system( - stateA_topology, - molecules=[s.to_openff() for s in components["small_mols"]], - ) - - # 3. Create the Interchange object - barostat_idx, barostat = forces.find_forces( - stateA_system, ".*Barostat.*", only_one=True - ) - stateA_system.removeForce(barostat_idx) - - stateA_interchange = Interchange.from_openmm( - topology=stateA_topology, - system=stateA_system, - positions=stateA_positions, - ) - - for molecule_index, molecule in enumerate( - stateA_interchange.topology.molecules - ): - for atom in molecule.atoms: - atom.metadata["residue_number"] = molecule_index + 1 - if len([*smc_components.values()]) > 0: - if molecule.n_atoms == [*smc_components.values()][0].n_atoms: - for atom in molecule.atoms: - atom.metadata["residue_name"] = "UNK" - - return stateA_interchange def run( self, *, dry=False, verbose=True, scratch_basepath=None, shared_basepath=None @@ -930,18 +790,13 @@ def run( solvent_comp, protein_comp, small_mols = system_validation.get_components( stateA ) - components = { - "solvent_comp": solvent_comp, - "protein_comp": protein_comp, - "small_mols": small_mols, - } # 1. Write out .mdp files mdps = self._write_mdp_files(settings, shared_basepath) # 2. Create the Interchange object - stateA_interchange = self._create_interchange( - settings, components, shared_basepath + stateA_interchange = system_creation.create_interchange( + settings, solvent_comp, protein_comp, small_mols, shared_basepath ) # 4. Save .gro and .top file of the entire system diff --git a/openfe_gromacs/protocols/gromacs_utils/system_creation.py b/openfe_gromacs/protocols/gromacs_utils/system_creation.py new file mode 100644 index 0000000..59fc2cf --- /dev/null +++ b/openfe_gromacs/protocols/gromacs_utils/system_creation.py @@ -0,0 +1,148 @@ +import os +import warnings +from openfe_gromacs.protocols.gromacs_md.md_settings import ( + IntegratorSettings, + OpenFFPartialChargeSettings, + OpenMMEngineSettings, + OpenMMSolvationSettings, +) +from openff.interchange import Interchange +from openff.toolkit.topology import Molecule as OFFMolecule +from gufe import ChemicalSystem, SmallMoleculeComponent, settings +from openff.units.openmm import from_openmm, to_openmm +from openmmtools import forces +from openfe.protocols.openmm_utils import charge_generation, system_creation +from openfe.utils import without_oechem_backend + + +def assign_partial_charges( + charge_settings: OpenFFPartialChargeSettings, + smc_components: dict[SmallMoleculeComponent, OFFMolecule], +) -> None: + """ + Assign partial charges to SMCs. + + Parameters + ---------- + charge_settings : OpenFFPartialChargeSettings + Settings for controlling how the partial charges are assigned. + smc_components : dict[SmallMoleculeComponent, openff.toolkit.Molecule] + Dictionary of OpenFF Molecules to add, keyed by + SmallMoleculeComponent. + """ + for mol in smc_components.values(): + charge_generation.assign_offmol_partial_charges( + offmol=mol, + overwrite=False, + method=charge_settings.partial_charge_method, + toolkit_backend=charge_settings.off_toolkit_backend, + generate_n_conformers=charge_settings.number_of_conformers, + nagl_model=charge_settings.nagl_model, + ) + + +def create_interchange(settings, solvent_comp, protein_comp, small_mols, shared_basepath): + """ + Creates the Interchange object for the system. + + Parameters + ---------- + settings: dict + Dictionary of all the settings + components: dict + Dictionary of the components of the settings, solvent, protein, and + small molecules + shared_basepath : Pathlike, optional + Where to run the calculation, defaults to current working directory + + Returns + ------- + stateA_interchange: Interchange object + The interchange object of the system. + """ + # Set the environment variable for using the experimental interchange + # functionality `from_openmm` and raise a warning + os.environ["INTERCHANGE_EXPERIMENTAL"] = "1" + war = ( + "Environment variable INTERCHANGE_EXPERIMENTAL=1 is set for using " + "the interchange functionality 'from_openmm' which is not well " + "tested yet." + ) + warnings.warn(war) + # Create the stateA system + # Create a dictionary of OFFMol for each SMC for bookkeeping + smc_components: dict[SmallMoleculeComponent, OFFMolecule] + smc_components = {i: i.to_openff() for i in small_mols} + + # a. assign partial charges to smcs + assign_partial_charges(settings["charge_settings"], smc_components) + + # b. get a system generator + if settings["output_settings_em"].forcefield_cache is not None: + ffcache = shared_basepath / settings[ + "output_settings_em"].forcefield_cache + else: + ffcache = None + + # Note: we block out the oechem backend for all systemgenerator + # linked operations to avoid any smiles operations that can + # go wrong when doing rdkit->OEchem roundtripping + with without_oechem_backend(): + system_generator = system_creation.get_system_generator( + forcefield_settings=settings["forcefield_settings"], + integrator_settings=settings["integrator_settings"], + thermo_settings=settings["thermo_settings"], + cache=ffcache, + has_solvent=solvent_comp is not None, + ) + + # Force creation of smc templates so we can solvate later + for mol in smc_components.values(): + system_generator.create_system( + mol.to_topology().to_openmm(), molecules=[mol] + ) + + # c. get OpenMM Modeller + a resids dictionary for each component + stateA_modeller, comp_resids = system_creation.get_omm_modeller( + protein_comp=protein_comp, + solvent_comp=solvent_comp, + small_mols=smc_components, + omm_forcefield=system_generator.forcefield, + solvent_settings=settings["solvation_settings"], + ) + + # d. get topology & positions + # Note: roundtrip positions to remove vec3 issues + stateA_topology = stateA_modeller.getTopology() + stateA_positions = to_openmm( + from_openmm(stateA_modeller.getPositions())) + + # e. create the stateA System + stateA_system = system_generator.create_system( + stateA_topology, + molecules=[s.to_openff() for s in small_mols], + ) + + # 3. Create the Interchange object + barostat_idx, barostat = forces.find_forces( + stateA_system, ".*Barostat.*", only_one=True + ) + stateA_system.removeForce(barostat_idx) + + stateA_interchange = Interchange.from_openmm( + topology=stateA_topology, + system=stateA_system, + positions=stateA_positions, + ) + + for molecule_index, molecule in enumerate( + stateA_interchange.topology.molecules + ): + for atom in molecule.atoms: + atom.metadata["residue_number"] = molecule_index + 1 + if len([*smc_components.values()]) > 0: + if molecule.n_atoms == [*smc_components.values()][0].n_atoms: + for atom in molecule.atoms: + atom.metadata["residue_name"] = "UNK" + + return stateA_interchange From 38413d3b5e9b93c45a471dc59610f591f995ad15 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 09:35:56 +0000 Subject: [PATCH 02/36] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../protocols/gromacs_md/md_methods.py | 6 +--- .../gromacs_utils/system_creation.py | 28 ++++++++++--------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/openfe_gromacs/protocols/gromacs_md/md_methods.py b/openfe_gromacs/protocols/gromacs_md/md_methods.py index 5edd4fe..6791eac 100644 --- a/openfe_gromacs/protocols/gromacs_md/md_methods.py +++ b/openfe_gromacs/protocols/gromacs_md/md_methods.py @@ -22,9 +22,7 @@ import gufe import pint from gufe import ChemicalSystem, SmallMoleculeComponent, settings -from openfe.protocols.openmm_utils import ( - system_validation, -) +from openfe.protocols.openmm_utils import system_validation from openfe.utils import log_system_probe from openff.units import unit @@ -653,7 +651,6 @@ def __init__( generation=generation, ) - def _handle_settings(self) -> dict[str, gufe.settings.SettingsBaseModel]: """ Extract the relevant settings for an MD simulation. @@ -741,7 +738,6 @@ def _write_mdp_files(self, settings: dict, shared_basepath): return mdps - def run( self, *, dry=False, verbose=True, scratch_basepath=None, shared_basepath=None ) -> dict[str, Any]: diff --git a/openfe_gromacs/protocols/gromacs_utils/system_creation.py b/openfe_gromacs/protocols/gromacs_utils/system_creation.py index 59fc2cf..f501720 100644 --- a/openfe_gromacs/protocols/gromacs_utils/system_creation.py +++ b/openfe_gromacs/protocols/gromacs_utils/system_creation.py @@ -1,18 +1,20 @@ import os import warnings + +from gufe import ChemicalSystem, SmallMoleculeComponent, settings +from openfe.protocols.openmm_utils import charge_generation, system_creation +from openfe.utils import without_oechem_backend +from openff.interchange import Interchange +from openff.toolkit.topology import Molecule as OFFMolecule +from openff.units.openmm import from_openmm, to_openmm +from openmmtools import forces + from openfe_gromacs.protocols.gromacs_md.md_settings import ( IntegratorSettings, OpenFFPartialChargeSettings, OpenMMEngineSettings, OpenMMSolvationSettings, ) -from openff.interchange import Interchange -from openff.toolkit.topology import Molecule as OFFMolecule -from gufe import ChemicalSystem, SmallMoleculeComponent, settings -from openff.units.openmm import from_openmm, to_openmm -from openmmtools import forces -from openfe.protocols.openmm_utils import charge_generation, system_creation -from openfe.utils import without_oechem_backend def assign_partial_charges( @@ -41,7 +43,9 @@ def assign_partial_charges( ) -def create_interchange(settings, solvent_comp, protein_comp, small_mols, shared_basepath): +def create_interchange( + settings, solvent_comp, protein_comp, small_mols, shared_basepath +): """ Creates the Interchange object for the system. @@ -79,8 +83,7 @@ def create_interchange(settings, solvent_comp, protein_comp, small_mols, shared_ # b. get a system generator if settings["output_settings_em"].forcefield_cache is not None: - ffcache = shared_basepath / settings[ - "output_settings_em"].forcefield_cache + ffcache = shared_basepath / settings["output_settings_em"].forcefield_cache else: ffcache = None @@ -114,8 +117,7 @@ def create_interchange(settings, solvent_comp, protein_comp, small_mols, shared_ # d. get topology & positions # Note: roundtrip positions to remove vec3 issues stateA_topology = stateA_modeller.getTopology() - stateA_positions = to_openmm( - from_openmm(stateA_modeller.getPositions())) + stateA_positions = to_openmm(from_openmm(stateA_modeller.getPositions())) # e. create the stateA System stateA_system = system_generator.create_system( @@ -136,7 +138,7 @@ def create_interchange(settings, solvent_comp, protein_comp, small_mols, shared_ ) for molecule_index, molecule in enumerate( - stateA_interchange.topology.molecules + stateA_interchange.topology.molecules ): for atom in molecule.atoms: atom.metadata["residue_number"] = molecule_index + 1 From 00b712d05bf8a70f0d3a25ed890c073a55d00dc6 Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Wed, 25 Sep 2024 14:39:36 +0200 Subject: [PATCH 03/36] Test for interchange creation --- .../protocols/gromacs_md/md_methods.py | 13 +- .../gromacs_utils/system_creation.py | 132 ++++++++++-------- .../tests/protocols/test_system_creation.py | 29 ++++ 3 files changed, 117 insertions(+), 57 deletions(-) create mode 100644 openfe_gromacs/tests/protocols/test_system_creation.py diff --git a/openfe_gromacs/protocols/gromacs_md/md_methods.py b/openfe_gromacs/protocols/gromacs_md/md_methods.py index 6791eac..9ab942a 100644 --- a/openfe_gromacs/protocols/gromacs_md/md_methods.py +++ b/openfe_gromacs/protocols/gromacs_md/md_methods.py @@ -790,9 +790,18 @@ def run( # 1. Write out .mdp files mdps = self._write_mdp_files(settings, shared_basepath) - # 2. Create the Interchange object + # 2. Create the OpenMM system + + # Create a dictionary of OFFMol for each SMC for bookkeeping + smc_components: dict[gufe.SmallMoleculeComponent, OFFMolecule] + smc_components = {i: i.to_openff() for i in small_mols} + + stateA_system, stateA_topology, stateA_positions = system_creation.create_openmm_system( + settings, solvent_comp, protein_comp, smc_components, shared_basepath, + ) + # 3. Create the Interchange object stateA_interchange = system_creation.create_interchange( - settings, solvent_comp, protein_comp, small_mols, shared_basepath + stateA_system, stateA_topology, stateA_positions, smc_components, ) # 4. Save .gro and .top file of the entire system diff --git a/openfe_gromacs/protocols/gromacs_utils/system_creation.py b/openfe_gromacs/protocols/gromacs_utils/system_creation.py index f501720..4f2fa66 100644 --- a/openfe_gromacs/protocols/gromacs_utils/system_creation.py +++ b/openfe_gromacs/protocols/gromacs_utils/system_creation.py @@ -1,7 +1,7 @@ import os import warnings -from gufe import ChemicalSystem, SmallMoleculeComponent, settings +import gufe from openfe.protocols.openmm_utils import charge_generation, system_creation from openfe.utils import without_oechem_backend from openff.interchange import Interchange @@ -19,7 +19,7 @@ def assign_partial_charges( charge_settings: OpenFFPartialChargeSettings, - smc_components: dict[SmallMoleculeComponent, OFFMolecule], + smc_components: dict[gufe.SmallMoleculeComponent, OFFMolecule], ) -> None: """ Assign partial charges to SMCs. @@ -28,7 +28,7 @@ def assign_partial_charges( ---------- charge_settings : OpenFFPartialChargeSettings Settings for controlling how the partial charges are assigned. - smc_components : dict[SmallMoleculeComponent, openff.toolkit.Molecule] + smc_components : dict[gufe.SmallMoleculeComponent, openff.toolkit.Molecule] Dictionary of OpenFF Molecules to add, keyed by SmallMoleculeComponent. """ @@ -42,48 +42,38 @@ def assign_partial_charges( nagl_model=charge_settings.nagl_model, ) - -def create_interchange( - settings, solvent_comp, protein_comp, small_mols, shared_basepath -): +def create_openmm_system( + settings, solvent_comp, protein_comp, smc_components, shared_basepath): """ - Creates the Interchange object for the system. + Creates the OpenMM system. Parameters ---------- settings: dict Dictionary of all the settings - components: dict - Dictionary of the components of the settings, solvent, protein, and - small molecules + solvent_comp: gufe.SolventComponent + The SolventComponent for the system + protein_comp: gufe.ProteinComponent + The ProteinComponent for the system + smc_components: dict[gufe.SmallMoleculeComponent, OFFMolecule] + A dictionary with SmallMoleculeComponents as keys and OpenFF molecules + as values shared_basepath : Pathlike, optional Where to run the calculation, defaults to current working directory Returns ------- - stateA_interchange: Interchange object - The interchange object of the system. + stateA_system: OpenMM system + stateA_topology: OpenMM topology + stateA_positions: Positions """ - # Set the environment variable for using the experimental interchange - # functionality `from_openmm` and raise a warning - os.environ["INTERCHANGE_EXPERIMENTAL"] = "1" - war = ( - "Environment variable INTERCHANGE_EXPERIMENTAL=1 is set for using " - "the interchange functionality 'from_openmm' which is not well " - "tested yet." - ) - warnings.warn(war) - # Create the stateA system - # Create a dictionary of OFFMol for each SMC for bookkeeping - smc_components: dict[SmallMoleculeComponent, OFFMolecule] - smc_components = {i: i.to_openff() for i in small_mols} - # a. assign partial charges to smcs - assign_partial_charges(settings["charge_settings"], smc_components) + assign_partial_charges(settings.partial_charge_settings, smc_components) # b. get a system generator - if settings["output_settings_em"].forcefield_cache is not None: - ffcache = shared_basepath / settings["output_settings_em"].forcefield_cache + if settings.output_settings_em.forcefield_cache is not None: + ffcache = shared_basepath / \ + settings.output_settings_em.forcefield_cache else: ffcache = None @@ -92,9 +82,9 @@ def create_interchange( # go wrong when doing rdkit->OEchem roundtripping with without_oechem_backend(): system_generator = system_creation.get_system_generator( - forcefield_settings=settings["forcefield_settings"], - integrator_settings=settings["integrator_settings"], - thermo_settings=settings["thermo_settings"], + forcefield_settings=settings.forcefield_settings, + integrator_settings=settings.integrator_settings, + thermo_settings=settings.thermo_settings, cache=ffcache, has_solvent=solvent_comp is not None, ) @@ -111,40 +101,72 @@ def create_interchange( solvent_comp=solvent_comp, small_mols=smc_components, omm_forcefield=system_generator.forcefield, - solvent_settings=settings["solvation_settings"], + solvent_settings=settings.solvation_settings, ) # d. get topology & positions # Note: roundtrip positions to remove vec3 issues stateA_topology = stateA_modeller.getTopology() - stateA_positions = to_openmm(from_openmm(stateA_modeller.getPositions())) + stateA_positions = to_openmm( + from_openmm(stateA_modeller.getPositions())) # e. create the stateA System stateA_system = system_generator.create_system( stateA_topology, - molecules=[s.to_openff() for s in small_mols], + molecules=smc_components.values(), ) + return stateA_system, stateA_topology, stateA_positions - # 3. Create the Interchange object - barostat_idx, barostat = forces.find_forces( - stateA_system, ".*Barostat.*", only_one=True - ) - stateA_system.removeForce(barostat_idx) - stateA_interchange = Interchange.from_openmm( - topology=stateA_topology, - system=stateA_system, - positions=stateA_positions, - ) +def create_interchange( + stateA_system, stateA_topology, stateA_positions, smc_components, +): + """ + Creates the Interchange object for the system. + + Parameters + ---------- + stateA_system: OpenMM system + stateA_topology: OpenMM topology + stateA_positions: Positions + smc_components: dict[gufe.SmallMoleculeComponent, OFFMolecule] + A dictionary with SmallMoleculeComponents as keys and OpenFF molecules + as values + + Returns + ------- + stateA_interchange: Interchange object + The interchange object of the system. + """ + # Set the environment variable for using the experimental interchange + # functionality `from_openmm` and raise a warning + os.environ["INTERCHANGE_EXPERIMENTAL"] = "1" + war = ( + "Environment variable INTERCHANGE_EXPERIMENTAL=1 is set for using " + "the interchange functionality 'from_openmm' which is not well " + "tested yet." + ) + warnings.warn(war) + + barostat_idx, barostat = forces.find_forces( + stateA_system, ".*Barostat.*", only_one=True + ) + stateA_system.removeForce(barostat_idx) + + stateA_interchange = Interchange.from_openmm( + topology=stateA_topology, + system=stateA_system, + positions=stateA_positions, + ) - for molecule_index, molecule in enumerate( - stateA_interchange.topology.molecules - ): - for atom in molecule.atoms: - atom.metadata["residue_number"] = molecule_index + 1 - if len([*smc_components.values()]) > 0: - if molecule.n_atoms == [*smc_components.values()][0].n_atoms: - for atom in molecule.atoms: - atom.metadata["residue_name"] = "UNK" + for molecule_index, molecule in enumerate( + stateA_interchange.topology.molecules + ): + for atom in molecule.atoms: + atom.metadata["residue_number"] = molecule_index + 1 + if len([*smc_components.values()]) > 0: + if molecule.n_atoms == [*smc_components.values()][0].n_atoms: + for atom in molecule.atoms: + atom.metadata["residue_name"] = "UNK" return stateA_interchange diff --git a/openfe_gromacs/tests/protocols/test_system_creation.py b/openfe_gromacs/tests/protocols/test_system_creation.py new file mode 100644 index 0000000..d1f8a88 --- /dev/null +++ b/openfe_gromacs/tests/protocols/test_system_creation.py @@ -0,0 +1,29 @@ +# This code is part of OpenFE and is licensed under the MIT license. +# For details, see https://github.com/OpenFreeEnergy/openfe-gromacs +import gufe +import pytest +from openfe_gromacs.protocols.gromacs_md.md_methods import GromacsMDProtocol +from openfe_gromacs.protocols.gromacs_utils import system_creation +from openmm.app import GromacsGroFile + + +def test_interchange_gromacs(T4_protein_component, tmpdir): + solvent = gufe.SolventComponent() + smc_components = {} + settings = GromacsMDProtocol.default_settings() + omm_system, omm_topology, omm_positions = system_creation.create_openmm_system( + settings, solvent, T4_protein_component, smc_components, tmpdir) + omm_atom_names = [atom.name for atom in omm_topology.atoms()] + interchange = system_creation.create_interchange(omm_system, omm_topology, + omm_positions, + smc_components) + interchange_atom_names = [atom.name for atom in interchange.topology.atoms] + interchange.to_gro(f"{tmpdir}/test.gro") + gro_atom_names = GromacsGroFile(f"{tmpdir}/test.gro").atomNames + assert len(omm_atom_names) == len(interchange_atom_names) == len( + gro_atom_names) + assert omm_atom_names == interchange_atom_names == gro_atom_names + + # check a few atom names to ensure these are not empty sets + for atom_name in ("HA", "CH3", "CA", "CB"): + assert atom_name in interchange_atom_names From 3a848e93ce99140ded289375770d874c9b39f631 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 12:40:11 +0000 Subject: [PATCH 04/36] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../protocols/gromacs_md/md_methods.py | 17 ++++++++++++++--- .../gromacs_utils/system_creation.py | 19 ++++++++++--------- .../tests/protocols/test_system_creation.py | 15 ++++++++------- 3 files changed, 32 insertions(+), 19 deletions(-) diff --git a/openfe_gromacs/protocols/gromacs_md/md_methods.py b/openfe_gromacs/protocols/gromacs_md/md_methods.py index 9ab942a..b1fd3ec 100644 --- a/openfe_gromacs/protocols/gromacs_md/md_methods.py +++ b/openfe_gromacs/protocols/gromacs_md/md_methods.py @@ -796,12 +796,23 @@ def run( smc_components: dict[gufe.SmallMoleculeComponent, OFFMolecule] smc_components = {i: i.to_openff() for i in small_mols} - stateA_system, stateA_topology, stateA_positions = system_creation.create_openmm_system( - settings, solvent_comp, protein_comp, smc_components, shared_basepath, + ( + stateA_system, + stateA_topology, + stateA_positions, + ) = system_creation.create_openmm_system( + settings, + solvent_comp, + protein_comp, + smc_components, + shared_basepath, ) # 3. Create the Interchange object stateA_interchange = system_creation.create_interchange( - stateA_system, stateA_topology, stateA_positions, smc_components, + stateA_system, + stateA_topology, + stateA_positions, + smc_components, ) # 4. Save .gro and .top file of the entire system diff --git a/openfe_gromacs/protocols/gromacs_utils/system_creation.py b/openfe_gromacs/protocols/gromacs_utils/system_creation.py index 4f2fa66..017050f 100644 --- a/openfe_gromacs/protocols/gromacs_utils/system_creation.py +++ b/openfe_gromacs/protocols/gromacs_utils/system_creation.py @@ -42,8 +42,10 @@ def assign_partial_charges( nagl_model=charge_settings.nagl_model, ) + def create_openmm_system( - settings, solvent_comp, protein_comp, smc_components, shared_basepath): + settings, solvent_comp, protein_comp, smc_components, shared_basepath +): """ Creates the OpenMM system. @@ -72,8 +74,7 @@ def create_openmm_system( # b. get a system generator if settings.output_settings_em.forcefield_cache is not None: - ffcache = shared_basepath / \ - settings.output_settings_em.forcefield_cache + ffcache = shared_basepath / settings.output_settings_em.forcefield_cache else: ffcache = None @@ -107,8 +108,7 @@ def create_openmm_system( # d. get topology & positions # Note: roundtrip positions to remove vec3 issues stateA_topology = stateA_modeller.getTopology() - stateA_positions = to_openmm( - from_openmm(stateA_modeller.getPositions())) + stateA_positions = to_openmm(from_openmm(stateA_modeller.getPositions())) # e. create the stateA System stateA_system = system_generator.create_system( @@ -119,7 +119,10 @@ def create_openmm_system( def create_interchange( - stateA_system, stateA_topology, stateA_positions, smc_components, + stateA_system, + stateA_topology, + stateA_positions, + smc_components, ): """ Creates the Interchange object for the system. @@ -159,9 +162,7 @@ def create_interchange( positions=stateA_positions, ) - for molecule_index, molecule in enumerate( - stateA_interchange.topology.molecules - ): + for molecule_index, molecule in enumerate(stateA_interchange.topology.molecules): for atom in molecule.atoms: atom.metadata["residue_number"] = molecule_index + 1 if len([*smc_components.values()]) > 0: diff --git a/openfe_gromacs/tests/protocols/test_system_creation.py b/openfe_gromacs/tests/protocols/test_system_creation.py index d1f8a88..b21bf4d 100644 --- a/openfe_gromacs/tests/protocols/test_system_creation.py +++ b/openfe_gromacs/tests/protocols/test_system_creation.py @@ -2,9 +2,10 @@ # For details, see https://github.com/OpenFreeEnergy/openfe-gromacs import gufe import pytest +from openmm.app import GromacsGroFile + from openfe_gromacs.protocols.gromacs_md.md_methods import GromacsMDProtocol from openfe_gromacs.protocols.gromacs_utils import system_creation -from openmm.app import GromacsGroFile def test_interchange_gromacs(T4_protein_component, tmpdir): @@ -12,16 +13,16 @@ def test_interchange_gromacs(T4_protein_component, tmpdir): smc_components = {} settings = GromacsMDProtocol.default_settings() omm_system, omm_topology, omm_positions = system_creation.create_openmm_system( - settings, solvent, T4_protein_component, smc_components, tmpdir) + settings, solvent, T4_protein_component, smc_components, tmpdir + ) omm_atom_names = [atom.name for atom in omm_topology.atoms()] - interchange = system_creation.create_interchange(omm_system, omm_topology, - omm_positions, - smc_components) + interchange = system_creation.create_interchange( + omm_system, omm_topology, omm_positions, smc_components + ) interchange_atom_names = [atom.name for atom in interchange.topology.atoms] interchange.to_gro(f"{tmpdir}/test.gro") gro_atom_names = GromacsGroFile(f"{tmpdir}/test.gro").atomNames - assert len(omm_atom_names) == len(interchange_atom_names) == len( - gro_atom_names) + assert len(omm_atom_names) == len(interchange_atom_names) == len(gro_atom_names) assert omm_atom_names == interchange_atom_names == gro_atom_names # check a few atom names to ensure these are not empty sets From 477bef2fe3077895d5e0bbca80e304a963d51936 Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Wed, 25 Sep 2024 15:43:01 +0200 Subject: [PATCH 05/36] Add test for partial charges --- .../gromacs_utils/system_creation.py | 12 ++-- .../tests/protocols/test_system_creation.py | 58 ++++++++++++++----- 2 files changed, 52 insertions(+), 18 deletions(-) diff --git a/openfe_gromacs/protocols/gromacs_utils/system_creation.py b/openfe_gromacs/protocols/gromacs_utils/system_creation.py index 017050f..6fb1135 100644 --- a/openfe_gromacs/protocols/gromacs_utils/system_creation.py +++ b/openfe_gromacs/protocols/gromacs_utils/system_creation.py @@ -151,10 +151,14 @@ def create_interchange( ) warnings.warn(war) - barostat_idx, barostat = forces.find_forces( - stateA_system, ".*Barostat.*", only_one=True - ) - stateA_system.removeForce(barostat_idx) + try: + barostat_idx, barostat = forces.find_forces( + stateA_system, ".*Barostat.*", only_one=True + ) + stateA_system.removeForce(barostat_idx) + + except forces.NoForceFoundError: + pass stateA_interchange = Interchange.from_openmm( topology=stateA_topology, diff --git a/openfe_gromacs/tests/protocols/test_system_creation.py b/openfe_gromacs/tests/protocols/test_system_creation.py index b21bf4d..70ce138 100644 --- a/openfe_gromacs/tests/protocols/test_system_creation.py +++ b/openfe_gromacs/tests/protocols/test_system_creation.py @@ -2,29 +2,59 @@ # For details, see https://github.com/OpenFreeEnergy/openfe-gromacs import gufe import pytest -from openmm.app import GromacsGroFile +import numpy as np +from openmm.app import GromacsGroFile, GromacsTopFile +from openmm import NonbondedForce from openfe_gromacs.protocols.gromacs_md.md_methods import GromacsMDProtocol from openfe_gromacs.protocols.gromacs_utils import system_creation -def test_interchange_gromacs(T4_protein_component, tmpdir): + +# def test_interchange_gromacs(T4_protein_component, tmpdir): +# solvent = gufe.SolventComponent() +# smc_components = {} +# settings = GromacsMDProtocol.default_settings() +# omm_system, omm_topology, omm_positions = system_creation.create_openmm_system( +# settings, solvent, T4_protein_component, smc_components, tmpdir +# ) +# omm_atom_names = [atom.name for atom in omm_topology.atoms()] +# interchange = system_creation.create_interchange( +# omm_system, omm_topology, omm_positions, smc_components +# ) +# interchange_atom_names = [atom.name for atom in interchange.topology.atoms] +# interchange.to_gro(f"{tmpdir}/test.gro") +# gro_atom_names = GromacsGroFile(f"{tmpdir}/test.gro").atomNames +# assert len(omm_atom_names) == len(interchange_atom_names) == len(gro_atom_names) +# assert omm_atom_names == interchange_atom_names == gro_atom_names +# +# # check a few atom names to ensure these are not empty sets +# for atom_name in ("HA", "CH3", "CA", "CB"): +# assert atom_name in interchange_atom_names + + +def test_user_charges(ethane, tmpdir): solvent = gufe.SolventComponent() - smc_components = {} + off_ethane = ethane.to_openff() + off_ethane.assign_partial_charges(partial_charge_method="am1bcc") + off_charges = off_ethane.partial_charges settings = GromacsMDProtocol.default_settings() + smc_components = {ethane: off_ethane} omm_system, omm_topology, omm_positions = system_creation.create_openmm_system( - settings, solvent, T4_protein_component, smc_components, tmpdir + settings, solvent, None, smc_components, tmpdir ) - omm_atom_names = [atom.name for atom in omm_topology.atoms()] + interchange = system_creation.create_interchange( omm_system, omm_topology, omm_positions, smc_components ) - interchange_atom_names = [atom.name for atom in interchange.topology.atoms] - interchange.to_gro(f"{tmpdir}/test.gro") - gro_atom_names = GromacsGroFile(f"{tmpdir}/test.gro").atomNames - assert len(omm_atom_names) == len(interchange_atom_names) == len(gro_atom_names) - assert omm_atom_names == interchange_atom_names == gro_atom_names - - # check a few atom names to ensure these are not empty sets - for atom_name in ("HA", "CH3", "CA", "CB"): - assert atom_name in interchange_atom_names + # Save to Gromacs .top file + interchange.to_top(f"{tmpdir}/test.top") + # Load Gromacs .top file back in as OpenMM system + gromacs_system = GromacsTopFile(f"{tmpdir}/test.top").createSystem() + # Get the partial charges of the ligand atoms + nonbonded = [f for f in gromacs_system.getForces() if isinstance(f, NonbondedForce)][0] + gro_charges = [] + for i in range(len(off_charges)): + charge, sigma, epsilon = nonbonded.getParticleParameters(i) + gro_charges.append(charge._value) + np.testing.assert_almost_equal(off_charges.m, gro_charges, decimal=5) From bab16de35b4f3b55f92d26c9badaf3a716259611 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 13:43:15 +0000 Subject: [PATCH 06/36] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- openfe_gromacs/tests/protocols/test_system_creation.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/openfe_gromacs/tests/protocols/test_system_creation.py b/openfe_gromacs/tests/protocols/test_system_creation.py index 70ce138..b72d6af 100644 --- a/openfe_gromacs/tests/protocols/test_system_creation.py +++ b/openfe_gromacs/tests/protocols/test_system_creation.py @@ -1,16 +1,14 @@ # This code is part of OpenFE and is licensed under the MIT license. # For details, see https://github.com/OpenFreeEnergy/openfe-gromacs import gufe -import pytest import numpy as np -from openmm.app import GromacsGroFile, GromacsTopFile +import pytest from openmm import NonbondedForce +from openmm.app import GromacsGroFile, GromacsTopFile from openfe_gromacs.protocols.gromacs_md.md_methods import GromacsMDProtocol from openfe_gromacs.protocols.gromacs_utils import system_creation - - # def test_interchange_gromacs(T4_protein_component, tmpdir): # solvent = gufe.SolventComponent() # smc_components = {} @@ -52,7 +50,9 @@ def test_user_charges(ethane, tmpdir): # Load Gromacs .top file back in as OpenMM system gromacs_system = GromacsTopFile(f"{tmpdir}/test.top").createSystem() # Get the partial charges of the ligand atoms - nonbonded = [f for f in gromacs_system.getForces() if isinstance(f, NonbondedForce)][0] + nonbonded = [ + f for f in gromacs_system.getForces() if isinstance(f, NonbondedForce) + ][0] gro_charges = [] for i in range(len(off_charges)): charge, sigma, epsilon = nonbonded.getParticleParameters(i) From 8ad6e9dec1842031c334f73de61c0de2a8bb9ff2 Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Wed, 25 Sep 2024 16:30:34 +0200 Subject: [PATCH 07/36] Rename utils file --- .../protocols/gromacs_md/md_methods.py | 6 +-- .../{system_creation.py => create_systems.py} | 0 .../tests/protocols/test_system_creation.py | 42 +++++++++---------- 3 files changed, 24 insertions(+), 24 deletions(-) rename openfe_gromacs/protocols/gromacs_utils/{system_creation.py => create_systems.py} (100%) diff --git a/openfe_gromacs/protocols/gromacs_md/md_methods.py b/openfe_gromacs/protocols/gromacs_md/md_methods.py index b1fd3ec..e3a6cf8 100644 --- a/openfe_gromacs/protocols/gromacs_md/md_methods.py +++ b/openfe_gromacs/protocols/gromacs_md/md_methods.py @@ -40,7 +40,7 @@ OpenMMEngineSettings, OpenMMSolvationSettings, ) -from openfe_gromacs.protocols.gromacs_utils import system_creation +from openfe_gromacs.protocols.gromacs_utils import create_systems logger = logging.getLogger(__name__) @@ -800,7 +800,7 @@ def run( stateA_system, stateA_topology, stateA_positions, - ) = system_creation.create_openmm_system( + ) = create_systems.create_openmm_system( settings, solvent_comp, protein_comp, @@ -808,7 +808,7 @@ def run( shared_basepath, ) # 3. Create the Interchange object - stateA_interchange = system_creation.create_interchange( + stateA_interchange = create_systems.create_interchange( stateA_system, stateA_topology, stateA_positions, diff --git a/openfe_gromacs/protocols/gromacs_utils/system_creation.py b/openfe_gromacs/protocols/gromacs_utils/create_systems.py similarity index 100% rename from openfe_gromacs/protocols/gromacs_utils/system_creation.py rename to openfe_gromacs/protocols/gromacs_utils/create_systems.py diff --git a/openfe_gromacs/tests/protocols/test_system_creation.py b/openfe_gromacs/tests/protocols/test_system_creation.py index b72d6af..a0b4f52 100644 --- a/openfe_gromacs/tests/protocols/test_system_creation.py +++ b/openfe_gromacs/tests/protocols/test_system_creation.py @@ -7,28 +7,28 @@ from openmm.app import GromacsGroFile, GromacsTopFile from openfe_gromacs.protocols.gromacs_md.md_methods import GromacsMDProtocol -from openfe_gromacs.protocols.gromacs_utils import system_creation +from openfe_gromacs.protocols.gromacs_utils import create_systems -# def test_interchange_gromacs(T4_protein_component, tmpdir): -# solvent = gufe.SolventComponent() -# smc_components = {} -# settings = GromacsMDProtocol.default_settings() -# omm_system, omm_topology, omm_positions = system_creation.create_openmm_system( -# settings, solvent, T4_protein_component, smc_components, tmpdir -# ) -# omm_atom_names = [atom.name for atom in omm_topology.atoms()] -# interchange = system_creation.create_interchange( -# omm_system, omm_topology, omm_positions, smc_components -# ) -# interchange_atom_names = [atom.name for atom in interchange.topology.atoms] -# interchange.to_gro(f"{tmpdir}/test.gro") -# gro_atom_names = GromacsGroFile(f"{tmpdir}/test.gro").atomNames -# assert len(omm_atom_names) == len(interchange_atom_names) == len(gro_atom_names) -# assert omm_atom_names == interchange_atom_names == gro_atom_names -# -# # check a few atom names to ensure these are not empty sets -# for atom_name in ("HA", "CH3", "CA", "CB"): -# assert atom_name in interchange_atom_names +def test_interchange_gromacs(T4_protein_component, tmpdir): + solvent = gufe.SolventComponent() + smc_components = {} + settings = GromacsMDProtocol.default_settings() + omm_system, omm_topology, omm_positions = create_systems.create_openmm_system( + settings, solvent, T4_protein_component, smc_components, tmpdir + ) + omm_atom_names = [atom.name for atom in omm_topology.atoms()] + interchange = create_systems.create_interchange( + omm_system, omm_topology, omm_positions, smc_components + ) + interchange_atom_names = [atom.name for atom in interchange.topology.atoms] + interchange.to_gro(f"{tmpdir}/test.gro") + gro_atom_names = GromacsGroFile(f"{tmpdir}/test.gro").atomNames + assert len(omm_atom_names) == len(interchange_atom_names) == len(gro_atom_names) + assert omm_atom_names == interchange_atom_names == gro_atom_names + + # check a few atom names to ensure these are not empty sets + for atom_name in ("HA", "CH3", "CA", "CB"): + assert atom_name in interchange_atom_names def test_user_charges(ethane, tmpdir): From c459221440be2b4efca12b827a8df2b1b55e10d1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 25 Sep 2024 14:31:00 +0000 Subject: [PATCH 08/36] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- openfe_gromacs/tests/protocols/test_system_creation.py | 1 + 1 file changed, 1 insertion(+) diff --git a/openfe_gromacs/tests/protocols/test_system_creation.py b/openfe_gromacs/tests/protocols/test_system_creation.py index a0b4f52..fb15c55 100644 --- a/openfe_gromacs/tests/protocols/test_system_creation.py +++ b/openfe_gromacs/tests/protocols/test_system_creation.py @@ -9,6 +9,7 @@ from openfe_gromacs.protocols.gromacs_md.md_methods import GromacsMDProtocol from openfe_gromacs.protocols.gromacs_utils import create_systems + def test_interchange_gromacs(T4_protein_component, tmpdir): solvent = gufe.SolventComponent() smc_components = {} From a1eeaedaeaf2bc5af4c0d5e8494201fa91979814 Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Thu, 26 Sep 2024 09:54:30 +0200 Subject: [PATCH 09/36] Small fix --- ...tem_creation.py => test_create_systems.py} | 30 +++++++++++++++++-- openfe_gromacs/tests/test_openfe_gromacs.py | 26 ---------------- 2 files changed, 28 insertions(+), 28 deletions(-) rename openfe_gromacs/tests/protocols/{test_system_creation.py => test_create_systems.py} (70%) delete mode 100644 openfe_gromacs/tests/test_openfe_gromacs.py diff --git a/openfe_gromacs/tests/protocols/test_system_creation.py b/openfe_gromacs/tests/protocols/test_create_systems.py similarity index 70% rename from openfe_gromacs/tests/protocols/test_system_creation.py rename to openfe_gromacs/tests/protocols/test_create_systems.py index fb15c55..af894bb 100644 --- a/openfe_gromacs/tests/protocols/test_system_creation.py +++ b/openfe_gromacs/tests/protocols/test_create_systems.py @@ -39,11 +39,11 @@ def test_user_charges(ethane, tmpdir): off_charges = off_ethane.partial_charges settings = GromacsMDProtocol.default_settings() smc_components = {ethane: off_ethane} - omm_system, omm_topology, omm_positions = system_creation.create_openmm_system( + omm_system, omm_topology, omm_positions = create_systems.create_openmm_system( settings, solvent, None, smc_components, tmpdir ) - interchange = system_creation.create_interchange( + interchange = create_systems.create_interchange( omm_system, omm_topology, omm_positions, smc_components ) # Save to Gromacs .top file @@ -59,3 +59,29 @@ def test_user_charges(ethane, tmpdir): charge, sigma, epsilon = nonbonded.getParticleParameters(i) gro_charges.append(charge._value) np.testing.assert_almost_equal(off_charges.m, gro_charges, decimal=5) + + +# def test_tip4p(ethane, tmpdir): +# settings = GromacsMDProtocol.default_settings() +# settings.forcefield_settings.forcefields = [ +# "amber/ff14SB.xml", # Choose ff14SB for the protein +# "amber/tip4pew_standard.xml", # Choose tip4p for the water +# ] +# settings.solvation_settings.solvent_model = 'tip4pew' +# +# solvent = gufe.SolventComponent() +# smc_components = {ethane: ethane.to_openff()} +# # smc_components = {} +# omm_system, omm_topology, omm_positions = \ +# create_systems.create_openmm_system( +# settings, solvent, None, smc_components, tmpdir +# ) +# +# interchange = create_systems.create_interchange( +# omm_system, omm_topology, omm_positions, smc_components +# ) +# # Save to Gromacs files +# interchange.to_top(f"{tmpdir}/test.top") +# interchange.to_gro(f"{tmpdir}/test.gro") +# +# # Check diff --git a/openfe_gromacs/tests/test_openfe_gromacs.py b/openfe_gromacs/tests/test_openfe_gromacs.py deleted file mode 100644 index 96b22c9..0000000 --- a/openfe_gromacs/tests/test_openfe_gromacs.py +++ /dev/null @@ -1,26 +0,0 @@ -""" -Unit and regression test for the openfe_gromacs package. -""" - -# Import package, test suite, and other packages as needed -import sys - -import pytest - -import openfe_gromacs - - -def test_openfe_gromacs_imported(): - """Sample test, will always pass so long as import statement worked.""" - print("importing ", openfe_gromacs.__name__) - assert "openfe_gromacs" in sys.modules - - -# Assert that a certain exception is raised -def f(): - raise SystemExit(1) - - -def test_mytest(): - with pytest.raises(SystemExit): - f() From 085c8c88cd0a7815c560f49a20d1981eac6bd014 Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Thu, 26 Sep 2024 11:00:23 +0200 Subject: [PATCH 10/36] Move mdp writing to utils --- .../protocols/gromacs_md/md_methods.py | 135 +----------------- .../protocols/gromacs_utils/create_systems.py | 14 +- .../protocols/gromacs_utils/write_mdp.py | 132 +++++++++++++++++ .../tests/protocols/test_create_systems.py | 19 ++- 4 files changed, 159 insertions(+), 141 deletions(-) create mode 100644 openfe_gromacs/protocols/gromacs_utils/write_mdp.py diff --git a/openfe_gromacs/protocols/gromacs_md/md_methods.py b/openfe_gromacs/protocols/gromacs_md/md_methods.py index e3a6cf8..953cf28 100644 --- a/openfe_gromacs/protocols/gromacs_md/md_methods.py +++ b/openfe_gromacs/protocols/gromacs_md/md_methods.py @@ -20,8 +20,7 @@ from typing import Any import gufe -import pint -from gufe import ChemicalSystem, SmallMoleculeComponent, settings +from gufe import ChemicalSystem, settings from openfe.protocols.openmm_utils import system_validation from openfe.utils import log_system_probe from openff.units import unit @@ -40,90 +39,10 @@ OpenMMEngineSettings, OpenMMSolvationSettings, ) -from openfe_gromacs.protocols.gromacs_utils import create_systems +from openfe_gromacs.protocols.gromacs_utils import create_systems, write_mdp logger = logging.getLogger(__name__) -# Settings that are not exposed to the user -PRE_DEFINED_SETTINGS = { - "tinit": 0 * unit.picosecond, - "init_step": 0, - "simulation_part": 0, - "comm_mode": "Linear", - "nstcomm": 100, - "comm_grps": "system", - "pbc": "xyz", - "verlet_buffer_tolerance": 0.005 * unit.kilojoule / (unit.mole * unit.picosecond), - "verlet_buffer_pressure_tolerance": 0.5 * unit.bar, - "coulomb_modifier": "Potential-shift", - "epsilon_r": 1, - "epsilon_rf": 0, - "fourierspacing": 0.12 * unit.nanometer, - "lj_pme_comb_rule": "Geometric", - "ewald_geometry": "3d", - "epsilon_surface": 0, - "lincs_warnangle": 30 * unit.degree, - "continuation": "no", - "morse": "no", -} - -PRE_DEFINED_SETTINGS_EM = { - "emtol": 10.0 * unit.kilojoule / (unit.mole * unit.nanometer), - "emstep": 0.01 * unit.nanometer, -} - -PRE_DEFINED_SETTINGS_MD = { - "nsttcouple": -1, - "tc_grps": "system", - "tau_t": 2.0 * unit.picosecond, - "pcoupltype": "isotropic", - "nstpcouple": -1, - "tau_p": 5 * unit.picosecond, - "compressibility": 4.5e-05 / unit.bar, -} - - -def _dict2mdp(settings_dict: dict, shared_basepath): - """ - Write out a Gromacs .mdp file given a settings dictionary - :param settings_dict: dict - Dictionary of settings - :param shared_basepath: Pathlike - Where to save the .mdp files - """ - filename = shared_basepath / settings_dict["mdp_file"] - # Remove non-mdp settings from the dictionary - non_mdps = [ - "forcefield_cache", - "mdp_file", - "tpr_file", - "trr_file", - "xtc_file", - "gro_file", - "edr_file", - "log_file", - "cpt_file", - "ntomp", - ] - for setting in non_mdps: - settings_dict.pop(setting) - with open(filename, "w") as f: - for key, value in settings_dict.items(): - # First convert units to units in the mdp file, then remove units - if isinstance(value, pint.Quantity): - if value.is_compatible_with(unit.nanometer): - value = value.to(unit.nanometer) - if value.is_compatible_with(unit.picosecond): - value = value.to(unit.picosecond) - if value.is_compatible_with(unit.kelvin): - value = value.to(unit.kelvin) - if value.is_compatible_with(unit.bar): - value = value.to(unit.bar) - value = value.magnitude - # Write out all the setting, value pairs - f.write(f"{key} = {value}\n") - return filename - class GromacsMDProtocolResult(gufe.ProtocolResult): """ @@ -690,54 +609,6 @@ def _handle_settings(self) -> dict[str, gufe.settings.SettingsBaseModel]: return settings - def _write_mdp_files(self, settings: dict, shared_basepath): - """ - Writes out the .mdp files for running a Gromacs MD simulation. - - Parameters - ---------- - settings: dict - Dictionary of all the settings - shared_basepath : Pathlike, optional - Where to run the calculation, defaults to current working directory - - Returns - ------- - mdps: dict - Dictionary of file paths to mdp files. - """ - - mdps = {} - if settings["sim_settings_em"].nsteps > 0: - settings_dict = ( - settings["sim_settings_em"].dict() - | settings["output_settings_em"].dict() - | PRE_DEFINED_SETTINGS - | PRE_DEFINED_SETTINGS_EM - ) - mdp = _dict2mdp(settings_dict, shared_basepath) - mdps["em"] = mdp - if settings["sim_settings_nvt"].nsteps > 0: - settings_dict = ( - settings["sim_settings_nvt"].dict() - | settings["output_settings_nvt"].dict() - | PRE_DEFINED_SETTINGS - | PRE_DEFINED_SETTINGS_MD - ) - mdp = _dict2mdp(settings_dict, shared_basepath) - mdps["nvt"] = mdp - if settings["sim_settings_npt"].nsteps > 0: - settings_dict = ( - settings["sim_settings_npt"].dict() - | settings["output_settings_npt"].dict() - | PRE_DEFINED_SETTINGS - | PRE_DEFINED_SETTINGS_MD - ) - mdp = _dict2mdp(settings_dict, shared_basepath) - mdps["npt"] = mdp - - return mdps - def run( self, *, dry=False, verbose=True, scratch_basepath=None, shared_basepath=None ) -> dict[str, Any]: @@ -788,7 +659,7 @@ def run( ) # 1. Write out .mdp files - mdps = self._write_mdp_files(settings, shared_basepath) + mdps = write_mdp.write_mdp_files(settings, shared_basepath) # 2. Create the OpenMM system diff --git a/openfe_gromacs/protocols/gromacs_utils/create_systems.py b/openfe_gromacs/protocols/gromacs_utils/create_systems.py index 6fb1135..6fe7eb1 100644 --- a/openfe_gromacs/protocols/gromacs_utils/create_systems.py +++ b/openfe_gromacs/protocols/gromacs_utils/create_systems.py @@ -70,11 +70,11 @@ def create_openmm_system( stateA_positions: Positions """ # a. assign partial charges to smcs - assign_partial_charges(settings.partial_charge_settings, smc_components) + assign_partial_charges(settings["charge_settings"], smc_components) # b. get a system generator - if settings.output_settings_em.forcefield_cache is not None: - ffcache = shared_basepath / settings.output_settings_em.forcefield_cache + if settings["output_settings_em"].forcefield_cache is not None: + ffcache = shared_basepath / settings["output_settings_em"].forcefield_cache else: ffcache = None @@ -83,9 +83,9 @@ def create_openmm_system( # go wrong when doing rdkit->OEchem roundtripping with without_oechem_backend(): system_generator = system_creation.get_system_generator( - forcefield_settings=settings.forcefield_settings, - integrator_settings=settings.integrator_settings, - thermo_settings=settings.thermo_settings, + forcefield_settings=settings["forcefield_settings"], + integrator_settings=settings["integrator_settings"], + thermo_settings=settings["thermo_settings"], cache=ffcache, has_solvent=solvent_comp is not None, ) @@ -102,7 +102,7 @@ def create_openmm_system( solvent_comp=solvent_comp, small_mols=smc_components, omm_forcefield=system_generator.forcefield, - solvent_settings=settings.solvation_settings, + solvent_settings=settings["solvation_settings"], ) # d. get topology & positions diff --git a/openfe_gromacs/protocols/gromacs_utils/write_mdp.py b/openfe_gromacs/protocols/gromacs_utils/write_mdp.py new file mode 100644 index 0000000..930eb5d --- /dev/null +++ b/openfe_gromacs/protocols/gromacs_utils/write_mdp.py @@ -0,0 +1,132 @@ +import pint + +from openff.units import unit + +# Settings that are not exposed to the user +PRE_DEFINED_SETTINGS = { + "tinit": 0 * unit.picosecond, + "init_step": 0, + "simulation_part": 0, + "comm_mode": "Linear", + "nstcomm": 100, + "comm_grps": "system", + "pbc": "xyz", + "verlet_buffer_tolerance": 0.005 * unit.kilojoule / ( + unit.mole * unit.picosecond), + "verlet_buffer_pressure_tolerance": 0.5 * unit.bar, + "coulomb_modifier": "Potential-shift", + "epsilon_r": 1, + "epsilon_rf": 0, + "fourierspacing": 0.12 * unit.nanometer, + "lj_pme_comb_rule": "Geometric", + "ewald_geometry": "3d", + "epsilon_surface": 0, + "lincs_warnangle": 30 * unit.degree, + "continuation": "no", + "morse": "no", +} + +PRE_DEFINED_SETTINGS_EM = { + "emtol": 10.0 * unit.kilojoule / (unit.mole * unit.nanometer), + "emstep": 0.01 * unit.nanometer, +} + +PRE_DEFINED_SETTINGS_MD = { + "nsttcouple": -1, + "tc_grps": "system", + "tau_t": 2.0 * unit.picosecond, + "pcoupltype": "isotropic", + "nstpcouple": -1, + "tau_p": 5 * unit.picosecond, + "compressibility": 4.5e-05 / unit.bar, +} + + +def dict2mdp(settings_dict: dict, shared_basepath): + """ + Write out a Gromacs .mdp file given a settings dictionary + :param settings_dict: dict + Dictionary of settings + :param shared_basepath: Pathlike + Where to save the .mdp files + """ + filename = shared_basepath / settings_dict["mdp_file"] + # Remove non-mdp settings from the dictionary + non_mdps = [ + "forcefield_cache", + "mdp_file", + "tpr_file", + "trr_file", + "xtc_file", + "gro_file", + "edr_file", + "log_file", + "cpt_file", + "ntomp", + ] + for setting in non_mdps: + settings_dict.pop(setting) + with open(filename, "w") as f: + for key, value in settings_dict.items(): + # First convert units to units in the mdp file, then remove units + if isinstance(value, pint.Quantity): + if value.is_compatible_with(unit.nanometer): + value = value.to(unit.nanometer) + if value.is_compatible_with(unit.picosecond): + value = value.to(unit.picosecond) + if value.is_compatible_with(unit.kelvin): + value = value.to(unit.kelvin) + if value.is_compatible_with(unit.bar): + value = value.to(unit.bar) + value = value.magnitude + # Write out all the setting, value pairs + f.write(f"{key} = {value}\n") + return filename + +def write_mdp_files(settings: dict, shared_basepath): + """ + Writes out the .mdp files for running a Gromacs simulation. + + Parameters + ---------- + settings: dict + Dictionary of all the settings + shared_basepath : Pathlike, optional + Where to run the calculation, defaults to current working directory + + Returns + ------- + mdps: dict + Dictionary of file paths to mdp files. + """ + + mdps = {} + if settings["sim_settings_em"].nsteps > 0: + settings_dict = ( + settings["sim_settings_em"].dict() + | settings["output_settings_em"].dict() + | PRE_DEFINED_SETTINGS + | PRE_DEFINED_SETTINGS_EM + ) + mdp = dict2mdp(settings_dict, shared_basepath) + mdps["em"] = mdp + if settings["sim_settings_nvt"].nsteps > 0: + settings_dict = ( + settings["sim_settings_nvt"].dict() + | settings["output_settings_nvt"].dict() + | PRE_DEFINED_SETTINGS + | PRE_DEFINED_SETTINGS_MD + ) + mdp = dict2mdp(settings_dict, shared_basepath) + mdps["nvt"] = mdp + if settings["sim_settings_npt"].nsteps > 0: + settings_dict = ( + settings["sim_settings_npt"].dict() + | settings["output_settings_npt"].dict() + | PRE_DEFINED_SETTINGS + | PRE_DEFINED_SETTINGS_MD + ) + mdp = dict2mdp(settings_dict, shared_basepath) + mdps["npt"] = mdp + + return mdps diff --git a/openfe_gromacs/tests/protocols/test_create_systems.py b/openfe_gromacs/tests/protocols/test_create_systems.py index af894bb..ef7c604 100644 --- a/openfe_gromacs/tests/protocols/test_create_systems.py +++ b/openfe_gromacs/tests/protocols/test_create_systems.py @@ -13,7 +13,15 @@ def test_interchange_gromacs(T4_protein_component, tmpdir): solvent = gufe.SolventComponent() smc_components = {} - settings = GromacsMDProtocol.default_settings() + prot_settings = GromacsMDProtocol.default_settings() + # The function expects a settings dict + settings = {} + settings["forcefield_settings"] = prot_settings.forcefield_settings + settings["thermo_settings"] = prot_settings.thermo_settings + settings["solvation_settings"] = prot_settings.solvation_settings + settings["charge_settings"] = prot_settings.partial_charge_settings + settings["integrator_settings"] = prot_settings.integrator_settings + settings["output_settings_em"] = prot_settings.output_settings_em omm_system, omm_topology, omm_positions = create_systems.create_openmm_system( settings, solvent, T4_protein_component, smc_components, tmpdir ) @@ -37,7 +45,14 @@ def test_user_charges(ethane, tmpdir): off_ethane = ethane.to_openff() off_ethane.assign_partial_charges(partial_charge_method="am1bcc") off_charges = off_ethane.partial_charges - settings = GromacsMDProtocol.default_settings() + prot_settings = GromacsMDProtocol.default_settings() + settings = {} + settings["forcefield_settings"] = prot_settings.forcefield_settings + settings["thermo_settings"] = prot_settings.thermo_settings + settings["solvation_settings"] = prot_settings.solvation_settings + settings["charge_settings"] = prot_settings.partial_charge_settings + settings["integrator_settings"] = prot_settings.integrator_settings + settings["output_settings_em"] = prot_settings.output_settings_em smc_components = {ethane: off_ethane} omm_system, omm_topology, omm_positions = create_systems.create_openmm_system( settings, solvent, None, smc_components, tmpdir From b416c1c11855b43b19cba569edba417464ed0d8d Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 09:00:39 +0000 Subject: [PATCH 11/36] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- openfe_gromacs/protocols/gromacs_utils/write_mdp.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/openfe_gromacs/protocols/gromacs_utils/write_mdp.py b/openfe_gromacs/protocols/gromacs_utils/write_mdp.py index 930eb5d..7426f6d 100644 --- a/openfe_gromacs/protocols/gromacs_utils/write_mdp.py +++ b/openfe_gromacs/protocols/gromacs_utils/write_mdp.py @@ -1,5 +1,4 @@ import pint - from openff.units import unit # Settings that are not exposed to the user @@ -11,8 +10,7 @@ "nstcomm": 100, "comm_grps": "system", "pbc": "xyz", - "verlet_buffer_tolerance": 0.005 * unit.kilojoule / ( - unit.mole * unit.picosecond), + "verlet_buffer_tolerance": 0.005 * unit.kilojoule / (unit.mole * unit.picosecond), "verlet_buffer_pressure_tolerance": 0.5 * unit.bar, "coulomb_modifier": "Potential-shift", "epsilon_r": 1, @@ -83,6 +81,7 @@ def dict2mdp(settings_dict: dict, shared_basepath): f.write(f"{key} = {value}\n") return filename + def write_mdp_files(settings: dict, shared_basepath): """ Writes out the .mdp files for running a Gromacs simulation. From d8e36e98329905bd8e6087a9c4fa06a73c65a5bf Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Thu, 26 Sep 2024 11:21:30 +0200 Subject: [PATCH 12/36] Try and fix tests that take so long --- openfe_gromacs/tests/protocols/test_md_tokenization.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/openfe_gromacs/tests/protocols/test_md_tokenization.py b/openfe_gromacs/tests/protocols/test_md_tokenization.py index 8701ffe..f1666ea 100644 --- a/openfe_gromacs/tests/protocols/test_md_tokenization.py +++ b/openfe_gromacs/tests/protocols/test_md_tokenization.py @@ -19,7 +19,7 @@ def protocol(): def protocol_units(protocol, benzene_system): pus = protocol.create( stateA=benzene_system, - stateB=openfe.ChemicalSystem({"solvent": openfe.SolventComponent()}), + stateB=benzene_system, mapping=None, ) return list(pus.protocol_units) @@ -62,10 +62,11 @@ def test_key_stable(self): pytest.skip() +@pytest.mark.skip class TestGromacsMDProtocolResult(GufeTokenizableTestsMixin): cls = gromacs_md.GromacsMDProtocolResult - key = "GromacsMDProtocolResult-4739ae9a56f36a1e7c95c503601769f4" - repr = f"<{key}>" + key = "" + repr = "" @pytest.fixture() def instance(self, protocol_result): From 8fecc09988ee0fc2dead698ac0363312d1068628 Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Thu, 26 Sep 2024 11:38:18 +0200 Subject: [PATCH 13/36] Update results --- .../tests/data/MDProtocol_json_results.gz | Bin 3614 -> 3655 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/openfe_gromacs/tests/data/MDProtocol_json_results.gz b/openfe_gromacs/tests/data/MDProtocol_json_results.gz index 532efec39c6459b10eb5302e171759d3fdeac92c..db146fbbc2f08f8a27fb438673808b752952ebf6 100644 GIT binary patch literal 3655 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 C!U?1R literal 3614 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 From 0a72927398bd34bb4045cc4552236bf5139b817e Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Thu, 26 Sep 2024 14:15:55 +0200 Subject: [PATCH 14/36] Skip result check tests to see if that solves slowness problem --- .../tests/protocols/test_gromacs_md.py | 214 +++++++++--------- 1 file changed, 107 insertions(+), 107 deletions(-) diff --git a/openfe_gromacs/tests/protocols/test_gromacs_md.py b/openfe_gromacs/tests/protocols/test_gromacs_md.py index 76c5431..209e533 100644 --- a/openfe_gromacs/tests/protocols/test_gromacs_md.py +++ b/openfe_gromacs/tests/protocols/test_gromacs_md.py @@ -198,110 +198,110 @@ def test_dry_many_molecules_solvent( ) -class TestProtocolResult: - @pytest.fixture() - def protocolresult(self, md_json): - d = json.loads(md_json, cls=gufe.tokenization.JSON_HANDLER.decoder) - - pr = openfe_gromacs.ProtocolResult.from_dict(d["protocol_result"]) - - return pr - - def test_reload_protocol_result(self, md_json): - d = json.loads(md_json, cls=gufe.tokenization.JSON_HANDLER.decoder) - - pr = GromacsMDProtocolResult.from_dict(d["protocol_result"]) - - assert pr - - def test_get_estimate(self, protocolresult): - est = protocolresult.get_estimate() - - assert est is None - - def test_get_uncertainty(self, protocolresult): - est = protocolresult.get_uncertainty() - - assert est is None - - def test_get_gro_filename(self, protocolresult): - gro = protocolresult.get_gro_filename() - - assert isinstance(gro, list) - assert isinstance(gro[0], pathlib.Path) - - def test_get_top_filename(self, protocolresult): - top = protocolresult.get_top_filename() - - assert isinstance(top, list) - assert isinstance(top[0], pathlib.Path) - - def test_get_mdp_filenames(self, protocolresult): - mdps = protocolresult.get_mdp_filenames() - - assert isinstance(mdps, list) - assert isinstance(mdps[0], dict) - assert all(isinstance(mdp, pathlib.Path) for mdp in mdps[0].values()) - - def test_get_filenames_em(self, protocolresult): - dict_file_path = protocolresult.get_filenames_em() - assert isinstance(dict_file_path, dict) - assert len(dict_file_path) == 7 - for name, file_path in dict_file_path.items(): - assert isinstance(file_path, list) - assert len(file_path) == 1 - assert isinstance(file_path[0], pathlib.Path) - - def test_get_gro_em_filename(self, protocolresult): - file_path = protocolresult.get_gro_em_filename() - - assert isinstance(file_path, list) - assert isinstance(file_path[0], pathlib.Path) - - def test_get_xtc_em_filename(self, protocolresult): - file_path = protocolresult.get_xtc_em_filename() - - assert isinstance(file_path, list) - assert isinstance(file_path[0], pathlib.Path) - - def test_get_filenames_nvt(self, protocolresult): - dict_file_path = protocolresult.get_filenames_nvt() - assert isinstance(dict_file_path, dict) - assert len(dict_file_path) == 7 - for name, file_path in dict_file_path.items(): - assert isinstance(file_path, list) - assert len(file_path) == 1 - assert isinstance(file_path[0], pathlib.Path) - - def test_get_gro_nvt_filename(self, protocolresult): - file_path = protocolresult.get_gro_nvt_filename() - - assert isinstance(file_path, list) - assert isinstance(file_path[0], pathlib.Path) - - def test_get_xtc_nvt_filename(self, protocolresult): - file_path = protocolresult.get_xtc_nvt_filename() - - assert isinstance(file_path, list) - assert isinstance(file_path[0], pathlib.Path) - - def test_get_filenames_npt(self, protocolresult): - dict_file_path = protocolresult.get_filenames_npt() - assert isinstance(dict_file_path, dict) - assert len(dict_file_path) == 7 - for name, file_path in dict_file_path.items(): - assert isinstance(file_path, list) - assert len(file_path) == 1 - assert isinstance(file_path[0], pathlib.Path) - - def test_get_gro_npt_filename(self, protocolresult): - file_path = protocolresult.get_gro_npt_filename() - - assert isinstance(file_path, list) - assert isinstance(file_path[0], pathlib.Path) - - def test_get_xtc_npt_filename(self, protocolresult): - file_path = protocolresult.get_xtc_npt_filename() - - assert isinstance(file_path, list) - assert isinstance(file_path[0], pathlib.Path) +#class TestProtocolResult: +# @pytest.fixture() +# def protocolresult(self, md_json): +# d = json.loads(md_json, cls=gufe.tokenization.JSON_HANDLER.decoder) +# +# pr = openfe_gromacs.ProtocolResult.from_dict(d["protocol_result"]) +# +# return pr +# +# def test_reload_protocol_result(self, md_json): +# d = json.loads(md_json, cls=gufe.tokenization.JSON_HANDLER.decoder) +# +# pr = GromacsMDProtocolResult.from_dict(d["protocol_result"]) +# +# assert pr +# +# def test_get_estimate(self, protocolresult): +# est = protocolresult.get_estimate() +# +# assert est is None +# +# def test_get_uncertainty(self, protocolresult): +# est = protocolresult.get_uncertainty() +# +# assert est is None +# +# def test_get_gro_filename(self, protocolresult): +# gro = protocolresult.get_gro_filename() +# +# assert isinstance(gro, list) +# assert isinstance(gro[0], pathlib.Path) +# +# def test_get_top_filename(self, protocolresult): +# top = protocolresult.get_top_filename() +# +# assert isinstance(top, list) +# assert isinstance(top[0], pathlib.Path) +# +# def test_get_mdp_filenames(self, protocolresult): +# mdps = protocolresult.get_mdp_filenames() +# +# assert isinstance(mdps, list) +# assert isinstance(mdps[0], dict) +# assert all(isinstance(mdp, pathlib.Path) for mdp in mdps[0].values()) +# +# def test_get_filenames_em(self, protocolresult): +# dict_file_path = protocolresult.get_filenames_em() +# assert isinstance(dict_file_path, dict) +# assert len(dict_file_path) == 7 +# for name, file_path in dict_file_path.items(): +# assert isinstance(file_path, list) +# assert len(file_path) == 1 +# assert isinstance(file_path[0], pathlib.Path) +# +# def test_get_gro_em_filename(self, protocolresult): +# file_path = protocolresult.get_gro_em_filename() +# +# assert isinstance(file_path, list) +# assert isinstance(file_path[0], pathlib.Path) +# +# def test_get_xtc_em_filename(self, protocolresult): +# file_path = protocolresult.get_xtc_em_filename() +# +# assert isinstance(file_path, list) +# assert isinstance(file_path[0], pathlib.Path) +# +# def test_get_filenames_nvt(self, protocolresult): +# dict_file_path = protocolresult.get_filenames_nvt() +# assert isinstance(dict_file_path, dict) +# assert len(dict_file_path) == 7 +# for name, file_path in dict_file_path.items(): +# assert isinstance(file_path, list) +# assert len(file_path) == 1 +# assert isinstance(file_path[0], pathlib.Path) +# +# def test_get_gro_nvt_filename(self, protocolresult): +# file_path = protocolresult.get_gro_nvt_filename() +# +# assert isinstance(file_path, list) +# assert isinstance(file_path[0], pathlib.Path) +# +# def test_get_xtc_nvt_filename(self, protocolresult): +# file_path = protocolresult.get_xtc_nvt_filename() +# +# assert isinstance(file_path, list) +# assert isinstance(file_path[0], pathlib.Path) +# +# def test_get_filenames_npt(self, protocolresult): +# dict_file_path = protocolresult.get_filenames_npt() +# assert isinstance(dict_file_path, dict) +# assert len(dict_file_path) == 7 +# for name, file_path in dict_file_path.items(): +# assert isinstance(file_path, list) +# assert len(file_path) == 1 +# assert isinstance(file_path[0], pathlib.Path) +# +# def test_get_gro_npt_filename(self, protocolresult): +# file_path = protocolresult.get_gro_npt_filename() +# +# assert isinstance(file_path, list) +# assert isinstance(file_path[0], pathlib.Path) +# +# def test_get_xtc_npt_filename(self, protocolresult): +# file_path = protocolresult.get_xtc_npt_filename() +# +# assert isinstance(file_path, list) +# assert isinstance(file_path[0], pathlib.Path) From a5772486d1c92aab17098f128ea003846ecbce8e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 12:16:13 +0000 Subject: [PATCH 15/36] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- openfe_gromacs/tests/protocols/test_gromacs_md.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfe_gromacs/tests/protocols/test_gromacs_md.py b/openfe_gromacs/tests/protocols/test_gromacs_md.py index 209e533..0cb0dad 100644 --- a/openfe_gromacs/tests/protocols/test_gromacs_md.py +++ b/openfe_gromacs/tests/protocols/test_gromacs_md.py @@ -198,7 +198,7 @@ def test_dry_many_molecules_solvent( ) -#class TestProtocolResult: +# class TestProtocolResult: # @pytest.fixture() # def protocolresult(self, md_json): # d = json.loads(md_json, cls=gufe.tokenization.JSON_HANDLER.decoder) From ec99d9e6b0f1fc225469854fcccf4cd934ab845a Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Thu, 26 Sep 2024 14:24:13 +0200 Subject: [PATCH 16/36] Fix results --- .../tests/data/MDProtocol_json_results.gz | Bin 3655 -> 3613 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/openfe_gromacs/tests/data/MDProtocol_json_results.gz b/openfe_gromacs/tests/data/MDProtocol_json_results.gz index db146fbbc2f08f8a27fb438673808b752952ebf6..80857255d62bd705dc5cdd2c5ea2348de1233e5b 100644 GIT binary patch delta 3515 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 delta 3559 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 LmB+GgDJcF6W7pV4 From f20b429ec50a0f1d7d5ab1dbfca81970147fb408 Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Fri, 27 Sep 2024 11:04:12 +0200 Subject: [PATCH 17/36] Update tests --- openfe_gromacs/__init__.py | 3 + .../protocols/gromacs_md/md_methods.py | 4 +- .../protocols/gromacs_md/md_settings.py | 11 +- openfe_gromacs/tests/conftest.py | 28 ++- .../tests/protocols/test_create_systems.py | 31 +-- .../tests/protocols/test_gromacs_md.py | 214 +++++++++--------- 6 files changed, 143 insertions(+), 148 deletions(-) diff --git a/openfe_gromacs/__init__.py b/openfe_gromacs/__init__.py index feb953d..f0f5f48 100644 --- a/openfe_gromacs/__init__.py +++ b/openfe_gromacs/__init__.py @@ -19,3 +19,6 @@ ProtocolUnitResult, execute_DAG, ) + +from importlib.metadata import version +__version__ = version("openfe_gromacs") diff --git a/openfe_gromacs/protocols/gromacs_md/md_methods.py b/openfe_gromacs/protocols/gromacs_md/md_methods.py index 953cf28..aec78fb 100644 --- a/openfe_gromacs/protocols/gromacs_md/md_methods.py +++ b/openfe_gromacs/protocols/gromacs_md/md_methods.py @@ -37,7 +37,7 @@ NVTSimulationSettings, OpenFFPartialChargeSettings, OpenMMEngineSettings, - OpenMMSolvationSettings, + SolvationSettings, ) from openfe_gromacs.protocols.gromacs_utils import create_systems, write_mdp @@ -390,7 +390,7 @@ def _default_settings(cls): pressure=1 * unit.bar, ), partial_charge_settings=OpenFFPartialChargeSettings(), - solvation_settings=OpenMMSolvationSettings(), + solvation_settings=SolvationSettings(), engine_settings=OpenMMEngineSettings(), integrator_settings=IntegratorSettings(), simulation_settings_em=EMSimulationSettings( diff --git a/openfe_gromacs/protocols/gromacs_md/md_settings.py b/openfe_gromacs/protocols/gromacs_md/md_settings.py index a77b1bd..4a3c7d7 100644 --- a/openfe_gromacs/protocols/gromacs_md/md_settings.py +++ b/openfe_gromacs/protocols/gromacs_md/md_settings.py @@ -673,6 +673,15 @@ def has_no_constraints(cls, v): return v +class SolvationSettings(OpenMMSolvationSettings): + """ + Solvation settings for solvating the system using OpenMM. For now, + water models with virtual sites are not supported when creating an + Interchange object `from_openmm`. + """ + solvent_model: Literal['tip3p'] = 'tip3p' + + class GromacsMDProtocolSettings(Settings): class Config: arbitrary_types_allowed = True @@ -696,7 +705,7 @@ def must_be_positive(cls, v): # Things for creating the OpenMM systems forcefield_settings: FFSettingsOpenMM partial_charge_settings: OpenFFPartialChargeSettings - solvation_settings: OpenMMSolvationSettings + solvation_settings: SolvationSettings # MD Engine things engine_settings: OpenMMEngineSettings diff --git a/openfe_gromacs/tests/conftest.py b/openfe_gromacs/tests/conftest.py index cb1b894..0a482d1 100644 --- a/openfe_gromacs/tests/conftest.py +++ b/openfe_gromacs/tests/conftest.py @@ -5,12 +5,13 @@ from importlib import resources import gufe -import openfe +import openfe_gromacs import pytest from gufe import SmallMoleculeComponent from openff.units import unit from rdkit import Chem from rdkit.Chem import AllChem +import pathlib class SlowTests: @@ -125,7 +126,7 @@ def ethane(): @pytest.fixture(scope="session") def benzene_modifications(): files = {} - with importlib.resources.files("openfe.tests.data") as d: + with importlib.resources.files("openfe_gromacs.tests.data") as d: fn = str(d / "benzene_modifications.sdf") supp = Chem.SDMolSupplier(str(fn), removeHs=False) for rdmol in supp: @@ -135,34 +136,43 @@ def benzene_modifications(): @pytest.fixture(scope="session") def T4_protein_component(): - with resources.files("openfe.tests.data") as d: + with resources.files("openfe_gromacs.tests.data") as d: fn = str(d / "181l_only.pdb") comp = gufe.ProteinComponent.from_pdb_file(fn, name="T4_protein") return comp +@pytest.fixture(scope="session") +def alanine_dipeptide_component(): + with resources.files("openfe_gromacs.tests.data") as d: + fn = str(d / "alanine-dipeptide.pdb") + comp = gufe.ProteinComponent.from_pdb_file(fn, name="Alanine_dipeptide") + + return comp + + @pytest.fixture() def eg5_protein_pdb(): - with resources.files("openfe.tests.data.eg5") as d: + with resources.files("openfe_gromacs.tests.data.eg5") as d: yield str(d / "eg5_protein.pdb") @pytest.fixture() def eg5_ligands_sdf(): - with resources.files("openfe.tests.data.eg5") as d: + with resources.files("openfe_gromacs.tests.data.eg5") as d: yield str(d / "eg5_ligands.sdf") @pytest.fixture() def eg5_cofactor_sdf(): - with resources.files("openfe.tests.data.eg5") as d: + with resources.files("openfe_gromacs.tests.data.eg5") as d: yield str(d / "eg5_cofactor.sdf") @pytest.fixture() -def eg5_protein(eg5_protein_pdb) -> openfe.ProteinComponent: - return openfe.ProteinComponent.from_pdb_file(eg5_protein_pdb) +def eg5_protein(eg5_protein_pdb) -> openfe_gromacs.ProteinComponent: + return openfe_gromacs.ProteinComponent.from_pdb_file(eg5_protein_pdb) @pytest.fixture() @@ -183,7 +193,7 @@ def CN_molecule(): """ A basic CH3NH2 molecule for quick testing. """ - with resources.files("openfe.tests.data") as d: + with resources.files("openfe-gromacs.tests.data") as d: fn = str(d / "CN.sdf") supp = Chem.SDMolSupplier(str(fn), removeHs=False) diff --git a/openfe_gromacs/tests/protocols/test_create_systems.py b/openfe_gromacs/tests/protocols/test_create_systems.py index ef7c604..68a6fa3 100644 --- a/openfe_gromacs/tests/protocols/test_create_systems.py +++ b/openfe_gromacs/tests/protocols/test_create_systems.py @@ -2,7 +2,6 @@ # For details, see https://github.com/OpenFreeEnergy/openfe-gromacs import gufe import numpy as np -import pytest from openmm import NonbondedForce from openmm.app import GromacsGroFile, GromacsTopFile @@ -10,7 +9,7 @@ from openfe_gromacs.protocols.gromacs_utils import create_systems -def test_interchange_gromacs(T4_protein_component, tmpdir): +def test_interchange_gromacs(alanine_dipeptide_component, tmpdir): solvent = gufe.SolventComponent() smc_components = {} prot_settings = GromacsMDProtocol.default_settings() @@ -23,7 +22,7 @@ def test_interchange_gromacs(T4_protein_component, tmpdir): settings["integrator_settings"] = prot_settings.integrator_settings settings["output_settings_em"] = prot_settings.output_settings_em omm_system, omm_topology, omm_positions = create_systems.create_openmm_system( - settings, solvent, T4_protein_component, smc_components, tmpdir + settings, solvent, alanine_dipeptide_component, smc_components, tmpdir ) omm_atom_names = [atom.name for atom in omm_topology.atoms()] interchange = create_systems.create_interchange( @@ -74,29 +73,3 @@ def test_user_charges(ethane, tmpdir): charge, sigma, epsilon = nonbonded.getParticleParameters(i) gro_charges.append(charge._value) np.testing.assert_almost_equal(off_charges.m, gro_charges, decimal=5) - - -# def test_tip4p(ethane, tmpdir): -# settings = GromacsMDProtocol.default_settings() -# settings.forcefield_settings.forcefields = [ -# "amber/ff14SB.xml", # Choose ff14SB for the protein -# "amber/tip4pew_standard.xml", # Choose tip4p for the water -# ] -# settings.solvation_settings.solvent_model = 'tip4pew' -# -# solvent = gufe.SolventComponent() -# smc_components = {ethane: ethane.to_openff()} -# # smc_components = {} -# omm_system, omm_topology, omm_positions = \ -# create_systems.create_openmm_system( -# settings, solvent, None, smc_components, tmpdir -# ) -# -# interchange = create_systems.create_interchange( -# omm_system, omm_topology, omm_positions, smc_components -# ) -# # Save to Gromacs files -# interchange.to_top(f"{tmpdir}/test.top") -# interchange.to_gro(f"{tmpdir}/test.gro") -# -# # Check diff --git a/openfe_gromacs/tests/protocols/test_gromacs_md.py b/openfe_gromacs/tests/protocols/test_gromacs_md.py index 0cb0dad..76c5431 100644 --- a/openfe_gromacs/tests/protocols/test_gromacs_md.py +++ b/openfe_gromacs/tests/protocols/test_gromacs_md.py @@ -198,110 +198,110 @@ def test_dry_many_molecules_solvent( ) -# class TestProtocolResult: -# @pytest.fixture() -# def protocolresult(self, md_json): -# d = json.loads(md_json, cls=gufe.tokenization.JSON_HANDLER.decoder) -# -# pr = openfe_gromacs.ProtocolResult.from_dict(d["protocol_result"]) -# -# return pr -# -# def test_reload_protocol_result(self, md_json): -# d = json.loads(md_json, cls=gufe.tokenization.JSON_HANDLER.decoder) -# -# pr = GromacsMDProtocolResult.from_dict(d["protocol_result"]) -# -# assert pr -# -# def test_get_estimate(self, protocolresult): -# est = protocolresult.get_estimate() -# -# assert est is None -# -# def test_get_uncertainty(self, protocolresult): -# est = protocolresult.get_uncertainty() -# -# assert est is None -# -# def test_get_gro_filename(self, protocolresult): -# gro = protocolresult.get_gro_filename() -# -# assert isinstance(gro, list) -# assert isinstance(gro[0], pathlib.Path) -# -# def test_get_top_filename(self, protocolresult): -# top = protocolresult.get_top_filename() -# -# assert isinstance(top, list) -# assert isinstance(top[0], pathlib.Path) -# -# def test_get_mdp_filenames(self, protocolresult): -# mdps = protocolresult.get_mdp_filenames() -# -# assert isinstance(mdps, list) -# assert isinstance(mdps[0], dict) -# assert all(isinstance(mdp, pathlib.Path) for mdp in mdps[0].values()) -# -# def test_get_filenames_em(self, protocolresult): -# dict_file_path = protocolresult.get_filenames_em() -# assert isinstance(dict_file_path, dict) -# assert len(dict_file_path) == 7 -# for name, file_path in dict_file_path.items(): -# assert isinstance(file_path, list) -# assert len(file_path) == 1 -# assert isinstance(file_path[0], pathlib.Path) -# -# def test_get_gro_em_filename(self, protocolresult): -# file_path = protocolresult.get_gro_em_filename() -# -# assert isinstance(file_path, list) -# assert isinstance(file_path[0], pathlib.Path) -# -# def test_get_xtc_em_filename(self, protocolresult): -# file_path = protocolresult.get_xtc_em_filename() -# -# assert isinstance(file_path, list) -# assert isinstance(file_path[0], pathlib.Path) -# -# def test_get_filenames_nvt(self, protocolresult): -# dict_file_path = protocolresult.get_filenames_nvt() -# assert isinstance(dict_file_path, dict) -# assert len(dict_file_path) == 7 -# for name, file_path in dict_file_path.items(): -# assert isinstance(file_path, list) -# assert len(file_path) == 1 -# assert isinstance(file_path[0], pathlib.Path) -# -# def test_get_gro_nvt_filename(self, protocolresult): -# file_path = protocolresult.get_gro_nvt_filename() -# -# assert isinstance(file_path, list) -# assert isinstance(file_path[0], pathlib.Path) -# -# def test_get_xtc_nvt_filename(self, protocolresult): -# file_path = protocolresult.get_xtc_nvt_filename() -# -# assert isinstance(file_path, list) -# assert isinstance(file_path[0], pathlib.Path) -# -# def test_get_filenames_npt(self, protocolresult): -# dict_file_path = protocolresult.get_filenames_npt() -# assert isinstance(dict_file_path, dict) -# assert len(dict_file_path) == 7 -# for name, file_path in dict_file_path.items(): -# assert isinstance(file_path, list) -# assert len(file_path) == 1 -# assert isinstance(file_path[0], pathlib.Path) -# -# def test_get_gro_npt_filename(self, protocolresult): -# file_path = protocolresult.get_gro_npt_filename() -# -# assert isinstance(file_path, list) -# assert isinstance(file_path[0], pathlib.Path) -# -# def test_get_xtc_npt_filename(self, protocolresult): -# file_path = protocolresult.get_xtc_npt_filename() -# -# assert isinstance(file_path, list) -# assert isinstance(file_path[0], pathlib.Path) +class TestProtocolResult: + @pytest.fixture() + def protocolresult(self, md_json): + d = json.loads(md_json, cls=gufe.tokenization.JSON_HANDLER.decoder) + + pr = openfe_gromacs.ProtocolResult.from_dict(d["protocol_result"]) + + return pr + + def test_reload_protocol_result(self, md_json): + d = json.loads(md_json, cls=gufe.tokenization.JSON_HANDLER.decoder) + + pr = GromacsMDProtocolResult.from_dict(d["protocol_result"]) + + assert pr + + def test_get_estimate(self, protocolresult): + est = protocolresult.get_estimate() + + assert est is None + + def test_get_uncertainty(self, protocolresult): + est = protocolresult.get_uncertainty() + + assert est is None + + def test_get_gro_filename(self, protocolresult): + gro = protocolresult.get_gro_filename() + + assert isinstance(gro, list) + assert isinstance(gro[0], pathlib.Path) + + def test_get_top_filename(self, protocolresult): + top = protocolresult.get_top_filename() + + assert isinstance(top, list) + assert isinstance(top[0], pathlib.Path) + + def test_get_mdp_filenames(self, protocolresult): + mdps = protocolresult.get_mdp_filenames() + + assert isinstance(mdps, list) + assert isinstance(mdps[0], dict) + assert all(isinstance(mdp, pathlib.Path) for mdp in mdps[0].values()) + + def test_get_filenames_em(self, protocolresult): + dict_file_path = protocolresult.get_filenames_em() + assert isinstance(dict_file_path, dict) + assert len(dict_file_path) == 7 + for name, file_path in dict_file_path.items(): + assert isinstance(file_path, list) + assert len(file_path) == 1 + assert isinstance(file_path[0], pathlib.Path) + + def test_get_gro_em_filename(self, protocolresult): + file_path = protocolresult.get_gro_em_filename() + + assert isinstance(file_path, list) + assert isinstance(file_path[0], pathlib.Path) + + def test_get_xtc_em_filename(self, protocolresult): + file_path = protocolresult.get_xtc_em_filename() + + assert isinstance(file_path, list) + assert isinstance(file_path[0], pathlib.Path) + + def test_get_filenames_nvt(self, protocolresult): + dict_file_path = protocolresult.get_filenames_nvt() + assert isinstance(dict_file_path, dict) + assert len(dict_file_path) == 7 + for name, file_path in dict_file_path.items(): + assert isinstance(file_path, list) + assert len(file_path) == 1 + assert isinstance(file_path[0], pathlib.Path) + + def test_get_gro_nvt_filename(self, protocolresult): + file_path = protocolresult.get_gro_nvt_filename() + + assert isinstance(file_path, list) + assert isinstance(file_path[0], pathlib.Path) + + def test_get_xtc_nvt_filename(self, protocolresult): + file_path = protocolresult.get_xtc_nvt_filename() + + assert isinstance(file_path, list) + assert isinstance(file_path[0], pathlib.Path) + + def test_get_filenames_npt(self, protocolresult): + dict_file_path = protocolresult.get_filenames_npt() + assert isinstance(dict_file_path, dict) + assert len(dict_file_path) == 7 + for name, file_path in dict_file_path.items(): + assert isinstance(file_path, list) + assert len(file_path) == 1 + assert isinstance(file_path[0], pathlib.Path) + + def test_get_gro_npt_filename(self, protocolresult): + file_path = protocolresult.get_gro_npt_filename() + + assert isinstance(file_path, list) + assert isinstance(file_path[0], pathlib.Path) + + def test_get_xtc_npt_filename(self, protocolresult): + file_path = protocolresult.get_xtc_npt_filename() + + assert isinstance(file_path, list) + assert isinstance(file_path[0], pathlib.Path) From 4beb1c38fa0bde6b53f680923e9ed048508c3a12 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 27 Sep 2024 09:36:32 +0000 Subject: [PATCH 18/36] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- openfe_gromacs/__init__.py | 3 ++- openfe_gromacs/protocols/gromacs_md/md_settings.py | 4 +++- openfe_gromacs/tests/conftest.py | 5 +++-- openfe_gromacs/tests/data/alanine-dipeptide.pdb | 6 +++--- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/openfe_gromacs/__init__.py b/openfe_gromacs/__init__.py index f0f5f48..ad2c10f 100644 --- a/openfe_gromacs/__init__.py +++ b/openfe_gromacs/__init__.py @@ -1,3 +1,5 @@ +from importlib.metadata import version + from gufe import ( AlchemicalNetwork, ChemicalSystem, @@ -20,5 +22,4 @@ execute_DAG, ) -from importlib.metadata import version __version__ = version("openfe_gromacs") diff --git a/openfe_gromacs/protocols/gromacs_md/md_settings.py b/openfe_gromacs/protocols/gromacs_md/md_settings.py index 4bd9ab2..f823b2a 100644 --- a/openfe_gromacs/protocols/gromacs_md/md_settings.py +++ b/openfe_gromacs/protocols/gromacs_md/md_settings.py @@ -671,7 +671,9 @@ class SolvationSettings(OpenMMSolvationSettings): water models with virtual sites are not supported when creating an Interchange object `from_openmm`. """ - solvent_model: Literal['tip3p'] = 'tip3p' + + solvent_model: Literal["tip3p"] = "tip3p" + class GromacsEngineSettings(SettingsBaseModel): """ diff --git a/openfe_gromacs/tests/conftest.py b/openfe_gromacs/tests/conftest.py index 400347b..7b8177f 100644 --- a/openfe_gromacs/tests/conftest.py +++ b/openfe_gromacs/tests/conftest.py @@ -2,16 +2,17 @@ # For details, see https://github.com/OpenFreeEnergy/openfe import importlib import os +import pathlib from importlib import resources import gufe -import openfe_gromacs import pytest from gufe import SmallMoleculeComponent from openff.units import unit from rdkit import Chem from rdkit.Chem import AllChem -import pathlib + +import openfe_gromacs class SlowTests: diff --git a/openfe_gromacs/tests/data/alanine-dipeptide.pdb b/openfe_gromacs/tests/data/alanine-dipeptide.pdb index 32ba37b..8c2501a 100644 --- a/openfe_gromacs/tests/data/alanine-dipeptide.pdb +++ b/openfe_gromacs/tests/data/alanine-dipeptide.pdb @@ -1,4 +1,4 @@ -REMARK ACE +REMARK ACE ATOM 1 1HH3 ACE 1 2.000 1.000 -0.000 ATOM 2 CH3 ACE 1 2.000 2.090 0.000 ATOM 3 2HH3 ACE 1 1.486 2.454 0.890 @@ -21,5 +21,5 @@ ATOM 19 CH3 NME 3 5.846 8.284 0.000 ATOM 20 1HH3 NME 3 4.819 8.648 0.000 ATOM 21 2HH3 NME 3 6.360 8.648 0.890 ATOM 22 3HH3 NME 3 6.360 8.648 -0.890 -TER -END +TER +END From 6deccb4a176b602159e570321b0c25a72907eca8 Mon Sep 17 00:00:00 2001 From: IAlibay Date: Sat, 28 Sep 2024 23:20:51 +0100 Subject: [PATCH 19/36] Add missing init file --- openfe_gromacs/tests/data/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 openfe_gromacs/tests/data/__init__.py diff --git a/openfe_gromacs/tests/data/__init__.py b/openfe_gromacs/tests/data/__init__.py new file mode 100644 index 0000000..e69de29 From 544cc0fff7494d34833edb93326fbf3aaec728c9 Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Mon, 30 Sep 2024 10:44:00 +0200 Subject: [PATCH 20/36] Change partial charge test --- openfe_gromacs/tests/conftest.py | 12 ++++++------ .../tests/protocols/test_create_systems.py | 14 +++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/openfe_gromacs/tests/conftest.py b/openfe_gromacs/tests/conftest.py index 7b8177f..62fa118 100644 --- a/openfe_gromacs/tests/conftest.py +++ b/openfe_gromacs/tests/conftest.py @@ -127,7 +127,7 @@ def ethane(): @pytest.fixture(scope="session") def benzene_modifications(): files = {} - with importlib.resources.files("openfe.tests.data") as d: + with importlib.resources.files("openfe_gromacs.tests.data") as d: fn = str(d / "benzene_modifications.sdf") supp = Chem.SDMolSupplier(str(fn), removeHs=False) for rdmol in supp: @@ -137,7 +137,7 @@ def benzene_modifications(): @pytest.fixture(scope="session") def T4_protein_component(): - with resources.files("openfe.tests.data") as d: + with resources.files("openfe_gromacs.tests.data") as d: fn = str(d / "181l_only.pdb") comp = gufe.ProteinComponent.from_pdb_file(fn, name="T4_protein") @@ -155,19 +155,19 @@ def alanine_dipeptide_component(): @pytest.fixture() def eg5_protein_pdb(): - with resources.files("openfe.tests.data.eg5") as d: + with resources.files("openfe_gromacs.tests.data.eg5") as d: yield str(d / "eg5_protein.pdb") @pytest.fixture() def eg5_ligands_sdf(): - with resources.files("openfe.tests.data.eg5") as d: + with resources.files("openfe_gromacs.tests.data.eg5") as d: yield str(d / "eg5_ligands.sdf") @pytest.fixture() def eg5_cofactor_sdf(): - with resources.files("openfe.tests.data.eg5") as d: + with resources.files("openfe_gromacs.tests.data.eg5") as d: yield str(d / "eg5_cofactor.sdf") @@ -194,7 +194,7 @@ def CN_molecule(): """ A basic CH3NH2 molecule for quick testing. """ - with resources.files("openfe-gromacs.tests.data") as d: + with resources.files("openfe_gromacs.tests.data") as d: fn = str(d / "CN.sdf") supp = Chem.SDMolSupplier(str(fn), removeHs=False) diff --git a/openfe_gromacs/tests/protocols/test_create_systems.py b/openfe_gromacs/tests/protocols/test_create_systems.py index 0ca273e..efe9f32 100644 --- a/openfe_gromacs/tests/protocols/test_create_systems.py +++ b/openfe_gromacs/tests/protocols/test_create_systems.py @@ -9,7 +9,7 @@ from openfe_gromacs.protocols.gromacs_utils import create_systems -def test_interchange_gromacs(T4_protein_component, tmpdir): +def test_interchange_gromacs(alanine_dipeptide_component, tmpdir): solvent = gufe.SolventComponent() smc_components = {} prot_settings = GromacsMDProtocol.default_settings() @@ -22,7 +22,7 @@ def test_interchange_gromacs(T4_protein_component, tmpdir): settings["integrator_settings"] = prot_settings.integrator_settings settings["output_settings_em"] = prot_settings.output_settings_em omm_system, omm_topology, omm_positions = create_systems.create_openmm_system( - settings, solvent, T4_protein_component, smc_components, tmpdir + settings, solvent, alanine_dipeptide_component, smc_components, tmpdir ) omm_atom_names = [atom.name for atom in omm_topology.atoms()] interchange = create_systems.create_interchange( @@ -39,11 +39,11 @@ def test_interchange_gromacs(T4_protein_component, tmpdir): assert atom_name in interchange_atom_names -def test_user_charges(ethane, tmpdir): +def test_user_charges(CN_molecule, tmpdir): solvent = gufe.SolventComponent() - off_ethane = ethane.to_openff() - off_ethane.assign_partial_charges(partial_charge_method="am1bcc") - off_charges = off_ethane.partial_charges + off_cn = CN_molecule.to_openff() + off_cn.assign_partial_charges(partial_charge_method="am1-mulliken") + off_charges = off_cn.partial_charges prot_settings = GromacsMDProtocol.default_settings() settings = {} settings["forcefield_settings"] = prot_settings.forcefield_settings @@ -52,7 +52,7 @@ def test_user_charges(ethane, tmpdir): settings["charge_settings"] = prot_settings.partial_charge_settings settings["integrator_settings"] = prot_settings.integrator_settings settings["output_settings_em"] = prot_settings.output_settings_em - smc_components = {ethane: off_ethane} + smc_components = {CN_molecule: off_cn} omm_system, omm_topology, omm_positions = create_systems.create_openmm_system( settings, solvent, None, smc_components, tmpdir ) From fa6dab8fbb39abe8b6d5851eb8aae506069d173d Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Mon, 30 Sep 2024 10:52:43 +0200 Subject: [PATCH 21/36] Update doc strings --- .../protocols/gromacs_md/md_methods.py | 24 +++++++++---------- .../protocols/gromacs_utils/write_mdp.py | 11 +++++---- .../tests/protocols/test_md_tokenization.py | 2 +- 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/openfe_gromacs/protocols/gromacs_md/md_methods.py b/openfe_gromacs/protocols/gromacs_md/md_methods.py index 7944b77..49464a9 100644 --- a/openfe_gromacs/protocols/gromacs_md/md_methods.py +++ b/openfe_gromacs/protocols/gromacs_md/md_methods.py @@ -738,19 +738,19 @@ def _run_gromacs( Parameters ---------- - :param mdp: pathlib.Path + mdp: pathlib.Path Path to the mdp file - :param in_gro: pathlib.Path - :param top: pathlib.Path - :param tpr: pathlib.Path - :param out_gro: str - :param xtc: str - :param trr: str - :param cpt: str - :param log: str - :param edr: str - :param engine_settings: GromacsEngineSettings - :param shared_basebath: Pathlike, optional + in_gro: pathlib.Path + top: pathlib.Path + tpr: pathlib.Path + out_gro: str + xtc: str + trr: str + cpt: str + log: str + edr: str + engine_settings: GromacsEngineSettings + shared_basebath: Pathlike, optional Where to run the calculation, defaults to current working directory """ assert os.path.exists(in_gro) diff --git a/openfe_gromacs/protocols/gromacs_utils/write_mdp.py b/openfe_gromacs/protocols/gromacs_utils/write_mdp.py index fa451d8..261b895 100644 --- a/openfe_gromacs/protocols/gromacs_utils/write_mdp.py +++ b/openfe_gromacs/protocols/gromacs_utils/write_mdp.py @@ -43,10 +43,13 @@ def dict2mdp(settings_dict: dict, shared_basepath): """ Write out a Gromacs .mdp file given a settings dictionary - :param settings_dict: dict - Dictionary of settings - :param shared_basepath: Pathlike - Where to save the .mdp files + + Parameters + ---------- + settings_dict: dict + Dictionary of settings + shared_basepath: Pathlike + Where to save the .mdp files """ filename = shared_basepath / settings_dict["mdp_file"] # Remove non-mdp settings from the dictionary diff --git a/openfe_gromacs/tests/protocols/test_md_tokenization.py b/openfe_gromacs/tests/protocols/test_md_tokenization.py index ef84ca0..90836d4 100644 --- a/openfe_gromacs/tests/protocols/test_md_tokenization.py +++ b/openfe_gromacs/tests/protocols/test_md_tokenization.py @@ -41,7 +41,7 @@ def protocol_result(md_json): class TestGromacsMDProtocol(GufeTokenizableTestsMixin): cls = gromacs_md.GromacsMDProtocol - key = "GromacsMDProtocol-ec824b46b95c4ee8393d59287cf2feab" + key = "GromacsMDProtocol-c75de773fddf547f15daf4c01a455c66" repr = f"<{key}>" @pytest.fixture() From c1c4a00888e3f23713e34b549c9497eb103016b3 Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Mon, 30 Sep 2024 11:07:04 +0200 Subject: [PATCH 22/36] Pass individual settings to create_openmm_system --- .../protocols/gromacs_md/md_methods.py | 7 +++- .../protocols/gromacs_utils/create_systems.py | 36 +++++++++++++----- .../tests/protocols/test_create_systems.py | 38 ++++++++++--------- 3 files changed, 53 insertions(+), 28 deletions(-) diff --git a/openfe_gromacs/protocols/gromacs_md/md_methods.py b/openfe_gromacs/protocols/gromacs_md/md_methods.py index 49464a9..046ba9e 100644 --- a/openfe_gromacs/protocols/gromacs_md/md_methods.py +++ b/openfe_gromacs/protocols/gromacs_md/md_methods.py @@ -670,10 +670,15 @@ def run( stateA_topology, stateA_positions, ) = create_systems.create_openmm_system( - settings, solvent_comp, protein_comp, smc_components, + settings["charge_settings"], + settings["forcefield_settings"], + settings["integrator_settings"], + settings["thermo_settings"], + settings["solvation_settings"], + settings["output_settings_em"], shared_basepath, ) # 3. Create the Interchange object diff --git a/openfe_gromacs/protocols/gromacs_utils/create_systems.py b/openfe_gromacs/protocols/gromacs_utils/create_systems.py index 8fa0384..ca9d65a 100644 --- a/openfe_gromacs/protocols/gromacs_utils/create_systems.py +++ b/openfe_gromacs/protocols/gromacs_utils/create_systems.py @@ -10,8 +10,11 @@ from openmmtools import forces from openfe_gromacs.protocols.gromacs_md.md_settings import ( + EMOutputSettings, + FFSettingsOpenMM, IntegratorSettings, OpenFFPartialChargeSettings, + SolvationSettings, ) @@ -42,15 +45,22 @@ def assign_partial_charges( def create_openmm_system( - settings, solvent_comp, protein_comp, smc_components, shared_basepath + solvent_comp, + protein_comp, + smc_components, + partial_charge_settings, + forcefield_settings, + integrator_settings, + thermo_settings, + solvation_settings, + output_settings_em, + shared_basepath, ): """ Creates the OpenMM system. Parameters ---------- - settings: dict - Dictionary of all the settings solvent_comp: gufe.SolventComponent The SolventComponent for the system protein_comp: gufe.ProteinComponent @@ -58,6 +68,12 @@ def create_openmm_system( smc_components: dict[gufe.SmallMoleculeComponent, OFFMolecule] A dictionary with SmallMoleculeComponents as keys and OpenFF molecules as values + partial_charge_settings: OpenFFPartialChargeSettings + forcefield_settings: FFSettingsOpenMM + integrator_settings: IntegratorSettings + thermo_settings: gufe.settings.ThermoSettings + solvation_settings: SolvationSettings + output_settings_em: EMOutputSettings shared_basepath : Pathlike, optional Where to run the calculation, defaults to current working directory @@ -68,11 +84,11 @@ def create_openmm_system( stateA_positions: Positions """ # a. assign partial charges to smcs - assign_partial_charges(settings["charge_settings"], smc_components) + assign_partial_charges(partial_charge_settings, smc_components) # b. get a system generator - if settings["output_settings_em"].forcefield_cache is not None: - ffcache = shared_basepath / settings["output_settings_em"].forcefield_cache + if output_settings_em.forcefield_cache is not None: + ffcache = shared_basepath / output_settings_em.forcefield_cache else: ffcache = None @@ -81,9 +97,9 @@ def create_openmm_system( # go wrong when doing rdkit->OEchem roundtripping with without_oechem_backend(): system_generator = system_creation.get_system_generator( - forcefield_settings=settings["forcefield_settings"], - integrator_settings=settings["integrator_settings"], - thermo_settings=settings["thermo_settings"], + forcefield_settings=forcefield_settings, + integrator_settings=integrator_settings, + thermo_settings=thermo_settings, cache=ffcache, has_solvent=solvent_comp is not None, ) @@ -100,7 +116,7 @@ def create_openmm_system( solvent_comp=solvent_comp, small_mols=smc_components, omm_forcefield=system_generator.forcefield, - solvent_settings=settings["solvation_settings"], + solvent_settings=solvation_settings, ) # d. get topology & positions diff --git a/openfe_gromacs/tests/protocols/test_create_systems.py b/openfe_gromacs/tests/protocols/test_create_systems.py index efe9f32..dcf696e 100644 --- a/openfe_gromacs/tests/protocols/test_create_systems.py +++ b/openfe_gromacs/tests/protocols/test_create_systems.py @@ -13,16 +13,18 @@ def test_interchange_gromacs(alanine_dipeptide_component, tmpdir): solvent = gufe.SolventComponent() smc_components = {} prot_settings = GromacsMDProtocol.default_settings() - # The function expects a settings dict - settings = {} - settings["forcefield_settings"] = prot_settings.forcefield_settings - settings["thermo_settings"] = prot_settings.thermo_settings - settings["solvation_settings"] = prot_settings.solvation_settings - settings["charge_settings"] = prot_settings.partial_charge_settings - settings["integrator_settings"] = prot_settings.integrator_settings - settings["output_settings_em"] = prot_settings.output_settings_em + omm_system, omm_topology, omm_positions = create_systems.create_openmm_system( - settings, solvent, alanine_dipeptide_component, smc_components, tmpdir + solvent, + alanine_dipeptide_component, + smc_components, + prot_settings.partial_charge_settings, + prot_settings.forcefield_settings, + prot_settings.integrator_settings, + prot_settings.thermo_settings, + prot_settings.solvation_settings, + prot_settings.output_settings_em, + tmpdir, ) omm_atom_names = [atom.name for atom in omm_topology.atoms()] interchange = create_systems.create_interchange( @@ -45,16 +47,18 @@ def test_user_charges(CN_molecule, tmpdir): off_cn.assign_partial_charges(partial_charge_method="am1-mulliken") off_charges = off_cn.partial_charges prot_settings = GromacsMDProtocol.default_settings() - settings = {} - settings["forcefield_settings"] = prot_settings.forcefield_settings - settings["thermo_settings"] = prot_settings.thermo_settings - settings["solvation_settings"] = prot_settings.solvation_settings - settings["charge_settings"] = prot_settings.partial_charge_settings - settings["integrator_settings"] = prot_settings.integrator_settings - settings["output_settings_em"] = prot_settings.output_settings_em smc_components = {CN_molecule: off_cn} omm_system, omm_topology, omm_positions = create_systems.create_openmm_system( - settings, solvent, None, smc_components, tmpdir + solvent, + None, + smc_components, + prot_settings.partial_charge_settings, + prot_settings.forcefield_settings, + prot_settings.integrator_settings, + prot_settings.thermo_settings, + prot_settings.solvation_settings, + prot_settings.output_settings_em, + tmpdir, ) interchange = create_systems.create_interchange( From 40ede957f70244c7ff5bf9780ce209a49ae92b4a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2024 09:07:20 +0000 Subject: [PATCH 23/36] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../protocols/gromacs_utils/create_systems.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/openfe_gromacs/protocols/gromacs_utils/create_systems.py b/openfe_gromacs/protocols/gromacs_utils/create_systems.py index ca9d65a..d078d07 100644 --- a/openfe_gromacs/protocols/gromacs_utils/create_systems.py +++ b/openfe_gromacs/protocols/gromacs_utils/create_systems.py @@ -45,16 +45,16 @@ def assign_partial_charges( def create_openmm_system( - solvent_comp, - protein_comp, - smc_components, - partial_charge_settings, - forcefield_settings, - integrator_settings, - thermo_settings, - solvation_settings, - output_settings_em, - shared_basepath, + solvent_comp, + protein_comp, + smc_components, + partial_charge_settings, + forcefield_settings, + integrator_settings, + thermo_settings, + solvation_settings, + output_settings_em, + shared_basepath, ): """ Creates the OpenMM system. From 839130ee1167f8577d9cf5603d01626574a8a540 Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Mon, 30 Sep 2024 12:18:53 +0200 Subject: [PATCH 24/36] Add tests for residue number and name --- .../tests/protocols/test_create_systems.py | 89 +++++++++++-------- 1 file changed, 53 insertions(+), 36 deletions(-) diff --git a/openfe_gromacs/tests/protocols/test_create_systems.py b/openfe_gromacs/tests/protocols/test_create_systems.py index dcf696e..4b06437 100644 --- a/openfe_gromacs/tests/protocols/test_create_systems.py +++ b/openfe_gromacs/tests/protocols/test_create_systems.py @@ -31,49 +31,66 @@ def test_interchange_gromacs(alanine_dipeptide_component, tmpdir): omm_system, omm_topology, omm_positions, smc_components ) interchange_atom_names = [atom.name for atom in interchange.topology.atoms] + interchange.to_gro(f"{tmpdir}/test.gro") gro_atom_names = GromacsGroFile(f"{tmpdir}/test.gro").atomNames + + # Testing that the number of atoms is the same assert len(omm_atom_names) == len(interchange_atom_names) == len(gro_atom_names) + # Testing that atom names are the same assert omm_atom_names == interchange_atom_names == gro_atom_names + # Testing that residue names are the same + interchange_res_names = [atom.metadata["residue_name"] for atom in + interchange.topology.atoms] + gro_res_names = GromacsGroFile(f"{tmpdir}/test.gro").residueNames + combined_res_names = interchange_res_names + gro_res_names + assert len(set(combined_res_names)) == len(set(gro_res_names)) + # Testing that residue numbers are the same + interchange_res_numbers = [atom.metadata["residue_number"] for atom in + interchange.topology.atoms] + with open(f"{tmpdir}/test.gro") as f: + gromacs_res_numbers = [int(line[:5].strip()) for line in f.readlines()[2:-1]] + assert interchange_res_numbers == gromacs_res_numbers + # check a few atom names to ensure these are not empty sets for atom_name in ("HA", "CH3", "CA", "CB"): assert atom_name in interchange_atom_names -def test_user_charges(CN_molecule, tmpdir): - solvent = gufe.SolventComponent() - off_cn = CN_molecule.to_openff() - off_cn.assign_partial_charges(partial_charge_method="am1-mulliken") - off_charges = off_cn.partial_charges - prot_settings = GromacsMDProtocol.default_settings() - smc_components = {CN_molecule: off_cn} - omm_system, omm_topology, omm_positions = create_systems.create_openmm_system( - solvent, - None, - smc_components, - prot_settings.partial_charge_settings, - prot_settings.forcefield_settings, - prot_settings.integrator_settings, - prot_settings.thermo_settings, - prot_settings.solvation_settings, - prot_settings.output_settings_em, - tmpdir, - ) - - interchange = create_systems.create_interchange( - omm_system, omm_topology, omm_positions, smc_components - ) - # Save to Gromacs .top file - interchange.to_top(f"{tmpdir}/test.top") - # Load Gromacs .top file back in as OpenMM system - gromacs_system = GromacsTopFile(f"{tmpdir}/test.top").createSystem() - # Get the partial charges of the ligand atoms - nonbonded = [ - f for f in gromacs_system.getForces() if isinstance(f, NonbondedForce) - ][0] - gro_charges = [] - for i in range(len(off_charges)): - charge, sigma, epsilon = nonbonded.getParticleParameters(i) - gro_charges.append(charge._value) - np.testing.assert_almost_equal(off_charges.m, gro_charges, decimal=5) +# def test_user_charges(CN_molecule, tmpdir): +# solvent = gufe.SolventComponent() +# off_cn = CN_molecule.to_openff() +# off_cn.assign_partial_charges(partial_charge_method="am1-mulliken") +# off_charges = off_cn.partial_charges +# prot_settings = GromacsMDProtocol.default_settings() +# smc_components = {CN_molecule: off_cn} +# omm_system, omm_topology, omm_positions = create_systems.create_openmm_system( +# solvent, +# None, +# smc_components, +# prot_settings.partial_charge_settings, +# prot_settings.forcefield_settings, +# prot_settings.integrator_settings, +# prot_settings.thermo_settings, +# prot_settings.solvation_settings, +# prot_settings.output_settings_em, +# tmpdir, +# ) +# +# interchange = create_systems.create_interchange( +# omm_system, omm_topology, omm_positions, smc_components +# ) +# # Save to Gromacs .top file +# interchange.to_top(f"{tmpdir}/test.top") +# # Load Gromacs .top file back in as OpenMM system +# gromacs_system = GromacsTopFile(f"{tmpdir}/test.top").createSystem() +# # Get the partial charges of the ligand atoms +# nonbonded = [ +# f for f in gromacs_system.getForces() if isinstance(f, NonbondedForce) +# ][0] +# gro_charges = [] +# for i in range(len(off_charges)): +# charge, sigma, epsilon = nonbonded.getParticleParameters(i) +# gro_charges.append(charge._value) +# np.testing.assert_almost_equal(off_charges.m, gro_charges, decimal=5) From f269ff6b1fe8d1fc4a172dacba643f15c5a63edd Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Mon, 30 Sep 2024 12:19:18 +0200 Subject: [PATCH 25/36] Add other test back in --- .../tests/protocols/test_create_systems.py | 72 +++++++++---------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/openfe_gromacs/tests/protocols/test_create_systems.py b/openfe_gromacs/tests/protocols/test_create_systems.py index 4b06437..9635ba3 100644 --- a/openfe_gromacs/tests/protocols/test_create_systems.py +++ b/openfe_gromacs/tests/protocols/test_create_systems.py @@ -58,39 +58,39 @@ def test_interchange_gromacs(alanine_dipeptide_component, tmpdir): assert atom_name in interchange_atom_names -# def test_user_charges(CN_molecule, tmpdir): -# solvent = gufe.SolventComponent() -# off_cn = CN_molecule.to_openff() -# off_cn.assign_partial_charges(partial_charge_method="am1-mulliken") -# off_charges = off_cn.partial_charges -# prot_settings = GromacsMDProtocol.default_settings() -# smc_components = {CN_molecule: off_cn} -# omm_system, omm_topology, omm_positions = create_systems.create_openmm_system( -# solvent, -# None, -# smc_components, -# prot_settings.partial_charge_settings, -# prot_settings.forcefield_settings, -# prot_settings.integrator_settings, -# prot_settings.thermo_settings, -# prot_settings.solvation_settings, -# prot_settings.output_settings_em, -# tmpdir, -# ) -# -# interchange = create_systems.create_interchange( -# omm_system, omm_topology, omm_positions, smc_components -# ) -# # Save to Gromacs .top file -# interchange.to_top(f"{tmpdir}/test.top") -# # Load Gromacs .top file back in as OpenMM system -# gromacs_system = GromacsTopFile(f"{tmpdir}/test.top").createSystem() -# # Get the partial charges of the ligand atoms -# nonbonded = [ -# f for f in gromacs_system.getForces() if isinstance(f, NonbondedForce) -# ][0] -# gro_charges = [] -# for i in range(len(off_charges)): -# charge, sigma, epsilon = nonbonded.getParticleParameters(i) -# gro_charges.append(charge._value) -# np.testing.assert_almost_equal(off_charges.m, gro_charges, decimal=5) +def test_user_charges(CN_molecule, tmpdir): + solvent = gufe.SolventComponent() + off_cn = CN_molecule.to_openff() + off_cn.assign_partial_charges(partial_charge_method="am1-mulliken") + off_charges = off_cn.partial_charges + prot_settings = GromacsMDProtocol.default_settings() + smc_components = {CN_molecule: off_cn} + omm_system, omm_topology, omm_positions = create_systems.create_openmm_system( + solvent, + None, + smc_components, + prot_settings.partial_charge_settings, + prot_settings.forcefield_settings, + prot_settings.integrator_settings, + prot_settings.thermo_settings, + prot_settings.solvation_settings, + prot_settings.output_settings_em, + tmpdir, + ) + + interchange = create_systems.create_interchange( + omm_system, omm_topology, omm_positions, smc_components + ) + # Save to Gromacs .top file + interchange.to_top(f"{tmpdir}/test.top") + # Load Gromacs .top file back in as OpenMM system + gromacs_system = GromacsTopFile(f"{tmpdir}/test.top").createSystem() + # Get the partial charges of the ligand atoms + nonbonded = [ + f for f in gromacs_system.getForces() if isinstance(f, NonbondedForce) + ][0] + gro_charges = [] + for i in range(len(off_charges)): + charge, sigma, epsilon = nonbonded.getParticleParameters(i) + gro_charges.append(charge._value) + np.testing.assert_almost_equal(off_charges.m, gro_charges, decimal=5) From 2f80f6ffe6c5ced0264d9053099cea29803189b0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2024 10:20:02 +0000 Subject: [PATCH 26/36] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- openfe_gromacs/tests/protocols/test_create_systems.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/openfe_gromacs/tests/protocols/test_create_systems.py b/openfe_gromacs/tests/protocols/test_create_systems.py index 9635ba3..58150d2 100644 --- a/openfe_gromacs/tests/protocols/test_create_systems.py +++ b/openfe_gromacs/tests/protocols/test_create_systems.py @@ -40,19 +40,20 @@ def test_interchange_gromacs(alanine_dipeptide_component, tmpdir): # Testing that atom names are the same assert omm_atom_names == interchange_atom_names == gro_atom_names # Testing that residue names are the same - interchange_res_names = [atom.metadata["residue_name"] for atom in - interchange.topology.atoms] + interchange_res_names = [ + atom.metadata["residue_name"] for atom in interchange.topology.atoms + ] gro_res_names = GromacsGroFile(f"{tmpdir}/test.gro").residueNames combined_res_names = interchange_res_names + gro_res_names assert len(set(combined_res_names)) == len(set(gro_res_names)) # Testing that residue numbers are the same - interchange_res_numbers = [atom.metadata["residue_number"] for atom in - interchange.topology.atoms] + interchange_res_numbers = [ + atom.metadata["residue_number"] for atom in interchange.topology.atoms + ] with open(f"{tmpdir}/test.gro") as f: gromacs_res_numbers = [int(line[:5].strip()) for line in f.readlines()[2:-1]] assert interchange_res_numbers == gromacs_res_numbers - # check a few atom names to ensure these are not empty sets for atom_name in ("HA", "CH3", "CA", "CB"): assert atom_name in interchange_atom_names From 031b04b89d20a3aa530e06597961390370063eec Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Mon, 30 Sep 2024 14:17:15 +0200 Subject: [PATCH 27/36] Test out new interchange --- environment.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/environment.yml b/environment.yml index 71824fd..a290d07 100644 --- a/environment.yml +++ b/environment.yml @@ -9,3 +9,4 @@ dependencies: - pytest - pytest-xdist - pytest-cov + - openff-interchange>=0.4 From 4e7853084201faefbb20afaaa8bfa12517d970d5 Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Mon, 30 Sep 2024 14:20:49 +0200 Subject: [PATCH 28/36] Disable residue number check for now till new interchange release --- environment.yml | 1 - openfe_gromacs/tests/protocols/test_create_systems.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/environment.yml b/environment.yml index a290d07..71824fd 100644 --- a/environment.yml +++ b/environment.yml @@ -9,4 +9,3 @@ dependencies: - pytest - pytest-xdist - pytest-cov - - openff-interchange>=0.4 diff --git a/openfe_gromacs/tests/protocols/test_create_systems.py b/openfe_gromacs/tests/protocols/test_create_systems.py index 58150d2..90f7a75 100644 --- a/openfe_gromacs/tests/protocols/test_create_systems.py +++ b/openfe_gromacs/tests/protocols/test_create_systems.py @@ -52,7 +52,7 @@ def test_interchange_gromacs(alanine_dipeptide_component, tmpdir): ] with open(f"{tmpdir}/test.gro") as f: gromacs_res_numbers = [int(line[:5].strip()) for line in f.readlines()[2:-1]] - assert interchange_res_numbers == gromacs_res_numbers +# assert interchange_res_numbers == gromacs_res_numbers # check a few atom names to ensure these are not empty sets for atom_name in ("HA", "CH3", "CA", "CB"): From c7dd5038a923a995f9f041c17b935c4c071c3004 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:22:12 +0000 Subject: [PATCH 29/36] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- openfe_gromacs/tests/protocols/test_create_systems.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfe_gromacs/tests/protocols/test_create_systems.py b/openfe_gromacs/tests/protocols/test_create_systems.py index 90f7a75..b57ca5c 100644 --- a/openfe_gromacs/tests/protocols/test_create_systems.py +++ b/openfe_gromacs/tests/protocols/test_create_systems.py @@ -52,7 +52,7 @@ def test_interchange_gromacs(alanine_dipeptide_component, tmpdir): ] with open(f"{tmpdir}/test.gro") as f: gromacs_res_numbers = [int(line[:5].strip()) for line in f.readlines()[2:-1]] -# assert interchange_res_numbers == gromacs_res_numbers + # assert interchange_res_numbers == gromacs_res_numbers # check a few atom names to ensure these are not empty sets for atom_name in ("HA", "CH3", "CA", "CB"): From e1f996bc420b2386bcc59a3909fbb8dd51ef9e98 Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Mon, 30 Sep 2024 14:32:35 +0200 Subject: [PATCH 30/36] Update precommit.yaml --- .pre-commit-config.yaml | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 342dbda..77221ad 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ ci: autoupdate_schedule: "quarterly" repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.6.0 hooks: - id: check-yaml - id: debug-statements @@ -12,23 +12,28 @@ repos: - id: check-executables-have-shebangs - id: check-json - repo: https://github.com/psf/black - rev: 22.12.0 + rev: 24.8.0 hooks: - id: black files: ^openfe_gromacs - repo: https://github.com/PyCQA/isort - rev: 5.12.0 + rev: 5.13.2 hooks: - id: isort files: ^openfe_gromacs - repo: https://github.com/PyCQA/flake8 - rev: 6.0.0 + rev: 7.1.1 hooks: - id: flake8 files: ^openfe_gromacs - additional_dependencies: [Flake8-pyproject] + additional_dependencies: [ + 'flake8-bugbear', + 'flake8-absolute-import', + 'flake8-pytest-style==2', + 'flake8-no-pep420', + ] - repo: https://github.com/asottile/pyupgrade - rev: 'v3.3.1' + rev: 'v3.17.0' hooks: - id: pyupgrade args: From b546e015c0641141edb18b8cc5277120da11e805 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:33:11 +0000 Subject: [PATCH 31/36] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- openfe_gromacs/protocols/gromacs_md/md_settings.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openfe_gromacs/protocols/gromacs_md/md_settings.py b/openfe_gromacs/protocols/gromacs_md/md_settings.py index f823b2a..7ab0c78 100644 --- a/openfe_gromacs/protocols/gromacs_md/md_settings.py +++ b/openfe_gromacs/protocols/gromacs_md/md_settings.py @@ -146,9 +146,9 @@ class Config: """ # # # Bonds # # # - constraints: Literal[ - "none", "h-bonds", "all-bonds", "h-angles", "all-angles" - ] = "h-bonds" + constraints: Literal["none", "h-bonds", "all-bonds", "h-angles", "all-angles"] = ( + "h-bonds" + ) """ Controls which bonds in the topology will be converted to rigid holonomic constraints. Note that typical rigid water models do not have bonds, but From f7ccedff8825dfee3dda44caa1ce81c289e3119f Mon Sep 17 00:00:00 2001 From: Mike Henry <11765982+mikemhenry@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:38:36 -0700 Subject: [PATCH 32/36] install openff-interchange from source + re-enable test --- environment.yml | 2 ++ openfe_gromacs/tests/protocols/test_create_systems.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/environment.yml b/environment.yml index 71824fd..a9643c1 100644 --- a/environment.yml +++ b/environment.yml @@ -9,3 +9,5 @@ dependencies: - pytest - pytest-xdist - pytest-cov + - pip: + - git+https://github.com/openforcefield/openff-interchange.git diff --git a/openfe_gromacs/tests/protocols/test_create_systems.py b/openfe_gromacs/tests/protocols/test_create_systems.py index b57ca5c..7170bcd 100644 --- a/openfe_gromacs/tests/protocols/test_create_systems.py +++ b/openfe_gromacs/tests/protocols/test_create_systems.py @@ -52,7 +52,7 @@ def test_interchange_gromacs(alanine_dipeptide_component, tmpdir): ] with open(f"{tmpdir}/test.gro") as f: gromacs_res_numbers = [int(line[:5].strip()) for line in f.readlines()[2:-1]] - # assert interchange_res_numbers == gromacs_res_numbers + assert interchange_res_numbers == gromacs_res_numbers # check a few atom names to ensure these are not empty sets for atom_name in ("HA", "CH3", "CA", "CB"): From db009fe8657519f241547d2ff9528bac29737b56 Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Tue, 1 Oct 2024 09:31:34 +0200 Subject: [PATCH 33/36] Add mdout file to output_settings --- .pre-commit-config.yaml | 7 +------ .../protocols/gromacs_md/md_methods.py | 19 ++++++++++++++++++ .../protocols/gromacs_md/md_settings.py | 6 ++++++ .../protocols/gromacs_utils/write_mdp.py | 1 + .../tests/data/MDProtocol_json_results.gz | Bin 3622 -> 3704 bytes .../data/MDProtocol_json_results_no_EM.gz | Bin 3564 -> 3633 bytes .../tests/protocols/test_gromacs_md.py | 8 ++++---- 7 files changed, 31 insertions(+), 10 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 77221ad..834451b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -26,12 +26,7 @@ repos: hooks: - id: flake8 files: ^openfe_gromacs - additional_dependencies: [ - 'flake8-bugbear', - 'flake8-absolute-import', - 'flake8-pytest-style==2', - 'flake8-no-pep420', - ] + additional_dependencies: [Flake8-pyproject] - repo: https://github.com/asottile/pyupgrade rev: 'v3.17.0' hooks: diff --git a/openfe_gromacs/protocols/gromacs_md/md_methods.py b/openfe_gromacs/protocols/gromacs_md/md_methods.py index 046ba9e..5773bed 100644 --- a/openfe_gromacs/protocols/gromacs_md/md_methods.py +++ b/openfe_gromacs/protocols/gromacs_md/md_methods.py @@ -168,6 +168,7 @@ def get_filenames_em(self) -> dict[str, list[pathlib.Path]]: - "edr_em" - "log_em" - "cpt_em" + - "grompp_mdp_em" Returns ------- @@ -183,6 +184,7 @@ def get_filenames_em(self) -> dict[str, list[pathlib.Path]]: "edr_em", "log_em", "cpt_em", + "grompp_mdp_em", ] dict_npt = {} for file in file_keys: @@ -231,6 +233,7 @@ def get_filenames_nvt(self) -> dict[str, list[pathlib.Path]]: - "edr_nvt" - "log_nvt" - "cpt_nvt" + - "grompp_mdp_nvt" Returns ------- @@ -246,6 +249,7 @@ def get_filenames_nvt(self) -> dict[str, list[pathlib.Path]]: "edr_nvt", "log_nvt", "cpt_nvt", + "grompp_mdp_nvt", ] dict_npt = {} for file in file_keys: @@ -294,6 +298,7 @@ def get_filenames_npt(self) -> dict[str, list[pathlib.Path]]: - "edr_npt" - "log_npt" - "cpt_npt" + - "grompp_mdp_npt" Returns ------- @@ -309,6 +314,7 @@ def get_filenames_npt(self) -> dict[str, list[pathlib.Path]]: "edr_npt", "log_npt", "cpt_npt", + "grompp_mdp_em", ] dict_npt = {} for file in file_keys: @@ -403,6 +409,7 @@ def _default_settings(cls): engine_settings=GromacsEngineSettings(), output_settings_em=EMOutputSettings( mdp_file="em.mdp", + grompp_mdp_file="mdout_em.mdp", tpr_file="em.tpr", gro_file="em.gro", trr_file="em.trr", @@ -413,6 +420,7 @@ def _default_settings(cls): ), output_settings_nvt=NVTOutputSettings( mdp_file="nvt.mdp", + grompp_mdp_file="mdout_nvt.mdp", tpr_file="nvt.tpr", gro_file="nvt.gro", trr_file="nvt.trr", @@ -423,6 +431,7 @@ def _default_settings(cls): ), output_settings_npt=NPTOutputSettings( mdp_file="npt.mdp", + grompp_mdp_file="mdout_npt.mdp", tpr_file="npt.tpr", gro_file="npt.gro", trr_file="npt.trr", @@ -735,6 +744,7 @@ def _run_gromacs( cpt: str, log: str, edr: str, + out_mdp: str, engine_settings: GromacsEngineSettings, shared_basebath: pathlib.Path, ): @@ -754,6 +764,7 @@ def _run_gromacs( cpt: str log: str edr: str + out_mdp: str engine_settings: GromacsEngineSettings shared_basebath: Pathlike, optional Where to run the calculation, defaults to current working directory @@ -773,6 +784,8 @@ def _run_gromacs( top, "-o", tpr, + "-po", + shared_basebath / out_mdp, ], stdin=subprocess.PIPE, ) @@ -894,6 +907,7 @@ def _execute( output_settings_em.cpt_file, output_settings_em.log_file, output_settings_em.edr_file, + output_settings_em.grompp_mdp_file, engine_settings, ctx.shared, ) @@ -904,6 +918,7 @@ def _execute( output_dict["edr_em"] = shared_basepath / output_settings_em.edr_file output_dict["log_em"] = shared_basepath / output_settings_em.log_file output_dict["cpt_em"] = shared_basepath / output_settings_em.cpt_file + output_dict["grompp_mdp_em"] = shared_basepath / output_settings_em.grompp_mdp_file # ToDo: Should we disallow running MD without EM? # Run NVT @@ -929,6 +944,7 @@ def _execute( output_settings_nvt.cpt_file, output_settings_nvt.log_file, output_settings_nvt.edr_file, + output_settings_nvt.grompp_mdp_file, engine_settings, ctx.shared, ) @@ -939,6 +955,7 @@ def _execute( output_dict["edr_nvt"] = shared_basepath / output_settings_nvt.edr_file output_dict["log_nvt"] = shared_basepath / output_settings_nvt.log_file output_dict["cpt_nvt"] = shared_basepath / output_settings_nvt.cpt_file + output_dict["grompp_mdp_nvt"] = shared_basepath / output_settings_nvt.grompp_mdp_file # Run NPT MD simulation if sim_settings_npt.nsteps > 0: @@ -967,6 +984,7 @@ def _execute( output_settings_npt.cpt_file, output_settings_npt.log_file, output_settings_npt.edr_file, + output_settings_npt.grompp_mdp_file, engine_settings, ctx.shared, ) @@ -977,5 +995,6 @@ def _execute( output_dict["edr_npt"] = shared_basepath / output_settings_npt.edr_file output_dict["log_npt"] = shared_basepath / output_settings_npt.log_file output_dict["cpt_npt"] = shared_basepath / output_settings_npt.cpt_file + output_dict["grompp_mdp_nvt"] = shared_basepath / output_settings_nvt.grompp_mdp_file return output_dict diff --git a/openfe_gromacs/protocols/gromacs_md/md_settings.py b/openfe_gromacs/protocols/gromacs_md/md_settings.py index 7ab0c78..d22acdb 100644 --- a/openfe_gromacs/protocols/gromacs_md/md_settings.py +++ b/openfe_gromacs/protocols/gromacs_md/md_settings.py @@ -265,6 +265,12 @@ class OutputSettings(SettingsBaseModel): Filename for the mdp file for running simulations in Gromacs. Default 'em.mdp' """ + grompp_mdp_file: str = "mdout_em.mdp" + """ + Filename for the mdp file that gmx grompp outputs. This file contains + comment lines, as well as the input that gmx grompp has read. + Default 'mdout_em.mdp' + """ tpr_file: str = "em.tpr" """ Filename for the tpr file for running simulations in Gromacs. diff --git a/openfe_gromacs/protocols/gromacs_utils/write_mdp.py b/openfe_gromacs/protocols/gromacs_utils/write_mdp.py index 261b895..eed5b76 100644 --- a/openfe_gromacs/protocols/gromacs_utils/write_mdp.py +++ b/openfe_gromacs/protocols/gromacs_utils/write_mdp.py @@ -56,6 +56,7 @@ def dict2mdp(settings_dict: dict, shared_basepath): non_mdps = [ "forcefield_cache", "mdp_file", + "grompp_mdp_file", "tpr_file", "trr_file", "xtc_file", diff --git a/openfe_gromacs/tests/data/MDProtocol_json_results.gz b/openfe_gromacs/tests/data/MDProtocol_json_results.gz index 4355d88f15731754bf37503384d33833afebcd76..1aaae47fd81851fc4c92d3d4a787ce3bdb4e60c2 100644 GIT binary patch literal 3704 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

Azh6bm*Vx|Hb~V zjQ9O-XY40j>;5ETvnpHkP38nD+>(s{Px|}2QQE|n;iCPc%yT#)r#4WdF(fTR}-)7@pkwe7Uoxq?St&HO>qb|pq~Cs z2G6~K>FDjyJyFuTHO=zf!^_<2sZ?F7{ubfWo?Q7$-qx97x|kieBn658CS}T4$+?-2n!O(Z1$1qE#l3IG5A literal 3622 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 Date: Tue, 1 Oct 2024 07:32:05 +0000 Subject: [PATCH 34/36] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- openfe_gromacs/protocols/gromacs_md/md_methods.py | 12 +++++++++--- openfe_gromacs/protocols/gromacs_md/md_settings.py | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/openfe_gromacs/protocols/gromacs_md/md_methods.py b/openfe_gromacs/protocols/gromacs_md/md_methods.py index 350ed0d..54b9ecd 100644 --- a/openfe_gromacs/protocols/gromacs_md/md_methods.py +++ b/openfe_gromacs/protocols/gromacs_md/md_methods.py @@ -925,7 +925,9 @@ def _execute( output_dict["edr_em"] = shared_basepath / output_settings_em.edr_file output_dict["log_em"] = shared_basepath / output_settings_em.log_file output_dict["cpt_em"] = shared_basepath / output_settings_em.cpt_file - output_dict["grompp_mdp_em"] = shared_basepath / output_settings_em.grompp_mdp_file + output_dict["grompp_mdp_em"] = ( + shared_basepath / output_settings_em.grompp_mdp_file + ) # ToDo: Should we disallow running MD without EM? # Run NVT @@ -962,7 +964,9 @@ def _execute( output_dict["edr_nvt"] = shared_basepath / output_settings_nvt.edr_file output_dict["log_nvt"] = shared_basepath / output_settings_nvt.log_file output_dict["cpt_nvt"] = shared_basepath / output_settings_nvt.cpt_file - output_dict["grompp_mdp_nvt"] = shared_basepath / output_settings_nvt.grompp_mdp_file + output_dict["grompp_mdp_nvt"] = ( + shared_basepath / output_settings_nvt.grompp_mdp_file + ) # Run NPT MD simulation if sim_settings_npt.nsteps > 0: @@ -1002,6 +1006,8 @@ def _execute( output_dict["edr_npt"] = shared_basepath / output_settings_npt.edr_file output_dict["log_npt"] = shared_basepath / output_settings_npt.log_file output_dict["cpt_npt"] = shared_basepath / output_settings_npt.cpt_file - output_dict["grompp_mdp_nvt"] = shared_basepath / output_settings_nvt.grompp_mdp_file + output_dict["grompp_mdp_nvt"] = ( + shared_basepath / output_settings_nvt.grompp_mdp_file + ) return output_dict diff --git a/openfe_gromacs/protocols/gromacs_md/md_settings.py b/openfe_gromacs/protocols/gromacs_md/md_settings.py index d22acdb..f6a5e0b 100644 --- a/openfe_gromacs/protocols/gromacs_md/md_settings.py +++ b/openfe_gromacs/protocols/gromacs_md/md_settings.py @@ -267,7 +267,7 @@ class OutputSettings(SettingsBaseModel): """ grompp_mdp_file: str = "mdout_em.mdp" """ - Filename for the mdp file that gmx grompp outputs. This file contains + Filename for the mdp file that gmx grompp outputs. This file contains comment lines, as well as the input that gmx grompp has read. Default 'mdout_em.mdp' """ From c84ea909065f51fb5051fe4bbaf86d4e8719d34c Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Tue, 1 Oct 2024 09:38:00 +0200 Subject: [PATCH 35/36] Remove unused imports --- openfe_gromacs/protocols/gromacs_md/md_methods.py | 12 +++--------- .../protocols/gromacs_utils/create_systems.py | 8 +------- openfe_gromacs/tests/conftest.py | 1 - .../tests/protocols/test_md_tokenization.py | 1 - 4 files changed, 4 insertions(+), 18 deletions(-) diff --git a/openfe_gromacs/protocols/gromacs_md/md_methods.py b/openfe_gromacs/protocols/gromacs_md/md_methods.py index 350ed0d..e1efeb8 100644 --- a/openfe_gromacs/protocols/gromacs_md/md_methods.py +++ b/openfe_gromacs/protocols/gromacs_md/md_methods.py @@ -20,15 +20,9 @@ from typing import Any import gufe -import pint -from gufe import ChemicalSystem, SmallMoleculeComponent, settings -from openfe.protocols.openmm_utils import ( - charge_generation, - system_creation, - system_validation, -) -from openfe.utils import log_system_probe, without_oechem_backend -from openff.interchange import Interchange +from gufe import ChemicalSystem, settings +from openfe.protocols.openmm_utils import system_validation +from openfe.utils import log_system_probe from openff.toolkit.topology import Molecule as OFFMolecule from openff.units import unit diff --git a/openfe_gromacs/protocols/gromacs_utils/create_systems.py b/openfe_gromacs/protocols/gromacs_utils/create_systems.py index d078d07..3c38db5 100644 --- a/openfe_gromacs/protocols/gromacs_utils/create_systems.py +++ b/openfe_gromacs/protocols/gromacs_utils/create_systems.py @@ -9,13 +9,7 @@ from openff.units.openmm import from_openmm, to_openmm from openmmtools import forces -from openfe_gromacs.protocols.gromacs_md.md_settings import ( - EMOutputSettings, - FFSettingsOpenMM, - IntegratorSettings, - OpenFFPartialChargeSettings, - SolvationSettings, -) +from openfe_gromacs.protocols.gromacs_md.md_settings import OpenFFPartialChargeSettings def assign_partial_charges( diff --git a/openfe_gromacs/tests/conftest.py b/openfe_gromacs/tests/conftest.py index 62fa118..eec6ab7 100644 --- a/openfe_gromacs/tests/conftest.py +++ b/openfe_gromacs/tests/conftest.py @@ -2,7 +2,6 @@ # For details, see https://github.com/OpenFreeEnergy/openfe import importlib import os -import pathlib from importlib import resources import gufe diff --git a/openfe_gromacs/tests/protocols/test_md_tokenization.py b/openfe_gromacs/tests/protocols/test_md_tokenization.py index 90836d4..6a510a1 100644 --- a/openfe_gromacs/tests/protocols/test_md_tokenization.py +++ b/openfe_gromacs/tests/protocols/test_md_tokenization.py @@ -3,7 +3,6 @@ import json import gufe -import openfe import pytest from gufe.tests.test_tokenization import GufeTokenizableTestsMixin From 9ec736cac3a4a938e9f29a1942d2bcf29aa78ece Mon Sep 17 00:00:00 2001 From: hannahbaumann Date: Tue, 1 Oct 2024 09:48:14 +0200 Subject: [PATCH 36/36] Update token --- openfe_gromacs/tests/protocols/test_md_tokenization.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfe_gromacs/tests/protocols/test_md_tokenization.py b/openfe_gromacs/tests/protocols/test_md_tokenization.py index 6a510a1..4969494 100644 --- a/openfe_gromacs/tests/protocols/test_md_tokenization.py +++ b/openfe_gromacs/tests/protocols/test_md_tokenization.py @@ -40,7 +40,7 @@ def protocol_result(md_json): class TestGromacsMDProtocol(GufeTokenizableTestsMixin): cls = gromacs_md.GromacsMDProtocol - key = "GromacsMDProtocol-c75de773fddf547f15daf4c01a455c66" + key = "GromacsMDProtocol-829ed8e2ddfff11f9e86eec044222317" repr = f"<{key}>" @pytest.fixture()