Skip to content

Commit

Permalink
Merge pull request #762 from openforcefield/fixtures
Browse files Browse the repository at this point in the history
Reconfigure common objects into fixtures
  • Loading branch information
mattwthompson authored Jul 7, 2023
2 parents 0b90465 + 8748061 commit 7f912a4
Show file tree
Hide file tree
Showing 22 changed files with 200 additions and 420 deletions.
1 change: 1 addition & 0 deletions devtools/conda-envs/dev_env.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ dependencies:
- pytest
- pytest-cov
- pytest-xdist
- pytest-randomly
- nbval
- qcportal
- openff-qcsubmit
Expand Down
152 changes: 15 additions & 137 deletions openff/interchange/_tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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):
Expand All @@ -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."""
Expand Down Expand Up @@ -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 """<?xml version="1.0" encoding='ASCII'?>
<SMIRNOFF version="0.3" aromaticity_model="OEAroModel_MDL">
<Constraints version="0.3">
<Constraint smirks="[#1:1]-[*:2]" id="c1"></Constraint>
<Constraint smirks="[#1:1]-[#8X2H2+0:2]-[#1]"
id="c-tip3p-H-O" distance="0.9572 * angstrom"></Constraint>
<Constraint smirks="[#1:1]-[#8X2H2+0]-[#1:2]"
id="c-tip3p-H-O-H" distance="1.5139006545247014*angstrom"></Constraint>
</Constraints>
<vdW
version="0.3"
potential="Lennard-Jones-12-6"
combining_rules="Lorentz-Berthelot"
scale12="0.0"
scale13="0.0"
scale14="0.5"
scale15="1"
switch_width="1.0*angstroms"
cutoff="9.0*angstroms" method="cutoff"
>
<Atom
smirks="[#1]-[#8X2H2+0:1]-[#1]"
id="n1"
sigma="0.31507524065751241*nanometers"
epsilon="0.635968*kilojoules_per_mole"
/>
<Atom
smirks="[#1:1]-[#8X2H2+0]-[#1]"
id="n2"
sigma="1*nanometers"
epsilon="0*kilojoules_per_mole" />
</vdW>
<Electrostatics
version="0.3"
method="PME"
scale12="0.0"
scale13="0.0"
scale14="0.833333"
scale15="1.0"
switch_width="0.0*angstrom"
cutoff="9.0*angstrom"
></Electrostatics>
<LibraryCharges version="0.3">
<LibraryCharge
name="TIP3P"
smirks="[#1:1]-[#8X2H2+0:2]-[#1:3]"
charge1="0.417*elementary_charge"
charge2="-0.834*elementary_charge"
charge3="0.417*elementary_charge"/>
</LibraryCharges>
</SMIRNOFF>"""

@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 version="1.0" encoding='ASCII'?>
<SMIRNOFF version="0.3" aromaticity_model="OEAroModel_MDL">
<vdW
version="0.3"
potential="Lennard-Jones-12-6"
combining_rules="Lorentz-Berthelot"
scale12="0.0"
scale13="0.0"
scale14="0.5"
scale15="1"
switch_width="1.0*angstroms"
cutoff="9.0*angstroms" method="cutoff"
>
<Atom
smirks="[#1]-[#8X2H2+0:1]-[#1]"
id="n1"
sigma="0.31507524065751241*nanometers"
epsilon="0.635968*kilojoules_per_mole"
/>
<Atom
smirks="[#1:1]-[#8X2H2+0]-[#1]"
id="n2"
sigma="1*nanometers"
epsilon="0*kilojoules_per_mole" />
</vdW>
<LibraryCharges version="0.3">
<LibraryCharge
name="TIP3P"
smirks="[#1:1]-[#8X2H2+0:2]-[#1:3]"
charge1="0.417*elementary_charge"
charge2="-0.834*elementary_charge"
charge3="0.417*elementary_charge"/>
</LibraryCharges>
</SMIRNOFF>"""

xml_ff_bo_bonds = """<?xml version='1.0' encoding='ASCII'?>
<SMIRNOFF version="0.3" aromaticity_model="OEAroModel_MDL">
<Bonds version="0.3" fractional_bondorder_method="AM1-Wiberg" fractional_bondorder_interpolation="linear">
Expand Down Expand Up @@ -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
Expand Down
36 changes: 36 additions & 0 deletions openff/interchange/_tests/conftest.py
Original file line number Diff line number Diff line change
@@ -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
10 changes: 0 additions & 10 deletions openff/interchange/_tests/data/argon.offxml

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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

Expand Down
23 changes: 9 additions & 14 deletions openff/interchange/_tests/energy_tests/test_energies.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from openff.interchange._tests import (
HAS_GROMACS,
HAS_LAMMPS,
MoleculeWithConformer,
_BaseTest,
get_test_file_path,
needs_gmx,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -215,17 +211,16 @@ def test_interpolated_parameters(self, smi):
</SMIRNOFF>
"""

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(
Expand Down
Loading

0 comments on commit 7f912a4

Please sign in to comment.