Source code for icolos.core.workflow_steps.openff.openff2gmx
from icolos.core.workflow_steps.step import StepBase
from pydantic import BaseModel
from openmm.app import PDBFile
import parmed
from openff.toolkit.topology import Molecule, Topology
from openff.toolkit.typing.engines.smirnoff import ForceField
from openff.toolkit.utils import get_data_file_path
from icolos.utils.enums.step_enums import StepOpenFFEnum
import os
# Note that this implementation leverages parmed for now, although will likely move over to the OpenFF Interchange tooling once stable
_SOFE = StepOpenFFEnum()
# TOOD: Eventually this step should be able to do a pdb2gmx job
[docs]class StepOFF2gmx(StepBase, BaseModel):
def __init__(self, **data):
super().__init__(**data)
[docs] def parametrise_mols(self, tmp_dir: str):
"""
Generate parameters for each mol
"""
# TODO: do we want to throw everything together or split the params into separate files?
mols = [
Molecule.from_smiles(smi)
for smi in self._get_additional_setting(_SOFE.UNIQUE_MOLS)
]
pdb_file = PDBFile(
os.path.join(tmp_dir, self.data.generic.get_argument_by_extension("pdb"))
)
omm_topology = pdb_file.topology
off_topology = Topology.from_openmm(omm_topology, unique_molecules=mols)
forcefield = ForceField(self._get_additional_setting(_SOFE.FORCEFIELD))
omm_system = forcefield.create_openmm_system(off_topology)
if self._get_additional_setting(_SOFE.METHOD, _SOFE.PARMED) == _SOFE.PARMED:
parmed_struct = parmed.openmm.load_topology(
omm_topology, omm_system, pdb_file.positions
)
parmed_struct.save(os.path.join(tmp_dir, "MOL.top"), overwrite=True)
parmed_struct.save(os.path.join(tmp_dir, "MOL.gro"), overwrite=True)
# TODO: validate energy differences
elif self._get_additional_setting(_SOFE.METHOD) == _SOFE.INTERCHANGE:
raise NotImplementedError
else:
raise NotImplementedError
[docs] def execute(self):
"""
Builds a system and parametrise using OpenFF SAGE params, then convert to a GROMACS top/gro format for downstream simulation
"""
tmp_dir = self._prepare_tmpdir()
self.data.generic.write_out_all_files(tmp_dir)
self.parametrise_mols(tmp_dir)
self._parse_output(tmp_dir)
self._remove_temporary(tmp_dir)
# If we want to build OpenFF params instead of gaff, we would need to make a call to a different parametrisation pipeline, then load the protein into a ParmEd System, combine with the OpenFF-built system and combine into a gro/top file.