Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reconfigure common objects into fixtures #762

Merged
merged 1 commit into from
Jul 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading