Tools#

class bindflow.utils.tools.DotDict(**kwargs)[source]#

A simple implementation of dot-access dict

__init__(**kwargs)[source]#
bindflow.utils.tools.archive(root_path: PathLike | str | bytes, exclude_suffixes: List[str] | None = None, name: str = 'archive', compress_type: str = 'gz', remove_dirs: bool = False, out_check_file: bool = True)[source]#

Recursively archive root_path. Directories and/or files with any suffixes from exclude_suffixes are ignored . It creates a tar file with the XTC files (without compress) and a main_project.tar.{compress_type} with the rest of directories. Compression will only be applied to those files included in main_project.tar.{compress_type}. In-house benchmark showed a compress rate close to for a fep campaign 1.8 using gz compression (data taken from MCL1). 139 GB to 77 GB

Warning

It may be that the function fail because the directory is too large, in this case you must split the directory, this was the case for the p38 campaign (openforcefield/protein-ligand-benchmark) with 3 replicas

BE AWARE OF THE IMPLICATION TO DELETE A SIMULATION DIRECTORY with the option remove_dirs = True

In-house benchmark showed:

Time

Space

bz2

x s

x MB

gz

x s

x MB

xz

x s

x MB

Parameters:
  • root_path (PathLike) – The root path for which all the dirs will be compressed

  • exclude_suffixes (List[PathLike], optional) – List of suffix to exclude for compression either directories or files. The endswith method will be applied Use case example could be: [.snakemake, .log, .edr, .lis, .err]. In this case the directory .snakemake will be ignored and all the files with the specified extensions.

  • name (str, optional) – Output name of the archive file, by default ‘archive’

  • compress_type (str, optional) – Type of compression to use, tar, gz, bz2 and xz are possible, by default ‘gz’

  • remove_dirs (bool, optional) – Remove compressed root_path, by default False

  • out_check_file (bool, optional) – If the archive worked as expected, a file {name}_safe_remove.check will be written, by default True

Raises:
bindflow.utils.tools.center_xtc(tpr: PathLike | str | bytes, xtc: PathLike | str | bytes, run_dir: PathLike | str | bytes, host_name: str = 'Protein', load_dependencies: List[str] | None = None) PathLike | str | bytes[source]#

Center an xtc file

Parameters:
  • tpr (PathLike) – Binary GROMACS topology

  • xtc (PathLike) – Trajectory file

  • run_dir (PathLike) – Directory to run and save the center trajectory

  • host_name (str, optional) – Name of the host/receptor, by default ‘Protein’

  • load_dependencies (List[str], optional) – It is used in case some previous loading steps are needed; e.g: [‘source /groups/CBG/opt/spack-0.18.1/shared.bash’, ‘module load sandybridge/gromacs/2025.4’], by default None

Returns:

The path of the center trajectory: {run_dir}/center.xtc

Return type:

PathLike

bindflow.utils.tools.config_validator(global_config: dict) List[source]#

It checks for the validity of the global config. This dictionary is used for bindflow.runners.calculate()

Parameters:

global_config (dict) – The configuration of the BindFlow workflow

Returns:

result[0], True if pass all the checks. False otherwise. result[1], Extra information.

Return type:

List[bool,str]

bindflow.utils.tools.find_xtc(root_path: PathLike | str | bytes, exclude_suffixes: List[str] | None = None) List[PathLike | str | bytes][source]#

Find all the files with the extension .xtc that does not have any parent directory with any exclude_suffixes. If the name if the xtc file has as suffix some of the ones specified in excluded_suffixes, it will also discarded as well.

Parameters:
  • root_path (PathLike) – Root path to look for XTC files

  • exclude_suffixes (List[str], optional) – list of suffixes to exclude from wither parent directories or the XTC files themself , by default None

Returns:

LIst of XTC file paths

Return type:

List[PathLike]

bindflow.utils.tools.gmx_command(load_dependencies: List[str] | None = None, interactive: bool = False, stdout_file: PathLike | str | bytes | None = None, stdin_command: None | str = None)[source]#

Lazy wrapper of gmx commands

Parameters:
  • load_dependencies (List[str]) – It is used in case some previous loading steps are needed; e.g: [‘source /groups/CBG/opt/spack-0.18.1/shared.bash’, ‘module load sandybridge/gromacs/2025.4’]

  • interactive (bool) – In case, and interactive section is desired, by default False

  • stdout_file (bool) – If provided, it will append to the command ` >& {stdout_file}`, by default None

  • stdin_command (Union[None, str], optional) – Command to pipe to the main command, by default None.

A typical function will be:

Example

In [1]: from bindflow.utils import tools

In [2]: @tools.gmx_command()
   ...: def mdrun(**kwargs): ...
   ...: 

The important parts are:

  1. The name of the function must be the name of the gmx command, for example mdrun, grompp, etc.

  2. You must return the local variables of the function

  3. The names of the keywords are exactly the same name as got it by the respective function.

  4. For flags, a boolean will be provided as value, for example v = True, if you want to be verbose.

Some GROMACS functions need the user inputs (E.g. pdb2gmx, trjconv, make_ndx). For those cases we can use interactive mode or pipe the input as echo to the gmx command, for example:

echo 'System' | gmx trjconv -s prod.tpr -f prod.xtc -o whole.xtc -pbc whole

To achieve this with gmx_command, we can:

@gmx_command(stdin_command="echo 'System'")
def trjconv(**kwargs): ...
trjconv(s='prod.tpr', f='prod.xtc', o='whole.xtc', pbc='whole')

It is important to remark that every time that trjconv is executed, the output of the echo command will be passed. To change this you have to redefine the function.

@gmx_command(stdin_command="echo 'Protein'")
def trjconv(**kwargs): ...
trjconv(s='prod.tpr', f='prod.xtc', o='whole.xtc', pbc='whole')
bindflow.utils.tools.gmx_runner(mdp: PathLike | str | bytes, topology: PathLike | str | bytes, structure: PathLike | str | bytes, checkpoint: PathLike | str | bytes | None = None, index: PathLike | str | bytes | None = None, nthreads: int = 12, load_dependencies: List[str] | None = None, run_dir: PathLike | str | bytes = '.', **mdrun_extra)[source]#

This function create the tpr file based on the input provided And run the simulation. Note: During the tpr creation maxwarn = 2 (TODO: remove it in the future)

The following commands will be executed by default:

gmx grompp -f {mdp} -c {structure} -r {structure} -p {topology} -o {mdp-name}.tpr -maxwarn 2 gmx mdrun -nt 12 -deffnm {mdp-name}

mdrun will update the command based on mdrun_extra. You can also suppress the use of nt and/or deffnm passing them as False and construct your own mdrun command. E.g.

gmx_runner(mdp=’emin.mdp’, topology=’ligand.top’, structure=’ligand.gro’, deffnm=False, cpi=True, s=’emin.tpr’)

The last will give ():

gmx mdrun -nt 12 -cpi -s emin.tpr -o emin2

Parameters:
  • mdp (str) – The path to the MDP file. The name of the file will be used for the tpr and for the files generated during mdrun.

  • topology (PathLike) – GMX topology file

  • structure (PathLike) – The PDB, GRO, etc structure of the system

  • checkpoint (PathLike) – Full precision trajectory: trr cpt tng, by default None> if given will be used on grompp with the flag -t {checkpoint}

  • index (PathLike) – A GMX index to be used on grompp, by default None

  • nthreads (int, optional) – Number of threads to run, by default 12

  • load_dependencies (List[str], optional) – It is used in case some previous loading steps are needed; e.g: [‘source /groups/CBG/opt/spack-0.18.1/shared.bash’, ‘module load sandybridge/gromacs/2025.4’], by default None

  • run_dir (PathLike, optional) – Where the simulation should run (write files). If it does not exist will be created, by default ‘.’

  • **mdrun_extra (any) – Any valid keyword for mdrun. Flags are passing as boolean. E.g: cpi = True. There is not check of right keywords, for wrong keywords an error will be raised at GROMACS level

bindflow.utils.tools.input_helper(arg_name: str, user_input: PathLike | str | bytes | dict | None, default_ff: PathLike | str | bytes, default_ff_type: None | str = None, optional: bool = False) dict[source]#

This helper function is called inside bindflow.runners.calculate to check for the inputs: protein, ligands, membrane and cofactor

Parameters:
  • arg_name (str) – The name of the part of the system. It is just used for to print information in case of error

  • user_input (Union[PathLike, dict, None]) – The user input provided

  • default_ff (Union[PathLike, str]) – A code of the force field. Internally it will be check if [default_ff].ff exist as a directory. This allow a much bigger flexibility on the use of different force fields that do not come with the GROMACS distribution by default

  • default_ff_type (Union[PathLike, str]) –

    This is used for the small molecules. It must be openff, gaff or espaloma (case insensitive). If it is provided, default_ff will NOT be used and set to None. During the building of the system, it will be converted internally as:

    • openff -> openff_unconstrained-2.0.0.offxml

    • gaff -> gaff-2.11

    • espaloma -> espaloma-0.3.1

  • optional (bool, optional) – if the arguments under analysis is optional or not, by default False

Returns:

A dictionary with keywords: conf[configuration file], top[GROMACS topology file], ff:code[force field code], path[absolute path in case the directory exists]

Return type:

dict

Raises:
  • ValueError – if user_input is None but optional is False

  • FileNotFoundError – The configuration file is not found even when some path was provided

  • ValueError – In case conf is not provided when user_input is a dict and optional is False

  • FileNotFoundError – The configuration file is not found when user_input is suppose to be a path

bindflow.utils.tools.list_if_file(path: PathLike | str | bytes = '.', ext: str | None = None) List[Path][source]#

Dir all the files in path

Parameters:
  • path (PathLike, optional) – Path to look for the file, by default ‘.’

  • ext (str, optional) – The extension of the file, for example: “.py”, “.sh”, “.txt”, by default None

Returns:

The list of file names

Return type:

List[Path]

bindflow.utils.tools.natsort(iterable: List) Iterable[source]#

Natural sort of an iterable

Parameters:

iterable (List) – Some iterable

Example

In [1]: from bindflow.utils import tools

In [2]: my_list = ['1', '2', 3, '4', '11', 5, 'A', '0', 13, '6']

In [3]: try:
   ...:     print(sorted(my_list))
   ...: except TypeError:
   ...:     print("We need to convert to string but still is not what we are expecting")
   ...:     print(sorted(map(str, my_list)))
   ...: 
We need to convert to string but still is not what we are expecting
['0', '1', '11', '13', '2', '3', '4', '5', '6', 'A']

In [4]: print(tools.natsort(my_list))
['0', '1', '2', 3, '4', 5, '6', '11', 13, 'A']
Returns:

The natural sorted iterable

Return type:

Iterable

bindflow.utils.tools.paths_exist(paths: List, raise_error: bool = False, out: None | str = None) None[source]#

Check that the paths exist

Parameters:
  • paths (List) – A list of paths

  • raise_error (bool, optional) – If True will raise a RuntimeError when any path doe not exist, by default False

  • out (Union[str, None], optional) – In case that all files exist and out is st to some file; the existence of this file could be used as a check that all paths exist (useful for sanekemake), by default None

Raises:

RuntimeError – In case some path does not exist and rasie_error = True

bindflow.utils.tools.readParmEDMolecule(top_file: PathLike | str | bytes, gro_file: PathLike | str | bytes, check_box: bool = False) parmed.Structure[source]#

Read a gro and top GROMACS file and return a topology Structure

Parameters:
  • top_file (PathLike) – Path of the top file

  • gro_file (PathLike) – Path of the gro file

  • check_box (bool) – If True and sum(gmx_gro.box[:3]) == 0, gmx_gro.box[:3] = [10, 10, 10]

Returns:

Structure with topologies, coordinates and box information

Return type:

Structure

bindflow.utils.tools.run(command: str, shell: bool = True, executable: str = '/bin/bash', interactive: bool = False, stdin_command: None | str = None) CompletedProcess[source]#

A simple wrapper around subprocess.Popen/subprocess.run

Parameters:
  • command (str) – The command line to be executed

  • shell (bool, optional) – Create a shell section, by default True

  • executable (str, optional) – what executable to use, pass sys.executable to check yours, by default ‘/bin/bash’

  • interactive (bool, optional) – To interact with the command, by default False. If True, you can access stdout and stderr of the returned process.

  • stdin_command (Union[None, str], optional) – Command to pipe to the main command, by default None.

Returns:

The process

Return type:

subprocess.CompletedProcess

Raises:

RuntimeError – In case that the command fails, the error is raised in a nice way

bindflow.utils.tools.sum_uncertainty_propagation(errors: Iterable[float], coefficients: Iterable[float] | None = None) float[source]#

Compute the combined uncertainty using standard uncertainty propagation rules for a sum of terms with optional scaling coefficients.

The formula applied is:

sigma_total = sqrt( Σ (c_i * sigma_i)^2 )

where:
  • sigma_i is the uncertainty (error) of the i-th term

  • sigma_i is the coefficient (default = 1 for all terms)

Parameters:
  • errors (Sequence[float]) – A list or sequence of uncertainty values (standard deviations).

  • coefficients (Optional[Iterable[float]], default=None) – Coefficients corresponding to each error term. If not provided, all coefficients are assumed to be 1.

Returns:

The propagated uncertainty.

Return type:

float

Raises:

ValueError – If the length of coefficients does not match the length of errors.

Examples

>>> sum_uncertainty_propagation([0.1, 0.2, 0.15])
0.2692582403567252
>>> sum_uncertainty_propagation([0.1, 0.2, 0.15], coefficients=[2, 1, 0.5])
0.3301517104052358
bindflow.utils.tools.unarchive(archive_file: PathLike | str | bytes, target_path: PathLike | str | bytes, only_with_suffix: None | List[str] = None, prefix: Tuple[str] = 'main_project.tar')[source]#

It unarchive a project archived by the function bindflow.utils.tools.archive()

Parameters:
  • archive_file (PathLike) – Archived project

  • target_path (PathLike) – Out path to unarchive

  • only_with_suffix (Union[None, List[str]]) – Only extract those files that present the suffix