Coverage for biobb_pmx/pmxbiobb/pmxmerge_ff.py: 94%
51 statements
« prev ^ index » next coverage.py v7.14.1, created at 2026-05-29 06:59 +0000
« prev ^ index » next coverage.py v7.14.1, created at 2026-05-29 06:59 +0000
1#!/usr/bin/env python3
3"""Module containing the PMX merge_ff class and the command line interface."""
5import glob
6import os
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
14from pmx import ligand_alchemy # type: ignore
17class Pmxmerge_ff(BiobbObject):
18 """
19 | biobb_pmx Pmxmerge_ff
20 | Wrapper class for the `PMX merge_ff <https://github.com/deGrootLab/pmx>`_ module.
21 | Merge ligand topology files.
23 Args:
24 input_topology_path (str): Path to the input ligand topologies as a zip file containing a list of itp files. File type: input. `Sample file <https://github.com/bioexcel/biobb_pmx/raw/master/biobb_pmx/test/data/pmx/itps_to_merge.zip>`_. Accepted formats: zip (edam:format_3987).
25 output_topology_path (str): Path to the merged ligand topology file. File type: output. `Sample file <https://github.com/bioexcel/biobb_pmx/raw/master/biobb_pmx/test/reference/pmx/ref_mergedTopology.itp>`_. Accepted formats: itp (edam:format_3883).
26 properties (dic):
27 * **remove_tmp** (*bool*) - (True) [WF property] Remove temporal files.
28 * **restart** (*bool*) - (False) [WF property] Do not execute if output files exist.
29 * **sandbox_path** (*str*) - ("./") [WF property] Parent path to the sandbox directory.
31 Examples:
32 This is a use example of how to use the building block from Python::
34 from biobb_pmx.pmxbiobb.pmxmerge_ff import pmxmerge_ff
35 prop = {
36 'remove_tmp' : True
37 }
38 pmxmerge_ff(input_topology_path='/path/to/myTopologies.zip',
39 output_topology_path='/path/to/myMergedTopology.itp',
40 properties=prop)
42 Info:
43 * wrapped_software:
44 * name: PMX merge_ff
45 * version: >=1.0.1
46 * license: GNU
47 * ontology:
48 * name: EDAM
49 * schema: http://edamontology.org/EDAM.owl
51 """
53 def __init__(
54 self,
55 input_topology_path: str,
56 output_topology_path: str,
57 properties: Optional[dict] = None,
58 **kwargs,
59 ) -> None:
60 properties = properties or {}
62 # Call parent class constructor
63 super().__init__(properties)
64 self.locals_var_dict = locals().copy()
66 # Input/Output files
67 self.io_dict = {
68 "in": {"input_topology_path": input_topology_path},
69 "out": {"output_topology_path": output_topology_path},
70 }
72 # Properties specific for BB
73 # None yet
75 # Properties common in all PMX BB
76 self.gmx_lib = properties.get("gmx_lib", None)
77 if not self.gmx_lib and os.environ.get("CONDA_PREFIX", ""):
78 python_version = f"{sys.version_info.major}.{sys.version_info.minor}"
79 self.gmx_lib = str(
80 Path(os.environ.get("CONDA_PREFIX", "")).joinpath(
81 f"lib/python{python_version}/site-packages/pmx/data/mutff/"
82 )
83 )
84 if properties.get("container_path"):
85 self.gmx_lib = str(
86 Path("/usr/local/").joinpath(
87 "lib/python3.7/site-packages/pmx/data/mutff/"
88 )
89 )
91 # Check the properties
92 self.check_properties(properties)
93 self.check_arguments()
95 @launchlogger
96 def launch(self) -> int:
97 """Execute the :class:`Pmxmerge_ff <pmx.pmxmerge_ff.Pmxmerge_ff>` pmx.pmxmerge_ff.Pmxmerge_ff object."""
99 # Setup Biobb
100 if self.check_restart():
101 return 0
102 self.stage_files()
104 # Creating temporary folder
105 tmp_folder = fu.create_unique_dir()
106 fu.log("Creating %s temporary folder" % tmp_folder, self.out_log)
108 fu.unzip_list(
109 self.stage_io_dict["in"]["input_topology_path"],
110 tmp_folder,
111 out_log=self.out_log,
112 )
113 files = glob.glob(tmp_folder + "/*.itp")
114 ffsIn_list = []
115 for itp in files:
116 ffsIn_list.append(itp)
118 fu.log("Running merge_FF_files from pmx package...\n", self.out_log)
119 ligand_alchemy._merge_FF_files(
120 self.stage_io_dict["out"]["output_topology_path"], ffsIn=ffsIn_list
121 )
122 # ffsIn=[self.stage_io_dict["in"]["input_topology1_path"],self.stage_io_dict["in"]["input_topology2_path"]] )
124 fu.log("Exit code 0\n", self.out_log)
126 if self.gmx_lib:
127 self.env_vars_dict["GMXLIB"] = self.gmx_lib
129 # Run Biobb block
130 # self.run_biobb()
132 # Copy files to host
133 self.copy_to_host()
135 self.tmp_files.append(tmp_folder)
136 self.remove_tmp_files()
138 self.check_arguments(output_files_created=True, raise_exception=False)
139 return self.return_code
142def pmxmerge_ff(
143 input_topology_path: str,
144 output_topology_path: str,
145 properties: Optional[dict] = None,
146 **kwargs,
147) -> int:
148 """Create the :class:`Pmxmerge_ff <pmx.pmxmerge_ff.Pmxmerge_ff>` class and
149 execute the :meth:`launch() <pmx.pmxmerge_ff.Pmxmerge_ff.launch> method."""
150 return Pmxmerge_ff(**dict(locals())).launch()
153pmxmerge_ff.__doc__ = Pmxmerge_ff.__doc__
154main = Pmxmerge_ff.get_main(pmxmerge_ff, "Run PMX merge_ff module")
156if __name__ == "__main__":
157 main()