"""
FUNCTIONLIB: wrapper for gromos++
Description:
This file contains python wrappers for the bash commandline of gromos++
Author: Benjamin Schroeder
"""
import os
import pandas as pd
from pygromos.data import pdb_lib
from pygromos.gromos.gromosBashSyntaxParser import gromosBashSyntaxParser
from pygromos.gromos._gromosClass import _gromosClass
from pygromos.utils import bash
from pygromos.utils.typing import Union, List, Tuple, Number
[docs]class _gromosPPbase(_gromosClass):
"""
GromosPP
This is the gromosPP baseclass.
This should be inherited by a concrete class that might reimplement some new features, that are version dependent.
Attributes:
-----------
bin : str, optional
This is the path to the folder containing the binaries of gromosPP. If None, the bash enviroment variables will be used.
"""
_isValid: bool = False
[docs] def __init__(
self, gromosPP_bin_dir: Union[str, None] = None, _check_binary_paths: bool = True, verbose: bool = False
):
"""
Constructing a gromosPP object.
Parameters
----------
bin : Union[str, None], optional
This is the path to the folder containing the binaries of gromosXX. If None, the bash enviroment variables will be used.
_dont_check_binary : bool, optional
This flag removes the checks of the binary presence for this obj. This can make sense if system access is slow!, by default False - checks will be made
"""
# lazy me - doc text for functions:
functions_text = "\n Methods:\n ---------\n" + "\n".join(
["\t\t" + x for x in dir(self) if (not x.startswith("_") and callable(getattr(self, x)))]
)
self.__doc__ = self.__doc__ + functions_text
super().__init__(
in_bin_dir=gromosPP_bin_dir, _check_binary_paths=_check_binary_paths
) # initialises the binary checks
def __str__(self):
return self.__doc__
def __repr__(self):
return self.__str__()
"""
GromosPP Programms
"""
[docs] @_gromosClass._gromosTypeConverter
def amber2gromos(
self,
ambertop: str,
solvent: str,
ljscaling: float = 2.0,
chargegroups: str = None,
atomic_chargegroups: bool = False,
out_path: str = "topology.top",
_binary_name: str = "amber2gromos",
verbose: bool = False,
):
"""
Parameters
----------
ambertop : str
path to AMBER molecular topology file
solvent : str
path to GROMOS topology file with solvent
ljscaling : float, optional
scaling factor for LJ parameters (default: 2.0)
atomic_chargegroups : bool, optional
assign each atom to its own chargegroup (default: False)
chargegroups : str, optional
path to chargegroup file
_binary_name : str, otpional
binary name of gromosPP programm (default: amber2gromos)
Returns
-------
str
converted GROMOS topology
"""
additional_options = [""]
if ljscaling is not None:
additional_options += [" @ljscaling ", str(ljscaling)]
if atomic_chargegroups is not None:
additional_options += [" @atomic_chargegroups ", str(int(atomic_chargegroups))]
if chargegroups is not None:
additional_options += [" @chargegroups ", chargegroups]
additional_options = " ".join(map(str, additional_options))
command = [self._bin + _binary_name, " @ambertop ", ambertop, "@solvent", solvent, additional_options, " \n"]
if verbose:
print(command)
bash.execute(command, catch_STD=out_path, verbose=verbose)
[docs] @_gromosClass._gromosTypeConverter
def pdb2gromos(
self,
in_pdb_path: str,
in_top_path: str,
out_cnf_path: str = None,
in_lib_path: str = pdb_lib,
_binary_name: str = "pdb2g96",
verbose: bool = False,
) -> str:
"""
This is a wrapper for pdb2gromos. It executes the gromosPP binary.
Parameters
----------
in_pdb_path : str
in_top_path : str
in_lib_path : str, optional
The lib can be used as a look up table for residues or atoms etc. - see gromos manual
out_cnf_path : str, optional
The out_cnf is the path for the output file. if not given, the pdb basename and dir is taken as default.
_binary_name : str, optional
verbose : bool, optional
Returns
-------
str
Returns out_cnf path
See Also
--------
For more information checkout the Gromos Manual
"""
if out_cnf_path is None:
out_cnf_path = str(os.path.splitext(os.path.basename(in_pdb_path))[0]) + ".cnf"
if not out_cnf_path.endswith(".cnf"):
out_cnf_path += ".cnf"
command = self._bin + _binary_name + " @pdb " + in_pdb_path + " @topo " + in_top_path + " @out " + out_cnf_path
if in_lib_path is not None:
command += " @lib " + in_lib_path
command += "\n"
if verbose:
print(command)
p = bash.execute(command, catch_STD=True)
if verbose:
print(p.stdout.readlines())
return out_cnf_path
[docs] @_gromosClass._gromosTypeConverter
def pdb2seq(
self,
in_pdb_path: str,
out_path: str = "",
pH: float = 7.4,
select: str = "ALL",
gff: str = "54a7",
add_head: str = "NH3+",
add_tail: str = "COO-",
_binary_name: str = "pdb2seq",
) -> str:
"""
This function is translating a pdb into a sequence file, that can be used to generate for example topologies.
Parameters
----------
in_pdb_path : str
out_path : str, optional
out_path for output File
pH : float, optional
select : str, optional
gff : str,optional
which Gromos ForceField
add_head : str, optional
protein N-term capping with this group.
add_tail : str,optional
protein C-term capping with this group
_binary : str, optional
Returns
-------
str
out_path
See Also
--------
For more information checkout the Gromos Manual
"""
if out_path == "":
out_path = (
os.path.dirname(in_pdb_path) + "/" + str(os.path.splitext(os.path.basename(in_pdb_path))[0]) + ".seq"
)
command = (
self._bin
+ _binary_name
+ " @develop @pdb "
+ in_pdb_path
+ " @pH "
+ str(pH)
+ " @select "
+ select
+ " @gff "
+ gff
)
if add_head != "":
command += " @head " + add_head
if add_tail != "":
command += " @tail " + add_tail
command += " > " + out_path + " \n"
bash.execute(command)
return out_path
[docs] @_gromosClass._gromosTypeConverter
def make_top(
self,
out_top_path: str,
in_building_block_lib_path: str,
in_parameter_lib_path: str,
in_sequence: str,
in_solvent: str = "H2O",
_binary_name: str = "make_top",
) -> str:
"""
This wrapper uses make_top to generate a topology file.
Parameters
----------
out_top_path : str
in_building_block_lib_path : str
in_parameter_lib_path : str
in_sequence : str
in_solvent : str, optional
additional_options : str, optional
Returns
-------
str
returns out_file_path
See Also
--------
For more information checkout the Gromos Manual
"""
if os.path.exists(in_sequence):
seq_file = open(in_sequence, "r")
in_sequence = "".join(seq_file.readlines())
args = [
"@build " + in_building_block_lib_path,
"@param " + in_parameter_lib_path,
"@seq " + in_sequence,
"@solv " + in_solvent,
]
# arg_path = os.path.dirname(out_top_path) + "/topargs.arg"
# arg_file = open(arg_path, "w")
# arg_file.write("\n".join(args))
# arg_file.close()
# "@f " + arg_path
command = self._bin + _binary_name + " " + " ".join(args)
bash.execute(command, catch_STD=out_top_path)
return out_top_path
[docs] @_gromosClass._gromosTypeConverter
def com_top(
self,
in_topo_paths: Union[str, List[str]],
topo_multiplier: Union[int, List[int]] = 1,
out_top_path: str = "combined_out.top",
take_topology_params_of_file: int = 1,
take_solvent_parameters_of_file: int = 1,
_binary_name: str = "com_top",
) -> str: # Todo: also take lists as input ! bschroed
"""
Combine multiple topologies
Parameters
----------
in_topo_paths : (str or List[str])
out_top_path : str, optional
take_topology_params_of_file : int, optional
take_solvent_parameters_of_file : int, optional
_binary_name : str, optional
Returns
-------
str
output file_path
See Also
--------
make_top
For more information checkout the Gromos Manual
"""
if len(in_topo_paths) == 1 and type(in_topo_paths[0]) == list:
in_topo_paths = in_topo_paths[0]
if not out_top_path.endswith(".top"):
out_top_path += ".top"
if isinstance(in_topo_paths, list) and isinstance(topo_multiplier, int):
topo_multiplier = [topo_multiplier for x in range(len(in_topo_paths))]
topo_argument = gromosBashSyntaxParser.multiplyArgumentParser(in_topo_paths, topo_multiplier)
command = (
self._bin
+ _binary_name
+ " @topo "
+ topo_argument
+ " @param "
+ str(take_topology_params_of_file)
+ " @solv "
+ str(take_solvent_parameters_of_file)
)
bash.execute(command, catch_STD=out_top_path)
return out_top_path
[docs] @_gromosClass._gromosTypeConverter
def dfmult(
self,
in_endstate_file_paths: List[str],
in_reference_state_file_path: str,
out_file_path: str = "dfmult_temp.out",
temperature: float = 298,
_binary_name: str = "dfmult",
verbose: bool = False,
) -> str:
"""
This funciton wraps dfmult of the gromos suite, it is used to calculate the free energy of a EDS simulation.
Parameters
----------
in_endstate_file_paths : List[str]
potentials energy of single state (get with ene Ana)
in_reference_state_file_path : str
potential energy of reference State (get with ene Ana)
out_file_path : str, optional
temperature : float, optional
_binary_name : str, optional
verbose : bool, optional
Returns
-------
str
out_put file path
See Also
--------
For more information checkout the Gromos Manual
"""
# formulate command
if verbose:
print(" ".join(in_endstate_file_paths))
command = (
self._bin
+ _binary_name
+ " @stateR "
+ in_reference_state_file_path
+ " @temp "
+ str(temperature)
+ " @endstates "
+ " ".join(in_endstate_file_paths)
+ " > "
+ out_file_path
+ "\n"
)
if verbose:
print(command)
# do
ret = bash.execute_os(command, verbose=verbose)
if verbose:
print(ret.readlines())
bash.wait_for_fileSystem(out_file_path)
return out_file_path
[docs] @_gromosClass._gromosTypeConverter
def frameout(
self,
in_top_path: str,
in_coord_path: str,
periodic_boundary_condition: str,
out_file_path: str = None,
out_file_format: str = None,
single_file: bool = None,
gather: Union[int, str] = None,
include: str = "SOLUTE",
reference_structure_path: str = None,
atomsfit: str = None,
frames: int = None,
time: int = None,
dt: int = None,
notimeblock: bool = None,
_binary_name: str = "frameout",
verbose: bool = False,
) -> str:
"""
this wrapper wraps frameout.
frameout is a tool, that can be used for example to convert gromos coordinate files or to recenter them or ....
Optional parameters are not used in the command, when they are None!
Parameters
----------
in_top_path : str
in_coord_path : str
periodic_boundary_condition : str
out_file_path : None or str, optional
out_file_format : None or str, optional
single_file : None or bool, optional
gather : None or int or str optional
include : None or str, optional
ALL that also includes the solvent.
SOLUTE this option filters the Solvent out of the output file. (default)
alternative gromos selection synthax can be used.
reference_structure_path : None or str, optional
This path should provide a refrence position for atom fitting.
atomsfit : None or str, optional
This option can be used to fit all frames to one reference structure.
The selection Syntax follow the Gromos manual (e.g. "1:a" - aligns all frames to the first molecule and all its atoms)
requires reference_sturcture_path.
frames : None or int, optional
time : None or float, optional
dt : None or float, optional
notimeblock : None or bool, optional
_binary_name : str, optional
verbose : bool, optional
Returns
-------
str
out_file_path
See Also
--------
For more information checkout the Gromos Manual
"""
options = ""
if out_file_format is not None:
options += "@outformat " + str(out_file_format) + " "
periodic_boundary_condition = "@pbc " + periodic_boundary_condition + " "
if gather is not None:
periodic_boundary_condition += " " + str(gather) + " "
if include is not None:
options += "@include " + str(include) + " "
if single_file is not None:
options += "@single "
if atomsfit is not None and reference_structure_path is not None:
options += "@ref " + str(reference_structure_path) + " @atomsfit " + atomsfit + " "
if not isinstance(time, type(None)):
options += "@time " + str(time) + " "
if not isinstance(time, type(None)) and not isinstance(dt, type(None)):
options += " " + str(dt) + " "
if notimeblock:
options += "@time " + str(0)
if frames is not None:
raise NotImplementedError("Chosen Options for frameout not implemented yet!")
if out_file_path is not None:
orig = os.getcwd() + "/FRAME_00001." + out_file_format
else:
orig = os.getcwd() + "/FRAME* "
if not isinstance(out_file_format, type(None)):
out_file_path = os.path.dirname(in_coord_path) + "/FRAME_00001." + out_file_format
else:
out_file_path = os.path.dirname(in_coord_path) + "/FRAME_00001." + in_coord_path.split(".")[-1]
command = (
self._bin
+ _binary_name
+ " @topo "
+ str(in_top_path)
+ " @traj "
+ str(in_coord_path)
+ " "
+ periodic_boundary_condition
+ " "
+ options
)
if verbose:
print("gromosPP.frameout: command:\n" + command)
# DO
try:
ret = bash.execute(command, catch_STD=True)
if verbose:
print("STDOUT: ", "\n".join(ret.stdout.readlines()))
except Exception as err:
print("gromosPP.frameout: could not exectue framout:\n" + str(err.args))
raise Exception("gromosPP.frameout: could not exectue framout:\n" + str(err.args))
bash.wait_for_fileSystem(check_paths=orig, regex_mode=True)
# move to output
try:
bash.move_file(orig, out_file_path)
except Exception as err:
print("gromosPP.frameout: could not move new FRAME*.pdb file to out-parameter:\n" + str(err.args))
raise Exception("gromosPP.frameout: could not move new FRAME*.pdb file to out-parameter:\n" + str(err.args))
return out_file_path
[docs] @_gromosClass._gromosTypeConverter
def ene_ana(
self,
in_ene_ana_library_path: str,
in_en_file_paths: str,
in_properties: str,
out_energy_folder_path: str,
out_files_prefix: str = None,
out_files_suffix: str = None,
in_topo: str = None,
time: float = None,
single_file: bool = False,
return_outstat_also: bool = False,
verbose: bool = False,
_binary_name: str = "ene_ana",
workdir: bool = False,
) -> Union[List[str], str]:
"""
This is a wrapper for ene_ana.
ene_ana is a tool to extract energy properties from a x.tre file.
Parameters
----------
in_ene_ana_library_path : str
in_en_file_paths : str
in_properties : str
this str should name the properties, that shall be written out. For the variable names, check the ene_ana lib.
(e.g.: "solvtemp1 e1 eR")
out_energy_folder_path : str
give the path to an directory, where the output should be stored in.
out_files_prefix : None or str, optional
out_files_suffix : None or str, optional
in_topo : None or str, optional
time : None or float, optional
single_file: bool, optional
if used a single csv is generated. the return value gets the file_path(str).
verbose : bool, optional
_binary_name : str, optional
Returns
-------
List[str] or str
if single_file used, return = str
"""
# check input
if type(in_properties) == list:
in_properties = " ".join(in_properties)
elif type(in_properties) == str:
pass
else:
raise IOError(
"gromosPP.ene_ana: got an format for potentials, that is unknown! (Please give a list of strings or a final string)\n"
+ str(in_properties)
)
if isinstance(in_en_file_paths, list):
in_en_file_paths = " ".join(in_en_file_paths)
elif isinstance(in_en_file_paths, str):
pass
else:
raise IOError(
"gromosPP.ene_ana: got an format for potentials, that is unknown! (Please give a list of strings or a final string)\n"
+ str(in_en_file_paths)
)
# manage nice prefix
if out_files_prefix:
prefix = out_files_prefix
else:
prefix = ""
# manage nice suffix
if out_files_suffix:
if not out_files_suffix.startswith("_") and not out_files_prefix.endswith("_"):
suffix = "_" + out_files_suffix
else:
suffix = out_files_suffix
else:
suffix = ""
additional_options = ""
if in_topo:
additional_options += " @topo " + str(in_topo)
if not isinstance(time, type(None)):
additional_options += " @time " + str(time)
original_pos = os.getcwd()
if not workdir:
os.chdir(out_energy_folder_path)
if in_en_file_paths.strip().endswith("trg") or in_en_file_paths.strip().endswith("trg.gz"):
in_file_form = "@fr_files"
else:
in_file_form = "@en_files"
# ene_ana command and log deletion if ene_ana was successfull.:
command = (
self._bin
+ _binary_name
+ " @library "
+ str(in_ene_ana_library_path)
+ " "
+ in_file_form
+ " "
+ str(in_en_file_paths)
+ " @prop "
+ in_properties
+ " "
+ additional_options
)
if verbose:
print("Isolate_energies")
try:
out_fun = bash.execute(command, verbose=verbose)
except Exception as err:
raise Exception(
"gromosPP.ene_ana: could not read out energies:\n" + "\n".join(err.args) + "\n command used: " + command
)
# Wait for file system.
tmp_files = []
for prop in in_properties.split():
check_path = str(os.getcwd() + "/" + prop + ".dat")
bash.wait_for_fileSystem(check_path, verbose=verbose)
tmp_files.append(check_path)
if not single_file:
try:
# move results to outfolder and give them proper name
result_files = []
if type(in_properties) == str:
in_properties = in_properties.split()
for prop in in_properties:
orig_file = str(os.getcwd() + "/" + prop + ".dat")
target_file = str(out_energy_folder_path + "/" + prefix + prop + suffix + ".dat")
if target_file == orig_file:
pass
else:
bash.move_file(in_file_path=orig_file, out_file_path=target_file)
result_files.append(target_file)
except Exception as err:
raise Exception(
"gromosPP.ene_ana: could not move and rename Files:\n"
+ "\n".join(err.args)
+ "\n before use: "
+ command
)
bash.wait_for_fileSystem(result_files)
else:
if verbose:
print("reading in tmp_files files:\t" + "\n\t".join(tmp_files))
# energy_properties = [pd.read_csv(in_ene_traj_path, header=0, delim_whitespace=True) for in_ene_traj_path in tmp_files]
# fix columns
first = True
for in_ene_traj_path in tmp_files:
energy_property = pd.read_csv(in_ene_traj_path, header=0, delim_whitespace=True)
new_cols = [x.replace("#", "").strip() for x in energy_property.columns if (not x == "#")] + [""]
new_cols = [x if ("time" in x) else x for x in new_cols]
energy_property.columns = new_cols
energy_property.pop("")
if verbose:
print(energy_property.columns)
if verbose:
print(energy_property.shape)
if first:
first = False
concat_energy_traj = energy_property
else:
energy_property.pop("time")
concat_energy_traj = pd.concat([concat_energy_traj, energy_property], axis=1)
del energy_property
tmp_pandas_out = out_energy_folder_path + "/" + prefix + suffix + ".dat"
concat_energy_traj.to_csv(tmp_pandas_out, sep="\t", header=True, index=False)
del concat_energy_traj
# remove old trajs
for x in tmp_files:
if os.path.exists(x):
bash.remove_file(x)
result_files = tmp_pandas_out
if not workdir:
os.chdir(original_pos)
bash.wait_for_fileSystem(result_files)
if return_outstat_also:
return result_files, out_fun
else:
return result_files
[docs] @_gromosClass._gromosTypeConverter
def gch(
self,
in_cnf_path: str,
in_top_path: str,
out_cnf_path: str,
tolerance: float = 0.1,
periodic_boundary_condition: str = "v",
gathering: str = "cog",
_binary_name: str = "gch",
) -> str:
"""
This function adds reasonable hydrogenpositions a coordinate file.
Parameters
----------
in_cnf_path : str
in_top_path : str
out_cnf_path : str
tolerance : float, optional
periodic_boundary_condition : str, optional
gathering : str, optional
_binary_name : str, optional
Returns
-------
out_cnf_path
"""
command = (
self._bin
+ _binary_name
+ " @topo "
+ in_top_path
+ " @pos "
+ in_cnf_path
+ " @tol "
+ str(tolerance)
+ " "
"@pbc " + periodic_boundary_condition + " " + gathering
)
bash.execute(command, catch_STD=out_cnf_path)
return out_cnf_path
[docs] @_gromosClass._gromosTypeConverter
def add_hydrogens(
self,
in_cnf_path: str,
in_top_path: str,
out_cnf_path: str,
tolerance: float = 0.1,
periodic_boundary_condition: str = "v",
gathering: str = "cog",
_binary_name: str = "gch",
) -> str:
"""
This function protonates a coordinate file.
Parameters
----------
in_cnf_path : str
in_top_path : str
out_cnf_path : str
tolerance : float, optional
periodic_boundary_condition : str, optional
gathering : str, optional
_binary_name : str, optional
Returns
-------
out_cnf_path
"""
command = (
self._bin
+ _binary_name
+ " @topo "
+ in_top_path
+ " @pos "
+ in_cnf_path
+ " @tol "
+ str(tolerance)
+ " "
"@pbc " + periodic_boundary_condition + " " + gathering
)
bash.execute(command, catch_STD=out_cnf_path)
return out_cnf_path
[docs] @_gromosClass._gromosTypeConverter
def sim_box(
self,
in_top_path: str,
in_cnf_path: str,
in_solvent_cnf_file_path: str,
out_cnf_path: str = "",
periodic_boundary_condition: str = "r",
gathering_method: str = None,
minwall: float = 0.8,
threshold: float = None,
rotate: str = None,
boxsize: bool = False,
_binary_name: str = "sim_box",
verbose: bool = False,
) -> str:
"""
When simulating a molecule in solution or in a crystal containing solvent
molecules, the atomic coordinates of the solvent molecules are to be
generated, if they are not available from experiment. Program sim_box can
solvate a solute in a pre-equilibrated box of solvent molecules. The file
specifying the solvent configuration should contain a BOX block with the
dimensions corresponding to the pre-equilibrated density. The solvent
topology is read from the solvent block in the specified topology.
Parameters
----------
in_top_path : str
the path to the input topology file (.top)
in_cnf_path : str
the path to the input coordinate file (.cnf), which shall be solvated
in_solvent_cnf_file_path : str
the path to the input coordinate file of the solvent (.cnf), that shall be used to solvate (checkout pygromos.data.solvent_coordinates for templates)
out_cnf_path : str, optional
the path to the resulting coordinate (.cnf) file, by default ""
periodic_boundary_condition : str, optional
describes the boundary condition of the given system in the cnf. (r - rectangle, v - vacuum, ), by default "r"
gathering_method : str, optional
the gathering method to be used, by default None
minwall : float, optional
minimum solute to wall distance, by default 0.8
threshold : float, optional
minimum solvent-solute distance, by default None -> 0.23 nm
rotate : str, optional
rotate solute: biggest axis along z, second along y, by default None
boxsize : bool, optional
use boxsize specified in solute coordinate file, by default False
_binary_name : str, optional
name of the binary, by default "sim_box"
verbose : bool, optional
stay a while and listen!, by default False
Returns
-------
str
return the path to the resulting cnf path.
"""
command_suffix = ""
if out_cnf_path == "":
out_cnf_path = (
os.path.dirname(in_cnf_path)
+ "/"
+ str(os.path.splitext(os.path.basename(in_cnf_path))[0])
+ "_solvent.cnf"
)
if rotate is not None:
command_suffix += " @rotate "
if gathering_method is not None:
command_suffix += " @gather " + str(gathering_method)
if boxsize:
command_suffix += " @boxsize "
if threshold is not None:
command_suffix += " @thresh " + str(threshold)
if minwall is not None:
command_suffix += " @minwall " + str(minwall)
command = (
self._bin
+ _binary_name
+ " @topo "
+ in_top_path
+ " @pbc "
+ periodic_boundary_condition
+ " @pos "
+ in_cnf_path
+ " @solvent "
+ in_solvent_cnf_file_path
+ " "
+ command_suffix
)
p = bash.execute(command, verbose=verbose, catch_STD=out_cnf_path)
if verbose:
print(p.stdout)
print(p.stderr)
return out_cnf_path
[docs] @_gromosClass._gromosTypeConverter
def ran_box(
self,
in_top_path: str,
in_cnf_path: str,
out_cnf_path: str = "",
periodic_boundary_condition: str = "r",
nmolecule: int = 1,
dens: float = 1.0,
threshold: float = None,
layer: bool = False,
boxsize: float = None,
fixfirst: bool = False,
seed: float = None,
_binary_name: str = "ran_box",
verbose: bool = False,
return_command_only: bool = False,
) -> str:
command_suffix = ""
if out_cnf_path == "":
out_cnf_path = (
os.path.dirname(in_cnf_path)
+ "/"
+ str(os.path.splitext(os.path.basename(in_cnf_path))[0])
+ "_ran-box.cnf"
)
if threshold is not None:
command_suffix += " @thresh " + str(threshold)
if layer:
command_suffix += " @layer "
if boxsize is not None:
command_suffix += " @boxsize " + str(boxsize)
if fixfirst:
command_suffix += " @fixfirst "
if seed is not None:
command_suffix += " @seed " + str(seed)
command = (
self._bin
+ _binary_name
+ " @topo "
+ in_top_path
+ " @pbc "
+ periodic_boundary_condition
+ " @pos "
+ in_cnf_path
+ " @nsm "
+ str(nmolecule)
+ " @dens "
+ str(dens)
+ " "
+ command_suffix
+ " > "
+ out_cnf_path
+ " \n"
)
if not return_command_only:
print(command)
bash.execute(command, verbose=verbose)
return out_cnf_path
else:
return command
[docs] @_gromosClass._gromosTypeConverter
def build_box(
self,
in_top_path: str,
in_cnf_path: str,
out_cnf_path: str = "",
periodic_boundary_condition: str = "r",
nmolecule: int = 1,
dens: float = 1.0,
_binary_name: str = "build_box",
verbose: bool = False,
return_command_only: bool = False,
) -> str:
if out_cnf_path == "":
out_cnf_path = (
os.path.dirname(in_cnf_path)
+ "/"
+ str(os.path.splitext(os.path.basename(in_cnf_path))[0])
+ "_ran-box.cnf"
)
command = (
self._bin
+ _binary_name
+ " @topo "
+ in_top_path
+ " @pos "
+ in_cnf_path
+ " @nsm "
+ str(nmolecule)
+ " @dens "
+ str(dens)
+ " > "
+ out_cnf_path
+ " \n"
)
if not return_command_only:
print(command)
bash.execute(command, verbose=verbose)
return out_cnf_path
else:
return command
[docs] @_gromosClass._gromosTypeConverter
def tser(
self,
in_trc_path: str,
in_top_path: str,
out_csv_path: str,
property: str,
periodic_boundary_condition: str = "r",
time: float = None,
solvent: str = None,
normalise_distribution: bool = False,
skip_first_n_frames: int = 0,
take_each_nth_frame: int = 1,
_binary_name: str = "tser",
) -> str:
"""
Tser is a gromos programm, that can analyze trajectories.
Parameters
----------
in_trc_path : str
in_top_path : str
out_csv_path : str
property : str
periodic_boundary_condition : str, optional
time : float, optional
solvent : str, optional
normalise_distribution : bool, optional
skip_first_n_frames : int, optional
take_each_nth_frame : int, optional
_binary_name : str, optional
Warnings
--------
missing options: @nots, @dist
Returns
-------
str
out_csv_path
"""
optional_string = ""
if take_each_nth_frame > 1:
optional_string += " @stride " + str(take_each_nth_frame) + " "
if skip_first_n_frames > 0:
optional_string += " @skip " + str(skip_first_n_frames) + " "
if normalise_distribution:
optional_string += " @norm "
if isinstance(time, type(None)):
optional_string += " @time " + str(time) + " "
if isinstance(solvent, type(None)):
optional_string += " @solv " + str(solvent) + " "
command = (
self._bin
+ _binary_name
+ " @topo "
+ in_top_path
+ " @pbc "
+ periodic_boundary_condition
+ " @traj "
+ in_trc_path
+ ' @prop "'
+ str(property)
+ '" '
+ optional_string
+ " > "
+ out_csv_path
+ " \n"
)
bash.execute(command)
return out_csv_path
[docs] @_gromosClass._gromosTypeConverter
def red_top(self, in_top_path: str, atom_selection: str, out_top_path: str, _binary_name: str = "red_top") -> str:
"""
red_top is a gromos tool to reduce a gromos tool to a certain selection.
Parameters
----------
in_top_path : str
atom_selection : str
out_top_path : str
_binary_name : str, optional
Returns
-------
str
out_top_path
"""
command = [
self._bin + _binary_name,
" @topo ",
in_top_path,
" @atoms",
"'" + atom_selection + "'",
"> " + out_top_path + " \n",
]
bash.execute(command)
return out_top_path
[docs] @_gromosClass._gromosTypeConverter
def prep_eds(
self,
in_top_paths: List[str],
number_of_eds_states: int,
param_top_index: int = 1,
solv_top_index: int = 1,
out_file_path: str = "dev",
_binary_name: str = "prep_eds",
verbose: bool = False,
) -> Tuple[str, str]:
"""
prepare eds topology.
Parameters
----------
in_top_paths : List[str]
number_of_eds_states : int
param_top_index : int, optional
solv_top_index : int, optional
out_file_path : str, optional
output path without file ending. (prefix)
_binary_name : str, optional
verbose : bool, optional
Returns
-------
tuple[str,str]
out_top, out_ptp
"""
out_file_path = os.path.splitext(out_file_path)[0]
if type(in_top_paths) == str:
in_top_paths = [in_top_paths]
if len(in_top_paths) == 0:
raise ValueError("no topos were passed to function. please provide at least two")
command = (
self._bin
+ _binary_name
+ " @topo "
+ " ".join(in_top_paths)
+ " @numstat "
+ str(number_of_eds_states)
+ " @param "
+ str(param_top_index)
+ " @solv "
+ str(solv_top_index)
)
if verbose:
print(command)
ret = bash.execute(command)
if verbose:
print(ret.readlines())
bash.wait_for_fileSystem(["./pert_eds.ptp", "./com_eds.top"])
out_ptp = bash.move_file("./pert_eds.ptp", out_file_path + ".ptp")
out_top = bash.move_file("./com_eds.top", out_file_path + ".top")
return out_top, out_ptp
[docs] @_gromosClass._gromosTypeConverter
def prep_noe(
self,
in_top_path: str,
in_noe_path: str,
in_library_path: str,
out_path: str,
dish: float = 0.1,
disc: float = 0.153,
title: str = "NOE",
_binary_name: str = "prep_noe",
in_correction_path: str = None,
verbose: bool = False,
) -> str:
"""
Parameters
----------
in_top_path: str
molecular topology file
in_noe_path: str
NOE specification file
in_library_path: str
NOE specification library
out_path: str
path to the output file
dish: float, optional
carbon-hydrogen distance; default: 0.1 nm
disc: float, optional
carbon-carbon distance; default: 0.153 nm
title: str, optional
NOE title for output, default: "NOE"
correction: str, optional
Correction file -> <correction_file> [correction type]
Returns
-------
str
path to the output file
NotImplemented
-------
parsetype: <1,2,3>
Choices are:
1: Upper bound == first number
2: Upper bound == first + third number (most common, default)
3: Upper bound == first - second number (commonly the lower bound)
action: <add> or <substraction> = add
filter: discard nNOE's above a certain distance[nm] = 10000 nm
factor: conversion factor ang to nm , = 10
"""
additional_options = ""
if isinstance(in_correction_path, str):
additional_options += "@correction " + in_correction_path + " "
command = (
self._bin
+ _binary_name
+ " @topo "
+ in_top_path
+ " @title "
+ title
+ " @noe "
+ in_noe_path
+ " @lib "
+ in_library_path
+ " "
" @dish " + str(dish) + " @disc " + str(disc) + " " + additional_options + " &> " + out_path
)
if verbose:
print(command)
ret = bash.execute(command)
if verbose:
print(ret.readlines())
return out_path
[docs] @_gromosClass._gromosTypeConverter
def rmsf(
self,
in_top_path: str,
in_trcs: Union[str, List[str]],
atom_selection: str,
out_file_path: str,
pbc: str = "r",
_binary_name: str = "rmsf",
) -> str:
"""
this is a wrapper for gromosPP rmsf programm. (Root mean square fluctuation
Parameters
----------
in_top_path : str
path to topology file
in_trcs : Union[str, List[str]]
Path OR paths to trc coordinate files
atom_selection : str
selection of atoms
out_file_path :
out path.
pbc : str
periodic boundary condition of trc files
_binary_name: str
binary name of gromos file
Returns
-------
str
outpath of the traj
"""
if isinstance(in_trcs, list):
in_trcs = " ".join(in_trcs)
additional_options = [""]
additional_options = " ".join(map(str, additional_options))
command = " ".join(
[
self._bin + _binary_name,
" @topo ",
in_top_path,
" @atomsrmsf",
"'" + atom_selection + "'",
"@pbc",
pbc,
"@traj",
in_trcs,
additional_options,
" \n",
]
)
bash.execute(command, catch_STD=out_file_path)
return out_file_path
[docs] @_gromosClass._gromosTypeConverter
def rmsd(
self,
in_top_path: str,
in_trcs: Union[str, List[str]],
atom_selection: str,
out_file_path: str,
pbc: str = "r",
_binary_name: str = "rmsd",
) -> str:
"""
Parameters
----------
in_top_path
in_trcs
atom_selection
out_file_path
pbc
_binary_name
Returns
-------
"""
if isinstance(in_trcs, list):
in_trcs = " ".join(in_trcs)
additional_options = [""]
additional_options = " ".join(map(str, additional_options))
command = " ".join(
[
self._bin + _binary_name,
" @topo ",
in_top_path,
" @atomsrmsd",
"'" + atom_selection + "'",
"@pbc",
pbc,
"@traj",
in_trcs,
additional_options,
" \n",
]
)
bash.execute(command, catch_STD=out_file_path)
return out_file_path
[docs] @_gromosClass._gromosTypeConverter
def cog(
self,
in_top_path: str,
in_trcs: Union[str, List[str]],
out_file_path: str,
atom_selection: str = None,
outformat: str = None,
cog_com: str = None,
add_repl: str = None,
solv: str = None,
nthframe: str = None,
pbc: str = "r cog",
_binary_name: str = "cog",
verbose: bool = False,
) -> str:
"""
Parameters
----------
in_top_path : str
path to topo file
in_trcs : str
path to trc files
out_file_path : str
outpath
atom_selection: str, optional
atomspecifier(s) for which to calculate cog/com
outformat : str, optional
output coordinates format
cog_com : str, optional
calculate centre of geometry (cog) or mass (com); default: cog
add_repl: str, optional
add (add) the cog/com or replace (repl) the solutes; default: repl
solv: str, optional
include solvent in outcoordinates
nthframe: str, optional
write every nth frame (default: 1)
_binary_name : str, otpional
binary name of gromosPP programm (default: cog)
Returns
-------
str
output_path of the generated csv file
"""
if isinstance(in_trcs, list):
in_trcs = " ".join(in_trcs)
additional_options = [""]
if atom_selection is not None:
additional_options += [" @atomspec ", "'" + atom_selection + "'"]
if outformat is not None:
additional_options += [" @outformat ", outformat]
if cog_com is not None:
additional_options += [" @cog_com ", cog_com]
if add_repl is not None:
additional_options += [" @add_repl ", add_repl]
if solv is not None:
additional_options += [" @solv ", solv]
if nthframe is not None:
additional_options += [" @nthframe ", nthframe]
additional_options = " ".join(map(str, additional_options))
command = " ".join(
[self._bin + _binary_name, " @topo ", in_top_path, "@pbc", pbc, "@traj", in_trcs, additional_options, " \n"]
)
if verbose:
print(command)
bash.execute(command, catch_STD=out_file_path, verbose=verbose)
return out_file_path
[docs] @_gromosClass._gromosTypeConverter
def noe(
self,
in_top_path: str,
in_noe_path: str,
in_traj_path: str,
out_path: str,
pbc: str = "v",
gathering: str = "cog",
_binary_name: str = "noe",
verbose: bool = False,
) -> str:
"""
Parameters
----------
in_top_path: str
topology path
in_noe_path: str
output path of prep_noe
in_traj_path: str
coordinate file
out_path: str
path to the output file
pbc: str, optional
default: v
periodic boundary condition of the coordinates:
v - vacuum
r - rectangular box
gathering: str, optional
default: cog
how the coordinates shall be gathered before the calculation:
cog - center of geometry
com - center of mass
Returns
-------
str
out_path
NotImplemented
---------------
time: float, float (time, dt)
"""
command = (
self._bin
+ _binary_name
+ " @topo "
+ in_top_path
+ " @traj "
+ in_traj_path
+ " @noe "
+ in_noe_path
+ " @pbc "
+ str(pbc)
+ " "
+ str(gathering)
+ "\n"
)
if verbose:
print(command)
bash.execute(command, catch_STD=out_path, verbose=verbose)
return out_path
[docs] @_gromosClass._gromosTypeConverter
def jval(
self,
in_top_path: str,
in_jval_path: str,
in_traj_path: Union[str, List[str]],
out_path: str,
pbc: str = "v",
gathering: str = "cog",
timeseries: bool = False,
rmsd: bool = False,
time: float = None,
_binary_name: str = "jval",
verbose: bool = False,
):
"""
Parameters
----------
in_top_path: str
topology path
in_jval_path: str
jval specification path
in_traj_path: str
coordinate file
out_path: str
path to the output file
pbc: str, optional
default: v
periodic boundary condition of the coordinates:
v - vacuum
r - rectangular box
gathering: str, optional
default: cog
how the coordinates shall be gathered before the calculation:
cog - center of geometry
com - center of mass
timeseries: bool, optional
rmsd: bool, optional
time: (Number, str), optional
Returns
-------
str
out_path
NotImplemented
---------------
time: float, float (time, dt)
"""
additional_options = ""
if timeseries:
additional_options += " @timeseries "
if rmsd:
additional_options += " @rmsd "
if isinstance(time, (Number, str)):
additional_options += " @time " + str(time) + " "
if isinstance(in_traj_path, List):
in_traj_path = "\n".join(in_traj_path)
command = (
self._bin
+ _binary_name
+ " @topo "
+ in_top_path
+ " @traj "
+ in_traj_path
+ " @jval "
+ in_jval_path
+ " @pbc "
+ str(pbc)
+ " "
+ str(gathering)
+ " "
+ additional_options
+ " &> "
+ out_path
)
if verbose:
print(command)
ret = bash.execute(command)
if verbose:
print(ret.readlines())
return out_path
[docs] @_gromosClass._gromosTypeConverter
def ion(
self,
in_top_path: str,
in_cnf_path: str,
out_cnf_path: str,
periodic_boundary_condition: str = "v",
negative: list = None,
positive: list = None,
potential: float = 0.8,
mindist: float = 0.8,
random_seed: int = None,
exclude: str = None,
_binary_name: str = "ion",
verbose: bool = False,
) -> str:
"""
When simulating a charged solute in solution, one may wish to include
counter-ions in the molecular system in order to obtain a neutral system, or
a system with a specific ionic strength. The program ion can replace solvent
molecules by atomic ions by placing the
ion at the position of the first atom of a solvent molecule. Substitution of
solvent molecules by positive or negative ions can be performed by selecting
the solvent positions with the lowest or highest Coulomb potential, respectively,
or by random selection. In order to prevent two ions being placed too
close together, a sphere around each inserted ion can be specified from which
no solvent molecules will be substituted by additional ions. In addition, the user can
specify specific water molecules that should not be considered for
replacement.
Parameters
----------
in_top_path : str
the path to the input topology file (.top)
in_cnf_path : str
the path to the input coordinate file (.cnf), to which the ions shall be added
out_cnf_path : str
the path to the resulting coordinate (.cnf) file
periodic_boundary_condition : str, optional
describes the boundary condition of the given system in the cnf. (r - rectangle, v - vacuum, ). a gathering method can be optionally added with a whitespace seperation., by default "v"
negative : list, optional
the first element of the list is the number of ions and the second element of the list is the type of ion, optionally a third element can be passed giving the residue name, by default None
positive : list, optional
the first element of the list is the number of ions and the second element of the list is the type of ion, optionally a third element can be passed giving the residue name, by default None
potential : float, optional
cutoff for potential calculation[nm], by default 0.8
mindist : float, optional
minimum distance between ions[nm], by default 0.8
random_seed : int, optional
provide the used random seed, by default None
exclude : str, optional
if you want to exclude solvent molecules, define a gromos selection here, by default None
_binary_name : str, optional
the program name, by default "ion"
verbose : bool, optional
stay a while and listen, by default False
Returns
-------
str
returns the resulting cnf-file path
"""
optional_args = []
if positive is not None:
opt = "@positive " + " ".join(map(str, positive))
optional_args.append(opt)
if negative is not None:
opt = "@negative " + " ".join(map(str, negative))
optional_args.append(opt)
if random_seed is not None:
opt = "@random " + " ".join(map(str, random_seed))
optional_args.append(opt)
if exclude is not None:
opt = "@exclude " + " ".join(map(str, exclude))
optional_args.append(opt)
command = (
self._bin
+ _binary_name
+ " @topo "
+ in_top_path
+ " @pos "
+ in_cnf_path
+ " @pbc "
+ periodic_boundary_condition
+ " "
)
command += "@potential " + str(potential) + " @mindist " + str(mindist) + " " + " ".join(optional_args)
if verbose:
print(command)
bash.execute(command, catch_STD=out_cnf_path)
return out_cnf_path
# To implement
def _gr962pdb(self):
raise Exception("not implemented yet!")
[docs] def rgyr(
self,
out_rgyr_path: str,
in_coord_path: str,
in_top_path: str,
atom_selection: str = "1:a",
periodic_boundary_condition: str = "r cog",
time: int = None,
dt: int = None,
mass_weighted: bool = False,
_binary_name: str = "rgyr",
) -> str:
"""
This wrapper uses rgyr to compute the radius of gyration for a given atom selection.
Parameters
----------
out_rgyr_path: str
in_coord_path: str
in_top_path: str
atom_selection: str, optional
periodic_boundary_condition: str, optional
time: int, optional
dt: int, optional
mass_weighted:bool, optional
_binary_name: str, optional
Returns
-------
str
returns out_rgyr_path
See Also
--------
For more information checkout the Gromos Manual
"""
args = [
"@topo " + in_top_path,
"@pbc " + periodic_boundary_condition,
"@atoms " + atom_selection,
"@traj " + in_coord_path,
]
if not isinstance(time, type(None)):
args += "@time " + str(time) + " "
if not isinstance(time, type(None)) and not isinstance(dt, type(None)):
args += " " + str(dt) + " "
if not isinstance(mass_weighted, type(False)):
args += "@massweighted "
command = self._bin + _binary_name + " " + " ".join(args)
bash.execute(command, catch_STD=out_rgyr_path)
return out_rgyr_path
[docs] def sasa(
self,
out_sasa_path: str,
in_coord_path: str,
in_top_path: str,
atom_selection: str = "1:a",
sasa_atoms: str = "1:a",
probe: str = "4 1.4",
periodic_boundary_condition: str = "r cog",
zslice: float = None,
time: int = None,
dt: int = None,
verbose: bool = False,
_binary_name: str = "sasa",
) -> str:
"""
This wrapper uses sasa to compute the solvent accessible surface area (SASA) for a given atom selection. By default,
this is done for the first residue (1:a) with parameters for water (IAC type: 4, radius: 0.4 nm)
Parameters
----------
out_sasa_path: str
in_coord_path: str
in_top_path: str
atom_selection: str, optional
sasa_atoms: str, optional
probe: str, optional
periodic_boundary_condition: str, optional
zslice: float, optional
time: int, optional
dt: int, optional
verbose: bool, optional
_binary_name: str, optional
Returns
-------
str
returns out_sasa_path
See Also
--------
For more information checkout the Gromos Manual
"""
args = [
"@topo " + in_top_path,
"@pbc " + periodic_boundary_condition,
"@atoms " + atom_selection,
"@sasaatoms " + sasa_atoms,
"@probe " + probe,
"@traj " + in_coord_path,
]
if not isinstance(time, type(None)):
args += "@time " + str(time) + " "
if not isinstance(time, type(None)) and not isinstance(dt, type(None)):
args += " " + str(dt) + " "
if not isinstance(zslice, type(None)):
args += "@zslice " + zslice + " "
if not isinstance(verbose, type(False)):
args += "@verbose "
command = self._bin + _binary_name + " " + " ".join(args)
bash.execute(command, catch_STD=out_sasa_path)
return out_sasa_path
[docs] def filter(
self,
out_filter_path: str,
in_coord_path: str,
in_top_path: str,
atom_selection: str = None,
periodic_boundary_condition: str = "r cog",
cutoff: float = None,
pairlist: str = None,
select: str = "1:a",
reject: str = None,
time: int = None,
dt: int = None,
outformat: str = None,
_binary_name: str = "filter",
) -> str:
"""
This wrapper uses filter to reduce a given trajectory to a selection of atoms. By default, only the first residue (1:a) is retained.
Parameters
----------
out_filter_path: str
in_coord_path: str
in_top_path: str
atom_selection: str, optional
periodic_boundary_condition: str, optional
cutoff: float, optional
pairlist: str, optional
select: str, optional
reject: str, optional
time: int, optional
dt: int, optional
outformat: str, optional
_binary_name: str, optional
Returns
-------
str
returns out_filter_path
See Also
--------
For more information checkout the Gromos Manual
"""
args = [
f"@topo {in_top_path} ",
f"@pbc {periodic_boundary_condition} ",
f"@traj {in_coord_path} ",
f"@select {select} ",
]
if not isinstance(cutoff, type(None)):
args += f"@cutoff {cutoff} "
if not isinstance(pairlist, type(None)):
args += f"@pairlist {pairlist} "
if not isinstance(atom_selection, type(None)):
args += f"@atoms {atom_selection} "
if not isinstance(reject, type(None)):
args += f"@reject {reject} "
if not isinstance(time, type(None)):
args += f" @time {time} "
if not isinstance(time, type(None)) and not isinstance(dt, type(None)):
args += f"{dt} "
if not isinstance(outformat, type(None)):
args += f" @outformat {outformat} "
args_str = "".join(args)
command = f"{self._bin} {_binary_name} {args_str}"
bash.execute(command, catch_STD=out_filter_path)
return out_filter_path
[docs]class GromosPP(_gromosPPbase):
"""
GromosPP
This is the class represents gromosPP.
Attributes:
-----------
bin : str, optional
This is the path to the folder containing the binaries of gromosPP If None, the bash enviroment variables will be used.
"""
def __init__(self, gromosPP_bin_dir: str = None, _check_binary_paths: bool = True, verbose: bool = False):
super().__init__(gromosPP_bin_dir=gromosPP_bin_dir, verbose=verbose, _check_binary_paths=_check_binary_paths)