diff --git a/devtools/conda-envs/dev_env.yaml b/devtools/conda-envs/dev_env.yaml
index 77547ef41..4eec7d5a6 100644
--- a/devtools/conda-envs/dev_env.yaml
+++ b/devtools/conda-envs/dev_env.yaml
@@ -27,6 +27,7 @@ dependencies:
- pytest
- pytest-cov
- pytest-xdist
+ - pytest-randomly
- nbval
- qcportal
- openff-qcsubmit
diff --git a/openff/interchange/_tests/__init__.py b/openff/interchange/_tests/__init__.py
index 10f386335..69a04d010 100644
--- a/openff/interchange/_tests/__init__.py
+++ b/openff/interchange/_tests/__init__.py
@@ -7,10 +7,9 @@
import numpy as np
import openmm
import pytest
-from openff.toolkit._tests.create_molecules import create_ammonia, create_ethanol
+from openff.toolkit import ForceField, Molecule, Topology
+from openff.toolkit._tests.create_molecules import create_ethanol
from openff.toolkit._tests.utils import get_data_file_path
-from openff.toolkit.topology import Molecule, Topology
-from openff.toolkit.typing.engines.smirnoff import ForceField
from openff.units import unit
from openff.utilities.utilities import has_executable
from openmm import unit as openmm_unit
@@ -55,36 +54,23 @@ def get_test_files_dir_path(dirname: Optional[str] = None) -> pathlib.Path:
)
-class _BaseTest:
- @pytest.fixture(autouse=True)
- def _initdir(self, tmpdir):
- tmpdir.chdir()
+class MoleculeWithConformer(Molecule):
+ """Thin wrapper around `Molecule` to produce an instance with a conformer in one call."""
- # TODO: group fixtures up as dicts, i.e. argon['forcefield'], argon['topology'], ...
- @pytest.fixture()
- def argon_ff(self):
- """Fixture that loads an SMIRNOFF XML for argon."""
- return ForceField(get_test_file_path("argon.offxml"))
+ @classmethod
+ def from_smiles(self, smiles, name=""):
+ """Create from smiles and generate a single conformer."""
+ molecule = super().from_smiles(smiles)
+ molecule.generate_conformers(n_conformers=1)
+ molecule.name = name
- @pytest.fixture()
- def argon(self):
- """Fixture that builds a simple arogon topology."""
- argon = Molecule()
- argon.add_atom(
- atomic_number=18,
- formal_charge=0,
- is_aromatic=False,
- )
- return argon
+ return molecule
- @pytest.fixture()
- def ammonia_ff(self):
- """Fixture that loads an SMIRNOFF XML for ammonia."""
- return ForceField(get_test_file_path("ammonia.offxml"))
- @pytest.fixture()
- def ammonia(self):
- return create_ammonia()
+class _BaseTest:
+ @pytest.fixture(autouse=True)
+ def _initdir(self, tmpdir):
+ tmpdir.chdir()
@pytest.fixture()
def ethanol(self):
@@ -96,11 +82,6 @@ def basic_top(self):
top.box_vectors = unit.Quantity([5, 5, 5], unit.nanometer)
return top
- @pytest.fixture()
- def ammonia_top(self, ammonia):
- """Fixture that builds a simple ammonia topology."""
- return Topology.from_molecules(4 * [ammonia])
-
@pytest.fixture()
def ethanol_top(self, ethanol):
"""Fixture that builds a simple four ethanol topology."""
@@ -136,105 +117,6 @@ def mainchain_arg(self):
def two_peptides(self, mainchain_ala, mainchain_arg):
return Topology.from_molecules([mainchain_ala, mainchain_arg])
- @pytest.fixture()
- def tip3p_xml(self):
- # Modified (added Electrostatics tag) from below link
- # https://github.com/openforcefield/openff-toolkit/blob/0.10.2/openff/toolkit/data/test_forcefields/tip3p.offxml
- return """
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-"""
-
- @pytest.fixture()
- def tip3p(self, tip3p_xml):
- return ForceField(tip3p_xml)
-
- @pytest.fixture()
- def tip3p_missing_electrostatics_xml(self):
- # Stripped from below, follow link for details
- # https://github.com/openforcefield/openff-toolkit/blob/0.10.2/openff/toolkit/data/test_forcefields/tip3p.offxml
- return """
-
-
-
-
-
-
-
-
-"""
-
xml_ff_bo_bonds = """
@@ -284,10 +166,6 @@ def acetaldehyde(self):
"[C:1]([C:2](=[O:3])[H:7])([H:4])([H:5])[H:6]",
)
- @pytest.fixture()
- def water(self):
- return Molecule.from_mapped_smiles("[H:2][O:1][H:3]")
-
HAS_GROMACS = _find_gromacs_executable() is not None
HAS_LAMMPS = _find_lammps_executable() is not None
diff --git a/openff/interchange/_tests/conftest.py b/openff/interchange/_tests/conftest.py
new file mode 100644
index 000000000..57ee11bb6
--- /dev/null
+++ b/openff/interchange/_tests/conftest.py
@@ -0,0 +1,36 @@
+"""Pytest configuration."""
+import pytest
+from openff.toolkit import ForceField, Molecule
+
+from openff.interchange._tests import get_test_file_path
+
+
+@pytest.fixture()
+def _simple_force_field():
+ # TODO: Create a minimal force field for faster tests
+ pass
+
+
+@pytest.fixture()
+def tip3p() -> ForceField:
+ return ForceField("tip3p.offxml")
+
+
+@pytest.fixture()
+def tip4p() -> ForceField:
+ return ForceField("tip4p_fb.offxml")
+
+
+@pytest.fixture()
+def gbsa_force_field() -> ForceField:
+ return ForceField(
+ "openff-2.0.0.offxml",
+ get_test_file_path("gbsa.offxml"),
+ )
+
+
+@pytest.fixture(scope="session")
+def water() -> Molecule:
+ molecule = Molecule.from_mapped_smiles("[H:2][O:1][H:3]")
+ molecule.generate_conformers(n_conformers=1)
+ return molecule
diff --git a/openff/interchange/_tests/data/argon.offxml b/openff/interchange/_tests/data/argon.offxml
deleted file mode 100644
index 4fb264e35..000000000
--- a/openff/interchange/_tests/data/argon.offxml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/openff/interchange/_tests/energy_tests/components/tests_smirnoff.py b/openff/interchange/_tests/energy_tests/components/tests_smirnoff.py
index 51d8e386e..9e439bcc9 100644
--- a/openff/interchange/_tests/energy_tests/components/tests_smirnoff.py
+++ b/openff/interchange/_tests/energy_tests/components/tests_smirnoff.py
@@ -1,9 +1,8 @@
import numpy as np
import openmm
import pytest
+from openff.toolkit import ForceField, Molecule
from openff.toolkit._tests.utils import get_data_file_path
-from openff.toolkit.topology import Molecule
-from openff.toolkit.typing.engines.smirnoff.forcefield import ForceField
from openff.units import unit
from openmm import unit as openmm_unit
diff --git a/openff/interchange/_tests/energy_tests/test_energies.py b/openff/interchange/_tests/energy_tests/test_energies.py
index 32bf99b07..302b215c0 100644
--- a/openff/interchange/_tests/energy_tests/test_energies.py
+++ b/openff/interchange/_tests/energy_tests/test_energies.py
@@ -11,6 +11,7 @@
from openff.interchange._tests import (
HAS_GROMACS,
HAS_LAMMPS,
+ MoleculeWithConformer,
_BaseTest,
get_test_file_path,
needs_gmx,
@@ -45,17 +46,15 @@ def oplsaa(self):
def test_energies_single_mol(self, constrained, sage, sage_unconstrained, mol_smi):
import mbuild as mb
- mol = Molecule.from_smiles(mol_smi)
- mol.generate_conformers(n_conformers=1)
- mol.name = "FOO"
+ molecule = MoleculeWithConformer.from_smiles(mol_smi, name="FOO")
force_field = sage if constrained else sage_unconstrained
- interchange = Interchange.from_smirnoff(force_field, [mol])
+ interchange = Interchange.from_smirnoff(force_field, [molecule])
interchange.collections["Electrostatics"].periodic_potential = "cutoff"
- mol.to_file("out.xyz", file_format="xyz")
+ molecule.to_file("out.xyz", file_format="xyz")
compound = mb.load("out.xyz")
packed_box = mb.fill_box(
compound=compound,
@@ -107,8 +106,7 @@ def test_process_rb_torsions(self, oplsaa):
from openff.interchange.components.mbuild import offmol_to_compound
- ethanol = Molecule.from_smiles("CCO")
- ethanol.generate_conformers(n_conformers=1)
+ ethanol = MoleculeWithConformer.from_smiles("CCO")
ethanol.generate_unique_atom_names()
my_compound = offmol_to_compound(ethanol)
@@ -136,9 +134,7 @@ def test_gmx_14_energies_exist(self, sage):
# Use a molecule with only one 1-4 interaction, and
# make it between heavy atoms because H-H 1-4 are weak
- mol = Molecule.from_smiles("ClC#CCl")
- mol.name = "HPER"
- mol.generate_conformers(n_conformers=1)
+ mol = MoleculeWithConformer.from_smiles("ClC#CCl", name="HPER")
out = Interchange.from_smirnoff(sage, [mol])
out.positions = mol.conformers[0]
@@ -215,17 +211,16 @@ def test_interpolated_parameters(self, smi):
"""
- mol = Molecule.from_smiles(smi)
- mol.generate_conformers(n_conformers=1)
+ molecule = MoleculeWithConformer.from_smiles(smi)
forcefield = ForceField(
"openff-2.0.0.offxml",
xml_ff_bo_all_heavy_bonds,
)
- out = Interchange.from_smirnoff(forcefield, [mol])
+ out = Interchange.from_smirnoff(forcefield, [molecule])
out.box = [4, 4, 4] * unit.nanometer
- out.positions = mol.conformers[0]
+ out.positions = molecule.conformers[0]
for key in ["Bond", "Torsion"]:
interchange_energy = get_openmm_energies(
diff --git a/openff/interchange/_tests/interoperability_tests/internal/test_gromacs.py b/openff/interchange/_tests/interoperability_tests/internal/test_gromacs.py
index d461187a3..fd66d641d 100644
--- a/openff/interchange/_tests/interoperability_tests/internal/test_gromacs.py
+++ b/openff/interchange/_tests/interoperability_tests/internal/test_gromacs.py
@@ -15,7 +15,7 @@
from openmm import unit as openmm_unit
from openff.interchange import Interchange
-from openff.interchange._tests import _BaseTest, needs_gmx
+from openff.interchange._tests import MoleculeWithConformer, _BaseTest, needs_gmx
from openff.interchange.components.nonbonded import BuckinghamvdWCollection
from openff.interchange.components.potentials import Potential
from openff.interchange.drivers import get_gromacs_energies, get_openmm_energies
@@ -93,8 +93,7 @@ def converter(x):
assert n_decimals == 12
def test_vaccum_warning(self, sage):
- molecule = Molecule.from_smiles("CCO")
- molecule.generate_conformers(n_conformers=1)
+ molecule = MoleculeWithConformer.from_smiles("CCO")
out = Interchange.from_smirnoff(force_field=sage, topology=[molecule])
@@ -167,9 +166,8 @@ class TestGROMACS(_BaseTest):
],
)
def test_simple_roundtrip(self, sage, smiles, reader):
- molecule = Molecule.from_smiles(smiles)
+ molecule = MoleculeWithConformer.from_smiles(smiles)
molecule.name = molecule.to_hill_formula()
- molecule.generate_conformers(n_conformers=1)
topology = molecule.to_topology()
out = Interchange.from_smirnoff(force_field=sage, topology=topology)
@@ -194,8 +192,11 @@ def test_simple_roundtrip(self, sage, smiles, reader):
@skip_if_missing("parmed")
def test_num_impropers(self, sage):
- top = Molecule.from_smiles("CC1=CC=CC=C1").to_topology()
- out = Interchange.from_smirnoff(sage, top)
+ out = Interchange.from_smirnoff(
+ sage,
+ MoleculeWithConformer.from_smiles("CC1=CC=CC=C1").to_topology(),
+ )
+
out.box = unit.Quantity(4 * numpy.eye(3), units=unit.nanometer)
out.to_top("tmp.top")
@@ -279,8 +280,8 @@ def test_argon_buck(self):
SMIRNOFFElectrostaticsCollection,
)
- mol = Molecule.from_smiles("[#18]")
- mol.name = "Argon"
+ mol = MoleculeWithConformer.from_smiles("[#18]", name="Argon")
+
top = Topology.from_molecules([mol, mol])
# http://www.sklogwiki.org/SklogWiki/index.php/Argon#Buckingham_potential
@@ -421,16 +422,14 @@ def sage_with_monovalent_lone_pair(self, sage):
@skip_if_missing("parmed")
def test_sigma_hole_example(self, sage_with_sigma_hole):
"""Test that a single-molecule sigma hole example runs"""
- mol = Molecule.from_smiles("CCl")
- mol.name = "Chloromethane"
- mol.generate_conformers(n_conformers=1)
+ molecule = MoleculeWithConformer.from_smiles("CCl", name="Chloromethane")
out = Interchange.from_smirnoff(
force_field=sage_with_sigma_hole,
- topology=mol.to_topology(),
+ topology=molecule.to_topology(),
)
out.box = [4, 4, 4]
- out.positions = mol.conformers[0]
+ out.positions = molecule.conformers[0]
# TODO: Sanity-check reported energies
get_gromacs_energies(out)
@@ -442,9 +441,7 @@ def test_sigma_hole_example(self, sage_with_sigma_hole):
def test_carbonyl_example(self, sage_with_monovalent_lone_pair):
"""Test that a single-molecule DivalentLonePair example runs"""
- mol = Molecule.from_smiles("C=O")
- mol.name = "Carbon_monoxide"
- mol.generate_conformers(n_conformers=1)
+ mol = MoleculeWithConformer.from_smiles("C=O", name="Carbon_monoxide")
out = Interchange.from_smirnoff(
force_field=sage_with_monovalent_lone_pair,
diff --git a/openff/interchange/_tests/interoperability_tests/test_external.py b/openff/interchange/_tests/interoperability_tests/test_external.py
deleted file mode 100644
index 1a3bffd63..000000000
--- a/openff/interchange/_tests/interoperability_tests/test_external.py
+++ /dev/null
@@ -1,29 +0,0 @@
-import numpy as np
-import pytest
-from openff.toolkit.topology import Molecule, Topology
-from openff.units import unit
-from openff.units.openmm import from_openmm
-from openmm import app
-from openmm import unit as openmm_unit
-
-from openff.interchange import Interchange
-from openff.interchange._tests import _BaseTest, get_test_file_path
-
-
-class TestFromOpenMM(_BaseTest):
- @pytest.mark.slow()
- def test_from_openmm_pdbfile(self, argon_ff):
- pdb_file_path = get_test_file_path("10-argons.pdb").as_posix()
- pdbfile = app.PDBFile(pdb_file_path)
-
- mol = Molecule.from_smiles("[#18]")
- tmp = Topology.from_openmm(pdbfile.topology, unique_molecules=[mol])
-
- out = Interchange.from_smirnoff(argon_ff, tmp)
- out.box = from_openmm(pdbfile.topology.getPeriodicBoxVectors())
- out.positions = from_openmm(pdbfile.getPositions())
-
- assert np.allclose(
- out.positions.to(unit.nanometer).magnitude,
- pdbfile.getPositions().value_in_unit(openmm_unit.nanometer),
- )
diff --git a/openff/interchange/_tests/interoperability_tests/test_openmm.py b/openff/interchange/_tests/interoperability_tests/test_openmm.py
index ee713cc7d..3fc91f085 100644
--- a/openff/interchange/_tests/interoperability_tests/test_openmm.py
+++ b/openff/interchange/_tests/interoperability_tests/test_openmm.py
@@ -12,7 +12,11 @@
from openff.units import unit
from openff.interchange import Interchange
-from openff.interchange._tests import _BaseTest, get_test_file_path
+from openff.interchange._tests import (
+ MoleculeWithConformer,
+ _BaseTest,
+ get_test_file_path,
+)
from openff.interchange._tests.unit_tests.plugins.test_smirnoff_plugins import (
TestDoubleExponential,
)
@@ -229,14 +233,11 @@ def test_geometric_mixing_rule(self):
@pytest.mark.slow()
@pytest.mark.parametrize("mol_smi", ["C", "CC", "CCO"])
def test_openmm_roundtrip(self, sage, mol_smi):
- mol = Molecule.from_smiles(mol_smi)
- mol.generate_conformers(n_conformers=1)
- top = mol.to_topology()
+ topology = MoleculeWithConformer.from_smiles(mol_smi).to_topology()
- interchange = Interchange.from_smirnoff(sage, top)
+ interchange = Interchange.from_smirnoff(sage, topology)
interchange.box = [4, 4, 4]
- interchange.positions = mol.conformers[0].value_in_unit(openmm.unit.nanometer)
converted = from_openmm(
topology=interchange.to_openmm_topology(),
@@ -253,13 +254,13 @@ def test_openmm_roundtrip(self, sage, mol_smi):
@pytest.mark.xfail(reason="Broken because of splitting non-bonded forces")
@pytest.mark.slow()
def test_combine_nonbonded_forces(self, sage):
- mol = Molecule.from_smiles("ClC#CCl")
- mol.name = "HPER"
- mol.generate_conformers(n_conformers=1)
+ topology = MoleculeWithConformer.from_smiles(
+ "ClC#CCl",
+ name="HPER",
+ ).to_topology()
- out = Interchange.from_smirnoff(force_field=sage, topology=mol.to_topology())
+ out = Interchange.from_smirnoff(force_field=sage, topology=topology)
out.box = [4, 4, 4]
- out.positions = mol.conformers[0]
num_forces_combined = out.to_openmm(
combine_nonbonded_forces=True,
@@ -278,14 +279,12 @@ def test_combine_nonbonded_forces(self, sage):
separate["vdW"] + separate["Electrostatics"] - combined["Nonbonded"]
).m < 0.001
- def test_openmm_no_angle_force_if_constrained(self):
- # Sage includes angle parameters for water and also TIP3P constraints
- tip3p = ForceField("openff-2.0.0.offxml")
-
- topology = Molecule.from_smiles("O").to_topology()
+ def test_openmm_no_angle_force_if_constrained(self, water, sage):
+ topology = water.to_topology()
topology.box_vectors = [4, 4, 4] * unit.nanometer
- interchange = Interchange.from_smirnoff(tip3p, topology)
+ # Sage includes angle parameters for water and also TIP3P constraints
+ interchange = Interchange.from_smirnoff(sage, topology)
openmm_system = interchange.to_openmm(combine_nonbonded_forces=True)
# The only angle in the system (H-O-H) includes bonds with constrained lengths
@@ -446,9 +445,7 @@ def test_combine_compatibility(self, de_force_field):
def test_double_exponential_create_simulation(self, de_force_field):
from openff.toolkit.utils.openeye_wrapper import OpenEyeToolkitWrapper
- molecule = Molecule.from_smiles("CCO")
- molecule.generate_conformers(n_conformers=1)
- topology = molecule.to_topology()
+ topology = MoleculeWithConformer.from_smiles("CCO").to_topology()
topology.box_vectors = unit.Quantity([4, 4, 4], unit.nanometer)
out = Interchange.from_smirnoff(
@@ -508,7 +505,6 @@ def sage_with_sigma_hole(self, sage):
@pytest.fixture()
def sage_with_monovalent_lone_pair(self, sage):
- """Fixture that loads an SMIRNOFF XML for argon"""
virtual_site_handler = VirtualSiteHandler(version=0.3)
carbonyl_type = VirtualSiteHandler.VirtualSiteMonovalentLonePairType(
@@ -529,7 +525,7 @@ def sage_with_monovalent_lone_pair(self, sage):
return sage
- def test_valence_term_paticle_index_offsets(self):
+ def test_valence_term_paticle_index_offsets(self, water):
# Use a questionable version of TIP5P that includes angle parameters, since that's what's being tested
tip5p_offxml = """
@@ -604,7 +600,6 @@ def test_valence_term_paticle_index_offsets(self):
"""
tip5p = ForceField(tip5p_offxml)
- water = Molecule.from_mapped_smiles("[H:2][O:1][H:3]")
out = Interchange.from_smirnoff(tip5p, [water, water]).to_openmm(
combine_nonbonded_forces=True,
@@ -622,10 +617,8 @@ def test_valence_term_paticle_index_offsets(self):
class TestOpenMMVirtualSiteExclusions(_BaseTest):
- def test_tip5p_num_exceptions(self):
+ def test_tip5p_num_exceptions(self, water):
tip5p = ForceField(get_test_file_path("tip5p.offxml"))
- water = Molecule.from_smiles("O")
- water.generate_conformers(n_conformers=1)
out = Interchange.from_smirnoff(tip5p, [water]).to_openmm(
combine_nonbonded_forces=True,
@@ -695,10 +688,7 @@ def test_dichloroethane_exceptions(self, sage):
class TestToOpenMMTopology(_BaseTest):
- def test_num_virtual_sites(self):
- tip4p = ForceField("openff-2.0.0.offxml", get_test_file_path("tip4p.offxml"))
- water = Molecule.from_smiles("O")
-
+ def test_num_virtual_sites(self, water, tip4p):
out = Interchange.from_smirnoff(tip4p, [water])
assert _get_num_virtual_sites(to_openmm_topology(out)) == 1
@@ -707,13 +697,12 @@ def test_num_virtual_sites(self):
# to be used while virtual sites are present in a handler
assert _get_num_virtual_sites(out.topology.to_openmm()) == 0
- def test_interchange_method(self):
+ def test_interchange_method(self, water, tip4p):
"""
Ensure similar-ish behavior between `to_openmm_topology` as a standalone function
and as the wrapped method of the same name on the `Interchange` class.
"""
- tip4p = ForceField("openff-2.0.0.offxml", get_test_file_path("tip4p.offxml"))
- topology = Molecule.from_smiles("O").to_topology()
+ topology = water.to_topology()
topology.box_vectors = unit.Quantity([4, 4, 4], unit.nanometer)
out = Interchange.from_smirnoff(tip4p, topology)
@@ -721,7 +710,7 @@ def test_interchange_method(self):
_compare_openmm_topologies(out.to_openmm_topology(), to_openmm_topology(out))
@pytest.mark.parametrize("ensure_unique_atom_names", [True, "residues", "chains"])
- def test_assign_unique_atom_names(self, ensure_unique_atom_names):
+ def test_assign_unique_atom_names(self, ensure_unique_atom_names, sage):
"""
Ensure that OFF topologies with no pre-existing atom names have unique
atom names applied when being converted to openmm
@@ -737,7 +726,6 @@ def test_assign_unique_atom_names(self, ensure_unique_atom_names):
[mol._hierarchy_schemes for mol in off_topology.molecules],
), "Test assumes no hierarchy schemes"
- sage = ForceField("openff-2.0.0.offxml")
interchange = Interchange.from_smirnoff(sage, off_topology)
omm_topology = interchange.to_openmm_topology(
@@ -750,7 +738,7 @@ def test_assign_unique_atom_names(self, ensure_unique_atom_names):
assert len(atom_names) == 13
@pytest.mark.parametrize("ensure_unique_atom_names", [True, "residues", "chains"])
- def test_assign_some_unique_atom_names(self, ensure_unique_atom_names):
+ def test_assign_some_unique_atom_names(self, ensure_unique_atom_names, sage):
"""
Ensure that OFF topologies with some pre-existing atom names have unique
atom names applied to the other atoms when being converted to openmm
@@ -768,7 +756,6 @@ def test_assign_some_unique_atom_names(self, ensure_unique_atom_names):
[mol._hierarchy_schemes for mol in off_topology.molecules],
), "Test assumes no hierarchy schemes"
- sage = ForceField("openff-2.0.0.offxml")
interchange = Interchange.from_smirnoff(sage, off_topology)
omm_topology = interchange.to_openmm_topology(
@@ -782,7 +769,11 @@ def test_assign_some_unique_atom_names(self, ensure_unique_atom_names):
assert len(atom_names) == 21
@pytest.mark.parametrize("ensure_unique_atom_names", [True, "residues", "chains"])
- def test_assign_unique_atom_names_some_duplicates(self, ensure_unique_atom_names):
+ def test_assign_unique_atom_names_some_duplicates(
+ self,
+ ensure_unique_atom_names,
+ sage,
+ ):
"""
Ensure that OFF topologies where some molecules have invalid/duplicate
atom names have unique atom names applied while the other molecules are unaffected.
@@ -810,7 +801,6 @@ def test_assign_unique_atom_names_some_duplicates(self, ensure_unique_atom_names
[mol._hierarchy_schemes for mol in off_topology.molecules],
), "Test assumes no hierarchy schemes"
- sage = ForceField("openff-2.0.0.offxml")
interchange = Interchange.from_smirnoff(sage, off_topology)
omm_topology = interchange.to_openmm_topology(
@@ -824,7 +814,7 @@ def test_assign_unique_atom_names_some_duplicates(self, ensure_unique_atom_names
# 1 unique O, and 6 unique Hs, for a total of 21 unique atom names
assert len(atom_names) == 21
- def test_do_not_assign_unique_atom_names(self):
+ def test_do_not_assign_unique_atom_names(self, sage):
"""
Test disabling unique atom name assignment in Topology.to_openmm
"""
@@ -832,11 +822,12 @@ def test_do_not_assign_unique_atom_names(self):
ethanol = Molecule.from_smiles("CCO")
for atom in ethanol.atoms:
atom.name = "eth_test"
+
benzene = Molecule.from_smiles("c1ccccc1")
benzene.atoms[0].name = "bzn_test"
+
off_topology = Topology.from_molecules(molecules=[ethanol, benzene, benzene])
- sage = ForceField("openff-2.0.0.offxml")
interchange = Interchange.from_smirnoff(sage, off_topology)
omm_topology = interchange.to_openmm_topology(ensure_unique_atom_names=False)
@@ -849,7 +840,7 @@ def test_do_not_assign_unique_atom_names(self):
@pytest.mark.slow()
@pytest.mark.parametrize("explicit_arg", [True, False])
- def test_preserve_per_residue_unique_atom_names(self, explicit_arg):
+ def test_preserve_per_residue_unique_atom_names(self, explicit_arg, sage):
"""
Test that to_openmm preserves atom names that are unique per-residue by default
"""
@@ -874,7 +865,6 @@ def test_preserve_per_residue_unique_atom_names(self, explicit_arg):
# Record the initial atom names
init_atomnames = [str(atom.name) for atom in off_topology.atoms]
- sage = ForceField("openff-2.0.0.offxml")
interchange = Interchange.from_smirnoff(sage, off_topology)
# Perform the test
@@ -891,7 +881,7 @@ def test_preserve_per_residue_unique_atom_names(self, explicit_arg):
@pytest.mark.slow()
@pytest.mark.parametrize("explicit_arg", [True, False])
- def test_generate_per_residue_unique_atom_names(self, explicit_arg):
+ def test_generate_per_residue_unique_atom_names(self, explicit_arg, sage):
"""
Test that to_openmm generates atom names that are unique per-residue
"""
@@ -922,7 +912,6 @@ def test_generate_per_residue_unique_atom_names(self, explicit_arg):
), f"Test assumes atom names are not unique per-residue in {res}"
assert off_topology.n_atoms == 32, "Test assumes topology has 32 atoms"
- sage = ForceField("openff-2.0.0.offxml")
interchange = Interchange.from_smirnoff(sage, off_topology)
# Perform the test
@@ -951,6 +940,7 @@ def test_generate_per_residue_unique_atom_names(self, explicit_arg):
def test_generate_per_molecule_unique_atom_names_with_residues(
self,
ensure_unique_atom_names,
+ sage,
):
"""
Test that to_openmm can generate atom names that are unique per-molecule
@@ -983,7 +973,6 @@ def test_generate_per_molecule_unique_atom_names_with_residues(
), f"Test assumes atom names are not unique per-residue in {res}"
assert off_topology.n_atoms == 32, "Test assumes topology has 32 atoms"
- sage = ForceField("openff-2.0.0.offxml")
interchange = Interchange.from_smirnoff(sage, off_topology)
# Perform the test
@@ -1003,7 +992,7 @@ def test_generate_per_molecule_unique_atom_names_with_residues(
"ensure_unique_atom_names",
[True, "residues", "chains", False],
)
- def test_to_openmm_copies_molecules(self, ensure_unique_atom_names):
+ def test_to_openmm_copies_molecules(self, ensure_unique_atom_names, sage):
"""
Check that generating new atom names doesn't affect the input topology
"""
@@ -1020,7 +1009,6 @@ def test_to_openmm_copies_molecules(self, ensure_unique_atom_names):
[mol._hierarchy_schemes for mol in off_topology.molecules],
), "Test assumes no hierarchy schemes"
- sage = ForceField("openff-2.0.0.offxml")
interchange = Interchange.from_smirnoff(sage, off_topology)
# Record the initial atom names to compare to later
@@ -1061,17 +1049,8 @@ def test_missing_positions(self):
to_openmm_positions(Interchange())
@pytest.mark.parametrize("include_virtual_sites", [True, False])
- def test_positions_basic(self, include_virtual_sites):
- force_field = ForceField(
- "openff-2.0.0.offxml",
- get_test_file_path(
- "tip4p.offxml" if include_virtual_sites else "tip3p.offxml",
- ),
- )
- water = Molecule.from_smiles("O")
- water.generate_conformers(n_conformers=1)
-
- out = Interchange.from_smirnoff(force_field, [water])
+ def test_positions_basic(self, include_virtual_sites, water, tip4p):
+ out = Interchange.from_smirnoff(tip4p, [water])
positions = to_openmm_positions(
out,
@@ -1087,20 +1066,10 @@ def test_positions_basic(self, include_virtual_sites):
)
@pytest.mark.parametrize("include_virtual_sites", [True, False])
- def test_given_positions(self, include_virtual_sites):
+ def test_given_positions(self, include_virtual_sites, water, tip4p):
"""Test issue #616"""
- force_field = ForceField(
- "openff-2.0.0.offxml",
- get_test_file_path(
- "tip4p.offxml" if include_virtual_sites else "tip3p.offxml",
- ),
- )
-
- water = Molecule.from_smiles("O")
- water.generate_conformers(n_conformers=1)
-
topology = Topology.from_molecules([water, water])
- out = Interchange.from_smirnoff(force_field, topology)
+ out = Interchange.from_smirnoff(tip4p, topology)
# Approximate conformer position with a duplicate 5 A away in x
out.positions = unit.Quantity(
@@ -1134,41 +1103,30 @@ def test_given_positions(self, include_virtual_sites):
class TestOpenMMToPDB(_BaseTest):
- def test_to_pdb(self, sage):
- import mdtraj as md
+ def test_to_pdb(self, sage, water):
+ import mdtraj
- molecule = Molecule.from_smiles("O")
+ out = Interchange.from_smirnoff(sage, water.to_topology())
+ out.to_pdb("out.pdb")
- out = Interchange.from_smirnoff(sage, molecule.to_topology())
+ mdtraj.load("out.pdb")
+
+ out.positions = None
with pytest.raises(MissingPositionsError):
out.to_pdb("file_should_not_exist.pdb")
- molecule.generate_conformers(n_conformers=1)
- out.positions = molecule.conformers[0]
-
- out.to_pdb("out.pdb")
-
- md.load("out.pdb")
-
- with pytest.raises(UnsupportedExportError):
- out.to_pdb("file_should_not_exist.pdb", writer="magik")
-
class TestBuckingham:
- def test_water_with_virtual_sites(self):
+ def test_water_with_virtual_sites(self, water):
force_field = ForceField(
get_test_file_path("buckingham_virtual_sites.offxml"),
load_plugins=True,
)
- water = Molecule.from_mapped_smiles("[H:2][O:1][H:3]")
- water.generate_conformers(n_conformers=1)
- topology = water.to_topology()
-
interchange = Interchange.from_smirnoff(
force_field=force_field,
- topology=topology,
+ topology=water.to_topology(),
box=[4, 4, 4],
)
@@ -1236,53 +1194,27 @@ def test_water_with_virtual_sites(self):
class TestGBSA(_BaseTest):
- def test_create_gbsa(self):
- force_field = ForceField(
- "openff-2.0.0.offxml",
- get_test_file_path("gbsa.offxml"),
- )
-
- molecule = Molecule.from_smiles("CCO")
- molecule.generate_conformers(n_conformers=1)
-
+ def test_create_gbsa(self, gbsa_force_field):
interchange = Interchange.from_smirnoff(
- force_field=force_field,
- topology=molecule.to_topology(),
+ force_field=gbsa_force_field,
+ topology=MoleculeWithConformer.from_smiles("CCO").to_topology(),
box=[4, 4, 4] * unit.nanometer,
)
assert get_openmm_energies(interchange).total_energy is not None
- def test_cannot_split_nonbonded_forces(self):
- force_field = ForceField(
- "openff-2.0.0.offxml",
- get_test_file_path("gbsa.offxml"),
- )
-
- force_field["Electrostatics"]
- molecule = Molecule.from_smiles("CCO")
- molecule.generate_conformers(n_conformers=1)
-
+ def test_cannot_split_nonbonded_forces(self, gbsa_force_field):
with pytest.raises(UnsupportedExportError, match="exactly one"):
Interchange.from_smirnoff(
- force_field=force_field,
- topology=molecule.to_topology(),
+ force_field=gbsa_force_field,
+ topology=MoleculeWithConformer.from_smiles("CCO").to_topology(),
box=[4, 4, 4] * unit.nanometer,
).to_openmm(combine_nonbonded_forces=False)
- def test_no_cutoff(self):
- force_field = ForceField(
- "openff-2.0.0.offxml",
- get_test_file_path("gbsa.offxml"),
- )
-
- force_field["Electrostatics"]
- molecule = Molecule.from_smiles("CCO")
- molecule.generate_conformers(n_conformers=1)
-
+ def test_no_cutoff(self, gbsa_force_field):
system = Interchange.from_smirnoff(
- force_field=force_field,
- topology=molecule.to_topology(),
+ force_field=gbsa_force_field,
+ topology=MoleculeWithConformer.from_smiles("CCO").to_topology(),
box=None,
).to_openmm(combine_nonbonded_forces=True)
diff --git a/openff/interchange/_tests/unit_tests/components/test_interchange.py b/openff/interchange/_tests/unit_tests/components/test_interchange.py
index 14e3fae10..4d8bea336 100644
--- a/openff/interchange/_tests/unit_tests/components/test_interchange.py
+++ b/openff/interchange/_tests/unit_tests/components/test_interchange.py
@@ -3,7 +3,6 @@
import numpy as np
import pytest
from openff.toolkit.topology import Molecule, Topology
-from openff.toolkit.typing.engines.smirnoff import ForceField
from openff.toolkit.typing.engines.smirnoff.parameters import (
ElectrostaticsHandler,
ParameterHandler,
@@ -68,21 +67,19 @@ def test_get_parameters(self, sage):
with pytest.raises(MissingParametersError, match=r"atoms \(0, 100\)"):
out._get_parameters("Bonds", (0, 100))
- def test_missing_electrostatics_handler(self, tip3p_missing_electrostatics_xml):
+ def test_missing_electrostatics_handler(self, tip3p, water):
"""Test that an error is raised when an electrostatics handler is missing"""
- molecule = Molecule.from_smiles("O")
- topology = Topology.from_molecules(molecule)
- topology.box_vectors = unit.Quantity([4, 4, 4], units=unit.nanometer)
+ tip3p.deregister_parameter_handler("Electrostatics")
- tip3p_missing_electrostatics = ForceField(tip3p_missing_electrostatics_xml)
+ topology = water.to_topology()
+ topology.box_vectors = unit.Quantity([4, 4, 4], units=unit.nanometer)
with pytest.raises(MissingParameterHandlerError, match="modify partial"):
- Interchange.from_smirnoff(tip3p_missing_electrostatics, topology)
+ Interchange.from_smirnoff(tip3p, topology)
- tip3p = deepcopy(tip3p_missing_electrostatics)
-
- dummy_electrostatics_handler = ElectrostaticsHandler(skip_version_check=True)
- tip3p.register_parameter_handler(dummy_electrostatics_handler)
+ tip3p.register_parameter_handler(
+ ElectrostaticsHandler(skip_version_check=True),
+ )
Interchange.from_smirnoff(tip3p, topology)
diff --git a/openff/interchange/_tests/unit_tests/components/test_packmol.py b/openff/interchange/_tests/unit_tests/components/test_packmol.py
index 0c32bad75..77b299d1a 100644
--- a/openff/interchange/_tests/unit_tests/components/test_packmol.py
+++ b/openff/interchange/_tests/unit_tests/components/test_packmol.py
@@ -19,8 +19,8 @@
@pytest.fixture(scope="module")
-def molecules() -> list[Molecule]:
- return [Molecule.from_smiles("O")]
+def molecules(water) -> list[Molecule]:
+ return [water]
@pytest.mark.parametrize(
@@ -298,7 +298,7 @@ def test_pack_diatomic_ion():
)
-def test_solvate_structure():
+def test_solvate_structure(molecules):
benzene = Molecule.from_smiles("c1ccccc1")
with pytest.raises(
@@ -306,7 +306,7 @@ def test_solvate_structure():
match="missing some atomic positions",
):
pack_box(
- [Molecule.from_smiles("O")],
+ molecules,
[10],
box_vectors=50 * numpy.identity(3) * unit.angstrom,
solute=benzene.to_topology(),
@@ -315,7 +315,7 @@ def test_solvate_structure():
benzene.generate_conformers(n_conformers=1)
topology = pack_box(
- [Molecule.from_smiles("O")],
+ molecules,
[10],
box_vectors=50 * numpy.identity(3) * unit.angstrom,
solute=benzene.to_topology(),
diff --git a/openff/interchange/_tests/unit_tests/components/test_toolkit.py b/openff/interchange/_tests/unit_tests/components/test_toolkit.py
index 3b2abf4bb..2b4bf8dc6 100644
--- a/openff/interchange/_tests/unit_tests/components/test_toolkit.py
+++ b/openff/interchange/_tests/unit_tests/components/test_toolkit.py
@@ -1,5 +1,5 @@
import pytest
-from openff.toolkit import ForceField, Molecule, Topology
+from openff.toolkit import Molecule, Topology
from openff.toolkit.topology._mm_molecule import _SimpleMolecule
from openff.interchange._tests import _BaseTest
@@ -18,8 +18,8 @@ def simple_methane():
@pytest.fixture()
-def simple_water():
- return _SimpleMolecule.from_molecule(Molecule.from_smiles("O"))
+def simple_water(water):
+ return _SimpleMolecule.from_molecule(water)
def test_simple_topology_uniqueness(simple_methane, simple_water):
@@ -53,15 +53,14 @@ def test_get_14_pairs(self, smiles, num_pairs):
assert len([*_get_14_pairs(mol)]) == num_pairs
assert len([*_get_14_pairs(mol.to_topology())]) == num_pairs
- def test_check_electrostatics_handlers(self, tip3p_missing_electrostatics_xml):
- # https://github.com/openforcefield/openff-toolkit/blob/0.10.2/openff/toolkit/data/test_forcefields/tip3p.offxml
- tip3p_missing_electrostatics = ForceField(tip3p_missing_electrostatics_xml)
+ def test_check_electrostatics_handlers(self, tip3p):
+ tip3p.deregister_parameter_handler("Electrostatics")
- assert _check_electrostatics_handlers(tip3p_missing_electrostatics)
+ assert _check_electrostatics_handlers(tip3p)
- tip3p_missing_electrostatics.deregister_parameter_handler("LibraryCharges")
+ tip3p.deregister_parameter_handler("LibraryCharges")
- assert not _check_electrostatics_handlers(tip3p_missing_electrostatics)
+ assert not _check_electrostatics_handlers(tip3p)
@pytest.mark.parametrize(
("smiles", "num_h_bonds"),
@@ -71,12 +70,11 @@ def test_get_num_h_bonds(self, smiles, num_h_bonds):
topology = Molecule.from_smiles(smiles).to_topology()
assert _get_num_h_bonds(topology) == num_h_bonds, smiles
- def test_combine_topologies(self):
+ def test_combine_topologies(self, water):
ethanol = Molecule.from_smiles("CCO")
ethanol.name = "ETH"
ethanol_topology = ethanol.to_topology()
- water = Molecule.from_smiles("O")
water.name = "WAT"
water_topology = water.to_topology()
diff --git a/openff/interchange/_tests/unit_tests/interop/gromacs/export/test_export.py b/openff/interchange/_tests/unit_tests/interop/gromacs/export/test_export.py
index 2ae027c34..2c2e813e6 100644
--- a/openff/interchange/_tests/unit_tests/interop/gromacs/export/test_export.py
+++ b/openff/interchange/_tests/unit_tests/interop/gromacs/export/test_export.py
@@ -30,16 +30,14 @@ def test_residue_names(self, sage):
class TestSettles(_BaseTest):
- def test_settles_units(self, monkeypatch):
+ def test_settles_units(self, monkeypatch, water):
"""Reproduce issue #720."""
monkeypatch.setenv("INTERCHANGE_EXPERIMENTAL", "1")
- molecule = Molecule.from_mapped_smiles("[H:2][O:1][H:3]")
- molecule.generate_conformers(n_conformers=1)
- molecule.name = "WAT"
+ water.name = "WAT"
ForceField("openff-2.1.0.offxml").create_interchange(
- molecule.to_topology(),
+ water.to_topology(),
).to_gromacs(
prefix="settles",
)
diff --git a/openff/interchange/_tests/unit_tests/interop/gromacs/test_interchange.py b/openff/interchange/_tests/unit_tests/interop/gromacs/test_interchange.py
index 1f7454fe3..d0252c884 100644
--- a/openff/interchange/_tests/unit_tests/interop/gromacs/test_interchange.py
+++ b/openff/interchange/_tests/unit_tests/interop/gromacs/test_interchange.py
@@ -70,10 +70,8 @@ def simple_system(self, sage_unconstrained) -> GROMACSSystem:
return _convert(sage_unconstrained.create_interchange(topology))
@pytest.fixture()
- def water_dimer(self, sage_unconstrained):
- water = Molecule.from_mapped_smiles("[H:2][O:1][H:3]")
+ def water_dimer(self, sage_unconstrained, water):
water.name = "WAT"
- water.generate_conformers(n_conformers=1)
topology = Topology.from_molecules([water, water])
topology.box_vectors = [4, 4, 4] * unit.nanometer
diff --git a/openff/interchange/_tests/unit_tests/interop/test_openmm.py b/openff/interchange/_tests/unit_tests/interop/test_openmm.py
index 11dc8d39b..f44a9639d 100644
--- a/openff/interchange/_tests/unit_tests/interop/test_openmm.py
+++ b/openff/interchange/_tests/unit_tests/interop/test_openmm.py
@@ -1,6 +1,7 @@
+from copy import deepcopy
+
import numpy
import pytest
-from openff.toolkit import ForceField, Molecule
from openff.toolkit._tests.utils import get_14_scaling_factors
from openff.units import unit
from openff.units.openmm import ensure_quantity
@@ -12,25 +13,25 @@
)
from openff.interchange import Interchange
-from openff.interchange._tests import _BaseTest
+from openff.interchange._tests import MoleculeWithConformer, _BaseTest
class TestOpenMM(_BaseTest):
- def test_no_nonbonded_force(self):
+ def test_no_nonbonded_force(self, sage):
"""
Ensure a SMIRNOFF-style force field can be exported to OpenMM even if no nonbonded handlers are present. For
context, see https://github.com/openforcefield/openff-toolkit/issues/1102
"""
- sage = ForceField("openff_unconstrained-2.0.0.offxml")
+ del sage._parameter_handlers["Constraints"]
del sage._parameter_handlers["ToolkitAM1BCC"]
del sage._parameter_handlers["LibraryCharges"]
del sage._parameter_handlers["Electrostatics"]
del sage._parameter_handlers["vdW"]
- water = Molecule.from_smiles("C")
+ methane = MoleculeWithConformer.from_smiles("C")
- openmm_system = Interchange.from_smirnoff(sage, [water]).to_openmm()
+ openmm_system = Interchange.from_smirnoff(sage, [methane]).to_openmm()
for force in openmm_system.getForces():
if isinstance(force, NonbondedForce):
@@ -44,18 +45,18 @@ def test_no_nonbonded_force(self):
else:
pytest.fail(f"Unexpected force found, type: {type(force)}")
- def test_14_scale_factors_missing_electrostatics(self):
+ def test_14_scale_factors_missing_electrostatics(self, sage):
# Ported from the toolkit after #1276
- top = Molecule.from_smiles("CCCC").to_topology()
+ topology = MoleculeWithConformer.from_smiles("CCCC").to_topology()
- ff_no_electrostatics = ForceField("openff-2.0.0.offxml")
+ ff_no_electrostatics = deepcopy(sage)
ff_no_electrostatics.deregister_parameter_handler("Electrostatics")
ff_no_electrostatics.deregister_parameter_handler("ToolkitAM1BCC")
ff_no_electrostatics.deregister_parameter_handler("LibraryCharges")
out = Interchange.from_smirnoff(
ff_no_electrostatics,
- top,
+ topology,
).to_openmm(combine_nonbonded_forces=True)
numpy.testing.assert_almost_equal(
@@ -64,16 +65,16 @@ def test_14_scale_factors_missing_electrostatics(self):
decimal=8,
)
- def test_14_scale_factors_missing_vdw(self):
+ def test_14_scale_factors_missing_vdw(self, sage):
# Ported from the toolkit after #1276
- top = Molecule.from_smiles("CCCC").to_topology()
+ topology = MoleculeWithConformer.from_smiles("CCCC").to_topology()
- ff_no_vdw = ForceField("openff-2.0.0.offxml")
+ ff_no_vdw = deepcopy(sage)
ff_no_vdw.deregister_parameter_handler("vdW")
out = Interchange.from_smirnoff(
ff_no_vdw,
- top,
+ topology,
).to_openmm(combine_nonbonded_forces=True)
numpy.testing.assert_almost_equal(
@@ -86,43 +87,34 @@ def test_to_pdb_box_vectors(self, sage):
"""Reproduce https://github.com/openforcefield/openff-interchange/issues/548."""
from openmm.app import PDBFile
- molecule = Molecule.from_smiles("CC")
- molecule.generate_conformers(n_conformers=1)
- box_vectors = unit.Quantity(
+ topology = MoleculeWithConformer.from_smiles("CC").to_topology()
+ topology.box_vectors = unit.Quantity(
10.0 * numpy.eye(3),
unit.angstrom,
)
- interchange = Interchange.from_smirnoff(
- topology=[molecule],
- force_field=sage,
- box=box_vectors,
- )
+ interchange = Interchange.from_smirnoff(sage, topology)
interchange.to_pdb("temp.pdb")
parsed_box_vectors = PDBFile("temp.pdb").topology.getPeriodicBoxVectors()
numpy.testing.assert_allclose(
- box_vectors.m_as(unit.angstrom),
+ topology.box_vectors.m_as(unit.angstrom),
ensure_quantity(parsed_box_vectors, "openff").m_as(unit.angstrom),
)
class TestOpenMMMissingHandlers(_BaseTest):
- def test_missing_vdw_combine_energies(self):
+ def test_missing_vdw_combine_energies(self, sage):
from openff.interchange.drivers import get_openmm_energies
- molecule = Molecule.from_smiles("CC")
- molecule.generate_conformers(n_conformers=1)
+ topology = MoleculeWithConformer.from_smiles("CC").to_topology()
- ff_no_vdw = ForceField("openff-2.0.0.offxml")
+ ff_no_vdw = deepcopy(sage)
ff_no_vdw.deregister_parameter_handler("vdW")
- out = Interchange.from_smirnoff(
- ff_no_vdw,
- [molecule],
- )
+ out = Interchange.from_smirnoff(ff_no_vdw, topology)
energy1 = get_openmm_energies(out, combine_nonbonded_forces=True).total_energy
energy2 = get_openmm_energies(out, combine_nonbonded_forces=False).total_energy
diff --git a/openff/interchange/_tests/unit_tests/smirnoff/test_create.py b/openff/interchange/_tests/unit_tests/smirnoff/test_create.py
index 416d9849e..2ac908363 100644
--- a/openff/interchange/_tests/unit_tests/smirnoff/test_create.py
+++ b/openff/interchange/_tests/unit_tests/smirnoff/test_create.py
@@ -1,8 +1,6 @@
import numpy
import pytest
-from openff.toolkit.topology import Molecule, Topology
-from openff.toolkit.typing.engines.smirnoff.forcefield import ForceField
-from openff.toolkit.typing.engines.smirnoff.parameters import LibraryChargeHandler
+from openff.toolkit import ForceField, Molecule, Topology
from openff.units import unit
from openff.utilities.testing import skip_if_missing
@@ -111,6 +109,8 @@ def test_catch_unassigned_torsions(self, sage, ethanol_top):
# TODO: Remove xfail after openff-toolkit 0.10.0
@pytest.mark.xfail()
def test_library_charges_from_molecule():
+ from openff.toolkit.typing.engines.smirnoff.parameters import LibraryChargeHandler
+
mol = Molecule.from_mapped_smiles("[Cl:1][C:2]#[C:3][F:4]")
with pytest.raises(ValueError, match="missing partial"):
@@ -148,9 +148,9 @@ def test_charge_from_molecules_basic(self, sage):
assert numpy.allclose(found_charges_uses, molecule.partial_charges.m)
- def test_charges_on_molecules_in_topology(self, sage):
+ def test_charges_on_molecules_in_topology(self, sage, water):
ethanol = Molecule.from_smiles("CCO")
- water = Molecule.from_mapped_smiles("[H:2][O:1][H:3]")
+
ethanol_charges = numpy.linspace(-1, 1, 9) * 0.4
water_charges = numpy.linspace(-1, 1, 3)
@@ -330,7 +330,7 @@ def test_setup_plugins(self):
assert _PLUGIN_CLASS_MAPPING[BuckinghamHandler] == SMIRNOFFBuckinghamCollection
- def test_create_buckingham(self):
+ def test_create_buckingham(self, water):
force_field = ForceField(
get_test_file_path("buckingham.offxml"),
load_plugins=True,
@@ -338,7 +338,7 @@ def test_create_buckingham(self):
out = Interchange.from_smirnoff(
force_field,
- Molecule.from_smiles("O").to_topology(),
+ water.to_topology(),
)
assert "Buckingham" in out.collections
diff --git a/openff/interchange/_tests/unit_tests/smirnoff/test_valence.py b/openff/interchange/_tests/unit_tests/smirnoff/test_valence.py
index a6f289f29..4e6e14393 100644
--- a/openff/interchange/_tests/unit_tests/smirnoff/test_valence.py
+++ b/openff/interchange/_tests/unit_tests/smirnoff/test_valence.py
@@ -33,7 +33,7 @@
class TestSMIRNOFFValenceCollections(_BaseTest):
- def test_bond_collection(self):
+ def test_bond_collection(self, water):
bond_handler = BondHandler(version=0.3)
bond_handler.fractional_bondorder_method = "AM1-Wiberg"
bond_parameter = BondHandler.BondType(
@@ -48,7 +48,7 @@ def test_bond_collection(self):
forcefield.register_parameter_handler(bond_handler)
bond_potentials = SMIRNOFFBondCollection.create(
parameter_handler=forcefield["Bonds"],
- topology=Molecule.from_smiles("O").to_topology(),
+ topology=water.to_topology(),
)
top_key = BondKey(atom_indices=(0, 1))
diff --git a/openff/interchange/_tests/unit_tests/smirnoff/test_virtual_sites.py b/openff/interchange/_tests/unit_tests/smirnoff/test_virtual_sites.py
index 3ac5272b8..f5448aed2 100644
--- a/openff/interchange/_tests/unit_tests/smirnoff/test_virtual_sites.py
+++ b/openff/interchange/_tests/unit_tests/smirnoff/test_virtual_sites.py
@@ -3,8 +3,7 @@
import numpy
import openmm
import pytest
-from openff.toolkit.topology import Molecule, Topology
-from openff.toolkit.typing.engines.smirnoff.forcefield import ForceField
+from openff.toolkit import ForceField, Molecule, Topology
from openff.toolkit.typing.engines.smirnoff.parameters import (
ElectrostaticsHandler,
LibraryChargeHandler,
diff --git a/openff/interchange/components/interchange.py b/openff/interchange/components/interchange.py
index ebf5b93fe..ff8dae3b9 100644
--- a/openff/interchange/components/interchange.py
+++ b/openff/interchange/components/interchange.py
@@ -256,8 +256,7 @@ def from_smirnoff(
.. code-block:: pycon
>>> from openff.interchange import Interchange
- >>> from openff.toolkit.topology import Molecule
- >>> from openff.toolkit.typing.engines.smirnoff import ForceField
+ >>> from openff.toolkit import ForceField, Molecule
>>> mol = Molecule.from_smiles("CC")
>>> mol.generate_conformers(n_conformers=1)
>>> sage = ForceField("openff-2.0.0.offxml")
diff --git a/openff/interchange/interop/openmm/_positions.py b/openff/interchange/interop/openmm/_positions.py
index a3bba6178..745b4ca71 100644
--- a/openff/interchange/interop/openmm/_positions.py
+++ b/openff/interchange/interop/openmm/_positions.py
@@ -30,6 +30,8 @@ def to_openmm_positions(
topology = interchange.topology
+ molecule_virtual_site_map = defaultdict(list)
+
if include_virtual_sites:
from openff.interchange.interop._virtual_sites import (
_virtual_site_parent_molecule_mapping,
@@ -37,8 +39,6 @@ def to_openmm_positions(
virtual_site_molecule_map = _virtual_site_parent_molecule_mapping(interchange)
- molecule_virtual_site_map = defaultdict(list)
-
for virtual_site, molecule_index in virtual_site_molecule_map.items():
molecule_virtual_site_map[molecule_index].append(virtual_site)
diff --git a/openff/interchange/smirnoff/_base.py b/openff/interchange/smirnoff/_base.py
index 81e9c126a..49e36a71e 100644
--- a/openff/interchange/smirnoff/_base.py
+++ b/openff/interchange/smirnoff/_base.py
@@ -300,6 +300,6 @@ def create(
def __repr__(self) -> str:
return (
- f"Handler '{self.type}' with expression '{self.expression}', {len(self.key_map)} slots, "
+ f"Handler '{self.type}' with expression '{self.expression}', {len(self.key_map)} mapping keys, "
f"and {len(self.potentials)} potentials"
)
diff --git a/openff/interchange/smirnoff/_valence.py b/openff/interchange/smirnoff/_valence.py
index b453f57df..f8b2c2522 100644
--- a/openff/interchange/smirnoff/_valence.py
+++ b/openff/interchange/smirnoff/_valence.py
@@ -134,7 +134,7 @@ def store_matches(
topology: Topology,
) -> None:
"""
- Populate self.key_map with key-val pairs of slots and unique potential identifiers.
+ Populate self.key_map with key-val pairs of keys and unique potential identifiers.
"""
if self.key_map:
# TODO: Should the key_map always be reset, or should we be able to partially
@@ -464,7 +464,7 @@ def store_matches(
topology: Topology,
) -> None:
"""
- Populate self.key_map with key-val pairs of slots and unique potential identifiers.
+ Populate self.key_map with key-val pairs of keys and unique potential identifiers.
"""
if self.key_map:
@@ -620,7 +620,7 @@ def store_matches(
topology: Topology,
) -> None:
"""
- Populate self.key_map with key-val pairs of slots and unique potential identifiers.
+ Populate self.key_map with key-val pairs of keys and unique potential identifiers.
"""
if self.key_map: