Coverage for biobb_pmx/pmxbiobb/pmxligand_hybrid.py: 63%
97 statements
« prev ^ index » next coverage.py v7.6.10, created at 2025-01-23 10:10 +0000
« prev ^ index » next coverage.py v7.6.10, created at 2025-01-23 10:10 +0000
1#!/usr/bin/env python3
3"""Module containing the PMX ligand_hybrid class and the command line interface."""
5import argparse
6import os
7import shutil
8import sys
9from pathlib import Path
10from typing import Optional
12from biobb_common.configuration import settings
13from biobb_common.generic.biobb_object import BiobbObject
14from biobb_common.tools.file_utils import launchlogger
17class Pmxligand_hybrid(BiobbObject):
18 """
19 | biobb_pmx Pmxligand_hybrid
20 | Wrapper class for the `PMX ligand_hybrid <https://github.com/deGrootLab/pmx>`_ module.
21 | Create a hybrid topology and structure based on two ligand structures.
23 Args:
24 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/ligand.pdb>`_. Accepted formats: pdb (edam:format_1476).
25 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/ligand.pdb>`_. Accepted formats: pdb (edam:format_1476).
26 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/ligand.itp>`_. Accepted formats: itp (edam:format_3883).
27 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/ligand.itp>`_. Accepted formats: itp (edam:format_3883).
28 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/reference/pmx/ref_mapping_pairs.dat>`_. Accepted formats: dat (edam:format_1637), txt (edam:format_2330).
29 input_scaffold1_path (str) (Optional): Path to the index of atoms to consider for the ligand structure 1. File type: input. `Sample file <https://github.com/bioexcel/biobb_pmx/raw/master/biobb_pmx/test/reference/pmx/atoms_to_consider.ndx>`_. Accepted formats: ndx (edam:format_2033).
30 input_scaffold2_path (str) (Optional): Path to the index of atoms to consider for the ligand structure 2. File type: input. `Sample file <https://github.com/bioexcel/biobb_pmx/raw/master/biobb_pmx/test/reference/pmx/atoms_to_consider.ndx>`_. Accepted formats: ndx (edam:format_2033).
31 output_log_path (str): Path to the log file. File type: output. `Sample file <https://github.com/bioexcel/biobb_pmx/raw/master/biobb_pmx/test/reference/pmx/atom_mapping.log>`_. Accepted formats: log (edam:format_2330), txt (edam:format_2330), out (edam:format_2330).
32 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/superimposed_ligand.pdb>`_. Accepted formats: pdb (edam:format_1476).
33 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/superimposed_ligand.pdb>`_. Accepted formats: pdb (edam:format_1476).
34 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/ligand_hybrid.itp>`_. Accepted formats: itp (edam:format_3883).
35 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/ligand_hybrid_atomtypes.itp>`_. Accepted formats: itp (edam:format_3883).
37 properties (dic):
38 * **fit** (*bool*) - (False) Fit ligand structure 1 onto ligand structure 2 (Only used if input_pairs_path is provided).
39 * **split** (*bool*) - (False) Split the topology into separate transitions.
40 * **scDUMm** (*float*) - (1.0) Scale dummy masses using the counterpart atoms.
41 * **scDUMa** (*float*) - (1.0) Scale bonded dummy angle parameters.
42 * **scDUMd** (*float*) - (1.0) Scale bonded dummy dihedral parameters.
43 * **deAng** (*bool*) - (False) Decouple angles composed of 1 dummy and 2 non-dummies.
44 * **distance** (*float*) - (0.05) Distance (nm) between atoms to consider them morphable for alignment approach (Only used if input_pairs_path is not provided).
45 * **remove_tmp** (*bool*) - (True) [WF property] Remove temporal files.
46 * **restart** (*bool*) - (False) [WF property] Do not execute if output files exist.
47 * **sandbox_path** (*str*) - ("./") [WF property] Parent path to the sandbox directory.
48 * **container_path** (*str*) - (None) Path to the binary executable of your container.
49 * **container_image** (*str*) - (None) Container Image identifier.
50 * **container_volume_path** (*str*) - ("/inout") Path to an internal directory in the container.
51 * **container_working_dir** (*str*) - (None) Path to the internal CWD in the container.
52 * **container_user_id** (*str*) - (None) User number id to be mapped inside the container.
53 * **container_shell_path** (*str*) - ("/bin/bash") Path to the binary executable of the container shell.
55 Examples:
56 This is a use example of how to use the building block from Python::
58 from biobb_pmx.pmxbiobb.pmxligand_hybrid import pmxligand_hybrid
59 prop = {
60 'fit' : True,
61 'distance': 0.05
62 }
63 pmxligand_hybrid(input_structure1_path='/path/to/myStructure1.pdb',
64 input_structure2_path='/path/to/myStructure2.pdb',
65 input_topology1_path='/path/to/myTopology1.pdb',
66 input_topology2_path='/path/to/myTopology2.pdb',
67 input_pairs_path='/path/to/myPairs.dat',
68 output_log_path='/path/to/myLog.log',
69 output_structure1_path='/path/to/myStructureOutput1.pdb',
70 output_structure2_path='/path/to/myStructureOutput2.pdb',
71 output_topology_path='/path/to/myTopologyOutput.pdb',
72 output_atomtypes_path='/path/to/myAtomTypesOutput.pdb',
73 properties=prop)
75 Info:
76 * wrapped_software:
77 * name: PMX ligand_hybrid
78 * version: >=1.0.1
79 * license: GNU
80 * ontology:
81 * name: EDAM
82 * schema: http://edamontology.org/EDAM.owl
84 """
86 def __init__(
87 self,
88 input_structure1_path: str,
89 input_structure2_path: str,
90 input_topology1_path: str,
91 input_topology2_path: str,
92 output_log_path: str,
93 output_structure1_path: str,
94 output_structure2_path: str,
95 output_topology_path: str,
96 output_atomtypes_path: str,
97 input_scaffold1_path: Optional[str] = None,
98 input_scaffold2_path: Optional[str] = None,
99 input_pairs_path: Optional[str] = None,
100 properties: Optional[dict] = None,
101 **kwargs,
102 ) -> None:
103 properties = properties or {}
105 # Call parent class constructor
106 super().__init__(properties)
107 self.locals_var_dict = locals().copy()
109 # Input/Output files
110 self.io_dict = {
111 "in": {
112 "input_structure1_path": input_structure1_path,
113 "input_structure2_path": input_structure2_path,
114 "input_topology1_path": input_topology1_path,
115 "input_topology2_path": input_topology2_path,
116 "input_scaffold1_path": input_scaffold1_path,
117 "input_scaffold2_path": input_scaffold2_path,
118 "input_pairs_path": input_pairs_path,
119 },
120 "out": {
121 "output_structure1_path": output_structure1_path,
122 "output_structure2_path": output_structure2_path,
123 "output_topology_path": output_topology_path,
124 "output_atomtypes_path": output_atomtypes_path,
125 "output_log_path": output_log_path,
126 },
127 }
129 # Properties specific for BB
130 # self.fit = properties.get('fit', False)
131 # self.split = properties.get('split', False)
132 # self.scDUMm = properties.get('scDUMm', 1.0)
133 # self.scDUMa = properties.get('scDUMa', 1.0)
134 # self.scDUMd = properties.get('scDUMd', 1.0)
135 # self.deAng = properties.get('deAng', False)
136 # self.distance = properties.get('distance', 0.05)
138 self.fit = properties.get("fit")
139 self.split = properties.get("split")
140 self.scDUMm = properties.get("scDUMm")
141 self.scDUMa = properties.get("scDUMa")
142 self.scDUMd = properties.get("scDUMd")
143 self.deAng = properties.get("deAng")
144 self.distance = properties.get("distance")
146 # Properties common in all PMX BB
147 self.gmx_lib = properties.get("gmx_lib", None)
148 if not self.gmx_lib and os.environ.get("CONDA_PREFIX", ""):
149 python_version = f"{sys.version_info.major}.{sys.version_info.minor}"
150 self.gmx_lib = str(
151 Path(os.environ.get("CONDA_PREFIX", "")).joinpath(
152 f"lib/python{python_version}/site-packages/pmx/data/mutff/"
153 )
154 )
155 if properties.get("container_path"):
156 self.gmx_lib = str(
157 Path("/usr/local/").joinpath(
158 "lib/python3.7/site-packages/pmx/data/mutff/"
159 )
160 )
161 self.binary_path = properties.get("binary_path", "pmx")
163 # Check the properties
164 self.check_properties(properties)
165 self.check_arguments()
167 @launchlogger
168 def launch(self) -> int:
169 """Execute the :class:`Pmxmutate <pmx.pmxmutate.Pmxmutate>` pmx.pmxmutate.Pmxmutate object."""
171 # Setup Biobb
172 if self.check_restart():
173 return 0
174 self.stage_files()
176 # Check if executable exists
177 if not self.container_path:
178 if not Path(self.binary_path).is_file():
179 if not shutil.which(self.binary_path):
180 raise FileNotFoundError(
181 "Executable %s not found. Check if it is installed in your system and correctly defined in the properties"
182 % self.binary_path
183 )
185 self.cmd = [
186 self.binary_path,
187 "ligandHybrid",
188 "-i1",
189 self.stage_io_dict["in"]["input_structure1_path"],
190 "-i2",
191 self.stage_io_dict["in"]["input_structure2_path"],
192 "-itp1",
193 self.stage_io_dict["in"]["input_topology1_path"],
194 "-itp2",
195 self.stage_io_dict["in"]["input_topology2_path"],
196 "-pairs",
197 self.stage_io_dict["in"]["input_pairs_path"],
198 "-oA",
199 self.stage_io_dict["out"]["output_structure1_path"],
200 "-oB",
201 self.stage_io_dict["out"]["output_structure2_path"],
202 "-oitp",
203 self.stage_io_dict["out"]["output_topology_path"],
204 "-offitp",
205 self.stage_io_dict["out"]["output_atomtypes_path"],
206 "-log",
207 self.stage_io_dict["out"]["output_log_path"],
208 ]
210 if self.stage_io_dict["in"].get("output_scaffold1_path"):
211 self.cmd.append("-n1")
212 self.cmd.append(self.stage_io_dict["in"]["output_scaffold1_path"])
214 if self.stage_io_dict["in"].get("output_scaffold2_path"):
215 self.cmd.append("-n2")
216 self.cmd.append(self.stage_io_dict["in"]["output_scaffold2_path"])
218 if self.fit:
219 self.cmd.append("--fit")
220 if self.split:
221 self.cmd.append("--split")
222 if self.deAng:
223 self.cmd.append("--deAng")
224 if self.distance:
225 self.cmd.append("--d")
226 self.cmd.append(str(self.distance))
227 if self.scDUMm:
228 self.cmd.append("--scDUMm")
229 self.cmd.append(str(self.scDUMm))
230 if self.scDUMa:
231 self.cmd.append("--scDUMa")
232 self.cmd.append(str(self.scDUMa))
233 if self.scDUMd:
234 self.cmd.append("--scDUMd")
235 self.cmd.append(str(self.scDUMd))
237 if self.gmx_lib:
238 self.env_vars_dict["GMXLIB"] = self.gmx_lib
240 # Run Biobb block
241 self.run_biobb()
243 # Copy files to host
244 self.copy_to_host()
246 # self.tmp_files.append(self.stage_io_dict.get("unique_dir", ""))
247 self.remove_tmp_files()
249 self.check_arguments(output_files_created=True, raise_exception=False)
250 return self.return_code
253def pmxligand_hybrid(
254 input_structure1_path: str,
255 input_structure2_path: str,
256 input_topology1_path: str,
257 input_topology2_path: str,
258 output_log_path: str,
259 output_structure1_path: str,
260 output_structure2_path: str,
261 output_topology_path: str,
262 output_atomtypes_path: str,
263 input_scaffold1_path: Optional[str] = None,
264 input_scaffold2_path: Optional[str] = None,
265 input_pairs_path: Optional[str] = None,
266 properties: Optional[dict] = None,
267 **kwargs,
268) -> int:
269 """Execute the :class:`Pmxligand_hybrid <pmx.pmxmutate.Pmxligand_hybrid>` class and
270 execute the :meth:`launch() <pmx.pmxligand_hybrid.Pmxligand_hybrid.launch> method."""
272 return Pmxligand_hybrid(
273 input_structure1_path=input_structure1_path,
274 input_structure2_path=input_structure2_path,
275 input_topology1_path=input_topology1_path,
276 input_topology2_path=input_topology2_path,
277 output_log_path=output_log_path,
278 output_structure1_path=output_structure1_path,
279 output_structure2_path=output_structure2_path,
280 output_topology_path=output_topology_path,
281 output_atomtypes_path=output_atomtypes_path,
282 input_scaffold1_path=input_scaffold1_path,
283 input_scaffold2_path=input_scaffold2_path,
284 input_pairs_path=input_pairs_path,
285 properties=properties,
286 ).launch()
288 pmxligand_hybrid.__doc__ = Pmxligand_hybrid.__doc__
291def main():
292 """Command line execution of this building block. Please check the command line documentation."""
293 parser = argparse.ArgumentParser(
294 description="Run PMX ligand hybrid module",
295 formatter_class=lambda prog: argparse.RawTextHelpFormatter(prog, width=99999),
296 )
297 parser.add_argument(
298 "-c",
299 "--config",
300 required=False,
301 help="This file can be a YAML file, JSON file or JSON string",
302 )
304 # Specific args of each building block
305 required_args = parser.add_argument_group("required arguments")
306 required_args.add_argument(
307 "--input_structure1_path",
308 required=True,
309 help="Path to the input ligand structure file 1",
310 )
311 required_args.add_argument(
312 "--input_structure2_path",
313 required=True,
314 help="Path to the input ligand structure file 2",
315 )
316 required_args.add_argument(
317 "--input_topology1_path",
318 required=True,
319 help="Path to the input ligand topology file 1",
320 )
321 required_args.add_argument(
322 "--input_topology2_path",
323 required=True,
324 help="Path to the input ligand topology file 2",
325 )
326 required_args.add_argument(
327 "--output_structure1_path",
328 required=True,
329 help="Path to the output ligand structure file 1",
330 )
331 required_args.add_argument(
332 "--output_structure2_path",
333 required=True,
334 help="Path to the output ligand structure file 2",
335 )
336 required_args.add_argument(
337 "--output_topology1_path",
338 required=True,
339 help="Path to the output ligand topology file 1",
340 )
341 required_args.add_argument(
342 "--output_topology2_path",
343 required=True,
344 help="Path to the output ligand topology file 2",
345 )
346 required_args.add_argument(
347 "--output_log_path", required=True, help="Path to the log file"
348 )
349 parser.add_argument(
350 "--input_scaffold1_path",
351 required=False,
352 help="Path to the index of atoms to consider for the ligand structure 1",
353 )
354 parser.add_argument(
355 "--input_scaffold2_path",
356 required=False,
357 help="Path to the index of atoms to consider for the ligand structure 2",
358 )
359 parser.add_argument(
360 "--input_pairs_path",
361 required=False,
362 help="Path to the input atom pair mapping.",
363 )
365 args = parser.parse_args()
366 config = args.config if args.config else None
367 properties = settings.ConfReader(config=config).get_prop_dic()
369 # Specific call of each building block
370 pmxligand_hybrid(
371 input_structure1_path=args.input_structure1_path,
372 input_structure2_path=args.input_structure2_path,
373 input_topology1_path=args.input_topology1_path,
374 input_topology2_path=args.input_topology2_path,
375 output_log_path=args.output_log_path,
376 output_structure1_path=args.output_structure1_path,
377 output_structure2_path=args.output_structure2_path,
378 output_topology_path=args.output_topology_path,
379 output_atomtypes_path=args.output_atomtypes_path,
380 input_scaffold1_path=args.input_scaffold1_path,
381 input_scaffold2_path=args.input_scaffold2_path,
382 input_pairs_path=args.input_pairs_path,
383 properties=properties,
384 )
387if __name__ == "__main__":
388 main()