Skip to content
Draft
82 changes: 0 additions & 82 deletions .github/workflows/aws.yaml

This file was deleted.

154 changes: 73 additions & 81 deletions openff/evaluator/_tests/test_utils/test_packmol.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,32 @@

import numpy as np
import pytest
from openff.toolkit import ForceField, Molecule
from openff.units import unit

from openff.evaluator.utils import packmol
from openff.evaluator.utils.packmol import PackmolRuntimeException


def test_packmol_box_size():
from openff.toolkit.topology import Molecule

molecules = [Molecule.from_smiles("O")]

trajectory, _ = packmol.pack_box(
molecules, [10], box_size=([20] * 3) * unit.angstrom
)
topology, _ = packmol.pack_box(molecules, [10], box_size=([20] * 3) * unit.angstrom)

assert trajectory is not None
assert topology is not None

assert trajectory.n_chains == 1
assert trajectory.n_residues == 10
assert trajectory.n_atoms == 30
assert trajectory.topology.n_bonds == 20
assert len(topology.chains) == 10 # should be 1 ...
assert len(topology.residues) == 10
assert topology.n_atoms == 30
assert topology.n_bonds == 20

assert all(x.name == "HOH" for x in trajectory.top.residues)
assert all(x.residue_name == "HOH" for x in topology.residues)

assert np.allclose(trajectory.unitcell_lengths, 2.2)
assert np.allclose(topology.box_vectors.m_as("nanometer").diagonal(), 2.2)


def test_packmol_bad_input():
from openff.toolkit.topology import Molecule

molecules = [Molecule.from_smiles("O")]

Expand All @@ -41,7 +38,6 @@ def test_packmol_bad_input():


def test_packmol_failed():
from openff.toolkit.topology import Molecule

molecules = [Molecule.from_smiles("O")]

Expand All @@ -50,113 +46,109 @@ def test_packmol_failed():


def test_packmol_water():
from openff.toolkit.topology import Molecule

molecules = [Molecule.from_smiles("O")]

trajectory, _ = packmol.pack_box(
topology, _ = packmol.pack_box(
molecules,
[10],
mass_density=1.0 * unit.grams / unit.milliliters,
)

assert trajectory is not None
assert topology is not None

assert trajectory.n_chains == 1
assert trajectory.n_residues == 10
assert trajectory.n_atoms == 30
assert trajectory.topology.n_bonds == 20
assert len(topology.chains) == 10 # should be 1 ...
assert len(topology.residues) == 10
assert topology.n_atoms == 30
assert topology.n_bonds == 20

assert all(x.name == "HOH" for x in trajectory.top.residues)
assert all(residue.residue_name == "HOH" for residue in topology.residues)


def test_packmol_ions():
from openff.toolkit.topology import Molecule

molecules = [
Molecule.from_smiles("[Na+]"),
Molecule.from_smiles("[Cl-]"),
Molecule.from_smiles("[K+]"),
]

trajectory, _ = packmol.pack_box(
topology, _ = packmol.pack_box(
molecules, [1, 1, 1], box_size=([20] * 3) * unit.angstrom
)

assert trajectory is not None
assert topology is not None

assert trajectory.n_chains == 3
assert trajectory.n_residues == 3
assert trajectory.n_atoms == 3
assert trajectory.topology.n_bonds == 0
assert len(topology.chains) == 3
assert len(topology.residues) == 3
assert topology.n_atoms == 3
assert topology.n_bonds == 0

assert trajectory.top.residue(0).name == "Na+"
assert trajectory.top.residue(1).name == "Cl-"
assert trajectory.top.residue(2).name == "K+"
assert topology.residues[0].residue_name == "Na+"
assert topology.residues[1].residue_name == "Cl-"
assert topology.residues[2].residue_name == "K+"

assert trajectory.top.atom(0).name == "Na+"
assert trajectory.top.atom(1).name == "Cl-"
assert trajectory.top.atom(2).name == "K+"
assert topology.atom(0).name == "Na+"
assert topology.atom(1).name == "Cl-"
assert topology.atom(2).name == "K+"


def test_packmol_paracetamol():
from openff.toolkit.topology import Molecule

# Test something a bit more tricky than water
molecules = [Molecule.from_smiles("CC(=O)NC1=CC=C(C=C1)O")]

trajectory, _ = packmol.pack_box(
molecules, [1], box_size=([20] * 3) * unit.angstrom
)

assert trajectory is not None

assert trajectory.n_chains == 1
assert trajectory.n_residues == 1
assert trajectory.n_atoms == 20
assert trajectory.topology.n_bonds == 20


def test_amino_acids():
amino_residues = {
"C[C@H](N)C(=O)O": "ALA",
# Undefined stereochemistry error.
# "N=C(N)NCCC[C@H](N)C(=O)O": "ARG",
"NC(=O)C[C@H](N)C(=O)O": "ASN",
"N[C@@H](CC(=O)O)C(=O)O": "ASP",
"N[C@@H](CS)C(=O)O": "CYS",
"N[C@@H](CCC(=O)O)C(=O)O": "GLU",
"NC(=O)CC[C@H](N)C(=O)O": "GLN",
"NCC(=O)O": "GLY",
"N[C@@H](Cc1c[nH]cn1)C(=O)O": "HIS",
"CC[C@H](C)[C@H](N)C(=O)O": "ILE",
"CC(C)C[C@H](N)C(=O)O": "LEU",
"NCCCC[C@H](N)C(=O)O": "LYS",
"CSCC[C@H](N)C(=O)O": "MET",
"N[C@@H](Cc1ccccc1)C(=O)O": "PHE",
"O=C(O)[C@@H]1CCCN1": "PRO",
"N[C@@H](CO)C(=O)O": "SER",
"C[C@@H](O)[C@H](N)C(=O)O": "THR",
"N[C@@H](Cc1c[nH]c2ccccc12)C(=O)O": "TRP",
"N[C@@H](Cc1ccc(O)cc1)C(=O)O": "TYR",
"CC(C)[C@H](N)C(=O)O": "VAL",
}

topology, _ = packmol.pack_box(molecules, [1], box_size=([20] * 3) * unit.angstrom)

assert topology is not None

assert len(topology.chains) == 1
assert len(topology.residues) == 1
assert topology.n_atoms == 20
assert topology.n_bonds == 20


amino_residues = {
"C[C@H](N)C(=O)O": "ALA",
# Undefined stereochemistry error.
# "N=C(N)NCCC[C@H](N)C(=O)O": "ARG",
"NC(=O)C[C@H](N)C(=O)O": "ASN",
"N[C@@H](CC(=O)O)C(=O)O": "ASP",
"N[C@@H](CS)C(=O)O": "CYS",
"N[C@@H](CCC(=O)O)C(=O)O": "GLU",
"NC(=O)CC[C@H](N)C(=O)O": "GLN",
"NCC(=O)O": "GLY",
"N[C@@H](Cc1c[nH]cn1)C(=O)O": "HIS",
"CC[C@H](C)[C@H](N)C(=O)O": "ILE",
"CC(C)C[C@H](N)C(=O)O": "LEU",
"NCCCC[C@H](N)C(=O)O": "LYS",
"CSCC[C@H](N)C(=O)O": "MET",
"N[C@@H](Cc1ccccc1)C(=O)O": "PHE",
"O=C(O)[C@@H]1CCCN1": "PRO",
"N[C@@H](CO)C(=O)O": "SER",
"C[C@@H](O)[C@H](N)C(=O)O": "THR",
"N[C@@H](Cc1c[nH]c2ccccc12)C(=O)O": "TRP",
"N[C@@H](Cc1ccc(O)cc1)C(=O)O": "TYR",
"CC(C)[C@H](N)C(=O)O": "VAL",
}


def test_amino_acid_residue_information():
smiles = [*amino_residues]

from openff.toolkit.topology import Molecule

molecules = [Molecule.from_smiles(x) for x in smiles]
counts = [1] * len(smiles)

trajectory, _ = packmol.pack_box(
topology, _ = packmol.pack_box(
molecules, counts, box_size=([1000] * 3) * unit.angstrom
)

assert trajectory is not None

assert trajectory.n_chains == len(smiles)
assert trajectory.n_residues == len(smiles)
for residue, smiles in zip(
topology.residues,
smiles,
):
assert residue.residue_name == amino_residues[smiles]

for index, smiles in enumerate(smiles):
assert trajectory.top.residue(index).name == amino_residues[smiles]
# dummy check to make sure enough chemical information is present to parametrize,
# even though this force field is not necessarily designed for amino acids
ForceField("openff_unconstrained-2.3.0-rc2.offxml").create_openmm_system(topology)
15 changes: 2 additions & 13 deletions openff/evaluator/forcefield/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,9 @@ def topology_path(self) -> str:

@property
def topology(self) -> "Topology":
from openff.toolkit.topology import Molecule, Topology
from openmm import app
from openff.toolkit.topology import Topology

pdb_file = app.PDBFile(self._topology_path)

topology = Topology.from_openmm(
pdb_file.topology,
unique_molecules=[
Molecule.from_smiles(smiles=component.smiles)
for component in self._substance.components
],
)

return topology
return Topology.from_json(open(self._topology_path).read())

@property
def system_path(self) -> str:
Expand Down
Loading
Loading