From 534bd4ee34242ab5fd42924140ff12b3e4ea43df Mon Sep 17 00:00:00 2001 From: John Chodera Date: Fri, 27 Aug 2021 17:48:27 -0700 Subject: [PATCH 1/3] Update all simtk.openmm -> openmm and simtk.unit -> openmm.unit imports for OpenMM 7.6; pin to >=7.6 --- amber/convert_amber.py | 5 +- charmm/convert_charmm.py | 6 +- devtools/conda-envs/test_env.yaml | 2 +- .../generators/system_generators.py | 30 +++--- .../generators/template_generators.py | 38 +++---- openmmforcefields/tests/test_amber_import.py | 8 +- .../tests/test_system_generator.py | 28 ++--- .../tests/test_template_generators.py | 101 +++++++++--------- 8 files changed, 109 insertions(+), 109 deletions(-) diff --git a/amber/convert_amber.py b/amber/convert_amber.py index e6bdd072..c528ab45 100644 --- a/amber/convert_amber.py +++ b/amber/convert_amber.py @@ -4,9 +4,8 @@ import parmed from parmed.utils.six import iteritems from parmed.utils.six.moves import StringIO, zip -import simtk.openmm.app as app -import simtk.unit as u -import simtk +import openmm.app as app +import openmm.unit as u import os import sys import re diff --git a/charmm/convert_charmm.py b/charmm/convert_charmm.py index 81978ee6..07eed03a 100644 --- a/charmm/convert_charmm.py +++ b/charmm/convert_charmm.py @@ -5,9 +5,9 @@ from collections import OrderedDict import hashlib import os -import simtk.openmm.app as app -import simtk.openmm as mm -import simtk.unit as u +import openmm.app as app +import openmm as mm +import openmm.unit as u import argparse import csv import logging diff --git a/devtools/conda-envs/test_env.yaml b/devtools/conda-envs/test_env.yaml index 2a8148ee..829699ee 100644 --- a/devtools/conda-envs/test_env.yaml +++ b/devtools/conda-envs/test_env.yaml @@ -16,7 +16,7 @@ dependencies: - codecov # Requirements for converted force field installer - - openmm >=7.4.2 + - openmm >=7.6.0 # Requirements for conversion tools - pyyaml diff --git a/openmmforcefields/generators/system_generators.py b/openmmforcefields/generators/system_generators.py index 96476fb9..147eca51 100644 --- a/openmmforcefields/generators/system_generators.py +++ b/openmmforcefields/generators/system_generators.py @@ -10,7 +10,7 @@ import logging _logger = logging.getLogger("openmmforcefields.system_generators") -from simtk.openmm import app +from openmm import app ################################################################################ # System generator base class @@ -42,19 +42,19 @@ class SystemGenerator(object): Parameters ---------- - forcefield : simtk.openmm.app.ForceField + forcefield : openmm.app.ForceField The ForceField object used to create new System objects. New ffxml files can be read in at any time. forcefield_kwargs : dict - Keyword arguments fed to ``simtk.openmm.app.ForceField.createSystem()`` during System generation. + Keyword arguments fed to ``openmm.app.ForceField.createSystem()`` during System generation. These keyword arguments can be modified at any time. periodic_forcefield_kwargs : dict - Keyword arguments fed to ``simtk.openmm.app.ForceField.createSystem()`` during System generation for periodic systems. + Keyword arguments fed to ``openmm.app.ForceField.createSystem()`` during System generation for periodic systems. These keyword arguments can be modified at any time. nonperiodic_forcefield_kwargs : dict - Keyword arguments fed to ``simtk.openmm.app.ForceField.createSystem()`` during System generation for non-periodic systems. + Keyword arguments fed to ``openmm.app.ForceField.createSystem()`` during System generation for non-periodic systems. These keyword arguments can be modified at any time. - barostat : simtk.openmm.MonteCarloBarostat + barostat : openmm.MonteCarloBarostat If not None, this container holds the barostat parameters to use for newly created System objects. molecules : openff.toolkit.topology.Molecule or list, optional, default=None Can alternatively be an object (such as an OpenEye OEMol or RDKit Mol or SMILES string) that can be used to construct a Molecule. @@ -85,12 +85,12 @@ def __init__(self, forcefields=None, small_molecule_forcefield='openff-1.0.0', f Supported SMIRNOFF force fields include: [`openff-1.0.0`, `smirnoff99Frosst-1.1.0`] (See ``SMIRNOFFTemplateGenerator.INSTALLED_FORCEFIELDS`` for a complete list.) forcefield_kwargs : dict, optional, default=None - Keyword arguments to be passed to ``simtk.openmm.app.ForceField.createSystem()`` during ``System`` object creation. + Keyword arguments to be passed to ``openmm.app.ForceField.createSystem()`` during ``System`` object creation. nonperiodic_forcefield_kwargs : dict, optional, default={'nonbondedMethod' : NoCutoff} Keyword arguments added to forcefield_kwargs when the Topology is non-periodic. periodic_forcefield_kwargs : NonbondedMethod, optional, default={'nonbondedMethod' : PME} Keyword arguments added to forcefield_kwargs when the Topology is periodic. - barostat : simtk.openmm.MonteCarloBarostat, optional, default=None + barostat : openmm.MonteCarloBarostat, optional, default=None If not None, a new ``MonteCarloBarostat`` with matching parameters (but a different random number seed) will be created and added to each newly created ``System``. molecules : openff.toolkit.topology.Molecule or list, optional, default=None @@ -111,12 +111,12 @@ def __init__(self, forcefields=None, small_molecule_forcefield='openff-1.0.0', f `Open Force Field Topology `_ object: >>> # Define the keyword arguments to feed to ForceField - >>> from simtk import unit - >>> from simtk.openmm import app + >>> from openmm import unit + >>> from openmm import app >>> # Define standard OpenMM biopolymer and solvent force fields to use To initialize the ``SystemGenerator``, we specify the OpenMM force fields, the small molecule force field, and any ``kwargs`` to be fed - to the OpenMM ``simtk.openmm.app.ForceField.createSystem()`` method: + to the OpenMM ``openmm.app.ForceField.createSystem()`` method: >>> from openmmforcefields.generators import SystemGenerator >>> amber_forcefields = ['amber/protein.ff14SB.xml', 'amber/tip3p_standard.xml', 'amber/tip3p_HFE_multivalent.xml'] @@ -173,7 +173,7 @@ def __init__(self, forcefields=None, small_molecule_forcefield='openff-1.0.0', f # Create OpenMM ForceField object forcefields = forcefields if (forcefields is not None) else list() - from simtk.openmm import app + from openmm import app self.forcefield = app.ForceField(*forcefields) # Cache force fields and settings to use @@ -244,7 +244,7 @@ def _modify_forces(self, system): # Add barostat if requested. if self.barostat is not None: import numpy as np - from simtk import openmm + import openmm MAXINT = np.iinfo(np.int32).max # Determine pressure, temperature, and frequency @@ -304,7 +304,7 @@ def create_system(self, topology, molecules=None): Returns ------- - system : simtk.openmm.System + system : openmm.System A system object generated from the topology """ @@ -363,7 +363,7 @@ def create_system(self, topology, **kwargs): Returns ------- - system : simtk.openmm.System + system : openmm.System The System object """ diff --git a/openmmforcefields/generators/template_generators.py b/openmmforcefields/generators/template_generators.py index 0c85e74d..3df5c5ef 100644 --- a/openmmforcefields/generators/template_generators.py +++ b/openmmforcefields/generators/template_generators.py @@ -131,7 +131,7 @@ def _match_residue(residue, molecule_template): Parameters ---------- - residue : simtk.openmm.app.topology.Residue + residue : openmm.app.topology.Residue The residue to check molecule_template : openff.toolkit.topology.Molecule The Molecule template to compare it to @@ -218,7 +218,7 @@ def _molecule_has_user_charges(self, molecule): """ import numpy as np - from simtk import unit + from openmm import unit zeros = np.zeros([molecule.n_particles]) if (molecule.partial_charges is None) or (np.allclose(molecule.partial_charges / unit.elementary_charge, zeros)): charges_are_zero = True @@ -244,13 +244,13 @@ def _generate_unique_atom_names(self, molecule): def generator(self, forcefield, residue): """ - Residue template generator method to register with simtk.openmm.app.ForceField + Residue template generator method to register with openmm.app.ForceField Parameters ---------- - forcefield : simtk.openmm.app.ForceField + forcefield : openmm.app.ForceField The ForceField object to which residue templates and/or parameters are to be added. - residue : simtk.openmm.app.Topology.Residue + residue : openmm.app.Topology.Residue The residue topology for which a template is to be generated. Returns @@ -355,7 +355,7 @@ class GAFFTemplateGenerator(SmallMoleculeTemplateGenerator): >>> from openmoltools.forcefield_generators import GAFFTemplateGenerator >>> template_generator = GAFFTemplateGenerator(molecules=molecule) >>> # Create an OpenMM ForceField - >>> from simtk.openmm.app import ForceField + >>> from openmm.app import ForceField >>> amber_forcefields = ['amber/protein.ff14SB.xml', 'amber/tip3p_standard.xml', 'amber/tip3p_HFE_multivalent.xml'] >>> forcefield = ForceField(*amber_forcefields) >>> # Register the template generator @@ -416,7 +416,7 @@ def __init__(self, molecules=None, forcefield=None, cache=None): >>> molecule = Molecule.from_smiles('c1ccccc1') >>> from openmoltools.forcefield_generators import GAFFTemplateGenerator >>> gaff = GAFFTemplateGenerator(molecules=molecule) - >>> from simtk.openmm.app import ForceField + >>> from openmm.app import ForceField >>> amber_forcefields = ['amber/protein.ff14SB.xml', 'amber/tip3p_standard.xml', 'amber/tip3p_HFE_multivalent.xml'] >>> forcefield = ForceField(*amber_forcefields) >>> forcefield.registerTemplateGenerator(gaff) @@ -509,13 +509,13 @@ def gaff_xml_filename(self): def generator(self, forcefield, residue): """ - Residue template generator method to register with simtk.openmm.app.ForceField + Residue template generator method to register with openmm.app.ForceField Parameters ---------- - forcefield : simtk.openmm.app.ForceField + forcefield : openmm.app.ForceField The ForceField object to which residue templates and/or parameters are to be added. - residue : simtk.openmm.app.Topology.Residue + residue : openmm.app.Topology.Residue The residue topology for which a template is to be generated. Returns @@ -570,7 +570,7 @@ def generate_residue_template(self, molecule, residue_atoms=None): # Compute net formal charge net_charge = molecule.total_charge - from simtk import unit + from openmm import unit if type(net_charge) != unit.Quantity: # openforcefield toolkit < 0.7.0 did not return unit-bearing quantity net_charge = float(net_charge) * unit.elementary_charge @@ -621,7 +621,7 @@ def generate_residue_template(self, molecule, residue_atoms=None): # or pure numbers. _logger.debug(f'Fixing partial charges...') _logger.debug(f'{molecule.partial_charges}') - from simtk import unit + from openmm import unit residue_charge = 0.0 * unit.elementary_charge total_charge = unit.sum(molecule.partial_charges) sum_of_absolute_charge = unit.sum(abs(molecule.partial_charges)) @@ -889,7 +889,7 @@ class SMIRNOFFTemplateGenerator(SmallMoleculeTemplateGenerator): >>> from openmoltools.forcefield_generators import SMIRNOFFTemplateGenerator >>> template_generator = SMIRNOFFTemplateGenerator(molecules=molecule) >>> # Create an OpenMM ForceField - >>> from simtk.openmm.app import ForceField + >>> from openmm.app import ForceField >>> amber_forcefields = ['amber/protein.ff14SB.xml', 'amber/tip3p_standard.xml', 'amber/tip3p_HFE_multivalent.xml'] >>> forcefield = ForceField(*amber_forcefields) >>> # Register the template generator @@ -947,7 +947,7 @@ def __init__(self, molecules=None, cache=None, forcefield=None): >>> molecule = Molecule.from_smiles('c1ccccc1') >>> from openmoltools.forcefield_generators import SMIRNOFFTemplateGenerator >>> smirnoff = SMIRNOFFTemplateGenerator(molecules=molecule) - >>> from simtk.openmm.app import ForceField + >>> from openmm.app import ForceField >>> amber_forcefields = ['amber/protein.ff14SB.xml', 'amber/tip3p_standard.xml', 'amber/tip3p_HFE_multivalent.xml'] >>> forcefield = ForceField(*amber_forcefields) @@ -1099,7 +1099,7 @@ def get_openmm_system(self, molecule): Returns ------- - system : simtk.openmm.System or None + system : openmm.System or None If the Molecule object has already been parameterized by this instance, this molecule is returned. Otherwise, None is returned. """ @@ -1161,13 +1161,13 @@ def generate_residue_template(self, molecule, residue_atoms=None): root = etree.Element("ForceField") def as_attrib(quantity): - """Format simtk.unit.Quantity as XML attribute.""" + """Format openmm.unit.Quantity as XML attribute.""" if isinstance(quantity, str): return quantity elif isinstance(quantity, float) or isinstance(quantity, int): return str(quantity) else: - from simtk import unit + from openmm import unit return str(quantity.value_in_unit_system(unit.md_unit_system)) # Append unique type names to atoms @@ -1208,7 +1208,7 @@ def classes(particle_indices): # Round parameters using strings for ease of comparison # DEBUG - #from simtk import unit + #from openmm import unit #def round_quantity(quantity): # NDECIMALS = 3 # value = quantity.value_in_unit_system(unit.md_unit_system) @@ -1288,7 +1288,7 @@ def torsion_tag(particle_indices): # Create residue definitions # TODO: Handle non-Atom particles too (virtual sites) - from simtk import unit + from openmm import unit residues = etree.SubElement(root, "Residues") residue = etree.SubElement(residues, "Residue", name=smiles) for particle_index, particle in enumerate(molecule.particles): diff --git a/openmmforcefields/tests/test_amber_import.py b/openmmforcefields/tests/test_amber_import.py index baf42244..97a8bf2a 100644 --- a/openmmforcefields/tests/test_amber_import.py +++ b/openmmforcefields/tests/test_amber_import.py @@ -21,7 +21,7 @@ def test_ffxml_import(filename): The AMBER forcefield filename. """ - from simtk.openmm import app + from openmm import app # Handle special cases if filename == 'amber/phosaa10.xml': @@ -47,7 +47,7 @@ def check_ffxml_parameterize(pdb_filename, ffxml_filename): The ffxml forcefield filename. """ - from simtk.openmm import app + from openmm import app pdbfile = app.PDBFile(pdb_filename) ff = app.ForceField(ffxml_filename) @@ -56,7 +56,7 @@ def test_amber_import_ff94(): Test import of ff94 """ - from simtk.openmm import app + from openmm import app ff = app.ForceField('amber/ff94.xml') def test_amber_parameterize_ff94(): @@ -65,5 +65,5 @@ def test_amber_parameterize_ff94(): """ from pkg_resources import resource_filename - pdb_filename = resource_filename('simtk.openmm.app', 'data/test.pdb') + pdb_filename = resource_filename('openmm.app', 'data/test.pdb') check_ffxml_parameterize(pdb_filename, 'amber/ff94.xml') diff --git a/openmmforcefields/tests/test_system_generator.py b/openmmforcefields/tests/test_system_generator.py index bb06b1f3..f18f0022 100644 --- a/openmmforcefields/tests/test_system_generator.py +++ b/openmmforcefields/tests/test_system_generator.py @@ -57,7 +57,7 @@ def setUp(self): #('tyk2', 'Tyk2'), ]: # Load protein - from simtk.openmm.app import PDBFile + from openmm.app import PDBFile pdb_filename = get_data_filename(os.path.join('perses_jacs_systems', system_name, prefix + '_protein.pdb')) pdbfile = PDBFile(pdb_filename) @@ -100,7 +100,7 @@ def setUp(self): # DEBUG for name, testsystem in self.testsystems.items(): - from simtk.openmm import app + from openmm import app filename = f'testsystem-{name}.pdb' print(filename) structure = testsystem['complex_structures'][0] @@ -132,8 +132,8 @@ def test_barostat(self): generator = SystemGenerator(forcefields=self.amber_forcefields) # Create a template barostat - from simtk.openmm import MonteCarloBarostat - from simtk import unit + from openmm import MonteCarloBarostat + from openmm import unit pressure = 0.95 * unit.atmospheres temperature = 301.0 * unit.kelvin frequency = 23 @@ -141,20 +141,20 @@ def test_barostat(self): # Load a PDB file import os - from simtk.openmm.app import PDBFile + from openmm.app import PDBFile pdb_filename = get_data_filename(os.path.join('perses_jacs_systems', 'mcl1', 'MCL1_protein.pdb')) pdbfile = PDBFile(pdb_filename) # Delete hydrogens from terminal protein residues # TODO: Fix the input files so we don't need to do this - from simtk.openmm import app + from openmm import app modeller = app.Modeller(pdbfile.topology, pdbfile.positions) residues = [residue for residue in modeller.topology.residues() if residue.name != 'UNL'] termini_ids = [residues[0].id, residues[-1].id] #hs = [atom for atom in modeller.topology.atoms() if atom.element.symbol in ['H'] and atom.residue.name != 'UNL'] hs = [atom for atom in modeller.topology.atoms() if atom.element.symbol in ['H'] and atom.residue.id in termini_ids] modeller.delete(hs) - from simtk.openmm.app import PDBFile + from openmm.app import PDBFile modeller.addHydrogens() # Create a System @@ -192,7 +192,7 @@ def test_create_with_template_generator(self): def test_forcefield_default_kwargs(self): """Test that default forcefield kwargs work correctly""" - from simtk import unit + from openmm import unit forcefield_kwargs = dict() from openmmforcefields.generators import SystemGenerator @@ -204,7 +204,7 @@ def test_forcefield_default_kwargs(self): for small_molecule_forcefield in SMALL_MOLECULE_FORCEFIELDS: # Create a SystemGenerator for this force field from simtk import openmm - from simtk.openmm import app + from openmm import app generator = SystemGenerator(forcefields=self.amber_forcefields, small_molecule_forcefield=small_molecule_forcefield, forcefield_kwargs=forcefield_kwargs, @@ -230,14 +230,14 @@ def test_forcefield_default_kwargs(self): def test_forcefield_kwargs(self): """Test that forcefield_kwargs and nonbonded method specifications work correctly""" - from simtk import unit + from openmm import unit forcefield_kwargs = { 'hydrogenMass' : 4*unit.amu } from openmmforcefields.generators import SystemGenerator # Test exception is raised with pytest.raises(ValueError) as excinfo: # Not allowed to specify nonbondedMethod in forcefield_kwargs - from simtk.openmm import app + from openmm import app generator = SystemGenerator(forcefield_kwargs={'nonbondedMethod':app.PME}) assert "nonbondedMethod cannot be specified in forcefield_kwargs" in str(excinfo.value) @@ -249,7 +249,7 @@ def test_forcefield_kwargs(self): for small_molecule_forcefield in SMALL_MOLECULE_FORCEFIELDS: # Create a SystemGenerator for this force field from simtk import openmm - from simtk.openmm import app + from openmm import app generator = SystemGenerator(forcefields=self.amber_forcefields, small_molecule_forcefield=small_molecule_forcefield, forcefield_kwargs=forcefield_kwargs, @@ -424,8 +424,8 @@ def test_complex(self): assert system.getNumParticles() == len(complex_structure.atoms) # Create solvated structure - from simtk.openmm import app - from simtk import unit + from openmm import app + from openmm import unit modeller = app.Modeller(complex_structure.topology, complex_structure.positions) modeller.addSolvent(generator.forcefield, padding=0*unit.angstroms, ionicStrength=300*unit.millimolar) diff --git a/openmmforcefields/tests/test_template_generators.py b/openmmforcefields/tests/test_template_generators.py index 60503e63..797d6e60 100644 --- a/openmmforcefields/tests/test_template_generators.py +++ b/openmmforcefields/tests/test_template_generators.py @@ -98,14 +98,14 @@ def test_add_molecules(self): # Create a generator that does not know about any molecules generator = self.TEMPLATE_GENERATOR() # Create a ForceField - from simtk.openmm.app import ForceField + from openmm.app import ForceField forcefield = ForceField() # Register the template generator forcefield.registerTemplateGenerator(generator.generator) # Check that parameterizing a molecule fails molecule = self.molecules[0] - from simtk.openmm.app import NoCutoff + from openmm.app import NoCutoff try: # This should fail with an exception openmm_topology = molecule.to_topology().to_openmm() @@ -121,7 +121,7 @@ def test_add_molecules(self): system = forcefield.createSystem(openmm_topology, nonbondedMethod=NoCutoff) except Exception as e: print(forcefield._atomTypes.keys()) - from simtk.openmm.app import PDBFile + from openmm.app import PDBFile PDBFile.writeFile(openmm_topology, molecule.conformers[0]) raise e assert system.getNumParticles() == molecule.n_atoms @@ -140,7 +140,7 @@ def charges_from_system(self, system): Parameters ---------- - system : simtk.openmm.System + system : openmm.System The System from which partial charges are to be extracted Returns @@ -150,7 +150,7 @@ def charges_from_system(self, system): """ import numpy as np - from simtk import unit + from openmm import unit system_charges = list() forces = { force.__class__.__name__ : force for force in system.getForces() } for particle_index in range(system.getNumParticles()): @@ -165,7 +165,7 @@ def charges_are_equal(self, system, molecule): Parameters ---------- - system : simtk.openmm.System + system : openmm.System The System from which partial charges are to be extracted molecule : openmmforcefield.topology.Molecule The Molecule from which partial charges are to be extracted @@ -179,7 +179,7 @@ def charges_are_equal(self, system, molecule): system_charges = self.charges_from_system(system) - from simtk import unit + from openmm import unit molecule_charges = molecule.partial_charges / unit.elementary_charge import numpy as np @@ -196,21 +196,21 @@ def test_charge(self): # Create a generator that does not know about any molecules generator = self.TEMPLATE_GENERATOR() # Create a ForceField - from simtk.openmm.app import ForceField + from openmm.app import ForceField forcefield = ForceField() # Register the template generator forcefield.registerTemplateGenerator(generator.generator) # Check that parameterizing a molecule using user-provided charges produces expected charges import numpy as np - from simtk import unit + from openmm import unit molecule = self.molecules[0] # Ensure partial charges are initially zero assert (molecule.partial_charges is None) or np.all(molecule.partial_charges / unit.elementary_charge == 0) # Add the molecule generator.add_molecules(molecule) # Create the System - from simtk.openmm.app import NoCutoff + from openmm.app import NoCutoff openmm_topology = molecule.to_topology().to_openmm() system = forcefield.createSystem(openmm_topology, nonbondedMethod=NoCutoff) # Ensure charges are no longer zero @@ -221,14 +221,14 @@ def test_charge_from_molecules(self): # Create a generator that does not know about any molecules generator = self.TEMPLATE_GENERATOR() # Create a ForceField - from simtk.openmm.app import ForceField + from openmm.app import ForceField forcefield = ForceField() # Register the template generator forcefield.registerTemplateGenerator(generator.generator) # Check that parameterizing a molecule using user-provided charges produces expected charges import numpy as np - from simtk import unit + from openmm import unit molecule = self.molecules[0] charges = np.random.random([molecule.n_particles]) total_charge = molecule.total_charge @@ -241,7 +241,7 @@ def test_charge_from_molecules(self): # Add the molecule generator.add_molecules(molecule) # Create the System - from simtk.openmm.app import NoCutoff + from openmm.app import NoCutoff openmm_topology = molecule.to_topology().to_openmm() system = forcefield.createSystem(openmm_topology, nonbondedMethod=NoCutoff) assert self.charges_are_equal(system, molecule) @@ -255,12 +255,12 @@ def test_debug_ffxml(self): molecule = self.molecules[0] generator = self.TEMPLATE_GENERATOR(molecules=molecule, cache=cache) # Create a ForceField - from simtk.openmm.app import ForceField + from openmm.app import ForceField forcefield = ForceField() # Register the template generator forcefield.registerTemplateGenerator(generator.generator) # Ensure no file is created - from simtk.openmm.app import NoCutoff + from openmm.app import NoCutoff openmm_topology = molecule.to_topology().to_openmm() system = forcefield.createSystem(openmm_topology, nonbondedMethod=NoCutoff) assert not os.path.exists(debug_ffxml_filename) @@ -282,7 +282,7 @@ def test_debug_ffxml(self): def test_cache(self): """Test template generator cache capability""" - from simtk.openmm.app import ForceField, NoCutoff + from openmm.app import ForceField, NoCutoff with tempfile.TemporaryDirectory() as tmpdirname: # Create a generator that also has a database cache cache = os.path.join(tmpdirname, 'db.json') @@ -337,15 +337,15 @@ def check_cache(generator, n_expected): forcefield.createSystem(openmm_topology, nonbondedMethod=NoCutoff) def test_add_solvent(self): - """Test using simtk.opnmm.app.Modeller to add solvent to a small molecule parameterized by template generator""" + """Test using openmm.app.Modeller to add solvent to a small molecule parameterized by template generator""" # Select a molecule to add solvent around - from simtk.openmm.app import NoCutoff, Modeller - from simtk import unit + from openmm.app import NoCutoff, Modeller + from openmm import unit molecule = self.molecules[0] openmm_topology = molecule.to_topology().to_openmm() openmm_positions = molecule.conformers[0] # Try adding solvent without residue template generator; this will fail - from simtk.openmm.app import ForceField + from openmm.app import ForceField forcefield = ForceField('tip3p.xml') # Add solvent to a system containing a small molecule modeller = Modeller(openmm_topology, openmm_positions) @@ -364,7 +364,7 @@ def test_add_solvent(self): def test_jacs_ligands(self): """Use template generator to parameterize the Schrodinger JACS set of ligands""" - from simtk.openmm.app import ForceField, NoCutoff + from openmm.app import ForceField, NoCutoff jacs_systems = { #'bace' : { 'prefix' : 'Bace' }, #'cdk2' : { 'prefix' : 'CDK2' }, @@ -445,9 +445,9 @@ def test_jacs_complexes(self): # Read ParmEd Structures import parmed - from simtk import unit + from openmm import unit protein_pdb_filename = get_data_filename(os.path.join('perses_jacs_systems', system_name, prefix + '_protein.pdb')) - from simtk.openmm.app import PDBFile + from openmm.app import PDBFile print(f'Reading protein from {protein_pdb_filename} ...') #protein_structure = parmed.load_file(protein_pdb_filename) # NOTE: This mis-interprets distorted geometry and sequentially-numbered residues that span chain breaks pdbfile = PDBFile(protein_pdb_filename) @@ -473,7 +473,7 @@ def test_jacs_complexes(self): generator = self.TEMPLATE_GENERATOR(molecules=molecules, cache=cache) # Create a ForceField - from simtk.openmm.app import ForceField + from openmm.app import ForceField forcefield = ForceField(*self.amber_forcefields) # Register the template generator forcefield.registerTemplateGenerator(generator.generator) @@ -486,24 +486,24 @@ def test_jacs_complexes(self): # Delete hydrogens from terminal protein residues # TODO: Fix the input files so we don't need to do this - from simtk.openmm import app + from openmm import app modeller = app.Modeller(complex_structure.topology, complex_structure.positions) residues = [residue for residue in modeller.topology.residues() if residue.name != 'UNL'] termini_ids = [residues[0].id, residues[-1].id] #hs = [atom for atom in modeller.topology.atoms() if atom.element.symbol in ['H'] and atom.residue.name != 'UNL'] hs = [atom for atom in modeller.topology.atoms() if atom.element.symbol in ['H'] and atom.residue.id in termini_ids] modeller.delete(hs) - from simtk.openmm.app import PDBFile + from openmm.app import PDBFile modeller.addHydrogens(forcefield) # Parameterize protein:ligand complex in vacuum print(f' Parameterizing {system_name} : {molecule.to_smiles()} in vacuum...') - from simtk.openmm.app import NoCutoff + from openmm.app import NoCutoff forcefield.createSystem(modeller.topology, nonbondedMethod=NoCutoff) # Parameterize protein:ligand complex in solvent print(f' Parameterizing {system_name} : {molecule.to_smiles()} in explicit solvent...') - from simtk.openmm.app import PME + from openmm.app import PME modeller.addSolvent(forcefield, padding=0*unit.angstroms, ionicStrength=300*unit.millimolar) forcefield.createSystem(modeller.topology, nonbondedMethod=PME) @@ -518,12 +518,12 @@ def test_parameterize(self): # Check that we have loaded the right force field assert generator.forcefield == small_molecule_forcefield # Create a ForceField with the appropriate small molecule force field - from simtk.openmm.app import ForceField + from openmm.app import ForceField forcefield = ForceField() # Register the template generator forcefield.registerTemplateGenerator(generator.generator) # Parameterize some molecules - from simtk.openmm.app import NoCutoff + from openmm.app import NoCutoff from openmmforcefields.utils import Timer for molecule in self.molecules: openmm_topology = molecule.to_topology().to_openmm() @@ -539,7 +539,7 @@ def test_parameterize(self): def test_multiple_registration(self): """Test registering the template generator with multiple force fields""" generator = self.TEMPLATE_GENERATOR(molecules=self.molecules) - from simtk.openmm.app import ForceField + from openmm.app import ForceField NUM_FORCEFIELDS = 2 # number of force fields to test forcefields = list() for index in range(NUM_FORCEFIELDS): @@ -550,7 +550,7 @@ def test_multiple_registration(self): # Parameterize a molecule in each force field instance molecule = self.molecules[0] openmm_topology = molecule.to_topology().to_openmm() - from simtk.openmm.app import NoCutoff + from openmm.app import NoCutoff for forcefield in forcefields: system = forcefield.createSystem(openmm_topology, nonbondedMethod=NoCutoff) assert system.getNumParticles() == molecule.n_atoms @@ -564,17 +564,17 @@ def compute_energy(system, positions): Parameters ---------- - system : simtk.openmm.System + system : openmm.System The System object - positions : simtk.unit.Quantity of shape (nparticles,3) with units compatible with nanometers + positions : openmm.unit.Quantity of shape (nparticles,3) with units compatible with nanometers The positions for which energy is to be computed Returns ------- - openmm_energy : dict of str : simtk.unit.Quantity + openmm_energy : dict of str : openmm.unit.Quantity openmm_energy['total'] is the total potential energy openmm_energy['components'][forcename] is the potential energy for the specified component force - openmm_forces : dict of str : simtk.unit.Quantity + openmm_forces : dict of str : openmm.unit.Quantity openmm_forces['total'] is the total force openmm_forces['components'][forcename] is the force for the specified component force """ @@ -582,7 +582,7 @@ def compute_energy(system, positions): system = copy.deepcopy(system) for index, force in enumerate(system.getForces()): force.setForceGroup(index) - from simtk import openmm + import openmm platform = openmm.Platform.getPlatformByName('Reference') integrator = openmm.VerletIntegrator(0.001) context = openmm.Context(system, integrator, platform) @@ -611,9 +611,9 @@ def compare_energies(cls, molecule, openmm_system, smirnoff_system): ---------- molecule : openff.toolkit.topology.Molecule The Molecule object to compare energy components (including positions) - openmm_system : simtk.openmm.System + openmm_system : openmm.System System generated by OpenMM ForceField - smirnoff_system : simtk.openmm.System + smirnoff_system : openmm.System System generated by SMIRNOFF engine """ @@ -622,10 +622,10 @@ def compare_energies(cls, molecule, openmm_system, smirnoff_system): openmm_energy, openmm_forces = cls.compute_energy(openmm_system, molecule.conformers[0]) smirnoff_energy, smirnoff_forces = cls.compute_energy(smirnoff_system, molecule.conformers[0]) - from simtk import unit + from openmm import unit def write_xml(filename, system): - from simtk import openmm + import openmm with open(filename, 'w') as outfile: print(f'Writing {filename}...') outfile.write(openmm.XmlSerializer.serialize(system)) @@ -677,7 +677,7 @@ def propagate_dynamics(self, molecule, system): ---------- molecule : openff.toolkit.topology.Molecule molecule.conformers[0] is used as initial positions - system : simtk.openmm.System + system : openmm.System System object for dynamics Returns @@ -687,7 +687,8 @@ def propagate_dynamics(self, molecule, system): """ # Run some dynamics - from simtk import openmm, unit + import openmm + from openmm import unit temperature = 300 * unit.kelvin collision_rate = 1.0 / unit.picoseconds timestep = 1.0 * unit.femtoseconds @@ -718,7 +719,7 @@ def test_energies(self): from openff.toolkit.topology import Molecule molecule = Molecule.from_smiles('C=O') molecule.generate_conformers(n_conformers=1) - from simtk import unit + from openmm import unit molecule.conformers[0][0,0] += 0.1*unit.angstroms self.molecules.insert(0, molecule) # Test all supported SMIRNOFF force fields @@ -728,14 +729,14 @@ def test_energies(self): # TODO: Should the generator also load the appropriate force field files into the ForceField object? generator = SMIRNOFFTemplateGenerator(molecules=self.molecules, forcefield=small_molecule_forcefield) # Create a ForceField - import simtk - openmm_forcefield = simtk.openmm.app.ForceField() + import openmm + openmm_forcefield = openmm.app.ForceField() # Register the template generator openmm_forcefield.registerTemplateGenerator(generator.generator) # Parameterize some molecules for molecule in self.molecules: # Create OpenMM System using OpenMM app - from simtk.openmm.app import NoCutoff + from openmm.app import NoCutoff openmm_system = openmm_forcefield.createSystem(molecule.to_topology().to_openmm(), removeCMMotion=False, onbondedMethod=NoCutoff) # Retrieve System generated by the SMIRNOFF typing engine @@ -766,12 +767,12 @@ def test_partial_charges_are_none(self): # TODO: Should the generator also load the appropriate force field files into the ForceField object? generator = SMIRNOFFTemplateGenerator(molecules=[molecule], forcefield=small_molecule_forcefield) # Create a ForceField - import simtk - openmm_forcefield = simtk.openmm.app.ForceField() + import openmm + openmm_forcefield = openmm.app.ForceField() # Register the template generator openmm_forcefield.registerTemplateGenerator(generator.generator) # Create OpenMM System using OpenMM app - from simtk.openmm.app import NoCutoff + from openmm.app import NoCutoff openmm_system = openmm_forcefield.createSystem(molecule.to_topology().to_openmm(), removeCMMotion=False, onbondedMethod=NoCutoff) smirnoff_system = generator.get_openmm_system(molecule) From d2faa82e6c1fa8598a80aec9a9a8649ad552e72c Mon Sep 17 00:00:00 2001 From: John Chodera Date: Fri, 27 Aug 2021 17:51:56 -0700 Subject: [PATCH 2/3] Update README changelog --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 63e3e06a..f32714a0 100644 --- a/README.md +++ b/README.md @@ -265,6 +265,12 @@ See the corresponding directories for information on how to use the provided con # Changelog +## 0.10.0 Updates for OpenMM 7.6 and AMBER GLYCAM addition +This release adds support for the AMBER GLYCAM force field supporting glycans and updates imports for OpenMM 7.6. + +* [(PR #156)](https://github.com/openmm/openmmforcefields/pull/156) Add support for GLYCAM +* [(PR #173)](https://github.com/openmm/openmmforcefields/pull/173) Update to OpenMM 7.6 imports + ## 0.9.0 Updates for openforcefield 0.9.0 toolkit This release utilizes the new [openforcefield 0.9.0 toolkit](https://open-forcefield-toolkit.readthedocs.io/en/0.9.0/) now distributed through [conda-forge](https://conda-forge.org/). From 6ac4ea596933072676491d599e617ac00c596e25 Mon Sep 17 00:00:00 2001 From: John Chodera Date: Fri, 27 Aug 2021 18:01:02 -0700 Subject: [PATCH 3/3] Don't interpret regex match strings as escape characters. --- openmmforcefields/generators/template_generators.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openmmforcefields/generators/template_generators.py b/openmmforcefields/generators/template_generators.py index 3df5c5ef..9de4f55c 100644 --- a/openmmforcefields/generators/template_generators.py +++ b/openmmforcefields/generators/template_generators.py @@ -462,7 +462,7 @@ def __init__(self, molecules=None, forcefield=None, cache=None): # Store user-specified GAFF version self._forcefield = forcefield import re - result = re.match('^gaff-(?P\d+)\.(?P\d+)$', forcefield) + result = re.match(r'^gaff-(?P\d+)\.(?P\d+)$', forcefield) if result is None: msg = "'forcefield' must be of form 'gaff-X.Y', where X and Y denote major and minor version\n" msg += f"Provided 'forcefield' argument was '{forcefield}'\n"