Coverage for biobb_pmx/pmxbiobb/pmxatom_mapping.py: 60%
122 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 atom_mapping 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 Pmxatom_mapping(BiobbObject):
18 """
19 | biobb_pmx Pmxatom_mapping
20 | Wrapper class for the `PMX atom_mapping <https://github.com/deGrootLab/pmx>`_ module.
21 | Perform atom mapping between 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 output_pairs1_path (str): Path to the output pairs for the ligand structure 1. File type: output. `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).
27 output_pairs2_path (str): Path to the output pairs for the ligand structure 2. File type: output. `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).
28 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).
29 output_structure1_path (str) (Optional): Path to the superimposed structure for the ligand structure 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).
30 output_structure2_path (str) (Optional): Path to the superimposed structure for the ligand structure 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).
31 output_morph1_path (str) (Optional): Path to the morphable atoms for the ligand structure 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).
32 output_morph2_path (str) (Optional): Path to the morphable atoms for the ligand structure 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).
33 output_scaffold1_path (str) (Optional): Path to the index of atoms to consider for the ligand structure 1. File type: output. `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).
34 output_scaffold2_path (str) (Optional): Path to the index of atoms to consider for the ligand structure 2. File type: output. `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).
35 output_score_path (str) (Optional): Path to the morphing score. File type: output. `Sample file <https://github.com/bioexcel/biobb_pmx/raw/master/biobb_pmx/test/reference/pmx/morph_score.dat>`_. Accepted formats: dat (edam:format_1637), txt (edam:format_2330).
37 properties (dic):
38 * **noalignment** (*bool*) - (False) Should the alignment method be disabled.
39 * **nomcs** (*bool*) - (False) Should the MCS method be disabled.
40 * **noH2H** (*bool*) - (True) Should non-polar hydrogens be discarded from morphing into any other hydrogen.
41 * **H2Hpolar** (*bool*) - (False) Should polar hydrogens be morphed into polar hydrogens.
42 * **H2Heavy** (*bool*) - (False) Should hydrogen be morphed into a heavy atom.
43 * **RingsOnly** (*bool*) - (False) Should rings only be used in the MCS search and alignemnt.
44 * **dMCS** (*bool*) - (False) Should the distance criterium be also applied in the MCS based search.
45 * **swap** (*bool*) - (False) Try swapping the molecule order which would be a cross-check and require double execution time.
46 * **nochirality** (*bool*) - (True) Perform chirality check for MCS mapping.
47 * **distance** (*float*) - (0.05) Distance (nm) between atoms to consider them morphable for alignment approach.
48 * **timeout** (*int*) - (10) Maximum time (s) for an MCS search.
49 * **remove_tmp** (*bool*) - (True) [WF property] Remove temporal files.
50 * **restart** (*bool*) - (False) [WF property] Do not execute if output files exist.
51 * **sandbox_path** (*str*) - ("./") [WF property] Parent path to the sandbox directory.
52 * **container_path** (*str*) - (None) Path to the binary executable of your container.
53 * **container_image** (*str*) - (None) Container Image identifier.
54 * **container_volume_path** (*str*) - ("/inout") Path to an internal directory in the container.
55 * **container_working_dir** (*str*) - (None) Path to the internal CWD in the container.
56 * **container_user_id** (*str*) - (None) User number id to be mapped inside the container.
57 * **container_shell_path** (*str*) - ("/bin/bash") Path to the binary executable of the container shell.
59 Examples:
60 This is a use example of how to use the building block from Python::
62 from biobb_pmx.pmxbiobb.pmxatom_mapping import pmxatom_mapping
63 prop = {
64 'no-alignment' : True,
65 'distance': 0.05
66 }
67 pmxatom_mapping(input_structure1_path='/path/to/myStructure1.pdb',
68 input_structure2_path='/path/to/myStructure2.pdb',
69 output_pairs1_path='/path/to/myPairs1.dat',
70 output_pairs2_path='/path/to/myPairs2.dat',
71 output_log_path='/path/to/myLog.log',
72 properties=prop)
74 Info:
75 * wrapped_software:
76 * name: PMX atom_mapping
77 * version: >=1.0.1
78 * license: GNU
79 * ontology:
80 * name: EDAM
81 * schema: http://edamontology.org/EDAM.owl
83 """
85 def __init__(
86 self,
87 input_structure1_path: str,
88 input_structure2_path: str,
89 output_pairs1_path: str,
90 output_pairs2_path: str,
91 output_log_path: str,
92 output_structure1_path: Optional[str] = None,
93 output_structure2_path: Optional[str] = None,
94 output_morph1_path: Optional[str] = None,
95 output_morph2_path: Optional[str] = None,
96 output_scaffold1_path: Optional[str] = None,
97 output_scaffold2_path: Optional[str] = None,
98 output_score_path: Optional[str] = None,
99 properties: Optional[dict] = None,
100 **kwargs,
101 ) -> None:
102 properties = properties or {}
104 # Call parent class constructor
105 super().__init__(properties)
106 self.locals_var_dict = locals().copy()
108 # Input/Output files
109 self.io_dict = {
110 "in": {
111 "input_structure1_path": input_structure1_path,
112 "input_structure2_path": input_structure2_path,
113 },
114 "out": {
115 "output_pairs1_path": output_pairs1_path,
116 "output_pairs2_path": output_pairs2_path,
117 "output_log_path": output_log_path,
118 "output_structure1_path": output_structure1_path,
119 "output_structure2_path": output_structure2_path,
120 "output_morph1_path": output_morph1_path,
121 "output_morph2_path": output_morph2_path,
122 "output_scaffold1_path": output_scaffold1_path,
123 "output_scaffold2_path": output_scaffold2_path,
124 "output_score_path": output_score_path,
125 },
126 }
128 # Properties specific for BB
129 # self.noalignment = properties.get('noalignment', False)
130 # self.nomcs = properties.get('nomcs', False)
131 # self.noH2H = properties.get('noH2H', True)
132 # self.H2Hpolar = properties.get('H2Hpolar', False)
133 # self.H2Heavy = properties.get('H2Heavy', False)
134 # self.RingsOnly = properties.get('RingsOnly', False)
135 # self.dMCS = properties.get('dMCS', False)
136 # self.swap = properties.get('swap', False)
137 # self.nochirality = properties.get('nochirality', True)
138 # self.distance = properties.get('distance', 0.05)
139 # self.timeout = properties.get('timeout', 10)
141 self.noalignment = properties.get("noalignment")
142 self.nomcs = properties.get("nomcs")
143 self.noH2H = properties.get("noH2H")
144 self.H2Hpolar = properties.get("H2Hpolar")
145 self.H2Heavy = properties.get("H2Heavy")
146 self.RingsOnly = properties.get("RingsOnly")
147 self.dMCS = properties.get("dMCS")
148 self.swap = properties.get("swap")
149 self.nochirality = properties.get("nochirality")
150 self.distance = properties.get("distance")
151 self.timeout = properties.get("timeout")
153 # Properties common in all PMX BB
154 self.gmx_lib = properties.get("gmx_lib", None)
155 if not self.gmx_lib and os.environ.get("CONDA_PREFIX", ""):
156 python_version = f"{sys.version_info.major}.{sys.version_info.minor}"
157 self.gmx_lib = str(
158 Path(os.environ.get("CONDA_PREFIX", "")).joinpath(
159 f"lib/python{python_version}/site-packages/pmx/data/mutff/"
160 )
161 )
162 if properties.get("container_path"):
163 self.gmx_lib = str(
164 Path("/usr/local/").joinpath(
165 "lib/python3.7/site-packages/pmx/data/mutff/"
166 )
167 )
168 self.binary_path = properties.get("binary_path", "pmx")
170 # Check the properties
171 self.check_properties(properties)
172 self.check_arguments()
174 @launchlogger
175 def launch(self) -> int:
176 """Execute the :class:`Pmxmutate <pmx.pmxmutate.Pmxmutate>` pmx.pmxmutate.Pmxmutate object."""
178 # Setup Biobb
179 if self.check_restart():
180 return 0
181 self.stage_files()
183 # Check if executable exists
184 if not self.container_path:
185 if not Path(self.binary_path).is_file():
186 if not shutil.which(self.binary_path):
187 raise FileNotFoundError(
188 "Executable %s not found. Check if it is installed in your system and correctly defined in the properties"
189 % self.binary_path
190 )
192 self.cmd = [
193 self.binary_path,
194 "atomMapping",
195 "-i1",
196 self.stage_io_dict["in"]["input_structure1_path"],
197 "-i2",
198 self.stage_io_dict["in"]["input_structure2_path"],
199 "-o1",
200 self.stage_io_dict["out"]["output_pairs1_path"],
201 "-o2",
202 self.stage_io_dict["out"]["output_pairs2_path"],
203 "-log",
204 self.stage_io_dict["out"]["output_log_path"],
205 ]
207 if self.stage_io_dict["out"].get("output_structure1_path"):
208 self.cmd.append("-opdb1")
209 self.cmd.append(self.stage_io_dict["out"]["output_structure1_path"])
211 if self.stage_io_dict["out"].get("output_structure2_path"):
212 self.cmd.append("-opdb2")
213 self.cmd.append(self.stage_io_dict["out"]["output_structure2_path"])
215 if self.stage_io_dict["out"].get("output_morph1_path"):
216 self.cmd.append("-opdbm1")
217 self.cmd.append(self.stage_io_dict["out"]["output_morph1_path"])
219 if self.stage_io_dict["out"].get("output_morph2_path"):
220 self.cmd.append("-opdbm2")
221 self.cmd.append(self.stage_io_dict["out"]["output_morph2_path"])
223 if self.stage_io_dict["out"].get("output_scaffold1_path"):
224 self.cmd.append("-n1")
225 self.cmd.append(self.stage_io_dict["out"]["output_scaffold1_path"])
227 if self.stage_io_dict["out"].get("output_scaffold2_path"):
228 self.cmd.append("-n2")
229 self.cmd.append(self.stage_io_dict["out"]["output_scaffold2_path"])
231 if self.stage_io_dict["out"].get("output_score_path"):
232 self.cmd.append("-score")
233 self.cmd.append(self.stage_io_dict["out"]["output_score_path"])
235 if self.noalignment:
236 self.cmd.append("--no-alignment")
237 if self.nomcs:
238 self.cmd.append("--no-mcs")
239 if self.noH2H:
240 self.cmd.append("--no-H2H")
241 if self.H2Hpolar:
242 self.cmd.append("--H2Hpolar")
243 if self.H2Heavy:
244 self.cmd.append("--H2Heavy")
245 if self.RingsOnly:
246 self.cmd.append("--RingsOnly")
247 if self.dMCS:
248 self.cmd.append("--dMCS")
249 if self.swap:
250 self.cmd.append("--swap")
251 if self.nochirality:
252 self.cmd.append("--no-chirality")
253 if self.distance:
254 self.cmd.append("--d")
255 self.cmd.append(str(self.distance))
256 if self.timeout:
257 self.cmd.append("--timeout")
258 self.cmd.append(str(self.timeout))
260 if self.gmx_lib:
261 self.env_vars_dict["GMXLIB"] = self.gmx_lib
263 # Run Biobb block
264 self.run_biobb()
266 # Copy files to host
267 self.copy_to_host()
269 # self.tmp_files.append(self.stage_io_dict.get("unique_dir", ""))
270 self.remove_tmp_files()
272 self.check_arguments(output_files_created=True, raise_exception=False)
273 return self.return_code
276def pmxatom_mapping(
277 input_structure1_path: str,
278 input_structure2_path: str,
279 output_pairs1_path: str,
280 output_pairs2_path: str,
281 output_log_path: str,
282 output_structure1_path: Optional[str] = None,
283 output_structure2_path: Optional[str] = None,
284 output_morph1_path: Optional[str] = None,
285 output_morph2_path: Optional[str] = None,
286 output_scaffold1_path: Optional[str] = None,
287 output_scaffold2_path: Optional[str] = None,
288 output_score_path: Optional[str] = None,
289 properties: Optional[dict] = None,
290 **kwargs,
291) -> int:
292 """Execute the :class:`Pmxatom_mapping <pmx.pmxmutate.Pmxatom_mapping>` class and
293 execute the :meth:`launch() <pmx.pmxatom_mapping.Pmxatom_mapping.launch> method."""
295 return Pmxatom_mapping(
296 input_structure1_path=input_structure1_path,
297 input_structure2_path=input_structure2_path,
298 output_pairs1_path=output_pairs1_path,
299 output_pairs2_path=output_pairs2_path,
300 output_log_path=output_log_path,
301 output_structure1_path=output_structure1_path,
302 output_structure2_path=output_structure2_path,
303 output_morph1_path=output_morph1_path,
304 output_morph2_path=output_morph2_path,
305 output_scaffold1_path=output_scaffold1_path,
306 output_scaffold2_path=output_scaffold2_path,
307 output_score_path=output_score_path,
308 properties=properties,
309 **kwargs,
310 ).launch()
312 pmxatom_mapping.__doc__ = Pmxatom_mapping.__doc__
315def main():
316 """Command line execution of this building block. Please check the command line documentation."""
317 parser = argparse.ArgumentParser(
318 description="Run PMX atom mapping module",
319 formatter_class=lambda prog: argparse.RawTextHelpFormatter(prog, width=99999),
320 )
321 parser.add_argument(
322 "-c",
323 "--config",
324 required=False,
325 help="This file can be a YAML file, JSON file or JSON string",
326 )
328 # Specific args of each building block
329 required_args = parser.add_argument_group("required arguments")
330 required_args.add_argument(
331 "--input_structure1_path",
332 required=True,
333 help="Path to the input ligand structure file 1",
334 )
335 required_args.add_argument(
336 "--input_structure2_path",
337 required=True,
338 help="Path to the input ligand structure file 2",
339 )
340 required_args.add_argument(
341 "--output_pairs1_path",
342 required=True,
343 help="Path to the output pairs for the ligand structure 1",
344 )
345 required_args.add_argument(
346 "--output_pairs2_path",
347 required=True,
348 help="Path to the output pairs for the ligand structure 2",
349 )
350 required_args.add_argument(
351 "--output_log_path", required=True, help="Path to the log file"
352 )
353 parser.add_argument(
354 "--output_structure1_path",
355 required=False,
356 help="Path to the superimposed structure for the ligand structure 1",
357 )
358 parser.add_argument(
359 "--output_structure2_path",
360 required=False,
361 help="Path to the superimposed structure for the ligand structure 2",
362 )
363 parser.add_argument(
364 "--output_morph1_path",
365 required=False,
366 help="Path to the morphable atoms for the ligand structure 1",
367 )
368 parser.add_argument(
369 "--output_morph2_path",
370 required=False,
371 help="Path to the morphable atoms for the ligand structure 2",
372 )
373 parser.add_argument(
374 "--output_scaffold1_path",
375 required=False,
376 help="Path to the index of atoms to consider for the ligand structure 1",
377 )
378 parser.add_argument(
379 "--output_scaffold2_path",
380 required=False,
381 help="Path to the index of atoms to consider for the ligand structure 2",
382 )
383 parser.add_argument(
384 "--output_score_path",
385 required=False,
386 help="Path to the morphing score. File type: output",
387 )
389 args = parser.parse_args()
390 config = args.config if args.config else None
391 properties = settings.ConfReader(config=config).get_prop_dic()
393 # Specific call of each building block
394 pmxatom_mapping(
395 input_structure1_path=args.input_structure1_path,
396 input_structure2_path=args.input_structure2_path,
397 output_pairs1_path=args.output_pairs1_path,
398 output_pairs2_path=args.output_pairs2_path,
399 output_log_path=args.output_log_path,
400 output_structure1_path=args.output_structure1_path,
401 output_structure2_path=args.output_structure2_path,
402 output_morph1_path=args.output_morph1_path,
403 output_morph2_path=args.output_morph2_path,
404 output_scaffold1_path=args.output_scaffold1_path,
405 output_scaffold2_path=args.output_scaffold2_path,
406 output_score_path=args.output_score_path,
407 properties=properties,
408 )
411if __name__ == "__main__":
412 main()