Coverage for biobb_pmx / pmxbiobb / pmxmerge_ff.py: 94%

52 statements  

« prev     ^ index     » next       coverage.py v7.13.0, created at 2025-12-22 11:48 +0000

1#!/usr/bin/env python3 

2 

3"""Module containing the PMX merge_ff class and the command line interface.""" 

4 

5import glob 

6import os 

7import sys 

8from pathlib import Path 

9from typing import Optional 

10 

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 

15 

16 

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. 

22 

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 

27 properties (dic): 

28 * **remove_tmp** (*bool*) - (True) [WF property] Remove temporal files. 

29 * **restart** (*bool*) - (False) [WF property] Do not execute if output files exist. 

30 * **sandbox_path** (*str*) - ("./") [WF property] Parent path to the sandbox directory. 

31 * **container_path** (*str*) - (None) Path to the binary executable of your container. 

32 * **container_image** (*str*) - (None) Container Image identifier. 

33 * **container_volume_path** (*str*) - ("/inout") Path to an internal directory in the container. 

34 * **container_working_dir** (*str*) - (None) Path to the internal CWD in the container. 

35 * **container_user_id** (*str*) - (None) User number id to be mapped inside the container. 

36 * **container_shell_path** (*str*) - ("/bin/bash") Path to the binary executable of the container shell. 

37 

38 Examples: 

39 This is a use example of how to use the building block from Python:: 

40 

41 from biobb_pmx.pmxbiobb.pmxmerge_ff import pmxmerge_ff 

42 prop = { 

43 'remove_tmp' : True 

44 } 

45 pmxmerge_ff(input_topology_path='/path/to/myTopologies.zip', 

46 output_topology_path='/path/to/myMergedTopology.itp', 

47 properties=prop) 

48 

49 Info: 

50 * wrapped_software: 

51 * name: PMX merge_ff 

52 * version: >=1.0.1 

53 * license: GNU 

54 * ontology: 

55 * name: EDAM 

56 * schema: http://edamontology.org/EDAM.owl 

57 

58 """ 

59 

60 def __init__( 

61 self, 

62 input_topology_path: str, 

63 output_topology_path: str, 

64 properties: Optional[dict] = None, 

65 **kwargs, 

66 ) -> None: 

67 properties = properties or {} 

68 

69 # Call parent class constructor 

70 super().__init__(properties) 

71 self.locals_var_dict = locals().copy() 

72 

73 # Input/Output files 

74 self.io_dict = { 

75 "in": {"input_topology_path": input_topology_path}, 

76 "out": {"output_topology_path": output_topology_path}, 

77 } 

78 

79 # Properties specific for BB 

80 # None yet 

81 

82 # Properties common in all PMX BB 

83 self.gmx_lib = properties.get("gmx_lib", None) 

84 if not self.gmx_lib and os.environ.get("CONDA_PREFIX", ""): 

85 python_version = f"{sys.version_info.major}.{sys.version_info.minor}" 

86 self.gmx_lib = str( 

87 Path(os.environ.get("CONDA_PREFIX", "")).joinpath( 

88 f"lib/python{python_version}/site-packages/pmx/data/mutff/" 

89 ) 

90 ) 

91 if properties.get("container_path"): 

92 self.gmx_lib = str( 

93 Path("/usr/local/").joinpath( 

94 "lib/python3.7/site-packages/pmx/data/mutff/" 

95 ) 

96 ) 

97 self.binary_path = properties.get("binary_path", "pmx") 

98 

99 # Check the properties 

100 self.check_properties(properties) 

101 self.check_arguments() 

102 

103 @launchlogger 

104 def launch(self) -> int: 

105 """Execute the :class:`Pmxmerge_ff <pmx.pmxmerge_ff.Pmxmerge_ff>` pmx.pmxmerge_ff.Pmxmerge_ff object.""" 

106 

107 # Setup Biobb 

108 if self.check_restart(): 

109 return 0 

110 self.stage_files() 

111 

112 # Creating temporary folder 

113 tmp_folder = fu.create_unique_dir() 

114 fu.log("Creating %s temporary folder" % tmp_folder, self.out_log) 

115 

116 fu.unzip_list( 

117 self.stage_io_dict["in"]["input_topology_path"], 

118 tmp_folder, 

119 out_log=self.out_log, 

120 ) 

121 files = glob.glob(tmp_folder + "/*.itp") 

122 ffsIn_list = [] 

123 for itp in files: 

124 ffsIn_list.append(itp) 

125 

126 fu.log("Running merge_FF_files from pmx package...\n", self.out_log) 

127 ligand_alchemy._merge_FF_files( 

128 self.stage_io_dict["out"]["output_topology_path"], ffsIn=ffsIn_list 

129 ) 

130 # ffsIn=[self.stage_io_dict["in"]["input_topology1_path"],self.stage_io_dict["in"]["input_topology2_path"]] ) 

131 

132 fu.log("Exit code 0\n", self.out_log) 

133 

134 if self.gmx_lib: 

135 self.env_vars_dict["GMXLIB"] = self.gmx_lib 

136 

137 # Run Biobb block 

138 # self.run_biobb() 

139 

140 # Copy files to host 

141 self.copy_to_host() 

142 

143 self.tmp_files.append(tmp_folder) 

144 self.remove_tmp_files() 

145 

146 self.check_arguments(output_files_created=True, raise_exception=False) 

147 return self.return_code 

148 

149 

150def pmxmerge_ff( 

151 input_topology_path: str, 

152 output_topology_path: str, 

153 properties: Optional[dict] = None, 

154 **kwargs, 

155) -> int: 

156 """Create the :class:`Pmxmerge_ff <pmx.pmxmerge_ff.Pmxmerge_ff>` class and 

157 execute the :meth:`launch() <pmx.pmxmerge_ff.Pmxmerge_ff.launch> method.""" 

158 return Pmxmerge_ff(**dict(locals())).launch() 

159 

160 

161pmxmerge_ff.__doc__ = Pmxmerge_ff.__doc__ 

162main = Pmxmerge_ff.get_main(pmxmerge_ff, "Run PMX merge_ff module") 

163 

164if __name__ == "__main__": 

165 main()