diff --git a/examples/workflow/gromacs/gromacs_ensemble_mmgbsa.json b/examples/workflow/gromacs/gromacs_ensemble_mmgbsa.json index 5b4adb3..e46ea98 100644 --- a/examples/workflow/gromacs/gromacs_ensemble_mmgbsa.json +++ b/examples/workflow/gromacs/gromacs_ensemble_mmgbsa.json @@ -473,7 +473,7 @@ "parameters": {} }, "additional": { - "coupling groups": "Protein Other", + "coupling_groups": "Protein Other", "forcefield": "/amber14sb.ff" } }, diff --git a/examples/workflow/gromacs/gromacs_ensemble_mmgbsa_replex.json b/examples/workflow/gromacs/gromacs_ensemble_mmgbsa_replex.json new file mode 100644 index 0000000..4f9eaff --- /dev/null +++ b/examples/workflow/gromacs/gromacs_ensemble_mmgbsa_replex.json @@ -0,0 +1,426 @@ +{ + "workflow": { + "header": { + "workflow_id": "gromacs_ensemble_mmgbsa", + "description": "ensemble MMGBSA demonstration - step iteration + SLURM job control", + "environment": { + "export": [ + { + "key": "GMX_GPU_DD_COMMS", + "value": "true" + }, + { + "key": "GMX_GPU_PME_PP_COMMS", + "value": "true" + }, + { + "key": "GMX_FORCE_UPDATE_DEFAULT_GPU", + "value": "true" + } + ] + }, + "global_variables": { + "file_base": "{package_dir}/../IcolosData/gromacs/protein", + "output_dir": "{package_dir}/tests/junk/gromacs" + } + }, + "steps": [ + { + "step_id": "01_pdb2gmx", + "type": "pdb2gmx", + "execution": { + "prefix_execution": "module load GROMACS/2021-fosscuda-2019a-PLUMED-2.7.1-Python-3.7.2" + }, + "settings": { + "arguments": { + "flags": [ + "-ignh" + ], + "parameters": { + "-water": "tip3p", + "-ff": "amber03" + } + }, + "additional": { + "charge_method": "gas" + } + }, + "input": { + "generic": [ + { + "source": "{file_base}/1BVG.pdb", + "extension": "pdb" + } + ] + } + }, + { + "step_id": "02_editconf", + "type": "editconf", + "execution": { + "prefix_execution": "module load GROMACS/2021-fosscuda-2019a-PLUMED-2.7.1-Python-3.7.2" + }, + "settings": { + "arguments": { + "flags": [ + "-c" + ], + "parameters": { + "-d": "1.2", + "-bt": "dodecahedron" + } + }, + "additional": {} + } + }, + { + "step_id": "03_solvate", + "type": "solvate", + "execution": { + "prefix_execution": "module load GROMACS/2021-fosscuda-2019a-PLUMED-2.7.1-Python-3.7.2" + }, + "settings": { + "arguments": { + "flags": [], + "parameters": { + "-cs": "spc216.gro" + } + }, + "additional": {} + } + }, + { + "step_id": "04_grompp", + "type": "grompp", + "execution": { + "prefix_execution": "module load GROMACS/2021-fosscuda-2019a-PLUMED-2.7.1-Python-3.7.2" + }, + "settings": { + "arguments": { + "flags": [], + "parameters": {} + }, + "additional": { + "-r": false + } + }, + "input": { + "generic": [ + { + "source": "{file_base}/ions.mdp", + "extension": "mdp" + } + ] + } + }, + { + "step_id": "05_genion", + "type": "genion", + "execution": { + "prefix_execution": "module load GROMACS/2021-fosscuda-2019a-PLUMED-2.7.1-Python-3.7.2" + }, + "settings": { + "arguments": { + "flags": [ + "-neutral" + ], + "parameters": { + "-pname": "NA", + "-nname": "CL" + } + }, + "additional": { + "pipe_input": "SOL" + } + } + }, + { + "step_id": "06_grompp_eminim", + "type": "grompp", + "execution": { + "prefix_execution": "module load GROMACS/2021-fosscuda-2019a-PLUMED-2.7.1-Python-3.7.2" + }, + "settings": { + "arguments": { + "flags": [], + "parameters": {} + }, + "additional": { + "-r": false, + "replicas": 4 + } + }, + "input": { + "generic": [ + { + "source": "{file_base}/minim.mdp", + "extension": "mdp" + } + ] + } + }, + { + "step_id": "07_eminim_mdrun", + "type": "mdrun", + "execution": { + "platform": "slurm", + "resources": { + "partition": "gpu", + "gres": "gpu:1", + "tasks": 4, + "other_args": { + }, + "modules": [ + "GROMACS/2021-fosscuda-2019a-PLUMED-2.7.1-Python-3.7.2" + ] + } + }, + "settings": { + "arguments": { + "flags": [], + "parameters": {} + }, + "additional": { + "multidir": true + } + } + }, + { + "step_id": "08_nvt_grompp", + "type": "grompp", + "execution": { + "prefix_execution": "module load GROMACS/2021-fosscuda-2019a-PLUMED-2.7.1-Python-3.7.2" + }, + "settings": { + "arguments": { + "flags": [], + "parameters": { + "-n": "index.ndx" + } + }, + "additional": { + "make_ndx_command": "auto", + "-r": true, + "replicas": 4 + } + }, + "input": { + "generic": [ + { + "source": "{file_base}/nvt_equil.mdp", + "extension": "mdp" + } + ] + } + }, + { + "step_id": "09_nvt_mdrun", + "type": "mdrun", + "execution": { + "platform": "slurm", + "resources": { + "partition": "gpu", + "gres": "gpu:1", + "tasks": 4, + "other_args": { + }, + "modules": [ + "GROMACS/2021-fosscuda-2019a-PLUMED-2.7.1-Python-3.7.2" + ] + } + }, + "settings": { + "arguments": { + "flags": [], + "parameters": {} + }, + "additional": { + "multidir": true + } + } + }, + { + "step_id": "10_npt_grompp", + "type": "grompp", + "execution": { + "prefix_execution": "module load GROMACS/2021-fosscuda-2019a-PLUMED-2.7.1-Python-3.7.2" + }, + "settings": { + "arguments": { + "flags": [], + "parameters": { + "-n": "index.ndx" + } + }, + "additional": { + "make_ndx_command": "auto", + "-r": true, + "replicas": 4 + } + }, + "input": { + "generic": [ + { + "source": "{file_base}/npt_equil.mdp", + "extension": "mdp" + } + ] + } + }, + { + "step_id": "11_npt_mdrun", + "type": "mdrun", + "execution": { + "platform": "slurm", + "resources": { + "partition": "gpu", + "tasks": 4, + "gres": "gpu:1", + "other_args": { + }, + "modules": [ + "GROMACS/2021-fosscuda-2019a-PLUMED-2.7.1-Python-3.7.2" + ] + } + }, + "settings": { + "arguments": { + "flags": [], + "parameters": {} + }, + "additional": { + "multidir": true + } + } + }, + { + "step_id": "12_prod_md_grompp", + "type": "grompp", + "execution": { + "prefix_execution": "module load GROMACS/2021-fosscuda-2019a-PLUMED-2.7.1-Python-3.7.2" + }, + "settings": { + "arguments": { + "flags": [], + "parameters": { + "-n": "index.ndx" + } + }, + "additional": { + "fields": { + "nsteps": "10000" + }, + "make_ndx_command": "auto", + "-r": false, + "replicas": 4 + } + }, + "input": { + "generic": [ + { + "source": "{file_base}/md.mdp", + "extension": "mdp" + } + ] + } + }, + { + "step_id": "13_prod_mdrun", + "type": "mdrun", + "execution": { + "platform": "slurm", + "resources": { + "partition": "gpu", + "gres": "gpu:1", + "tasks": 4, + "other_args": { + }, + "modules": [ + "GROMACS/2021-fosscuda-2019a-PLUMED-2.7.1-Python-3.7.2" + ] + } + }, + "settings": { + "arguments": { + "flags": [], + "parameters": { + "-nb": "gpu", + "-bonded": "gpu", + "-pme": "gpu", + "-update": "gpu" + } + }, + "additional": { + "multidir": true + } + } + }, + { + "step_id": "14_trjconv", + "type": "trjconv", + "execution": { + "prefix_execution": "module load GROMACS/2021-fosscuda-2019a-PLUMED-2.7.1-Python-3.7.2" + }, + "settings": { + "arguments": { + "flags": [ + "-center" + ], + "parameters": { + "-pbc": "mol", + "-n": "index.ndx" + } + }, + "additional": { + "pipe_input": "Protein_Other System" + } + } + }, + { + "step_id": "14b_trjconv", + "type": "trjconv", + "execution": { + "prefix_execution": "module load GROMACS/2021-fosscuda-2019a-PLUMED-2.7.1-Python-3.7.2" + }, + "settings": { + "arguments": { + "flags": [], + "parameters": { + "-fit": "rot+trans", + "-n": "index.ndx" + } + }, + "additional": { + "pipe_input": "Protein_Other System" + } + } + }, + { + "step_id": "15_gmx_MMPBSA", + "type": "gmx_mmpbsa", + "execution": { + "prefix_execution": "module load gmx_MMPBSA/1.3.3-fosscuda-2019a-Python-3.7.2" + }, + "settings": { + "arguments": { + "parameters": {} + }, + "additional": { + "coupling_groups": "Protein Other", + "forcefield": "//forcefields/amber14sb.ff" + } + }, + "writeout": [ + { + "generic": { + "key": "dat" + }, + "destination": { + "resource": "{output_dir}/FINAL_RESULTS_MMPBSA.dat" + } + } + ] + } + ] + } +} \ No newline at end of file diff --git a/src/icolos/config/amber/default_mmpbsa.in b/src/icolos/config/amber/default_mmpbsa.in index 843bebf..b23d150 100644 --- a/src/icolos/config/amber/default_mmpbsa.in +++ b/src/icolos/config/amber/default_mmpbsa.in @@ -1,5 +1,5 @@ &general -startframe=0, endframe=5000000000, verbose=2, +startframe=1, endframe=5000000000, verbose=2, / &gb igb=5, saltcon=0.150, diff --git a/src/icolos/core/containers/gromacs_topol.py b/src/icolos/core/containers/gromacs_topol.py index 40c8d91..19b06f4 100644 --- a/src/icolos/core/containers/gromacs_topol.py +++ b/src/icolos/core/containers/gromacs_topol.py @@ -2,6 +2,7 @@ from turtle import st from typing import AnyStr, Dict, List from pydantic import BaseModel +from icolos.core.containers.generic import GenericData from icolos.utils.enums.program_parameters import GromacsEnum from icolos.utils.enums.step_enums import StepGromacsEnum @@ -26,6 +27,9 @@ class AtomType(BaseModel): class GromacsTopol(BaseModel): + class Config: + arbitrary_types_allowed: True + top_lines: List = [] itps: Dict = {} posre: Dict = {} @@ -35,20 +39,23 @@ class GromacsTopol(BaseModel): water: str = "tip3p" system: List = [] molecules: Dict = {} - # TODO: we could make this a generic data object? - structure: List = [] + structures: List = [] + tprs: List = [] + trajectories: List = [] + ndx: List = [] + # store computed properties on the topology + properties: Dict = {} def __init__(self, **data) -> None: super().__init__(**data) - def parse(self, file): + def parse(self, path: str, file: str = _SGE.STD_TOPOL): """ Populate the fields from parsing a topol file (normally from gmx pdb2gmx) If a moleculetype has been defined in a single topology, this is separated into its own itp file """ # get the system name - work_dir = os.path.dirname(file) - with open(file, "r") as f: + with open(os.path.join(path, file), "r") as f: lines = f.readlines() # first check for included atomtypes to be extracted to their own itp files @@ -75,7 +82,7 @@ def parse(self, file): and all([item not in line for item in (".ff", "posre")]) ): itp_file = line.split()[-1].replace('"', "") - with open(os.path.join(work_dir, itp_file), "r") as f: + with open(os.path.join(path, itp_file), "r") as f: itp_lines = f.readlines() self.itps[itp_file] = itp_lines # extract water model @@ -85,21 +92,24 @@ def parse(self, file): self.forcefield = line.split()[-1].split(".")[0].replace('"', "") start = lines.index([l for l in lines if l.startswith(_GE.SYSTEM)][0]) stop = lines.index([l for l in lines[start:] if l.startswith(_GE.MOLECULES)][0]) - for line in lines[start + 1 : stop]: - if not line.startswith(";") and line.strip(): - self.system.append(line.strip()) + if not self.system: + for line in lines[start + 1 : stop]: + if not line.startswith(";") and line.strip(): + self.system.append(line.strip()) # excract molecules and counts for line in lines[stop + 1 :]: if not line.startswith(";") and line.strip(): parts = line.split() self.molecules[parts[0].strip()] = parts[1].strip() + self.top_lines = self.generate_base_topol_file() + def write_topol(self, base_dir: str, file: str = "topol.top"): """ Write a gromacs topology file, including its dependent itp files, to a dir """ - if not self.top_lines: - self.top_lines = self.generate_base_topol_file() + # update the base topol file + self.generate_base_topol_file() with open(os.path.join(base_dir, file), "w") as f: for l in self.top_lines: f.write(l) @@ -116,20 +126,22 @@ def write_topol(self, base_dir: str, file: str = "topol.top"): for l in lines: f.write(l) - def generate_base_topol_file(self) -> List[str]: + def generate_base_topol_file(self): """ Generates the main topology file """ top_lines = [] top_lines.append(f'#include "{self.forcefield}.ff/forcefield.itp"\n') # find any new atomtypes in the parametrised components, slot these in first - new_atomtypes = self.collect_atomtypes() - top_lines += new_atomtypes + if not self.atomtypes: + self.atomtypes = self.collect_atomtypes() + top_lines += self.atomtypes # now include the itp files for file in self.itps.keys(): top_lines.append(f'#include "{file}"\n') - if "Protein" not in file: + # pdb2gmx appends posre control info to the bottom of any itp files + if all([x not in file for x in ("Protein", "DNA", "RNA")]): # these are handled independently in the itp files top_lines.append(f'#ifdef POSRES\n#include "posre_{file}"\n#endif\n') @@ -142,7 +154,7 @@ def generate_base_topol_file(self) -> List[str]: top_lines.extend(self._construct_block(_GE.SYSTEM, self.system)) top_lines.extend(self._construct_block(_GE.MOLECULES, self.molecules)) - return top_lines + self.top_lines = top_lines def add_itp(self, path, files: List[str], gen_posre: bool = True) -> None: for file in files: @@ -153,8 +165,11 @@ def add_itp(self, path, files: List[str], gen_posre: bool = True) -> None: # also generate a posre file self.generate_posre(path, file) + self.generate_base_topol_file() + def add_molecule(self, name: str, num: int = 1): self.molecules[name] = num + self.generate_base_topol_file() def add_posre(self, path, files: List[str]) -> None: for file in files: @@ -162,6 +177,7 @@ def add_posre(self, path, files: List[str]) -> None: lines = f.readlines() self.posre[file] = lines + self.generate_base_topol_file() def generate_posre(self, path: str, itp_file: str, force: int = 1000): stub = itp_file.split(".")[0] @@ -257,29 +273,84 @@ def _remove_duplicate_atomtypes(self, atomtypes: List): def set_topol(self, path: str, file: str = _SGE.STD_TOPOL): """ - When solvate or genion produce a modified topol, read this into the + When solvate or genion produce a modified topol, read this into the topology lines """ with open(os.path.join(path, file), "r") as f: self.top_lines = f.readlines() - def set_structure(self, path: str, file: str = _SGE.STD_STRUCTURE, sanitize=False): + def set_structure( + self, path: str, file: str = _SGE.STD_STRUCTURE, sanitize=False, index: int = 0 + ): with open(os.path.join(path, file), "r") as f: lines = f.readlines() if sanitize: lines = [l for l in lines if any([l.startswith(idx) for idx in _GE.ATOMS])] - self.structure = lines - def write_structure(self, path: str, file: str = _SGE.STD_STRUCTURE): - with open(os.path.join(path, file), "w") as f: - for line in self.structure: - f.write(line) + struct = GenericData(file_name=file, file_data=lines) + try: + self.structures[index] = struct + except IndexError: + self.structures.append(struct) + + def set_tpr(self, path: str, file: str = _SGE.STD_TPR, index: int = 0): + with open(os.path.join(path, file), "rb") as f: + data = f.read() + data = GenericData(file_name=file, file_data=data, file_id=index) + # either the object already exists, or we are creating it for the first time + try: + self.tprs[index] = data + except IndexError: + self.tprs.append(data) + + def write_tpr(self, path: str, file: str = _SGE.STD_TPR, index: int = 0): + tpr = self.tprs[index] + tpr.write(os.path.join(path, file), join=False) + + def set_ndx(self, path: str, file: str = _SGE.STD_INDEX): + with open(os.path.join(path, file), "r") as f: + self.ndx = f.readlines() - def append_structure(self, path: str, file: str, sanitize=False) -> None: + def write_ndx(self, path: str, file: str = _SGE.STD_INDEX): + with open(os.path.join(path, file), "w") as f: + f.writelines(self.ndx) + + def write_structure( + self, path: str, file: str = _SGE.STD_STRUCTURE, index: int = 0 + ): + structure = self.structures[index] + path = os.path.join(path, file) + structure.write(path, join=False) + + def set_trajectory(self, path: str, file: str = _SGE.STD_XTC, index: int = 0): + # depending on mdp settings, some runs will not produce an xtc file, only trr + if not os.path.isfile(os.path.join(path, file)): + # avoid indexing errors + data = GenericData(file_name="empty_traj.txt") + else: + with open(os.path.join(path, file), "rb") as f: + data = f.read() + data = GenericData(file_name=file, file_data=data, file_id=index) + # either the object already exists, or we are creating it for the first time + try: + self.trajectories[index] = data + except IndexError: + self.trajectories.append(data) + + def write_trajectory(self, path: str, file: str = _SGE.STD_XTC, index: int = 0): + traj = self.trajectories[index] + + path = os.path.join(path, file) + traj.write(path, join=False) + + def append_structure( + self, path: str, file: str, sanitize=False, index: int = 0 + ) -> None: with open(os.path.join(path, file), "r") as f: lines = f.readlines() if sanitize: lines = [l for l in lines if any([l.startswith(idx) for idx in _GE.ATOMS])] - self.structure.extend(lines) + data = self.structures[index].get_data() + lines + self.structures[index].set_data(data) def __str__(self) -> str: return f"Gromacs Topology object: System: {self.system} | Molecules: {[m for m in self.molecules]} | FF: {self.forcefield} | itp files: {[f for f in self.itps.keys()]} | posre files {[f for f in self.posre.keys()]}" diff --git a/src/icolos/core/flow_control/iterator.py b/src/icolos/core/flow_control/iterator.py index f41ab98..6250e1d 100644 --- a/src/icolos/core/flow_control/iterator.py +++ b/src/icolos/core/flow_control/iterator.py @@ -10,6 +10,7 @@ from icolos.utils.enums.step_enums import StepBaseEnum from icolos.core.workflow_steps.step import StepBase from icolos.utils.enums.step_enums import IteratorEnum +from icolos.core.composite_agents.workflow import WorkflowHeaderParameters import os _IE = IteratorEnum @@ -40,6 +41,8 @@ class IterSettings(BaseModel): settings: Dict[str, IterSettingsParameters] = {} iter_mode: _IE = _IE.N_ITERS n_iters: int = None + remove_temporary_files: bool = True + single_directory: bool = False parallelizer_settings: IterParallelizer = IterParallelizer() @@ -101,9 +104,16 @@ def _initialize_n_iters(self) -> List[WorkFlow]: _WE.HEADER: { _WE.ID: f"workflow_{i}", _WE.ENVIRONMENT: {_WE.ENVIRONMENT_EXPORT: []}, + _WE.GLOBAL_SETTINGS: {}, + _WE.GLOBAL_VARIABLES: { + "remove_temporary_files": self.iter_settings.remove_temporary_files, + "single_directory": self.iter_settings.single_directory, + }, }, _WE.STEPS: workflow_steps, } + # manually set some things for these workflows + workflows.append(WorkFlow(**wf_config)) return workflows diff --git a/src/icolos/core/workflow_steps/gromacs/base.py b/src/icolos/core/workflow_steps/gromacs/base.py index 324c1bf..2c2902c 100644 --- a/src/icolos/core/workflow_steps/gromacs/base.py +++ b/src/icolos/core/workflow_steps/gromacs/base.py @@ -19,11 +19,9 @@ class StepGromacsBase(StepBase, BaseModel): def __init__(self, **data): super().__init__(**data) - def write_input_files(self, tmp_dir): + def write_input_files(self, tmp_dir: str, topol: GromacsTopol = None): """ - Prepares the tmpdir. Supports two modes of operation, depending on where the data has come from: - 1) If tmpdir is empty and generic data is not, dump generic data files into tmpdir - 2) if dir is not empty and generic data is (we run pmx abfe like this), parse the tmpdir + Defaults to writing all available data from the workflow's topology object, unless that file has been specified in generic data, which will be prioritised """ # Normally this should be handled by setting GMXLIB env variable, but for some programs (gmx_MMPBSA), this doesn't work and non-standard forcefields @@ -44,6 +42,25 @@ def write_input_files(self, tmp_dir): self._logger.log( f"Writing input files to working directory at {tmp_dir}", _LE.DEBUG ) + # if we have specified a topol object, write out these files unless overwritten by an argument from the config + if topol is not None: + # handle structure files + if not self.data.generic.get_files_by_extension("gro"): + if topol.structures: + topol.write_structure(tmp_dir) + if not self.data.generic.get_files_by_extension("top"): + if topol.top_lines: + topol.write_topol(tmp_dir) + if not self.data.generic.get_files_by_extension("tpr"): + if topol.tprs: + topol.write_tpr(tmp_dir) + if not self.data.generic.get_files_by_extension("xtc"): + if topol.trajectories: + topol.write_trajectory(tmp_dir) + if not self.data.generic.get_files_by_extension("ndx"): + if topol.ndx: + topol.write_ndx(tmp_dir) + for file in self.data.generic.get_flattened_files(): file.write(tmp_dir) @@ -102,21 +119,10 @@ def _modify_config_file( config_file.set_data(file_data) config_file.write(tmp_dir) - def _generate_index_groups(self, tmp_dir): - try: - - structure = [ - f for f in os.listdir(tmp_dir) if f.endswith(_SGE.FIELD_KEY_STRUCTURE) - ] - assert len(structure) == 1 - structure = structure[0] - except AssertionError: - structure = [ - f for f in os.listdir(tmp_dir) if f.endswith(_SGE.FIELD_KEY_TPR) - ] - structure = structure[0] - - args = ["-f", structure] + def _generate_index_groups(self, tmp_dir: str): + # dump the first structure file to the tmpdir + self.get_topol().structures[0].write(tmp_dir) + args = ["-f", _SGE.STD_STRUCTURE] ndx_list = [f for f in os.listdir(tmp_dir) if f.endswith(_SGE.FIELD_KEY_NDX)] if len(ndx_list) == 1: args.extend(["-n", ndx_list[0]]) @@ -127,6 +133,7 @@ def _generate_index_groups(self, tmp_dir): check=True, pipe_input='echo -e "q"', ) + self.get_topol().set_ndx(tmp_dir) return result def construct_pipe_arguments(self, tmp_dir, params) -> str: @@ -163,7 +170,7 @@ def construct_pipe_arguments(self, tmp_dir, params) -> str: return " ".join(output) def _add_index_group(self, tmp_dir, pipe_input): - ndx_args_2 = [ + ndx_args = [ "-f", os.path.join(tmp_dir, _SGE.STD_STRUCTURE), "-o", @@ -175,13 +182,14 @@ def _add_index_group(self, tmp_dir, pipe_input): ) result = self._backend_executor.execute( command=_GE.MAKE_NDX, - arguments=ndx_args_2, + arguments=ndx_args, location=tmp_dir, check=True, pipe_input=self.construct_pipe_arguments(tmp_dir, pipe_input), ) for line in result.stdout.split("\n"): self._logger_blank.log(line, _LE.INFO) + self.get_topol().set_ndx(tmp_dir) def get_topol(self) -> GromacsTopol: return self.get_workflow_object().workflow_data.gmx_topol diff --git a/src/icolos/core/workflow_steps/gromacs/cluster.py b/src/icolos/core/workflow_steps/gromacs/cluster.py index 9106a7f..d9e6fd4 100644 --- a/src/icolos/core/workflow_steps/gromacs/cluster.py +++ b/src/icolos/core/workflow_steps/gromacs/cluster.py @@ -24,7 +24,8 @@ def __init__(self, **data): def execute(self): tmp_dir = self._make_tmpdir() - self.write_input_files(tmp_dir) + topol = self.get_topol() + self.write_input_files(tmp_dir, topol=topol) # give the option to run a make_ndx step preceding clustering to facilitate clustering on custom groups if _SGE.INDEX_FLAG in self.settings.arguments.parameters.keys(): @@ -36,9 +37,7 @@ def execute(self): try: ndx_arguments = [ "-f", - self.data.generic.get_argument_by_extension( - _SGE.FIELD_KEY_STRUCTURE - ), + _SGE.STD_STRUCTURE, "-o", _SGE.STD_INDEX, ] @@ -59,8 +58,8 @@ def execute(self): ) flag_dict = { - "-s": self.data.generic.get_argument_by_extension(_SGE.FIELD_KEY_TPR), - "-f": self.data.generic.get_argument_by_extension(_SGE.FIELD_KEY_XTC), + "-s": _SGE.STD_TPR, + "-f": _SGE.STD_XTC, "-cl": "clusters.pdb", } arguments = self._parse_arguments(flag_dict=flag_dict) diff --git a/src/icolos/core/workflow_steps/gromacs/editconf.py b/src/icolos/core/workflow_steps/gromacs/editconf.py index 780f3f2..14dab64 100644 --- a/src/icolos/core/workflow_steps/gromacs/editconf.py +++ b/src/icolos/core/workflow_steps/gromacs/editconf.py @@ -25,8 +25,7 @@ def __init__(self, **data): def execute(self): tmp_dir = self._make_tmpdir() topol = self.get_topol() - topol.write_structure(tmp_dir) - self.write_input_files(tmp_dir) + self.write_input_files(tmp_dir, topol=topol) arguments = self._parse_arguments( flag_dict={"-f": _SGE.STD_STRUCTURE, "-o": _SGE.STD_STRUCTURE} ) diff --git a/src/icolos/core/workflow_steps/gromacs/genion.py b/src/icolos/core/workflow_steps/gromacs/genion.py index b591ae7..72121bf 100644 --- a/src/icolos/core/workflow_steps/gromacs/genion.py +++ b/src/icolos/core/workflow_steps/gromacs/genion.py @@ -25,14 +25,12 @@ def __init__(self, **data): def execute(self): tmp_dir = self._make_tmpdir() topol = self.get_topol() - topol.write_structure(tmp_dir) - topol.write_topol(tmp_dir) - self.write_input_files(tmp_dir) + self.write_input_files(tmp_dir, topol=topol) arguments = self._parse_arguments( { "-o": _SGE.STD_STRUCTURE, "-p": _SGE.STD_TOPOL, - "-s": self.data.generic.get_argument_by_extension(_SGE.FIELD_KEY_TPR), + "-s": _SGE.STD_TPR, } ) result = self._backend_executor.execute( @@ -69,5 +67,5 @@ def execute(self): self._logger.log('Added index group to "index.ndx"', _LE.DEBUG) self._parse_output(tmp_dir) topol.set_structure(tmp_dir) - topol.set_topol(tmp_dir) + topol.parse(tmp_dir) self._remove_temporary(tmp_dir) diff --git a/src/icolos/core/workflow_steps/gromacs/grompp.py b/src/icolos/core/workflow_steps/gromacs/grompp.py index d044b8d..1ff5210 100644 --- a/src/icolos/core/workflow_steps/gromacs/grompp.py +++ b/src/icolos/core/workflow_steps/gromacs/grompp.py @@ -1,3 +1,4 @@ +from icolos.core.containers.gromacs_topol import GromacsTopol from icolos.utils.enums.step_enums import StepGromacsEnum from icolos.utils.enums.program_parameters import GromacsEnum from icolos.core.workflow_steps.gromacs.base import StepGromacsBase @@ -15,6 +16,11 @@ class StepGMXGrompp(StepGromacsBase, BaseModel): Automatically handles coupling group updates """ + class Config: + arbitrary_types_allowed = True + + topol: GromacsTopol = None + def __init__(self, **data): super().__init__(**data) @@ -76,8 +82,8 @@ def execute(self): """ tmp_dir = self._make_tmpdir() topol = self.get_topol() - topol.write_structure(tmp_dir) - topol.write_topol(tmp_dir) + + # do this bit once # if make_ndx command has been specified in settings.additional, # add an index group here, commonly protein_ligand or protein_other @@ -102,24 +108,36 @@ def execute(self): ) mdp_file.write(tmp_dir) - args = ["-r", _SGE.STD_STRUCTURE] if self.settings.additional["-r"] else [] - - arguments = self._parse_arguments( - flag_dict={ - "-f": mdp_file.get_file_name(), - "-c": _SGE.STD_STRUCTURE, - "-p": _SGE.STD_TOPOL, - "-o": _SGE.STD_TPR, - }, - args=args, - ) - result = self._backend_executor.execute( - command=_GE.GROMPP, arguments=arguments, check=True, location=tmp_dir - ) - for line in result.stdout.split("\n"): - self._logger_blank.log(line, _LE.DEBUG) - self._logger.log( - f"Completed execution for {self.step_id} successfully", _LE.INFO - ) + replicas = self.get_additional_setting(_SGE.REPLICAS, default=1) + topol.write_topol(tmp_dir) + init_struct = len(topol.structures) + + for i in range(replicas): + index = 0 if init_struct == 1 else i + # we are branching for the first time, just use this confout.gro as the starting point + topol.write_structure(tmp_dir, index=index) + args = ["-r", _SGE.STD_STRUCTURE] if self.settings.additional["-r"] else [] + + arguments = self._parse_arguments( + flag_dict={ + "-f": mdp_file.get_file_name(), + "-c": _SGE.STD_STRUCTURE, + "-p": _SGE.STD_TOPOL, + "-o": _SGE.STD_TPR, + }, + args=args, + ) + result = self._backend_executor.execute( + command=_GE.GROMPP, arguments=arguments, check=True, location=tmp_dir + ) + for line in result.stdout.split("\n"): + self._logger_blank.log(line, _LE.DEBUG) + self._logger.log( + f"Completed execution for {self.step_id} successfully for replica {i}", + _LE.INFO, + ) + + topol.set_tpr(tmp_dir, index=i) + topol.set_structure(tmp_dir, index=i) self._parse_output(tmp_dir) self._remove_temporary(tmp_dir) diff --git a/src/icolos/core/workflow_steps/gromacs/mdrun.py b/src/icolos/core/workflow_steps/gromacs/mdrun.py index a0e058e..7503209 100644 --- a/src/icolos/core/workflow_steps/gromacs/mdrun.py +++ b/src/icolos/core/workflow_steps/gromacs/mdrun.py @@ -1,4 +1,7 @@ -from icolos.utils.enums.step_enums import StepGromacsEnum +import tempfile +from icolos.core.containers.gromacs_topol import GromacsTopol +from icolos.utils.enums.execution_enums import ExecutionPlatformEnum +from icolos.utils.enums.step_enums import StepBaseEnum, StepGromacsEnum from icolos.utils.enums.program_parameters import GromacsEnum from icolos.core.workflow_steps.gromacs.base import StepGromacsBase from pydantic import BaseModel @@ -9,6 +12,8 @@ _GE = GromacsEnum() _SGE = StepGromacsEnum() +_SBE = StepBaseEnum +_ERE = ExecutionPlatformEnum class StepGMXMDrun(StepGromacsBase, BaseModel): @@ -42,20 +47,17 @@ def _tail_log_file(self, tmp_dir): for line in log_file[-50:]: self._logger_blank.log(line, _LE.INFO) - def execute(self): - - tmp_dir = self._make_tmpdir() - topol = self.get_topol() + def run_single_tpr(self, tmp_dir: str, topol: GromacsTopol): # if we're simulating a protein, we need to modify the topol file to include the correct index groups \ # to allow ligand restraint. This means an ndx file must be specified in the json - self.write_input_files(tmp_dir) + self.write_input_files(tmp_dir, topol=topol) # append _out to the xtc file name - xtc_output_file = self.generate_output_file(_SGE.STD_XTC) + arguments = self._parse_arguments( flag_dict={ - "-s": self.data.generic.get_argument_by_extension(_SGE.FIELD_KEY_TPR), + "-s": _SGE.STD_TPR, "-c": _SGE.STD_STRUCTURE, - "-x": xtc_output_file, + "-x": _SGE.STD_XTC, } ) self._backend_executor.execute( @@ -71,5 +73,53 @@ def execute(self): topol.set_structure(tmp_dir, self.settings.arguments.parameters["-c"]) else: topol.set_structure(tmp_dir) + topol.set_trajectory(tmp_dir) + def run_multidir_sim(self, tmp_dir: str, topol: GromacsTopol): + """ + Runs a multidir simulation, allowing for replex simulations. Several conditions are required for this running mode + 1) the previous step in the workflow should have been an iterator to produce n tpr files. This must have been run with single_dir mode ON and remove_temprorary_files OFF, so we can extract files from those workflows' tmpdirs + + """ + if not self.execution.platform == _ERE.SLURM: + self._logger.log( + "WARNING: Running HREX simulation without external resources! Normally this should be run as a separate batch job", + _LE.WARNING, + ) + + # extract the tprs from the topol object, write to separate tmpdirs + work_dirs = [ + tempfile.mkdtemp(dir=tmp_dir) for _ in range(len(topol.structures)) + ] + self._logger.log( + f"Initiating gmx multidir run in directories {', '.join(work_dirs)}", + _LE.DEBUG, + ) + for path, tpr in zip(work_dirs, topol.tprs): + tpr.write(path) + + # note, this must be a multiple of the number of simulations + tasks = self.execution.resources.tasks + # map the PP and PME tasks to the GPUs + + command = f"mpirun -np {tasks} gmx_mpi mdrun -multidir {' '.join(work_dirs)}" + arguments = self._parse_arguments(flag_dict={"-x": _SGE.STD_XTC}) + self._backend_executor.execute( + command=command, arguments=arguments, location=tmp_dir, check=True + ) + # udpate the structures to the new coordinates + for i, work_dir in enumerate(work_dirs): + topol.set_structure(work_dir, index=i) + topol.set_trajectory(work_dir, index=i) + topol.set_tpr(work_dir, index=i) + + def execute(self): + + tmp_dir = self._make_tmpdir() + topol = self.get_topol() + multidir = self.get_additional_setting(_SGE.MULTIDIR, default=False) + if multidir: + self.run_multidir_sim(tmp_dir, topol=topol) + else: + self.run_single_tpr(tmp_dir, topol=topol) self._remove_temporary(tmp_dir) diff --git a/src/icolos/core/workflow_steps/gromacs/mmpbsa.py b/src/icolos/core/workflow_steps/gromacs/mmpbsa.py index d4fa008..607b4c1 100644 --- a/src/icolos/core/workflow_steps/gromacs/mmpbsa.py +++ b/src/icolos/core/workflow_steps/gromacs/mmpbsa.py @@ -119,18 +119,10 @@ def _get_file_from_dir(self, tmp_dir: str, ext: str) -> AnyStr: return file[0] def execute(self) -> None: - """ - Execute gmx_MMPBSA - Note: execution using mpirun is not supported for stability reasons - """ tmp_dir = self._make_tmpdir() - + topol = self.get_topol() self._generate_amber_input_file() - self.get_topol().write_structure(tmp_dir) - self.get_topol().write_topol(tmp_dir) - self.write_input_files(tmp_dir) - - # gmx_MMPBSA requires the coupling groups of the receptor and ligand + self.write_input_files(tmp_dir, topol=topol) # form any required coupling groups with make_ndx_command before parsing coupling groups # e.g. combine protein + cofactor @@ -143,20 +135,26 @@ def execute(self) -> None: # can run make_ndx multiple times for complex cases, each set of pipe imput must be separated by a semicolon for args in ndx_commands.split(";"): self._add_index_group(tmp_dir=tmp_dir, pipe_input=args) - flag_dict = { - "-i": _SGE.MMPBSA_IN, - "-cs": self._get_arg("tpr"), - "-cg": self._parse_coupling_groups(tmp_dir), - "-ci": self._get_file_from_dir(tmp_dir=tmp_dir, ext="ndx"), - "-ct": self._get_arg("xtc"), - "-cp": _SGE.STD_TOPOL, - # do not attempt to open the results in the GUI afterwards - "-nogui": "", - } - - flag_list = self._parse_arguments(flag_dict=flag_dict) - - result = self._run_mmpbsa(flag_list, tmp_dir) + + for i in range(len(topol.structures)): + topol.write_structure(tmp_dir, index=i) + topol.write_tpr(tmp_dir, index=i) + topol.write_trajectory(tmp_dir, index=i) + + flag_dict = { + "-i": _SGE.MMPBSA_IN, + "-cs": _SGE.STD_TPR, + "-cg": self._parse_coupling_groups(tmp_dir), + "-ci": _SGE.STD_INDEX, + "-ct": _SGE.STD_XTC, + "-cp": _SGE.STD_TOPOL, + # do not attempt to open the results in the GUI afterwards + "-nogui": "", + } + + flag_list = self._parse_arguments(flag_dict=flag_dict) + + result = self._run_mmpbsa(flag_list, tmp_dir) # parse and delete generated output self._parse_output(tmp_dir) diff --git a/src/icolos/core/workflow_steps/gromacs/pdb2gmx.py b/src/icolos/core/workflow_steps/gromacs/pdb2gmx.py index 9175c38..75acb52 100644 --- a/src/icolos/core/workflow_steps/gromacs/pdb2gmx.py +++ b/src/icolos/core/workflow_steps/gromacs/pdb2gmx.py @@ -235,7 +235,7 @@ def execute(self): topol.forcefield = self.settings.arguments.parameters["-ff"] topol.water = self.settings.arguments.parameters["-water"] - topol.parse(os.path.join(tmp_dir, _SGE.PROTEIN_TOP)) + topol.parse(tmp_dir, _SGE.PROTEIN_TOP) topol.set_structure(tmp_dir, _SGE.PROTEIN_PDB, sanitize=True) posre_files = [ f for f in os.listdir(tmp_dir) if f.endswith(".itp") and "posre" in f diff --git a/src/icolos/core/workflow_steps/gromacs/solvate.py b/src/icolos/core/workflow_steps/gromacs/solvate.py index 2b03685..730f722 100644 --- a/src/icolos/core/workflow_steps/gromacs/solvate.py +++ b/src/icolos/core/workflow_steps/gromacs/solvate.py @@ -1,3 +1,4 @@ +import os from icolos.utils.enums.step_enums import StepGromacsEnum from icolos.utils.enums.program_parameters import GromacsEnum from icolos.utils.execute_external.gromacs import GromacsExecutor @@ -23,9 +24,7 @@ def __init__(self, **data): def execute(self): tmp_dir = self._make_tmpdir() topol = self.get_topol() - topol.write_structure(tmp_dir) - topol.write_topol(tmp_dir) - + self.write_input_files(tmp_dir, topol=topol) arguments = self._parse_arguments( flag_dict={ "-cp": _SGE.STD_STRUCTURE, @@ -41,7 +40,8 @@ def execute(self): self._logger.log( f"Completed execution for {self.step_id} successfully.", _LE.INFO ) - # self._parse_output(tmp_dir) + self._parse_output(tmp_dir) topol.set_structure(tmp_dir) - topol.set_topol(tmp_dir) + topol.parse(tmp_dir) + self._remove_temporary(tmp_dir) diff --git a/src/icolos/core/workflow_steps/gromacs/trjconv.py b/src/icolos/core/workflow_steps/gromacs/trjconv.py index 9dc4ddc..310866f 100644 --- a/src/icolos/core/workflow_steps/gromacs/trjconv.py +++ b/src/icolos/core/workflow_steps/gromacs/trjconv.py @@ -25,26 +25,29 @@ def __init__(self, **data): def execute(self): tmp_dir = self._make_tmpdir() - self.write_input_files(tmp_dir) - - xtc_file = self.data.generic.get_argument_by_extension(_SGE.FIELD_KEY_XTC) - flag_dict = { - "-s": self.data.generic.get_argument_by_extension(_SGE.FIELD_KEY_TPR), - "-f": xtc_file, - "-o": xtc_file, - } - - arguments = self._parse_arguments(flag_dict=flag_dict) - result = self._backend_executor.execute( - command=_GE.TRJCONV, - arguments=arguments, - location=tmp_dir, - check=True, - pipe_input=self.construct_pipe_arguments( - tmp_dir, self.settings.additional[_SBE.PIPE_INPUT] - ), - ) - for line in result.stdout.split("\n"): - self._logger_blank.log(line, _LE.DEBUG) - self._parse_output(tmp_dir) + topol = self.get_topol() + topol.write_ndx(tmp_dir) + replicas = self.get_additional_setting(_SGE.REPLICAS, default=1) + for i in range(replicas): + topol.write_tpr(tmp_dir, index=i) + topol.write_trajectory(tmp_dir, index=i) + flag_dict = { + "-s": _SGE.STD_TPR, + "-f": _SGE.STD_XTC, + "-o": _SGE.STD_XTC, + } + + arguments = self._parse_arguments(flag_dict=flag_dict) + result = self._backend_executor.execute( + command=_GE.TRJCONV, + arguments=arguments, + location=tmp_dir, + check=True, + pipe_input=self.construct_pipe_arguments( + tmp_dir, self.settings.additional[_SBE.PIPE_INPUT] + ), + ) + for line in result.stdout.split("\n"): + self._logger_blank.log(line, _LE.DEBUG) + topol.set_trajectory(tmp_dir, index=i) self._remove_temporary(tmp_dir) diff --git a/src/icolos/core/workflow_steps/step.py b/src/icolos/core/workflow_steps/step.py index 3473cd6..0278b53 100644 --- a/src/icolos/core/workflow_steps/step.py +++ b/src/icolos/core/workflow_steps/step.py @@ -63,6 +63,7 @@ class StepExecutionResourceParameters(BaseModel): gres: str = None mem: str = "32g" cores: int = 8 + tasks: int = 1 modules: List = [] other_args: dict = {} @@ -235,6 +236,7 @@ def _initialize_backend(self, executor: Callable): prefix_execution=self.execution.prefix_execution, binary_location=self.execution.binary_location, cores=self.execution.resources.cores, + tasks=self.execution.resources.tasks, partition=self.execution.resources.partition, time=self.execution.resources.time, mem=self.execution.resources.mem, diff --git a/src/icolos/utils/enums/program_parameters.py b/src/icolos/utils/enums/program_parameters.py index 0fe1813..4cc2b1d 100644 --- a/src/icolos/utils/enums/program_parameters.py +++ b/src/icolos/utils/enums/program_parameters.py @@ -1053,6 +1053,7 @@ class GromacsEnum: GROMPP = "gmx grompp" GENION = "gmx genion" MDRUN = "gmx mdrun" + MPI_MDRUN = "gmx_mpi mdrun" MAKE_NDX = "gmx make_ndx" GENRESTR = "gmx genrestr" TRJCAT = "gmx trjcat" diff --git a/src/icolos/utils/enums/step_enums.py b/src/icolos/utils/enums/step_enums.py index 988f3bb..9afb374 100644 --- a/src/icolos/utils/enums/step_enums.py +++ b/src/icolos/utils/enums/step_enums.py @@ -94,6 +94,7 @@ class StepBaseEnum(str, Enum): EXEC_RESOURCES = "resources" EXEC_RESOURCES_PARTITION = "partition" EXEC_RESOURCES_GRES = "gres" + EXEC_RESOURCES_TASKS = "tasks" EXEC_RESOURCES_MODULES = "modules" EXEC_RESOURCES_MEM = "mem" EXEC_RESOURCES_CORES = "cores" @@ -733,8 +734,9 @@ class StepGromacsEnum: LIGAND_MOL2 = "Ligand.mol2" STD_INDEX = "index.ndx" STD_TOPOL = "topol.top" - STD_TPR = "structure.tpr" - STD_XTC = "structure.xtc" + STD_TPR = "topol.tpr" + STD_XTC = "traj.xtc" + STD_TRR = "traj.trr" STD_STRUCTURE = "confout.gro" POSRE_LIG = "posre_lig.itp" CHARGE_METHOD = "charge_method" @@ -764,6 +766,9 @@ class StepGromacsEnum: 1 1 1000 1000 1000 #endif\n""" + MULTIDIR = "multidir" + REPLICAS = "replicas" + def __getattr__(self, name): if name in self: return name diff --git a/src/icolos/utils/execute_external/gromacs.py b/src/icolos/utils/execute_external/gromacs.py index 72c1d01..befe8fe 100644 --- a/src/icolos/utils/execute_external/gromacs.py +++ b/src/icolos/utils/execute_external/gromacs.py @@ -19,6 +19,7 @@ def execute( _GE.GROMPP, _GE.SOLVATE, _GE.MDRUN, + _GE.MPI_MDRUN, _GE.PDB2GMX, _GE.MAKE_NDX, _GE.GENRESTR, diff --git a/src/icolos/utils/execute_external/slurm_executor.py b/src/icolos/utils/execute_external/slurm_executor.py index dabd77a..bfbf829 100644 --- a/src/icolos/utils/execute_external/slurm_executor.py +++ b/src/icolos/utils/execute_external/slurm_executor.py @@ -17,6 +17,7 @@ def __init__( self, cores: int, partition: str, + tasks: int, time: str, mem: str, modules: List, @@ -30,6 +31,7 @@ def __init__( self.cores = cores self.partition = partition self.time = time + self.tasks = tasks self.mem = mem self.modules = modules self.other_args = other_args @@ -194,8 +196,9 @@ def _check_job_status(self, job_id): def _construct_slurm_header(self): header = [ "#!/bin/bash", - f"#SBATCH -c{self.cores}", - f"#SBATCH -p {self.partition}", + f"#SBATCH --cores={self.cores}", + f"#SBATCH --partition={self.partition}", + f"#SBATCH --tasks={self.tasks}", f"#SBATCH --time={self.time}", ] if self.gres is not None: diff --git a/tests/gromacs/test_cluster.py b/tests/gromacs/test_cluster.py index c517141..5b65ba0 100644 --- a/tests/gromacs/test_cluster.py +++ b/tests/gromacs/test_cluster.py @@ -1,12 +1,14 @@ from icolos.core.containers.generic import GenericData +from icolos.core.containers.gromacs_topol import GromacsTopol from icolos.core.workflow_steps.gromacs.cluster import StepGMXCluster import unittest import os from icolos.utils.enums.step_enums import StepBaseEnum, StepGromacsEnum from tests.tests_paths import PATHS_EXAMPLEDATA, export_unit_test_env_vars +from icolos.core.composite_agents.workflow import WorkFlow from icolos.utils.general.files_paths import attach_root_path -SGE = StepGromacsEnum() +_SGE = StepGromacsEnum() SBE = StepBaseEnum @@ -20,16 +22,18 @@ def setUpClass(cls): export_unit_test_env_vars() def setUp(self): - with open(attach_root_path(PATHS_EXAMPLEDATA.GROMACS_1BVG_XTC), "rb") as f: - self.xtc = f.read() - - with open(attach_root_path(PATHS_EXAMPLEDATA.GROMACS_1BVG_TPR), "rb") as f: - self.tpr = f.read() - + with open(attach_root_path(PATHS_EXAMPLEDATA.GROMACS_1BVG_TOP), "r") as f: + topol = f.readlines() with open( attach_root_path(PATHS_EXAMPLEDATA.GROMACS_HOLO_STRUCTURE_GRO), "r" ) as f: - self.structure = f.read() + struct = f.readlines() + + self.topol = GromacsTopol() + self.topol.structures = [GenericData(_SGE.STD_STRUCTURE, file_data=struct)] + self.topol.top_lines = topol + self.topol.set_tpr(path="", file=PATHS_EXAMPLEDATA.GROMACS_1BVG_TPR) + self.topol.set_trajectory(path="", file=PATHS_EXAMPLEDATA.GROMACS_1BVG_XTC) def test_cluster(self): step_conf = { @@ -48,23 +52,16 @@ def test_cluster(self): }, SBE.SETTINGS_ADDITIONAL: { SBE.PIPE_INPUT: "2 System", - SGE.MAKE_NDX_COMMAND: "1 & a P", + _SGE.MAKE_NDX_COMMAND: "1 & a P", }, }, } step_cluster = StepGMXCluster(**step_conf) - step_cluster.data.generic.add_file( - GenericData(file_name="tmp10249.xtc", file_data=self.xtc, argument=True) - ) - step_cluster.data.generic.add_file( - GenericData(file_name="tmp03942.tpr", file_data=self.tpr, argument=True) - ) - step_cluster.data.generic.add_file( - GenericData( - file_name="structure.gro", file_data=self.structure, argument=True - ) - ) + wf = WorkFlow() + wf.workflow_data.gmx_topol = self.topol + step_cluster.set_workflow_object(wf) + step_cluster.execute() out_path = os.path.join(self._test_dir, "clusters.pdb") step_cluster.write_generic_by_extension(self._test_dir, "pdb") diff --git a/tests/gromacs/test_do_dssp.py b/tests/gromacs/test_do_dssp.py index 533b03d..c3a35fc 100644 --- a/tests/gromacs/test_do_dssp.py +++ b/tests/gromacs/test_do_dssp.py @@ -10,7 +10,7 @@ _SBE = StepBaseEnum -class Test_Editconf(unittest.TestCase): +class Test_do_dssp(unittest.TestCase): @classmethod def setUpClass(cls): cls._test_dir = attach_root_path("tests/junk/gromacs") @@ -25,7 +25,7 @@ def setUp(self): with open(attach_root_path(PATHS_EXAMPLEDATA.GROMACS_1BVG_XTC), "rb") as f: self.traj = f.read() - def test_editconf_run(self): + def test_dssp_run(self): step_conf = { _SBE.STEPID: "test_dssp", _SBE.STEP_TYPE: "dssp", diff --git a/tests/gromacs/test_editconf.py b/tests/gromacs/test_editconf.py index 5fe1b5d..f397ca6 100644 --- a/tests/gromacs/test_editconf.py +++ b/tests/gromacs/test_editconf.py @@ -25,11 +25,14 @@ def setUp(self): with open( attach_root_path(PATHS_EXAMPLEDATA.GROMACS_HOLO_STRUCTURE_GRO), "r" ) as f: - struct = f.readlines() + self.struct = f.readlines() self.topol = GromacsTopol() - self.topol.structure = struct + self.topol.structures = [GenericData(_SGE.STD_STRUCTURE, file_data=self.struct)] - def test_editconf_run(self): + def test_editconf_wf_input(self): + """ + Takes input from a workflow object + """ step_conf = { _SBE.STEPID: "test_editconf", _SBE.STEP_TYPE: "editconf", @@ -55,6 +58,39 @@ def test_editconf_run(self): step_editconf.execute() out_path = os.path.join(self._test_dir, "confout.gro") - step_editconf.write_generic_by_name(self._test_dir, "confout.gro") + step_editconf.get_topol().write_structure(self._test_dir) + stat_inf = os.stat(out_path) + self.assertEqual(stat_inf.st_size, 2102964) + + def test_editconf_external_input(self): + step_conf = { + _SBE.STEPID: "test_editconf", + _SBE.STEP_TYPE: "editconf", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2021-fosscuda-2019a-PLUMED-2.7.1-Python-3.7.2" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: [], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: { + "-d": "1.0", + "-bt": "dodecahedron", + }, + } + }, + } + + step_editconf = StepGMXEditConf(**step_conf) + + wf = WorkFlow() + wf.workflow_data.gmx_topol = self.topol + step_editconf.set_workflow_object(wf) + step_editconf.data.generic.add_file( + GenericData(file_name=_SGE.STD_STRUCTURE, file_data=self.struct) + ) + + step_editconf.execute() + out_path = os.path.join(self._test_dir, "confout.gro") + step_editconf.get_topol().write_structure(self._test_dir) stat_inf = os.stat(out_path) self.assertEqual(stat_inf.st_size, 2102964) diff --git a/tests/gromacs/test_genion.py b/tests/gromacs/test_genion.py index 1fa36a7..233779d 100644 --- a/tests/gromacs/test_genion.py +++ b/tests/gromacs/test_genion.py @@ -25,13 +25,14 @@ def setUp(self): with open(attach_root_path(PATHS_EXAMPLEDATA.GROMACS_1BVG_TOP), "r") as f: topol = f.readlines() with open(attach_root_path(PATHS_EXAMPLEDATA.GROMACS_1BVG_TPR), "rb") as f: - self.tpr = f.read() + tpr = f.read() with open( attach_root_path(PATHS_EXAMPLEDATA.GROMACS_HOLO_STRUCTURE_GRO), "r" ) as f: struct = f.readlines() self.topol = GromacsTopol() - self.topol.structure = struct + self.topol.structures = [GenericData(_SGE.STD_STRUCTURE, file_data=struct)] + self.topol.tprs = [GenericData(_SGE.STD_TPR, file_data=tpr)] self.topol.top_lines = topol def test_genion_run(self): @@ -54,9 +55,7 @@ def test_genion_run(self): } step_genion = StepGMXGenion(**step_conf) - step_genion.data.generic.add_file( - GenericData(file_name="structure.tpr", file_data=self.tpr, argument=True) - ) + wf = WorkFlow() wf.workflow_data.gmx_topol = self.topol step_genion.set_workflow_object(wf) diff --git a/tests/gromacs/test_grompp.py b/tests/gromacs/test_grompp.py index 2bd3380..487dbd7 100644 --- a/tests/gromacs/test_grompp.py +++ b/tests/gromacs/test_grompp.py @@ -22,8 +22,6 @@ def setUpClass(cls): export_unit_test_env_vars() def setUp(self): - with open(attach_root_path(PATHS_EXAMPLEDATA.GROMACS_1BVG_TOP), "r") as f: - topol = f.readlines() with open( attach_root_path(PATHS_EXAMPLEDATA.GROMACS_HOLO_STRUCTURE_GRO), "r" ) as f: @@ -32,12 +30,10 @@ def setUp(self): self.mdp = f.read() self.topol = GromacsTopol() - self.topol.structure = struct - self.topol.top_lines = topol - self.topol.add_itp( - os.path.join(MAIN_CONFIG["ICOLOS_TEST_DATA"], "gromacs/protein"), - ["DMP:100.itp"], - ) + self.topol.structures = [GenericData(_SGE.STD_STRUCTURE, file_data=struct)] + top_path = os.path.dirname(PATHS_EXAMPLEDATA.GROMACS_1BVG_TOP) + top_file = PATHS_EXAMPLEDATA.GROMACS_1BVG_TOP.split("/")[-1] + self.topol.parse(top_path, top_file) def test_grompp(self): step_conf = { @@ -74,7 +70,7 @@ def test_grompp(self): step_grompp.execute() - out_path = os.path.join(self._test_dir, "structure.tpr") - step_grompp.write_generic_by_name(self._test_dir, "structure.tpr") + out_path = os.path.join(self._test_dir, _SGE.STD_TPR) + step_grompp.get_topol().write_tpr(self._test_dir) stat_inf = os.stat(out_path) - self.assertEqual(stat_inf.st_size, 596160) + self.assertEqual(stat_inf.st_size, 1528248) diff --git a/tests/gromacs/test_mdrun.py b/tests/gromacs/test_mdrun.py index f69711a..1280aa1 100644 --- a/tests/gromacs/test_mdrun.py +++ b/tests/gromacs/test_mdrun.py @@ -26,7 +26,7 @@ def setUp(self): with open(PATHS_EXAMPLEDATA.GROMACS_1BVG_TPR, "rb") as f: self.tpr = f.read() - def test_mdrun(self): + def test_mdrun_external_tpr(self): step_conf = { _SBE.STEPID: "test_mdrun", _SBE.STEP_TYPE: "mdrun", @@ -47,7 +47,7 @@ def test_mdrun(self): wf.workflow_data.gmx_topol = topol step_mdrun.set_workflow_object(wf) step_mdrun.data.generic.add_file( - GenericData(file_name="structure.tpr", file_data=self.tpr, argument=True) + GenericData(file_name=_SGE.STD_TPR, file_data=self.tpr, argument=True) ) step_mdrun.execute() @@ -56,6 +56,37 @@ def test_mdrun(self): stat_inf = os.stat(out_path) self.assertGreater(stat_inf.st_size, 3224400) + def test_mdrun_internal_tpr(self): + step_conf = { + _SBE.STEPID: "test_mdrun", + _SBE.STEP_TYPE: "mdrun", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2021-fosscuda-2019a-PLUMED-2.7.1-Python-3.7.2" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: {"-nsteps": 1000} + } + }, + } + + step_mdrun = StepGMXMDrun(**step_conf) + topol = GromacsTopol() + topol.tprs = [ + GenericData(file_name=_SGE.STD_TPR, file_data=self.tpr, argument=True) + ] + step_mdrun = StepGMXMDrun(**step_conf) + wf = WorkFlow() + wf.workflow_data.gmx_topol = topol + + step_mdrun.set_workflow_object(wf) + step_mdrun.execute() + + out_path = os.path.join(self._test_dir, "confout.gro") + step_mdrun.write_generic_by_extension(self._test_dir, "gro") + stat_inf = os.stat(out_path) + self.assertGreater(stat_inf.st_size, 3224400) + def test_mdrun_slurm(self): step_conf = { _SBE.STEPID: "test_mdrun", @@ -83,7 +114,7 @@ def test_mdrun_slurm(self): wf.workflow_data.gmx_topol = topol step_mdrun.set_workflow_object(wf) step_mdrun.data.generic.add_file( - GenericData(file_name="structure.tpr", file_data=self.tpr, argument=True) + GenericData(file_name=_SGE.STD_TPR, file_data=self.tpr, argument=True) ) step_mdrun.execute() out_path = os.path.join(self._test_dir, "confout.gro") diff --git a/tests/gromacs/test_mmpbsa.py b/tests/gromacs/test_mmpbsa.py index f0430e0..8e439c6 100644 --- a/tests/gromacs/test_mmpbsa.py +++ b/tests/gromacs/test_mmpbsa.py @@ -41,20 +41,26 @@ def setUp(self) -> None: self.lig_posre = f.read() self.topol = GromacsTopol() - self.topol.parse(PATHS_EXAMPLEDATA.GROMACS_1BVG_TOP) - self.topol.structure = self.structure + top_path = os.path.dirname(PATHS_EXAMPLEDATA.GROMACS_1BVG_TOP) + top_file = PATHS_EXAMPLEDATA.GROMACS_1BVG_TOP.split("/")[-1] + self.topol.parse(top_path, top_file) + self.topol.structures = [ + GenericData(_SGE.STD_STRUCTURE, file_data=self.structure) + ] self.topol.add_itp( os.path.join(MAIN_CONFIG["ICOLOS_TEST_DATA"], "gromacs/protein"), ["DMP:100.itp"], ) + self.topol.trajectories = [ + GenericData(file_name=_SGE.STD_XTC, file_data=self.xtc_file) + ] + self.topol.tprs = [GenericData(_SGE.STD_TPR, self.tpr_file)] def test_protein_lig_single_traj(self): step_conf = { _SBE.STEPID: "test_gmmpbsa", _SBE.STEP_TYPE: "gmx_mmpbsa", - _SBE.EXEC: { - _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2021-fosscuda-2019a-PLUMED-2.7.1-Python-3.7.2 && module load gmx_MMPBSA " - }, + _SBE.EXEC: {_SBE.EXEC_PREFIXEXECUTION: "module load gmx_MMPBSA "}, _SBE.SETTINGS: { _SBE.SETTINGS_ARGUMENTS: { _SBE.SETTINGS_ARGUMENTS_FLAGS: [], @@ -71,12 +77,6 @@ def test_protein_lig_single_traj(self): step_mmpbsa = StepGMXmmpbsa(**step_conf) step_mmpbsa.set_workflow_object(wf) - step_mmpbsa.data.generic.add_file( - GenericData(file_name="structure.xtc", file_data=self.xtc_file) - ) - step_mmpbsa.data.generic.add_file( - GenericData(file_name="structure.tpr", file_data=self.tpr_file) - ) step_mmpbsa.data.generic.add_file( GenericData(file_name="DMP:100.itp", file_data=self.lig_itp) ) @@ -91,9 +91,7 @@ def test_protein_lig_single_traj_custom_file(self): step_conf = { _SBE.STEPID: "test_gmmpbsa", _SBE.STEP_TYPE: "gmx_mmpbsa", - _SBE.EXEC: { - _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2021-fosscuda-2019a-PLUMED-2.7.1-Python-3.7.2 && module load gmx_MMPBSA" - }, + _SBE.EXEC: {_SBE.EXEC_PREFIXEXECUTION: "module load gmx_MMPBSA"}, _SBE.SETTINGS: { _SBE.SETTINGS_ARGUMENTS: { _SBE.SETTINGS_ARGUMENTS_FLAGS: [], @@ -111,12 +109,42 @@ def test_protein_lig_single_traj_custom_file(self): step_mmpbsa = StepGMXmmpbsa(**step_conf) step_mmpbsa.set_workflow_object(wf) + step_mmpbsa.data.generic.add_file( - GenericData(file_name="structure.xtc", file_data=self.xtc_file) - ) - step_mmpbsa.data.generic.add_file( - GenericData(file_name="structure.tpr", file_data=self.tpr_file) + GenericData(file_name="DMP:100.itp", file_data=self.lig_itp) ) + step_mmpbsa.execute() + out_path = os.path.join(self._test_dir, "FINAL_RESULTS_MMPBSA.dat") + step_mmpbsa.write_generic_by_extension(self._test_dir, "dat") + stat_inf = os.stat(out_path) + + self.assertGreater(stat_inf.st_size, 4680) + + def test_protein_lig_single_traj_MPI(self): + + step_conf = { + _SBE.STEPID: "test_gmmpbsa", + _SBE.STEP_TYPE: "gmx_mmpbsa", + _SBE.EXEC: {_SBE.EXEC_PREFIXEXECUTION: "module load gmx_MMPBSA"}, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: ["MPI"], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: {}, + }, + _SBE.SETTINGS_ADDITIONAL: { + _SGE.FORCEFIELD: MAIN_CONFIG["FORCEFIELD"], + _SGE.COUPLING_GROUPS: "Protein Other", + _SGE.INPUT_FILE: PATHS_EXAMPLEDATA.MMPBSA_CUSTOM_INPUT, + _SGE.THREADS: 4, + }, + }, + } + wf = WorkFlow() + wf.workflow_data.gmx_topol = self.topol + + step_mmpbsa = StepGMXmmpbsa(**step_conf) + step_mmpbsa.set_workflow_object(wf) + step_mmpbsa.data.generic.add_file( GenericData(file_name="DMP:100.itp", file_data=self.lig_itp) ) diff --git a/tests/gromacs/test_solvate.py b/tests/gromacs/test_solvate.py index c4147f4..89bcc2a 100644 --- a/tests/gromacs/test_solvate.py +++ b/tests/gromacs/test_solvate.py @@ -23,11 +23,11 @@ def setUpClass(cls): def setUp(self): with open(PATHS_EXAMPLEDATA.GROMACS_HOLO_STRUCTURE_GRO, "r") as f: - self.structure = f.readlines() + self.data = f.readlines() self.topol = GromacsTopol() - self.topol.parse(PATHS_EXAMPLEDATA.GROMACS_1BVG_TOP) - self.topol.structure = self.structure + self.topol.set_topol("", PATHS_EXAMPLEDATA.GROMACS_1BVG_TOP) + self.topol.structures = [GenericData(_SGE.STD_STRUCTURE, file_data=self.data)] def test_solvate(self): step_conf = { @@ -51,8 +51,38 @@ def test_solvate(self): step_solvate.execute() out_path = os.path.join(self._test_dir, "confout.gro") - step_solvate.write_generic_by_extension( - self._test_dir, _SGE.FIELD_KEY_STRUCTURE + step_solvate.get_topol().write_structure(self._test_dir) + stat_inf = os.stat(out_path) + self.assertGreater(stat_inf.st_size, 142800) + + def test_solvate_external_file(self): + """ + Check structure file priority goes to the read-in file + """ + step_conf = { + _SBE.STEPID: "test_solvate", + _SBE.STEP_TYPE: "solvate", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2021-fosscuda-2019a-PLUMED-2.7.1-Python-3.7.2" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: [], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: {}, + } + }, + } + + step_solvate = StepGMXSolvate(**step_conf) + wf = WorkFlow() + wf.workflow_data.gmx_topol = self.topol + step_solvate.set_workflow_object(wf) + step_solvate.data.generic.add_file( + GenericData(_SGE.STD_STRUCTURE, file_data=self.data) ) + step_solvate.execute() + + out_path = os.path.join(self._test_dir, "confout.gro") + step_solvate.get_topol().write_structure(self._test_dir) stat_inf = os.stat(out_path) - self.assertGreater(stat_inf.st_size, 650000) + self.assertGreater(stat_inf.st_size, 142800) diff --git a/tests/gromacs/test_trjconv.py b/tests/gromacs/test_trjconv.py index 67a0012..4aa7f57 100644 --- a/tests/gromacs/test_trjconv.py +++ b/tests/gromacs/test_trjconv.py @@ -1,13 +1,15 @@ +from icolos.core.composite_agents.workflow import WorkFlow from icolos.core.containers.generic import GenericData import unittest import os +from icolos.core.containers.gromacs_topol import GromacsTopol from icolos.utils.enums.step_enums import StepBaseEnum, StepGromacsEnum from tests.tests_paths import PATHS_EXAMPLEDATA, export_unit_test_env_vars from icolos.utils.general.files_paths import attach_root_path from icolos.core.workflow_steps.gromacs.trjconv import StepGMXTrjconv -SGE = StepGromacsEnum() -SBE = StepBaseEnum +_SGE = StepGromacsEnum() +_SBE = StepBaseEnum class Test_Trjconv(unittest.TestCase): @@ -21,33 +23,39 @@ def setUpClass(cls): def setUp(self): with open(PATHS_EXAMPLEDATA.GROMACS_1BVG_XTC, "rb") as f: - self.xtc = f.read() + xtc = f.read() with open(PATHS_EXAMPLEDATA.GROMACS_1BVG_TPR, "rb") as f: - self.tpr = f.read() + tpr = f.read() + with open( + attach_root_path(PATHS_EXAMPLEDATA.GROMACS_HOLO_STRUCTURE_GRO), "r" + ) as f: + struct = f.readlines() + + self.topol = GromacsTopol() + self.topol.tprs = [GenericData(_SGE.STD_TPR, file_data=tpr)] + self.topol.trajectories = [GenericData(_SGE.STD_XTC, file_data=xtc)] + self.topol.structures = [GenericData(_SGE.STD_STRUCTURE, struct)] def test_trjconv(self): step_conf = { - SBE.STEPID: "test_trjconv", - SBE.STEP_TYPE: "trjconv", - SBE.EXEC: { - SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2021-fosscuda-2019a-PLUMED-2.7.1-Python-3.7.2" + _SBE.STEPID: "test_trjconv", + _SBE.STEP_TYPE: "trjconv", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2021-fosscuda-2019a-PLUMED-2.7.1-Python-3.7.2" }, - SBE.SETTINGS: { - SBE.SETTINGS_ARGUMENTS_FLAGS: ["-center"], - SBE.SETTINGS_ADDITIONAL: {SBE.PIPE_INPUT: "echo -ne 1 0"}, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: ["-center"], + _SBE.SETTINGS_ADDITIONAL: {_SBE.PIPE_INPUT: "echo -ne 1 0"}, }, } step_trjconv = StepGMXTrjconv(**step_conf) - step_trjconv.data.generic.add_file( - GenericData(file_name="structure.xtc", file_data=self.xtc, argument=True) - ) - step_trjconv.data.generic.add_file( - GenericData(file_name="structure.tpr", file_data=self.tpr, argument=True) - ) + wf = WorkFlow() + wf.workflow_data.gmx_topol = self.topol + step_trjconv.set_workflow_object(wf) step_trjconv.execute() - out_path = os.path.join(self._test_dir, "structure.xtc") - step_trjconv.write_generic_by_extension(self._test_dir, "xtc") + out_path = os.path.join(self._test_dir, "traj.xtc") + step_trjconv.get_topol().write_trajectory(self._test_dir) stat_inf = os.stat(out_path) self.assertGreater(stat_inf.st_size, 607000) diff --git a/tests/integration_tests/test_gromacs.py b/tests/integration_tests/test_gromacs.py index 480f71e..e59f3e0 100644 --- a/tests/integration_tests/test_gromacs.py +++ b/tests/integration_tests/test_gromacs.py @@ -483,7 +483,11 @@ def test_workflow_MD_fpocket_holo(self): stat_inf = os.stat(out_path) self.assertGreater(stat_inf.st_size, 62400) - def test_md_ligparam(self): + def test_md_ligparam_external_tpr(self): + """ + End to end gromacs workflow with ligand parametrisation and read-in of external tprs to "overwrite" existing files + Checks both generic file handling and gromacs topol play nicely together + """ conf = { _WE.HEADER: { @@ -570,7 +574,6 @@ def test_md_ligparam(self): }, _SBE.SETTINGS_ADDITIONAL: {}, }, - _SBE.INPUT: {_SBE.INPUT_GENERIC: []}, }, { _SBE.STEPID: "04_grompp", @@ -614,14 +617,6 @@ def test_md_ligparam(self): "pipe_input": "SOL", }, }, - _SBE.INPUT: { - _SBE.INPUT_GENERIC: [ - { - _SBE.INPUT_SOURCE: "04_grompp", - _SBE.INPUT_EXTENSION: "tpr", - }, - ] - }, }, { _SBE.STEPID: "06_grompp_eminim", @@ -660,14 +655,6 @@ def test_md_ligparam(self): }, _SBE.SETTINGS_ADDITIONAL: {}, }, - _SBE.INPUT: { - _SBE.INPUT_GENERIC: [ - { - _SBE.INPUT_SOURCE: "06_grompp_eminim", - _SBE.INPUT_EXTENSION: "tpr", - } - ] - }, }, { _SBE.STEPID: "08_nvt_grompp", @@ -810,18 +797,9 @@ def test_md_ligparam(self): "-nb": "gpu", "-bonded": "gpu", "-pme": "gpu", - "-c": "structure.pdb", }, } }, - _SBE.INPUT: { - _SBE.INPUT_GENERIC: [ - { - _SBE.INPUT_SOURCE: "12_prod_md_grompp", - _SBE.INPUT_EXTENSION: "tpr", - } - ] - }, _SBE.WRITEOUT: [ { _SBE.INPUT_GENERIC: {_SBE.WRITEOUT_GENERIC_KEY: "xtc"}, @@ -892,6 +870,46 @@ def test_md_ligparam(self): } ], }, + { + _SBE.STEPID: "15_mmgbsa", + _SBE.STEP_TYPE: "gmx_mmpbsa", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load gmx_MMPBSA/1.4.3-foss-2021a-CUDA-11.3.1" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: ["MPI"] + }, + _SBE.SETTINGS_ADDITIONAL: { + "coupling_groups": "Protein Other", + "pipe_input": "Protein Other", + "forcefield": MAIN_CONFIG["FORCEFIELD"], + "threads": 4, + }, + }, + _SBE.INPUT: { + _SBE.INPUT_GENERIC: [ + { + _SBE.INPUT_SOURCE: "14b_trjconv", + _SBE.INPUT_EXTENSION: "xtc", + }, + { + _SBE.INPUT_SOURCE: "13_prod_mdrun", + _SBE.INPUT_EXTENSION: "tpr", + }, + ] + }, + _SBE.WRITEOUT: [ + { + _SBE.INPUT_GENERIC: {_SBE.WRITEOUT_GENERIC_KEY: "xtc"}, + _SBE.WRITEOUT_DESTINATION: { + _SBE.WRITEOUT_DESTINATION_RESOURCE: "{output_dir}/md_0_1_trjconv.xtc", + _SBE.STEP_TYPE: "file", + _SBE.WRITEOUT_DESTINATION_FORMAT: "TXT", + }, + } + ], + }, ], } @@ -899,10 +917,800 @@ def test_md_ligparam(self): wflow = WorkFlow(**conf) wflow.initialize() - self.assertEqual(len(wflow.steps), 14) + self.assertEqual(len(wflow.steps), 15) wflow.execute() out_path = os.path.join(self._test_dir, "md_0_1_0.xtc") stat_inf = os.stat(out_path) self.assertGreater(stat_inf.st_size, 316516) + + out_path = os.path.join(self._test_dir, "FINAL_RESULTS_MMPBSA_0.dat") + stat_inf = os.stat(out_path) + self.assertGreater(stat_inf.st_size, 5000) + + def test_md_ligparam_dna_construct(self): + """ + End to end gromacs workflow with ligand parametrisation and read-in of external tprs to "overwrite" existing files + Checks both generic file handling and gromacs topol play nicely together + """ + + conf = { + _WE.HEADER: { + _WE.ID: "gromacs_test_ligparam", + _WE.DESCRIPTION: "full md run with gromacs, with ligand parametrisation", + _WE.ENVIRONMENT: { + _WE.ENVIRONMENT_EXPORT: [ + { + _WE.ENVIRONMENT_EXPORT_KEY: "GMX_GPU_DD_COMMS", + _WE.ENVIRONMENT_EXPORT_VALUE: "True", + }, + { + _WE.ENVIRONMENT_EXPORT_KEY: "GMX_GPU_PME_PP_COMMS", + _WE.ENVIRONMENT_EXPORT_VALUE: "True", + }, + { + _WE.ENVIRONMENT_EXPORT_KEY: "GMX_FORCE_UPDATE_DEFAULT_GPU", + _WE.ENVIRONMENT_EXPORT_VALUE: "True", + }, + ] + }, + _WE.GLOBAL_VARIABLES: { + "forcefield": "/gmx_workflow/forcefields/amber14sb_OL15.ff", + "output_dir": attach_root_path("tests/junk/integration"), + "file_base": PATHS_EXAMPLEDATA.GROMACS_PROTEIN_FILE_BASE, + }, + }, + _WE.STEPS: [ + { + _SBE.STEPID: "01_pdb2gmx", + _SBE.STEP_TYPE: "pdb2gmx", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2020.3-fosscuda-2019a" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: ["-ignh"], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: { + "-water": "tip3p", + "-ff": "amber03", + }, + }, + _SBE.SETTINGS_ADDITIONAL: {_SGE.CHARGE_METHOD: "gas"}, + }, + _SBE.INPUT: { + _SBE.INPUT_GENERIC: [ + { + _SBE.INPUT_SOURCE: attach_root_path( + PATHS_EXAMPLEDATA.GROMACS_DNA_STRUCTURE + ), + _SBE.INPUT_EXTENSION: "pdb", + } + ] + }, + }, + { + _SBE.STEPID: "02_editconf", + _SBE.STEP_TYPE: "editconf", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2020.3-fosscuda-2019a" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: [], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: { + "-d": "1.2", + "-bt": "dodecahedron", + }, + }, + _SBE.SETTINGS_ADDITIONAL: {}, + }, + _SBE.INPUT: {}, + }, + { + _SBE.STEPID: "03_solvate", + _SBE.STEP_TYPE: "solvate", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2020.3-fosscuda-2019a" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: [], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: {"-cs": "spc216"}, + }, + _SBE.SETTINGS_ADDITIONAL: {}, + }, + }, + { + _SBE.STEPID: "04_grompp", + _SBE.STEP_TYPE: "grompp", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2020.3-fosscuda-2019a" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: [], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: {}, + }, + _SBE.SETTINGS_ADDITIONAL: { + "-r": False, + }, + }, + _SBE.INPUT: { + _SBE.INPUT_GENERIC: [ + { + _SBE.INPUT_SOURCE: "{file_base}/ions.mdp", + _SBE.INPUT_EXTENSION: "mdp", + }, + ] + }, + }, + { + _SBE.STEPID: "05_genion", + _SBE.STEP_TYPE: "genion", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2020.3-fosscuda-2019a" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: ["-neutral"], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: { + "-pname": "NA", + "-nname": "CL", + }, + }, + _SBE.SETTINGS_ADDITIONAL: { + "pipe_input": "SOL", + }, + }, + }, + { + _SBE.STEPID: "06_grompp_eminim", + _SBE.STEP_TYPE: "grompp", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2020.3-fosscuda-2019a" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: [], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: {"-maxwarn": 50}, + }, + _SBE.SETTINGS_ADDITIONAL: { + "-r": False, + }, + }, + _SBE.INPUT: { + _SBE.INPUT_GENERIC: [ + { + _SBE.INPUT_SOURCE: "{file_base}/minim.mdp", + _SBE.INPUT_EXTENSION: "mdp", + }, + ] + }, + }, + { + _SBE.STEPID: "07_eminim_mdrun", + _SBE.STEP_TYPE: "mdrun", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2020.3-fosscuda-2019a" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: [], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: {}, + }, + _SBE.SETTINGS_ADDITIONAL: {}, + }, + }, + { + _SBE.STEPID: "08_nvt_grompp", + _SBE.STEP_TYPE: "grompp", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2020.3-fosscuda-2019a" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: [], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: {"-n": "index.ndx"}, + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: {"-n": "index.ndx"}, + }, + _SBE.SETTINGS_ADDITIONAL: { + "-r": True, + "make_ndx_command": "auto", + }, + }, + _SBE.INPUT: { + _SBE.INPUT_GENERIC: [ + { + _SBE.INPUT_SOURCE: "{file_base}/nvt_equil.mdp", + _SBE.INPUT_EXTENSION: "mdp", + }, + ] + }, + }, + { + _SBE.STEPID: "09_nvt_mdrun", + _SBE.STEP_TYPE: "mdrun", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2020.3-fosscuda-2019a" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: [], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: {}, + }, + _SBE.SETTINGS_ADDITIONAL: {}, + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: {}, + }, + _SBE.SETTINGS_ADDITIONAL: {}, + _SBE.INPUT: { + _SBE.INPUT_GENERIC: [ + { + _SBE.INPUT_SOURCE: "08_nvt_grompp", + _SBE.INPUT_EXTENSION: "tpr", + } + ] + }, + }, + { + _SBE.STEPID: "10_npt_grompp", + _SBE.STEP_TYPE: "grompp", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2020.3-fosscuda-2019a" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: [], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: {"-n": "index.ndx"}, + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: {"-n": "index.ndx"}, + }, + _SBE.SETTINGS_ADDITIONAL: { + "-r": True, + "make_ndx_command": "auto", + }, + }, + _SBE.INPUT: { + _SBE.INPUT_GENERIC: [ + { + _SBE.INPUT_SOURCE: "{file_base}/npt_equil.mdp", + _SBE.INPUT_EXTENSION: "mdp", + }, + ] + }, + }, + { + _SBE.STEPID: "11_npt_mdrun", + _SBE.STEP_TYPE: "mdrun", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2020.3-fosscuda-2019a" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: [], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: {}, + }, + _SBE.SETTINGS_ADDITIONAL: {}, + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: {}, + _SBE.SETTINGS_ADDITIONAL: {}, + }, + _SBE.INPUT: { + _SBE.INPUT_GENERIC: [ + { + _SBE.INPUT_SOURCE: "10_npt_grompp", + _SBE.INPUT_EXTENSION: "tpr", + } + ] + }, + }, + { + _SBE.STEPID: "12_prod_md_grompp", + _SBE.STEP_TYPE: "grompp", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2020.3-fosscuda-2019a" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: [], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: { + "-n": "index.ndx", + }, + }, + _SBE.SETTINGS_ADDITIONAL: { + "-r": False, + "fields": {"nsteps": "5000"}, + "make_ndx_command": "auto", + }, + }, + _SBE.INPUT: { + _SBE.INPUT_GENERIC: [ + { + _SBE.INPUT_SOURCE: "{file_base}/md.mdp", + _SBE.INPUT_EXTENSION: "mdp", + }, + ] + }, + }, + { + _SBE.STEPID: "13_prod_mdrun", + _SBE.STEP_TYPE: "mdrun", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2020.3-fosscuda-2019a" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: [], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: { + "-nb": "gpu", + "-bonded": "gpu", + "-pme": "gpu", + }, + } + }, + _SBE.WRITEOUT: [ + { + _SBE.INPUT_GENERIC: {_SBE.WRITEOUT_GENERIC_KEY: "xtc"}, + _SBE.WRITEOUT_DESTINATION: { + _SBE.WRITEOUT_DESTINATION_RESOURCE: "{output_dir}/md_0_1.xtc", + _SBE.STEP_TYPE: "file", + _SBE.WRITEOUT_DESTINATION_FORMAT: "TXT", + }, + }, + { + _SBE.INPUT_GENERIC: {_SBE.WRITEOUT_GENERIC_KEY: "log"}, + _SBE.WRITEOUT_DESTINATION: { + _SBE.WRITEOUT_DESTINATION_RESOURCE: "{output_dir}/md_0_1.log", + _SBE.STEP_TYPE: "file", + _SBE.WRITEOUT_DESTINATION_FORMAT: "TXT", + }, + }, + { + _SBE.INPUT_GENERIC: {_SBE.WRITEOUT_GENERIC_KEY: "gro"}, + _SBE.WRITEOUT_DESTINATION: { + _SBE.WRITEOUT_DESTINATION_RESOURCE: "{output_dir}/md_0_1.gro", + _SBE.STEP_TYPE: "file", + _SBE.WRITEOUT_DESTINATION_FORMAT: "TXT", + }, + }, + { + _SBE.INPUT_GENERIC: {_SBE.WRITEOUT_GENERIC_KEY: "tpr"}, + _SBE.WRITEOUT_DESTINATION: { + _SBE.WRITEOUT_DESTINATION_RESOURCE: "{output_dir}/md_0_1.tpr", + _SBE.STEP_TYPE: "file", + _SBE.WRITEOUT_DESTINATION_FORMAT: "TXT", + }, + }, + ], + }, + { + _SBE.STEPID: "14_trjconv", + _SBE.STEP_TYPE: "trjconv", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2020.3-fosscuda-2019a" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: ["-center"] + }, + _SBE.SETTINGS_ADDITIONAL: {"pipe_input": "echo -ne 1 0"}, + }, + _SBE.INPUT: { + _SBE.INPUT_GENERIC: [ + { + _SBE.INPUT_SOURCE: "13_prod_mdrun", + _SBE.INPUT_EXTENSION: "xtc", + }, + { + _SBE.INPUT_SOURCE: "13_prod_mdrun", + _SBE.INPUT_EXTENSION: "tpr", + }, + ] + }, + _SBE.WRITEOUT: [ + { + _SBE.INPUT_GENERIC: {_SBE.WRITEOUT_GENERIC_KEY: "xtc"}, + _SBE.WRITEOUT_DESTINATION: { + _SBE.WRITEOUT_DESTINATION_RESOURCE: "{output_dir}/md_0_1_trjconv.xtc", + _SBE.STEP_TYPE: "file", + _SBE.WRITEOUT_DESTINATION_FORMAT: "TXT", + }, + } + ], + }, + ], + } + + export_unit_test_env_vars() + wflow = WorkFlow(**conf) + wflow.initialize() + + self.assertEqual(len(wflow.steps), 14) + + wflow.execute() + + out_path = os.path.join(self._test_dir, "md_0_1_0.xtc") + stat_inf = os.stat(out_path) + self.assertGreater(stat_inf.st_size, 44700) + + def test_md_ligparam_mmgbsa_hrex(self): + """ + End to end gromacs workflow with ligand parametrisation and read-in of external tprs to "overwrite" existing files + Checks both generic file handling and gromacs topol play nicely together + """ + + conf = { + _WE.HEADER: { + _WE.ID: "gromacs_test_ligparam", + _WE.DESCRIPTION: "full md run with gromacs, with ligand parametrisation", + _WE.ENVIRONMENT: { + _WE.ENVIRONMENT_EXPORT: [ + { + _WE.ENVIRONMENT_EXPORT_KEY: "GMX_GPU_DD_COMMS", + _WE.ENVIRONMENT_EXPORT_VALUE: "True", + }, + { + _WE.ENVIRONMENT_EXPORT_KEY: "GMX_GPU_PME_PP_COMMS", + _WE.ENVIRONMENT_EXPORT_VALUE: "True", + }, + { + _WE.ENVIRONMENT_EXPORT_KEY: "GMX_FORCE_UPDATE_DEFAULT_GPU", + _WE.ENVIRONMENT_EXPORT_VALUE: "True", + }, + ] + }, + _WE.GLOBAL_VARIABLES: { + "forcefield": "/gmx_workflow/forcefields/amber14sb_OL15.ff", + "output_dir": attach_root_path("tests/junk/integration"), + "file_base": PATHS_EXAMPLEDATA.GROMACS_PROTEIN_FILE_BASE, + }, + }, + _WE.STEPS: [ + { + _SBE.STEPID: "01_pdb2gmx", + _SBE.STEP_TYPE: "pdb2gmx", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2020.3-fosscuda-2019a" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: ["-ignh"], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: { + "-water": "tip3p", + "-ff": "amber03", + }, + }, + _SBE.SETTINGS_ADDITIONAL: {_SGE.CHARGE_METHOD: "gas"}, + }, + _SBE.INPUT: { + _SBE.INPUT_GENERIC: [ + { + _SBE.INPUT_SOURCE: attach_root_path( + PATHS_EXAMPLEDATA.GROMACS_HOLO_STRUCTURE + ), + _SBE.INPUT_EXTENSION: "pdb", + } + ] + }, + }, + { + _SBE.STEPID: "02_editconf", + _SBE.STEP_TYPE: "editconf", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2020.3-fosscuda-2019a" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: [], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: { + "-d": "1.2", + "-bt": "dodecahedron", + }, + }, + _SBE.SETTINGS_ADDITIONAL: {}, + }, + _SBE.INPUT: {}, + }, + { + _SBE.STEPID: "03_solvate", + _SBE.STEP_TYPE: "solvate", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2020.3-fosscuda-2019a" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: [], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: {"-cs": "spc216"}, + }, + _SBE.SETTINGS_ADDITIONAL: {}, + }, + }, + { + _SBE.STEPID: "04_grompp", + _SBE.STEP_TYPE: "grompp", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2020.3-fosscuda-2019a" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: [], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: {}, + }, + _SBE.SETTINGS_ADDITIONAL: { + "-r": False, + }, + }, + _SBE.INPUT: { + _SBE.INPUT_GENERIC: [ + { + _SBE.INPUT_SOURCE: "{file_base}/ions.mdp", + _SBE.INPUT_EXTENSION: "mdp", + }, + ] + }, + }, + { + _SBE.STEPID: "05_genion", + _SBE.STEP_TYPE: "genion", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2020.3-fosscuda-2019a" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: ["-neutral"], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: { + "-pname": "NA", + "-nname": "CL", + }, + }, + _SBE.SETTINGS_ADDITIONAL: { + "pipe_input": "SOL", + }, + }, + }, + { + _SBE.STEPID: "06_grompp_eminim", + _SBE.STEP_TYPE: "grompp", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2020.3-fosscuda-2019a" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: [], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: {"-maxwarn": 50}, + }, + _SBE.SETTINGS_ADDITIONAL: {"-r": False, _SGE.REPLICAS: 4}, + }, + _SBE.INPUT: { + _SBE.INPUT_GENERIC: [ + { + _SBE.INPUT_SOURCE: "{file_base}/minim.mdp", + _SBE.INPUT_EXTENSION: "mdp", + }, + ] + }, + }, + { + _SBE.STEPID: "07_eminim_mdrun", + _SBE.STEP_TYPE: "mdrun", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2020.3-fosscuda-2019a", + _SBE.EXEC_RESOURCES: {_SBE.EXEC_RESOURCES_TASKS: 4}, + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: [], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: {}, + }, + _SBE.SETTINGS_ADDITIONAL: {_SGE.MULTIDIR: True}, + }, + }, + { + _SBE.STEPID: "08_nvt_grompp", + _SBE.STEP_TYPE: "grompp", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2020.3-fosscuda-2019a" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: [], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: {"-n": "index.ndx"}, + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: {"-n": "index.ndx"}, + }, + _SBE.SETTINGS_ADDITIONAL: { + "-r": True, + "make_ndx_command": "auto", + _SGE.REPLICAS: 4, + }, + }, + _SBE.INPUT: { + _SBE.INPUT_GENERIC: [ + { + _SBE.INPUT_SOURCE: "{file_base}/nvt_equil.mdp", + _SBE.INPUT_EXTENSION: "mdp", + }, + ] + }, + }, + { + _SBE.STEPID: "09_nvt_mdrun", + _SBE.STEP_TYPE: "mdrun", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2020.3-fosscuda-2019a", + _SBE.EXEC_RESOURCES: {_SBE.EXEC_RESOURCES_TASKS: 4}, + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: [], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: {}, + }, + _SBE.SETTINGS_ADDITIONAL: {}, + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: {}, + }, + _SBE.SETTINGS_ADDITIONAL: {_SGE.MULTIDIR: True}, + _SBE.INPUT: { + _SBE.INPUT_GENERIC: [ + { + _SBE.INPUT_SOURCE: "08_nvt_grompp", + _SBE.INPUT_EXTENSION: "tpr", + } + ] + }, + }, + { + _SBE.STEPID: "10_npt_grompp", + _SBE.STEP_TYPE: "grompp", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2020.3-fosscuda-2019a" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: [], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: {"-n": "index.ndx"}, + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: {"-n": "index.ndx"}, + }, + _SBE.SETTINGS_ADDITIONAL: { + "-r": True, + "make_ndx_command": "auto", + _SGE.REPLICAS: 4, + }, + }, + _SBE.INPUT: { + _SBE.INPUT_GENERIC: [ + { + _SBE.INPUT_SOURCE: "{file_base}/npt_equil.mdp", + _SBE.INPUT_EXTENSION: "mdp", + }, + ] + }, + }, + { + _SBE.STEPID: "11_npt_mdrun", + _SBE.STEP_TYPE: "mdrun", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2020.3-fosscuda-2019a", + _SBE.EXEC_RESOURCES: {_SBE.EXEC_RESOURCES_TASKS: 4}, + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: [], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: {}, + }, + _SBE.SETTINGS_ADDITIONAL: {}, + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: {}, + _SBE.SETTINGS_ADDITIONAL: {_SGE.MULTIDIR: True}, + }, + _SBE.INPUT: { + _SBE.INPUT_GENERIC: [ + { + _SBE.INPUT_SOURCE: "10_npt_grompp", + _SBE.INPUT_EXTENSION: "tpr", + } + ] + }, + }, + { + _SBE.STEPID: "12_prod_md_grompp", + _SBE.STEP_TYPE: "grompp", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2020.3-fosscuda-2019a" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: [], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: { + "-n": "index.ndx", + }, + }, + _SBE.SETTINGS_ADDITIONAL: { + "-r": False, + "fields": {"nsteps": "5000"}, + "make_ndx_command": "auto", + _SGE.REPLICAS: 4, + }, + }, + _SBE.INPUT: { + _SBE.INPUT_GENERIC: [ + { + _SBE.INPUT_SOURCE: "{file_base}/md.mdp", + _SBE.INPUT_EXTENSION: "mdp", + }, + ] + }, + }, + { + _SBE.STEPID: "13_prod_mdrun", + _SBE.STEP_TYPE: "mdrun", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2020.3-fosscuda-2019a", + _SBE.EXEC_RESOURCES: {_SBE.EXEC_RESOURCES_TASKS: 4}, + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: [], + _SBE.SETTINGS_ARGUMENTS_PARAMETERS: { + "-nb": "gpu", + "-bonded": "gpu", + "-pme": "gpu", + }, + }, + _SBE.SETTINGS_ADDITIONAL: {_SGE.MULTIDIR: True}, + }, + }, + { + _SBE.STEPID: "14_trjconv", + _SBE.STEP_TYPE: "trjconv", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load GROMACS/2020.3-fosscuda-2019a" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: { + _SBE.SETTINGS_ARGUMENTS_FLAGS: ["-center"] + }, + _SBE.SETTINGS_ADDITIONAL: {"pipe_input": "echo -ne 1 0"}, + }, + _SBE.WRITEOUT: [ + { + _SBE.INPUT_GENERIC: {_SBE.WRITEOUT_GENERIC_KEY: "xtc"}, + _SBE.WRITEOUT_DESTINATION: { + _SBE.WRITEOUT_DESTINATION_RESOURCE: "{output_dir}/md_0_1_trjconv.xtc", + _SBE.STEP_TYPE: "file", + _SBE.WRITEOUT_DESTINATION_FORMAT: "TXT", + }, + } + ], + }, + { + _SBE.STEPID: "15_mmgbsa", + _SBE.STEP_TYPE: "gmx_mmpbsa", + _SBE.EXEC: { + _SBE.EXEC_PREFIXEXECUTION: "module load gmx_MMPBSA/1.4.3-foss-2021a-CUDA-11.3.1" + }, + _SBE.SETTINGS: { + _SBE.SETTINGS_ARGUMENTS: {_SBE.SETTINGS_ARGUMENTS_FLAGS: []}, + _SBE.SETTINGS_ADDITIONAL: { + "coupling_groups": "Protein Other", + "pipe_input": "Protein Other", + }, + }, + _SBE.WRITEOUT: [ + { + _SBE.INPUT_GENERIC: {_SBE.WRITEOUT_GENERIC_KEY: "dat"}, + _SBE.WRITEOUT_DESTINATION: { + _SBE.WRITEOUT_DESTINATION_RESOURCE: "{output_dir}/scores.dat", + }, + } + ], + }, + ], + } + + export_unit_test_env_vars() + wflow = WorkFlow(**conf) + wflow.initialize() + + self.assertEqual(len(wflow.steps), 15) + + wflow.execute() + + out_path = os.path.join(self._test_dir, "scores.dat") + stat_inf = os.stat(out_path) + self.assertGreater(stat_inf.st_size, 44700) diff --git a/tests/tests_paths.py b/tests/tests_paths.py index 5334bd5..be59239 100644 --- a/tests/tests_paths.py +++ b/tests/tests_paths.py @@ -119,6 +119,7 @@ class PATHS_EXAMPLEDATA: GROMACS_IONS_MDP = expand_path("gromacs/protein/ions.mdp") GROMACS_MD_MDP = expand_path("gromacs/protein/md.mdp") GROMACS_HOLO_STRUCTURE = expand_path("gromacs/protein/1BVG.pdb") + GROMACS_DNA_STRUCTURE = expand_path("gromacs/cccc.pdb") GROMACS_HOLO_STRUCTURE_GRO = expand_path("gromacs/protein/1BVG.gro") GROMACS_DMP_LIGAND_TRJ = expand_path("gromacs/protein/DMP.xtc") GROMACS_DMP_LIGAND_SDF = expand_path("gromacs/protein/DMP.sdf")