Coverage for biobb_pmx / pmxbiobb / pmxligand_hybrid.py: 79%
76 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 ligand_hybrid 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.file_utils import launchlogger
15class Pmxligand_hybrid(BiobbObject):
16 """
17 | biobb_pmx Pmxligand_hybrid
18 | Wrapper class for the `PMX ligand_hybrid <https://github.com/deGrootLab/pmx>`_ module.
19 | Create a hybrid topology and structure based on two ligand structures.
21 Args:
22 input_structure1_path (str): Path to the input ligand structure file 1. File type: input. `Sample file <https://github.com/bioexcel/biobb_pmx/raw/master/biobb_pmx/test/data/pmx/lig1.pdb>`_. Accepted formats: pdb (edam:format_1476).
23 input_structure2_path (str): Path to the input ligand structure file 2. File type: input. `Sample file <https://github.com/bioexcel/biobb_pmx/raw/master/biobb_pmx/test/data/pmx/lig2.pdb>`_. Accepted formats: pdb (edam:format_1476).
24 input_topology1_path (str): Path to the input ligand topology file 1. File type: input. `Sample file <https://github.com/bioexcel/biobb_pmx/raw/master/biobb_pmx/test/data/pmx/topoLig1.itp>`_. Accepted formats: itp (edam:format_3883).
25 input_topology2_path (str): Path to the input ligand topology file 2. File type: input. `Sample file <https://github.com/bioexcel/biobb_pmx/raw/master/biobb_pmx/test/data/pmx/topoLig2.itp>`_. Accepted formats: itp (edam:format_3883).
26 input_pairs_path (str) (Optional): Path to the input atom pair mapping. File type: input. `Sample file <https://github.com/bioexcel/biobb_pmx/raw/master/biobb_pmx/test/data/pmx/myPairs1.dat>`_. Accepted formats: dat (edam:format_1637), txt (edam:format_2330).
27 input_scaffold1_path (str) (Optional): Path to the index of atoms to consider for the ligand structure 1. File type: input. Accepted formats: ndx (edam:format_2033).
28 input_scaffold2_path (str) (Optional): Path to the index of atoms to consider for the ligand structure 2. File type: input. Accepted formats: ndx (edam:format_2033).
29 output_log_path (str): Path to the log file. File type: output. Accepted formats: log (edam:format_2330), txt (edam:format_2330), out (edam:format_2330).
30 output_structure1_path (str): Path to the output hybrid structure based on the ligand 1. File type: output. `Sample file <https://github.com/bioexcel/biobb_pmx/raw/master/biobb_pmx/test/reference/pmx/ref_hybridStructure1.pdb>`_. Accepted formats: pdb (edam:format_1476).
31 output_structure2_path (str): Path to the output hybrid structure based on the ligand 2. File type: output. `Sample file <https://github.com/bioexcel/biobb_pmx/raw/master/biobb_pmx/test/reference/pmx/ref_hybridStructure2.pdb>`_. Accepted formats: pdb (edam:format_1476).
32 output_topology_path (str): Path to the output hybrid topology. File type: output. `Sample file <https://github.com/bioexcel/biobb_pmx/raw/master/biobb_pmx/test/reference/pmx/ref_hybridTopology.itp>`_. Accepted formats: itp (edam:format_3883).
33 output_atomtypes_path (str): Path to the atom types for the output hybrid topology. File type: output. `Sample file <https://github.com/bioexcel/biobb_pmx/raw/master/biobb_pmx/test/reference/pmx/ref_hybridAtomTypes.itp>`_. Accepted formats: itp (edam:format_3883).
35 properties (dic):
36 * **fit** (*bool*) - (False) Fit ligand structure 1 onto ligand structure 2 (Only used if input_pairs_path is provided).
37 * **split** (*bool*) - (False) Split the topology into separate transitions.
38 * **scDUMm** (*float*) - (1.0) Scale dummy masses using the counterpart atoms.
39 * **scDUMa** (*float*) - (1.0) Scale bonded dummy angle parameters.
40 * **scDUMd** (*float*) - (1.0) Scale bonded dummy dihedral parameters.
41 * **deAng** (*bool*) - (False) Decouple angles composed of 1 dummy and 2 non-dummies.
42 * **distance** (*float*) - (0.05) Distance (nm) between atoms to consider them morphable for alignment approach (Only used if input_pairs_path is not provided).
43 * **remove_tmp** (*bool*) - (True) [WF property] Remove temporal files.
44 * **restart** (*bool*) - (False) [WF property] Do not execute if output files exist.
45 * **sandbox_path** (*str*) - ("./") [WF property] Parent path to the sandbox directory.
46 * **container_path** (*str*) - (None) Path to the binary executable of your container.
47 * **container_image** (*str*) - (None) Container Image identifier.
48 * **container_volume_path** (*str*) - ("/inout") Path to an internal directory in the container.
49 * **container_working_dir** (*str*) - (None) Path to the internal CWD in the container.
50 * **container_user_id** (*str*) - (None) User number id to be mapped inside the container.
51 * **container_shell_path** (*str*) - ("/bin/bash") Path to the binary executable of the container shell.
53 Examples:
54 This is a use example of how to use the building block from Python::
56 from biobb_pmx.pmxbiobb.pmxligand_hybrid import pmxligand_hybrid
57 prop = {
58 'fit' : True,
59 'distance': 0.05
60 }
61 pmxligand_hybrid(input_structure1_path='/path/to/myStructure1.pdb',
62 input_structure2_path='/path/to/myStructure2.pdb',
63 input_topology1_path='/path/to/myTopology1.pdb',
64 input_topology2_path='/path/to/myTopology2.pdb',
65 input_pairs_path='/path/to/myPairs.dat',
66 output_log_path='/path/to/myLog.log',
67 output_structure1_path='/path/to/myStructureOutput1.pdb',
68 output_structure2_path='/path/to/myStructureOutput2.pdb',
69 output_topology_path='/path/to/myTopologyOutput.pdb',
70 output_atomtypes_path='/path/to/myAtomTypesOutput.pdb',
71 properties=prop)
73 Info:
74 * wrapped_software:
75 * name: PMX ligand_hybrid
76 * version: >=1.0.1
77 * license: GNU
78 * ontology:
79 * name: EDAM
80 * schema: http://edamontology.org/EDAM.owl
82 """
84 def __init__(
85 self,
86 input_structure1_path: str,
87 input_structure2_path: str,
88 input_topology1_path: str,
89 input_topology2_path: str,
90 output_log_path: str,
91 output_structure1_path: str,
92 output_structure2_path: str,
93 output_topology_path: str,
94 output_atomtypes_path: str,
95 input_scaffold1_path: Optional[str] = None,
96 input_scaffold2_path: Optional[str] = None,
97 input_pairs_path: Optional[str] = None,
98 properties: Optional[dict] = None,
99 **kwargs,
100 ) -> None:
101 properties = properties or {}
103 # Call parent class constructor
104 super().__init__(properties)
105 self.locals_var_dict = locals().copy()
107 # Input/Output files
108 self.io_dict = {
109 "in": {
110 "input_structure1_path": input_structure1_path,
111 "input_structure2_path": input_structure2_path,
112 "input_topology1_path": input_topology1_path,
113 "input_topology2_path": input_topology2_path,
114 "input_scaffold1_path": input_scaffold1_path,
115 "input_scaffold2_path": input_scaffold2_path,
116 "input_pairs_path": input_pairs_path,
117 },
118 "out": {
119 "output_structure1_path": output_structure1_path,
120 "output_structure2_path": output_structure2_path,
121 "output_topology_path": output_topology_path,
122 "output_atomtypes_path": output_atomtypes_path,
123 "output_log_path": output_log_path,
124 },
125 }
127 # Properties specific for BB
128 # self.fit = properties.get('fit', False)
129 # self.split = properties.get('split', False)
130 # self.scDUMm = properties.get('scDUMm', 1.0)
131 # self.scDUMa = properties.get('scDUMa', 1.0)
132 # self.scDUMd = properties.get('scDUMd', 1.0)
133 # self.deAng = properties.get('deAng', False)
134 # self.distance = properties.get('distance', 0.05)
136 self.fit = properties.get("fit")
137 self.split = properties.get("split")
138 self.scDUMm = properties.get("scDUMm")
139 self.scDUMa = properties.get("scDUMa")
140 self.scDUMd = properties.get("scDUMd")
141 self.deAng = properties.get("deAng")
142 self.distance = properties.get("distance")
144 # Properties common in all PMX BB
145 self.gmx_lib = properties.get("gmx_lib", None)
146 if not self.gmx_lib and os.environ.get("CONDA_PREFIX", ""):
147 python_version = f"{sys.version_info.major}.{sys.version_info.minor}"
148 self.gmx_lib = str(
149 Path(os.environ.get("CONDA_PREFIX", "")).joinpath(
150 f"lib/python{python_version}/site-packages/pmx/data/mutff/"
151 )
152 )
153 if properties.get("container_path"):
154 self.gmx_lib = str(
155 Path("/usr/local/").joinpath(
156 "lib/python3.7/site-packages/pmx/data/mutff/"
157 )
158 )
159 self.binary_path = properties.get("binary_path", "pmx")
161 # Check the properties
162 self.check_properties(properties)
163 self.check_arguments()
165 @launchlogger
166 def launch(self) -> int:
167 """Execute the :class:`Pmxmutate <pmx.pmxmutate.Pmxmutate>` pmx.pmxmutate.Pmxmutate object."""
169 # Setup Biobb
170 if self.check_restart():
171 return 0
172 self.stage_files()
174 # Check if executable exists
175 if not self.container_path:
176 if not Path(self.binary_path).is_file():
177 if not shutil.which(self.binary_path):
178 raise FileNotFoundError(
179 "Executable %s not found. Check if it is installed in your system and correctly defined in the properties"
180 % self.binary_path
181 )
183 self.cmd = [
184 self.binary_path,
185 "ligandHybrid",
186 "-i1",
187 self.stage_io_dict["in"]["input_structure1_path"],
188 "-i2",
189 self.stage_io_dict["in"]["input_structure2_path"],
190 "-itp1",
191 self.stage_io_dict["in"]["input_topology1_path"],
192 "-itp2",
193 self.stage_io_dict["in"]["input_topology2_path"],
194 "-pairs",
195 self.stage_io_dict["in"]["input_pairs_path"],
196 "-oA",
197 self.stage_io_dict["out"]["output_structure1_path"],
198 "-oB",
199 self.stage_io_dict["out"]["output_structure2_path"],
200 "-oitp",
201 self.stage_io_dict["out"]["output_topology_path"],
202 "-offitp",
203 self.stage_io_dict["out"]["output_atomtypes_path"],
204 "-log",
205 self.stage_io_dict["out"]["output_log_path"],
206 ]
208 if self.stage_io_dict["in"].get("output_scaffold1_path"):
209 self.cmd.append("-n1")
210 self.cmd.append(self.stage_io_dict["in"]["output_scaffold1_path"])
212 if self.stage_io_dict["in"].get("output_scaffold2_path"):
213 self.cmd.append("-n2")
214 self.cmd.append(self.stage_io_dict["in"]["output_scaffold2_path"])
216 if self.fit:
217 self.cmd.append("--fit")
218 if self.split:
219 self.cmd.append("--split")
220 if self.deAng:
221 self.cmd.append("--deAng")
222 if self.distance:
223 self.cmd.append("--d")
224 self.cmd.append(str(self.distance))
225 if self.scDUMm:
226 self.cmd.append("--scDUMm")
227 self.cmd.append(str(self.scDUMm))
228 if self.scDUMa:
229 self.cmd.append("--scDUMa")
230 self.cmd.append(str(self.scDUMa))
231 if self.scDUMd:
232 self.cmd.append("--scDUMd")
233 self.cmd.append(str(self.scDUMd))
235 if self.gmx_lib:
236 self.env_vars_dict["GMXLIB"] = self.gmx_lib
238 # Run Biobb block
239 self.run_biobb()
241 # Copy files to host
242 self.copy_to_host()
244 self.remove_tmp_files()
246 self.check_arguments(output_files_created=True, raise_exception=False)
247 return self.return_code
250def pmxligand_hybrid(
251 input_structure1_path: str,
252 input_structure2_path: str,
253 input_topology1_path: str,
254 input_topology2_path: str,
255 output_log_path: str,
256 output_structure1_path: str,
257 output_structure2_path: str,
258 output_topology_path: str,
259 output_atomtypes_path: str,
260 input_scaffold1_path: Optional[str] = None,
261 input_scaffold2_path: Optional[str] = None,
262 input_pairs_path: Optional[str] = None,
263 properties: Optional[dict] = None,
264 **kwargs,
265) -> int:
266 """Create the :class:`Pmxligand_hybrid <pmx.pmxmutate.Pmxligand_hybrid>` class and
267 execute the :meth:`launch() <pmx.pmxligand_hybrid.Pmxligand_hybrid.launch> method."""
268 return Pmxligand_hybrid(**dict(locals())).launch()
271pmxligand_hybrid.__doc__ = Pmxligand_hybrid.__doc__
272main = Pmxligand_hybrid.get_main(pmxligand_hybrid, "Run PMX ligand hybrid module")
274if __name__ == "__main__":
275 main()