diff --git a/openff/evaluator/datasets/curation/components/conversion.py b/openff/evaluator/datasets/curation/components/conversion.py index a707342f..ec3be49a 100644 --- a/openff/evaluator/datasets/curation/components/conversion.py +++ b/openff/evaluator/datasets/curation/components/conversion.py @@ -59,7 +59,11 @@ class ConvertExcessDensityData(CurationComponent): def _molecular_weight(cls, smiles): from openff.toolkit.topology import Molecule - from openmm import unit as openmm_unit + + try: + from openmm import unit as openmm_unit + except ImportError: + from simtk.openmm import unit as openmm_unit molecule = Molecule.from_smiles(smiles, allow_undefined_stereo=True) diff --git a/openff/evaluator/datasets/curation/components/filtering.py b/openff/evaluator/datasets/curation/components/filtering.py index 4f58d160..25fe6460 100644 --- a/openff/evaluator/datasets/curation/components/filtering.py +++ b/openff/evaluator/datasets/curation/components/filtering.py @@ -686,7 +686,11 @@ def _apply( ) -> pandas.DataFrame: from openff.toolkit.topology import Molecule - from openmm import unit as openmm_unit + + try: + from openmm import unit as openmm_unit + except ImportError: + from simtk.openmm import unit as openmm_unit def filter_function(data_row): diff --git a/openff/evaluator/datasets/taproom/taproom.py b/openff/evaluator/datasets/taproom/taproom.py index 592408c9..8ba9cef1 100644 --- a/openff/evaluator/datasets/taproom/taproom.py +++ b/openff/evaluator/datasets/taproom/taproom.py @@ -189,7 +189,11 @@ def _build_substance( The built substance. """ from openff.toolkit.topology import Molecule - from openmm import unit as openmm_unit + + try: + from openmm import unit as openmm_unit + except ImportError: + from simtk.openmm import unit as openmm_unit substance = Substance() diff --git a/openff/evaluator/datasets/thermoml/thermoml.py b/openff/evaluator/datasets/thermoml/thermoml.py index 80f57071..0d69ef7b 100644 --- a/openff/evaluator/datasets/thermoml/thermoml.py +++ b/openff/evaluator/datasets/thermoml/thermoml.py @@ -846,7 +846,11 @@ def _smiles_to_molecular_weight(smiles): """ from openff.toolkit.topology import Molecule - from openmm import unit as openmm_unit + + try: + from openmm import unit as openmm_unit + except ImportError: + from simtk.openmm import unit as openmm_unit try: diff --git a/openff/evaluator/forcefield/system.py b/openff/evaluator/forcefield/system.py index a8cff76a..410098e0 100644 --- a/openff/evaluator/forcefield/system.py +++ b/openff/evaluator/forcefield/system.py @@ -7,7 +7,11 @@ if TYPE_CHECKING: from openff.toolkit.topology import Topology - from openmm import System + + try: + from openmm import System + except ImportError: + from simtk.openmm import System class ParameterizedSystem(TypedBaseModel): @@ -31,7 +35,11 @@ def topology_path(self) -> str: def topology(self) -> "Topology": from openff.toolkit.topology import Molecule, Topology - from openmm import app + + try: + from openmm import app + except ImportError: + from simtk.openmm import app pdb_file = app.PDBFile(self._topology_path) @@ -51,7 +59,10 @@ def system_path(self) -> str: @property def system(self) -> "System": - import openmm + try: + import openmm + except ImportError: + from simtk import openmm with open(self._system_path) as file: system = openmm.XmlSerializer.deserialize(file.read()) diff --git a/openff/evaluator/protocols/analysis.py b/openff/evaluator/protocols/analysis.py index 309d8a6b..1f74a6ee 100644 --- a/openff/evaluator/protocols/analysis.py +++ b/openff/evaluator/protocols/analysis.py @@ -34,7 +34,11 @@ ) if typing.TYPE_CHECKING: - import openmm + + try: + import openmm + except ImportError: + from simtk import openmm E0 = 8.854187817e-12 * unit.farad / unit.meter # Taken from QCElemental @@ -578,8 +582,12 @@ def _extract_charges( The charge on each atom in the system if any are present, otherwise none. """ - import openmm - from openmm import unit as openmm_unit + try: + import openmm + from openmm import unit as openmm_unit + except ImportError: + from simtk import openmm + from simtk.openmm import unit as openmm_unit forces = [ system.getForce(force_index) diff --git a/openff/evaluator/protocols/coordinates.py b/openff/evaluator/protocols/coordinates.py index 3c0af38c..25f197e7 100644 --- a/openff/evaluator/protocols/coordinates.py +++ b/openff/evaluator/protocols/coordinates.py @@ -7,7 +7,11 @@ from os import path import numpy as np -from openmm import app + +try: + from openmm import app +except ImportError: + from simtk.openmm import app from openff.evaluator import unit from openff.evaluator.attributes import UNDEFINED @@ -446,7 +450,11 @@ def _execute(self, directory, available_resources): import mdtraj from openeye import oechem, oedocking - from openmm import unit as openmm_unit + + try: + from openmm import unit as openmm_unit + except ImportError: + from simtk.openmm import unit as openmm_unit if ( len(self.ligand_substance.components) != 1 diff --git a/openff/evaluator/protocols/forcefield.py b/openff/evaluator/protocols/forcefield.py index d5802000..5c522067 100644 --- a/openff/evaluator/protocols/forcefield.py +++ b/openff/evaluator/protocols/forcefield.py @@ -12,9 +12,17 @@ from enum import Enum import numpy as np -import openmm + +try: + import openmm +except ImportError: + from simtk import openmm import requests -from openmm import app + +try: + from openmm import app +except ImportError: + from simtk.openmm import app from openff.evaluator.attributes import UNDEFINED from openff.evaluator.forcefield import ( @@ -547,7 +555,10 @@ def _built_template(molecule, force_field_source): openmm.app.ForceField The force field template. """ - from openmm import unit as openmm_unit + try: + from openmm import unit as openmm_unit + except ImportError: + from simtk.openmm import unit as openmm_unit initial_request_url = force_field_source.request_url empty_stream = io.BytesIO(b"\r\n") @@ -643,7 +654,10 @@ def _parameterize_molecule(self, molecule, force_field_source, cutoff): openmm.System The parameterized system. """ - from openmm import unit as openmm_unit + try: + from openmm import unit as openmm_unit + except ImportError: + from simtk.openmm import unit as openmm_unit template = self._built_template(molecule, force_field_source) @@ -682,7 +696,10 @@ def _apply_opls_mixing_rules(system): system: openmm.System The system object to apply the OPLS mixing rules to. """ - from openmm import unit as openmm_unit + try: + from openmm import unit as openmm_unit + except ImportError: + from simtk.openmm import unit as openmm_unit forces = [system.getForce(index) for index in range(system.getNumForces())] forces = [force for force in forces if isinstance(force, openmm.NonbondedForce)] @@ -825,7 +842,10 @@ def _run_tleap(molecule, force_field_source, directory): str The file path to the `rst7` file. """ - from openmm import unit as openmm_unit + try: + from openmm import unit as openmm_unit + except ImportError: + from simtk.openmm import unit as openmm_unit # Change into the working directory. with temporarily_change_directory(directory): diff --git a/openff/evaluator/protocols/gradients.py b/openff/evaluator/protocols/gradients.py index c52a091f..7ccc018d 100644 --- a/openff/evaluator/protocols/gradients.py +++ b/openff/evaluator/protocols/gradients.py @@ -52,7 +52,10 @@ class ZeroGradients(Protocol, abc.ABC): def _execute(self, directory, available_resources): - from openmm import unit as openmm_unit + try: + from openmm import unit as openmm_unit + except ImportError: + from simtk.openmm import unit as openmm_unit force_field_source = ForceFieldSource.from_json(self.force_field_path) diff --git a/openff/evaluator/protocols/openmm.py b/openff/evaluator/protocols/openmm.py index 0484b42e..4a5a6319 100644 --- a/openff/evaluator/protocols/openmm.py +++ b/openff/evaluator/protocols/openmm.py @@ -45,7 +45,11 @@ if TYPE_CHECKING: - import openmm + try: + import openmm + except ImportError: + from simtk import openmm + from mdtraj import Trajectory from openff.toolkit.topology import Topology from openff.toolkit.typing.engines.smirnoff import ForceField @@ -84,8 +88,12 @@ def _evaluate_energies( ------- The array containing the evaluated potentials. """ - import openmm - from openmm import unit as openmm_unit + try: + import openmm + from openmm import unit as openmm_unit + except ImportError: + from simtk import openmm + from simtk.openmm import unit as openmm_unit integrator = openmm.VerletIntegrator(0.1 * openmm_unit.femtoseconds) @@ -178,7 +186,10 @@ def _compute_gradients( The amount to perturb for the force field parameter by. """ - import openmm + try: + import openmm + except ImportError: + from simtk import openmm gradients = defaultdict(list) observables.clear_gradients() @@ -334,9 +345,14 @@ class OpenMMEnergyMinimisation(BaseEnergyMinimisation): def _execute(self, directory, available_resources): - import openmm - from openmm import app - from openmm import unit as openmm_unit + try: + import openmm + from openmm import app + from openmm import unit as openmm_unit + except ImportError: + from simtk import openmm + from simtk.openmm import app + from simtk.openmm import unit as openmm_unit platform = setup_platform_with_resources(available_resources) @@ -445,7 +461,10 @@ def __init__(self, file, append=False): def report(self, simulation, state): - from openmm import app + try: + from openmm import app + except ImportError: + from simtk.openmm import app if self._dcd is None: @@ -486,7 +505,11 @@ def __init__(self, protocol_id): def _execute(self, directory, available_resources): import mdtraj - from openmm import app + + try: + from openmm import app + except ImportError: + from simtk.openmm import app # We handle most things in OMM units here. temperature = self.thermodynamic_state.temperature @@ -596,9 +619,14 @@ def _setup_simulation_objects(self, temperature, pressure, available_resources): the simulation. """ - import openmm import openmmtools - from openmm import app + + try: + import openmm + from openmm import app + except ImportError: + from simtk import openmm + from simtk.openmm import app # Create a platform with the correct resources. if not self.allow_gpu_platforms: @@ -678,7 +706,10 @@ def _write_checkpoint_file(self, current_step_number, context): context: openmm.Context The current OpenMM context. """ - import openmm + try: + import openmm + except ImportError: + from simtk import openmm # Write the current state to disk state = context.getState( @@ -831,7 +862,10 @@ def _resume_from_checkpoint(self, context): int The current step number. """ - import openmm + try: + import openmm + except ImportError: + from simtk import openmm current_step_number = 0 @@ -953,7 +987,10 @@ def _simulate(self, context, integrator): integrator: openmm.Integrator The integrator to evolve the simulation with. """ - from openmm import app + try: + from openmm import app + except ImportError: + from simtk.openmm import app # Define how many steps should be taken. total_number_of_steps = ( diff --git a/openff/evaluator/protocols/paprika/coordinates.py b/openff/evaluator/protocols/paprika/coordinates.py index b9653475..79fcd3b9 100644 --- a/openff/evaluator/protocols/paprika/coordinates.py +++ b/openff/evaluator/protocols/paprika/coordinates.py @@ -141,7 +141,11 @@ class PreparePullCoordinates(_PrepareAPRCoordinates): def _execute(self, directory, available_resources): - from openmm import app + try: + from openmm import app + except ImportError: + from simtk.openmm import app + from paprika.evaluator import Setup atom_indices_by_role = _atom_indices_by_role( @@ -177,7 +181,12 @@ class PrepareReleaseCoordinates(_PrepareAPRCoordinates): def _execute(self, directory, available_resources): import mdtraj - from openmm import app + + try: + from openmm import app + except ImportError: + from simtk.openmm import app + from paprika.evaluator import Setup mdtraj_trajectory = mdtraj.load_pdb(self.complex_file_path) @@ -248,7 +257,12 @@ class AddDummyAtoms(Protocol): def _execute(self, directory, available_resources): import parmed.geometry - from openmm import NonbondedForce, XmlSerializer, app + + try: + from openmm import NonbondedForce, XmlSerializer, app + except ImportError: + from simtk.openmm import NonbondedForce, XmlSerializer, app + from paprika.evaluator import Setup # Extract the host atoms to determine the offset of the dummy atoms. diff --git a/openff/evaluator/protocols/paprika/restraints.py b/openff/evaluator/protocols/paprika/restraints.py index cb33bd90..f9912555 100644 --- a/openff/evaluator/protocols/paprika/restraints.py +++ b/openff/evaluator/protocols/paprika/restraints.py @@ -350,7 +350,11 @@ def load_restraints(cls, file_path: str): def _execute(self, directory, available_resources): - from openmm import XmlSerializer + try: + from openmm import XmlSerializer + except ImportError: + from simtk.openmm import XmlSerializer + from paprika.restraints.openmm import ( apply_dat_restraint, apply_positional_restraints, diff --git a/openff/evaluator/protocols/yank.py b/openff/evaluator/protocols/yank.py index af0646cd..f0181bbb 100644 --- a/openff/evaluator/protocols/yank.py +++ b/openff/evaluator/protocols/yank.py @@ -154,7 +154,11 @@ def _get_residue_names_from_role(substances, coordinate_path, role): """ from openff.toolkit.topology import Molecule, Topology - from openmm import app + + try: + from openmm import app + except ImportError: + from simtk.openmm import app if role is None: return "all" @@ -461,7 +465,10 @@ def _run_yank(directory, available_resources, setup_only) -> Dict[str, Any]: if setup_only is True: - from openmm import unit as openmm_unit + try: + from openmm import unit as openmm_unit + except ImportError: + from simtk.openmm import unit as openmm_unit return { "free_energy": { @@ -1327,7 +1334,10 @@ def _analyze_phase( def _execute(self, directory, available_resources): - from openmm import XmlSerializer + try: + from openmm import XmlSerializer + except ImportError: + from simtk.openmm import XmlSerializer solute_components = [ component diff --git a/openff/evaluator/tests/test_protocols/test_coordinates.py b/openff/evaluator/tests/test_protocols/test_coordinates.py index f322ee49..67700672 100644 --- a/openff/evaluator/tests/test_protocols/test_coordinates.py +++ b/openff/evaluator/tests/test_protocols/test_coordinates.py @@ -4,7 +4,11 @@ import tempfile import pytest -from openmm.app import PDBFile + +try: + from openmm.app import PDBFile +except ImportError: + from simtk.openmm.app import PDBFile from openff.evaluator.backends import ComputeResources from openff.evaluator.protocols.coordinates import ( diff --git a/openff/evaluator/tests/test_protocols/test_openmm.py b/openff/evaluator/tests/test_protocols/test_openmm.py index 95c82676..6e0a333b 100644 --- a/openff/evaluator/tests/test_protocols/test_openmm.py +++ b/openff/evaluator/tests/test_protocols/test_openmm.py @@ -10,7 +10,12 @@ import numpy from openff.toolkit.topology import Molecule, Topology from openff.toolkit.typing.engines.smirnoff import ForceField -from openmm import unit as openmm_unit + +try: + from openmm import unit as openmm_unit +except ImportError: + from simtk.openmm import unit as openmm_unit + from smirnoff_plugins.handlers.nonbonded import DoubleExponential from openff.evaluator import unit diff --git a/openff/evaluator/tests/test_protocols/test_paprika.py b/openff/evaluator/tests/test_protocols/test_paprika.py index 5168369c..00d044be 100644 --- a/openff/evaluator/tests/test_protocols/test_paprika.py +++ b/openff/evaluator/tests/test_protocols/test_paprika.py @@ -216,8 +216,13 @@ def test_prepare_pull_coordinates(tmp_path, dummy_complex, window_index, expecte def test_add_dummy_atoms(tmp_path, dummy_complex): import mdtraj - import openmm - from openmm import unit as openmm_unit + + try: + import openmm + from openmm import unit as openmm_unit + except ImportError: + from simtk import openmm + from simtk.openmm import unit as openmm_unit # Create an empty system to add the dummy atoms to. system_path = os.path.join(tmp_path, "input.xml") @@ -303,8 +308,10 @@ def validate_generated_restraints(restraints_path, expected_restraint_types, pha def validate_system_file(system_path, expected_force_groups): - - import openmm + try: + import openmm + except ImportError: + from simtk import openmm assert os.path.isfile(system_path) @@ -371,8 +378,10 @@ def test_generate_release_restraints(tmp_path, complex_file_path, restraints_sch def test_apply_attach_restraints( tmp_path, dummy_complex, complex_file_path, attach_restraints_path ): - - import openmm + try: + import openmm + except ImportError: + from simtk import openmm with open(os.path.join(tmp_path, "system.xml"), "w") as file: file.write(openmm.XmlSerializer.serialize(openmm.System())) @@ -396,8 +405,10 @@ def test_apply_attach_restraints( def test_apply_pull_restraints( tmp_path, dummy_complex, complex_file_path, pull_restraints_path ): - - import openmm + try: + import openmm + except ImportError: + from simtk import openmm with open(os.path.join(tmp_path, "system.xml"), "w") as file: file.write(openmm.XmlSerializer.serialize(openmm.System())) @@ -421,8 +432,10 @@ def test_apply_pull_restraints( def test_apply_release_restraints( tmp_path, dummy_complex, complex_file_path, release_restraints_path ): - - import openmm + try: + import openmm + except ImportError: + from simtk import openmm with open(os.path.join(tmp_path, "system.xml"), "w") as file: file.write(openmm.XmlSerializer.serialize(openmm.System())) diff --git a/openff/evaluator/tests/test_protocols/test_yank.py b/openff/evaluator/tests/test_protocols/test_yank.py index 727b469b..00d8af27 100644 --- a/openff/evaluator/tests/test_protocols/test_yank.py +++ b/openff/evaluator/tests/test_protocols/test_yank.py @@ -214,8 +214,10 @@ def test_compute_state_energy_gradients(tmpdir): def test_analyze_phase(monkeypatch, tmpdir): - - from openmm import unit as openmm_unit + try: + from openmm import unit as openmm_unit + except ImportError: + from simtk.openmm import unit as openmm_unit # Generate the required inputs build_tip3p_smirnoff_force_field().json(os.path.join(tmpdir, "ff.json")) diff --git a/openff/evaluator/tests/test_utils/test_openmm.py b/openff/evaluator/tests/test_utils/test_openmm.py index b33a0ca3..5852cc58 100644 --- a/openff/evaluator/tests/test_utils/test_openmm.py +++ b/openff/evaluator/tests/test_utils/test_openmm.py @@ -4,7 +4,12 @@ import mdtraj import numpy import numpy as np -import openmm + +try: + import openmm +except ImportError: + from simtk import openmm + import pytest from openff.toolkit.topology import Molecule, Topology from openff.toolkit.typing.engines.smirnoff import ForceField, vdWHandler @@ -14,8 +19,13 @@ LibraryChargeHandler, VirtualSiteHandler, ) -from openmm import unit as openmm_unit -from openmm.app import PDBFile + +try: + from openmm import unit as openmm_unit + from openmm.app import PDBFile +except ImportError: + from simtk.openmm import unit as openmm_unit + from simtk.openmm.app import PDBFile from openff.evaluator import unit from openff.evaluator.backends import ComputeResources diff --git a/openff/evaluator/tests/test_workflow/test_workflow.py b/openff/evaluator/tests/test_workflow/test_workflow.py index 80a2bb87..0ac13654 100644 --- a/openff/evaluator/tests/test_workflow/test_workflow.py +++ b/openff/evaluator/tests/test_workflow/test_workflow.py @@ -270,8 +270,10 @@ def test_replicated_ids(): def test_find_relevant_gradient_keys(tmpdir): - - from openmm import unit as openmm_unit + try: + from openmm import unit as openmm_unit + except ImportError: + from simtk.openmm import unit as openmm_unit force_field = ForceField() diff --git a/openff/evaluator/utils/openmm.py b/openff/evaluator/utils/openmm.py index e6da26be..88ef0534 100644 --- a/openff/evaluator/utils/openmm.py +++ b/openff/evaluator/utils/openmm.py @@ -6,9 +6,16 @@ from typing import TYPE_CHECKING, List, Optional, Tuple import numpy -import openmm -from openmm import app -from openmm import unit as _openmm_unit + +try: + import openmm + from openmm import app + from openmm import unit as _openmm_unit +except ImportError: + from simtk import openmm + from simtk.openmm import app + from simtk.openmm import unit as _openmm_unit + from pint import UndefinedUnitError from openff.evaluator import unit @@ -40,7 +47,10 @@ def setup_platform_with_resources(compute_resources, high_precision=False): Platform The created platform """ - from openmm import Platform + try: + from openmm import Platform + except ImportError: + from simtk.openmm import Platform # Setup the requested platform: if compute_resources.number_of_gpus > 0: diff --git a/openff/evaluator/utils/packmol.py b/openff/evaluator/utils/packmol.py index 6d05a0d1..6402d9c1 100644 --- a/openff/evaluator/utils/packmol.py +++ b/openff/evaluator/utils/packmol.py @@ -306,7 +306,10 @@ def _ion_residue_name(molecule): str The residue name of the ion """ - from openmm import unit as openmm_unit + try: + from openmm import unit as openmm_unit + except ImportError: + from simtk.openmm import unit as openmm_unit element_symbol = molecule.atoms[0].element.symbol charge_symbol = "" diff --git a/setup.cfg b/setup.cfg index 4dc67272..df76a484 100644 --- a/setup.cfg +++ b/setup.cfg @@ -8,6 +8,10 @@ omit = # Omit generated versioneer openff/evaluator/_version.py +[coverage:report] +exclude_lines = + except ImportError: + [flake8] # Flake8, PyFlakes, etc max-line-length = 88