Coverage for biobb_pmx / pmxbiobb / pmxmutate.py: 84%
63 statements
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-22 17:32 +0000
« prev ^ index » next coverage.py v7.13.0, created at 2025-12-22 17:32 +0000
1#!/usr/bin/env python3
3"""Module containing the PMX mutate class and the command line interface."""
5import os
6import shutil
7import sys
8from pathlib import Path
9from typing import Optional
11from biobb_common.generic.biobb_object import BiobbObject
12from biobb_common.tools import file_utils as fu
13from biobb_common.tools.file_utils import launchlogger
15from biobb_pmx.pmxbiobb.common import MUTATION_DICT, create_mutations_file
18class Pmxmutate(BiobbObject):
19 """
20 | biobb_pmx Pmxmutate
21 | Wrapper class for the `PMX mutate <https://github.com/deGrootLab/pmx>`_ module.
22 | Mutate residues in a protein structure.
24 Args:
25 input_structure_path (str): Path to the input structure file. File type: input. `Sample file <https://github.com/bioexcel/biobb_pmx/raw/master/biobb_pmx/test/data/pmx/frame99.pdb>`_. Accepted formats: pdb (edam:format_1476), gro (edam:format_2033).
26 output_structure_path (str): Path to the output structure file. File type: output. `Sample file <https://github.com/bioexcel/biobb_pmx/raw/master/biobb_pmx/test/reference/pmx/ref_output_structure.pdb>`_. Accepted formats: pdb (edam:format_1476), gro (edam:format_2033).
27 input_b_structure_path (str) (Optional): Path to the mutated input structure file. File type: input. Accepted formats: pdb (edam:format_1476), gro (edam:format_2033).
28 properties (dic):
29 * **mutation_list** (*str*) - ("2Ala") Mutation list in the format "Chain:Resnum MUT_AA_Code" or "Chain:Resnum MUT_NA_Code" (no spaces between the elements) separated by commas. If no chain is provided as chain code all the chains in the pdb file will be mutated. ie: "A:15CYS". Possible MUT_AA_Code: 'ALA', 'ARG', 'ASN', 'ASP', 'ASPH', 'ASPP', 'ASH', 'CYS', 'CYS2', 'CYN', 'CYX', 'CYM', 'CYSH', 'GLU', 'GLUH', 'GLUP', 'GLH', 'GLN', 'GLY', 'HIS', 'HIE', 'HISE', 'HSE', 'HIP', 'HSP', 'HISH', 'HID', 'HSD', 'ILE', 'LEU', 'LYS', 'LYSH', 'LYP', 'LYN', 'LSN', 'MET', 'PHE', 'PRO', 'SER', 'SP1', 'SP2', 'THR', 'TRP', 'TYR', 'VAL'. Possible MUT_NA_Codes: 'A', 'T', 'C', 'G', 'U'.
30 * **force_field** (*str*) - ("amber99sb-star-ildn-mut") Forcefield to use.
31 * **resinfo** (*bool*) - (False) Show the list of 3-letter -> 1-letter residues.
32 * **gmx_lib** (*str*) - ("$CONDA_PREFIX/lib/python3.7/site-packages/pmx/data/mutff/") Path to the GMXLIB folder in your computer.
33 * **binary_path** (*str*) - ("pmx") Path to the PMX command line interface.
34 * **remove_tmp** (*bool*) - (True) [WF property] Remove temporal files.
35 * **restart** (*bool*) - (False) [WF property] Do not execute if output files exist.
36 * **sandbox_path** (*str*) - ("./") [WF property] Parent path to the sandbox directory.
37 * **container_path** (*str*) - (None) Path to the binary executable of your container.
38 * **container_image** (*str*) - (None) Container Image identifier.
39 * **container_volume_path** (*str*) - ("/inout") Path to an internal directory in the container.
40 * **container_working_dir** (*str*) - (None) Path to the internal CWD in the container.
41 * **container_user_id** (*str*) - (None) User number id to be mapped inside the container.
42 * **container_shell_path** (*str*) - ("/bin/bash") Path to the binary executable of the container shell.
44 Examples:
45 This is a use example of how to use the building block from Python::
47 from biobb_pmx.pmxbiobb.pmxmutate import pmxmutate
48 prop = {
49 'mutation_list': '2Ala, 3Val',
50 'gmx_lib': '/path/to/myGMXLIB/',
51 'force_field': 'amber99sb-star-ildn-mut'
52 }
53 pmxmutate(input_structure_path='/path/to/myStructure.pdb',
54 output_structure_path='/path/to/newStructure.pdb',
55 input_b_structure_path='/path/to/myStructureB.pdb'
56 properties=prop)
58 Info:
59 * wrapped_software:
60 * name: PMX mutate
61 * version: >=1.0.1
62 * license: GNU
63 * ontology:
64 * name: EDAM
65 * schema: http://edamontology.org/EDAM.owl
67 """
69 def __init__(
70 self,
71 input_structure_path: str,
72 output_structure_path: str,
73 input_b_structure_path: Optional[str] = None,
74 properties: Optional[dict] = None,
75 **kwargs,
76 ) -> None:
77 properties = properties or {}
79 # Call parent class constructor
80 super().__init__(properties)
81 self.locals_var_dict = locals().copy()
83 # Input/Output files
84 self.io_dict = {
85 "in": {
86 "input_structure_path": input_structure_path,
87 "input_b_structure_path": input_b_structure_path,
88 },
89 "out": {"output_structure_path": output_structure_path},
90 }
92 # Properties specific for BB
93 self.force_field = properties.get("force_field", "amber99sb-star-ildn-mut")
94 self.resinfo = properties.get("resinfo", False)
95 self.mutation_list = properties.get("mutation_list", "2Ala")
96 self.input_mutations_file = properties.get("mutations_file")
98 # Properties common in all PMX BB
99 self.gmx_lib = properties.get("gmx_lib", None)
100 if not self.gmx_lib and os.environ.get("CONDA_PREFIX"):
101 python_version = f"{sys.version_info.major}.{sys.version_info.minor}"
102 self.gmx_lib = str(
103 Path(os.environ.get("CONDA_PREFIX", "")).joinpath(
104 f"lib/python{python_version}/site-packages/pmx/data/mutff/"
105 )
106 )
107 if properties.get("container_path"):
108 self.gmx_lib = str(
109 Path("/usr/local/").joinpath(
110 "lib/python3.8/site-packages/pmx/data/mutff/"
111 )
112 )
113 self.binary_path = properties.get("binary_path", "pmx")
115 # Check the properties
116 self.check_properties(properties)
117 self.check_arguments()
119 @launchlogger
120 def launch(self) -> int:
121 """Execute the :class:`Pmxmutate <pmx.pmxmutate.Pmxmutate>` pmx.pmxmutate.Pmxmutate object."""
123 # Setup Biobb
124 if self.check_restart():
125 return 0
126 self.stage_files()
128 # Check if executable exists
129 if not self.container_path:
130 if not Path(self.binary_path).is_file():
131 if not shutil.which(self.binary_path):
132 raise FileNotFoundError(
133 "Executable %s not found. Check if it is installed in your system and correctly defined in the properties"
134 % self.binary_path
135 )
137 # Generate mutations file
139 mutations_dir = fu.create_unique_dir()
140 self.input_mutations_file = create_mutations_file(
141 input_mutations_path=str(Path(mutations_dir).joinpath("mutations.txt")),
142 mutation_list=self.mutation_list,
143 mutation_dict=MUTATION_DICT,
144 )
146 # Copy extra files to container: mutations file
147 if self.container_path:
148 fu.log("Container execution enabled", self.out_log)
150 shutil.copy2(
151 self.input_mutations_file, self.stage_io_dict.get("unique_dir", "")
152 )
153 self.input_mutations_file = str(
154 Path(self.container_volume_path).joinpath(
155 Path(self.input_mutations_file).name
156 )
157 )
159 self.cmd = [
160 self.binary_path,
161 "mutate",
162 "-f",
163 self.stage_io_dict["in"]["input_structure_path"],
164 "-o",
165 self.stage_io_dict["out"]["output_structure_path"],
166 "-ff",
167 self.force_field,
168 "--script",
169 self.input_mutations_file,
170 ]
172 if self.stage_io_dict["in"].get("input_b_structure_path"):
173 self.cmd.append("-fB")
174 self.cmd.append(self.stage_io_dict["in"]["input_b_structure_path"])
175 if self.resinfo:
176 self.cmd.append("-resinfo")
178 if self.gmx_lib:
179 self.env_vars_dict["GMXLIB"] = self.gmx_lib
181 # Run Biobb block
182 self.run_biobb()
184 # Copy files to host
185 self.copy_to_host()
187 self.tmp_files.append(mutations_dir)
188 self.remove_tmp_files()
190 self.check_arguments(output_files_created=True, raise_exception=False)
191 return self.return_code
194def pmxmutate(
195 input_structure_path: str,
196 output_structure_path: str,
197 input_b_structure_path: Optional[str] = None,
198 properties: Optional[dict] = None,
199 **kwargs,
200) -> int:
201 """Create the :class:`Pmxmutate <pmx.pmxmutate.Pmxmutate>` class and
202 execute the :meth:`launch() <pmx.pmxmutate.Pmxmutate.launch> method."""
203 return Pmxmutate(**dict(locals())).launch()
206pmxmutate.__doc__ = Pmxmutate.__doc__
207main = Pmxmutate.get_main(pmxmutate, "Run PMX mutate module")
209if __name__ == "__main__":
210 main()