Coverage for biobb_gromacs/gromacs/editconf.py: 87%

61 statements  

« prev     ^ index     » next       coverage.py v7.14.1, created at 2026-05-28 06:50 +0000

1#!/usr/bin/env python3 

2 

3"""Module containing the Editconf class and the command line interface.""" 

4 

5from pathlib import PurePath 

6from typing import Optional 

7 

8from biobb_common.generic.biobb_object import BiobbObject 

9from biobb_common.tools import file_utils as fu 

10from biobb_common.tools.file_utils import launchlogger 

11 

12from biobb_gromacs.gromacs.common import get_gromacs_version 

13 

14 

15class Editconf(BiobbObject): 

16 """ 

17 | biobb_gromacs Editconf 

18 | Wrapper class for the `GROMACS editconf <http://manual.gromacs.org/current/onlinehelp/gmx-editconf.html>`_ module. 

19 | The GROMACS editconf converts generic structure format to .gro, .g96 or .pdb. 

20 

21 Args: 

22 input_gro_path (str): Path to the input GRO file. File type: input. `Sample file <https://github.com/bioexcel/biobb_gromacs/raw/master/biobb_gromacs/test/data/gromacs/editconf.gro>`_. Accepted formats: gro (edam:format_2033), pdb (edam:format_1476). 

23 output_gro_path (str): Path to the output GRO file. File type: output. `Sample file <https://github.com/bioexcel/biobb_gromacs/raw/master/biobb_gromacs/test/reference/gromacs/ref_editconf.gro>`_. Accepted formats: pdb (edam:format_1476), gro (edam:format_2033). 

24 properties (dict - Python dictionary object containing the tool parameters, not input/output files): 

25 * **distance_to_molecule** (*float*) - (1.0) [0~100|0.1] Distance of the box from the outermost atom in nm. ie 1.0nm = 10 Angstroms. 

26 * **box_vector_lenghts** (*str*) - (None) Array of floats defining the box vector lenghts ie "0.5 0.5 0.5". If this option is used the distance_to_molecule property will be ignored. 

27 * **box_type** (*str*) - ("cubic") Geometrical shape of the solvent box. Values: cubic (rectangular box with all sides equal), triclinic (triclinic box), dodecahedron (rhombic dodecahedron), octahedron (truncated octahedron). 

28 * **center_molecule** (*bool*) - (True) Center molecule in the box. 

29 * **gmx_lib** (*str*) - (None) Path set GROMACS GMXLIB environment variable. 

30 * **binary_path** (*str*) - ("gmx") Path to the GROMACS executable binary. 

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

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

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

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

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

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

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

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

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

40 

41 Examples: 

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

43 

44 from biobb_gromacs.gromacs.editconf import editconf 

45 prop = { 'distance_to_molecule': 1.0, 

46 'box_type': 'cubic'} 

47 editconf(input_gro_path='/path/to/structure.gro', 

48 output_gro_path='/path/to/newStructure.gro', 

49 properties=prop) 

50 

51 Info: 

52 * wrapped_software: 

53 * name: GROMACS Solvate 

54 * version: 2025.2 

55 * license: LGPL 2.1 

56 * ontology: 

57 * name: EDAM 

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

59 """ 

60 

61 def __init__( 

62 self, 

63 input_gro_path: str, 

64 output_gro_path: str, 

65 properties: Optional[dict] = None, 

66 **kwargs, 

67 ) -> None: 

68 properties = properties or {} 

69 

70 # Call parent class constructor 

71 super().__init__(properties) 

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

73 

74 # Input/Output files 

75 self.io_dict = { 

76 "in": {"input_gro_path": input_gro_path}, 

77 "out": {"output_gro_path": output_gro_path}, 

78 } 

79 

80 # Properties specific for BB 

81 self.distance_to_molecule = properties.get("distance_to_molecule", 1.0) 

82 self.box_vector_lenghts = properties.get("box_vector_lenghts") 

83 self.box_type = properties.get("box_type", "cubic") 

84 self.center_molecule = properties.get("center_molecule", True) 

85 

86 # Properties common in all GROMACS BB 

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

88 self.binary_path: str = properties.get("binary_path", "gmx") 

89 self.gmx_nobackup = properties.get("gmx_nobackup", True) 

90 self.gmx_nocopyright = properties.get("gmx_nocopyright", True) 

91 if self.gmx_nobackup: 

92 self.binary_path += " -nobackup" 

93 if self.gmx_nocopyright: 

94 self.binary_path += " -nocopyright" 

95 if not self.container_path: 

96 self.gmx_version = get_gromacs_version(self.binary_path) 

97 

98 # Check the properties 

99 self.check_properties(properties) 

100 self.check_arguments() 

101 

102 @launchlogger 

103 def launch(self) -> int: 

104 """Execute the :class:`Editconf <gromacs.editconf.Editconf>` object.""" 

105 

106 # Setup Biobb 

107 if self.check_restart(): 

108 return 0 

109 self.stage_files() 

110 

111 if self.container_path: 

112 working_dir = self.container_volume_path if self.container_volume_path else "/data" 

113 else: 

114 working_dir = self.stage_io_dict.get('unique_dir', '') 

115 

116 # Create command line 

117 self.cmd = [ 

118 "cd", working_dir, ";", 

119 self.binary_path, 

120 "editconf", 

121 "-f", 

122 PurePath(self.stage_io_dict["in"]["input_gro_path"]).name, 

123 "-o", 

124 PurePath(self.stage_io_dict["out"]["output_gro_path"]).name, 

125 "-bt", 

126 self.box_type, 

127 ] 

128 

129 if self.box_vector_lenghts: 

130 if not isinstance(self.box_vector_lenghts, str): 

131 self.box_vector_lenghts = " ".join(map(str, self.box_vector_lenghts)) 

132 self.cmd.append("-box") 

133 self.cmd.append(self.box_vector_lenghts) 

134 else: 

135 self.cmd.append("-d") 

136 self.cmd.append(str(self.distance_to_molecule)) 

137 fu.log( 

138 "Distance of the box to molecule: %6.2f" % self.distance_to_molecule, 

139 self.out_log, 

140 self.global_log, 

141 ) 

142 

143 if self.center_molecule: 

144 self.cmd.append("-c") 

145 fu.log("Centering molecule in the box.", self.out_log, self.global_log) 

146 

147 fu.log("Box type: %s" % self.box_type, self.out_log, self.global_log) 

148 

149 if self.gmx_lib: 

150 self.env_vars_dict = self.gmx_lib 

151 

152 # Run Biobb block 

153 self.run_biobb() 

154 

155 # Copy files to host 

156 self.copy_to_host() 

157 

158 # Remove temporal files 

159 self.remove_tmp_files() 

160 

161 # self.check_arguments(output_files_created=True, raise_exception=False) 

162 return self.return_code 

163 

164 

165def editconf( 

166 input_gro_path: str, 

167 output_gro_path: str, 

168 properties: Optional[dict] = None, 

169 **kwargs, 

170) -> int: 

171 """Create :class:`Editconf <gromacs.editconf.Editconf>` class and 

172 execute the :meth:`launch() <gromacs.editconf.Editconf.launch>` method.""" 

173 return Editconf(**dict(locals())).launch() 

174 

175 

176editconf.__doc__ = Editconf.__doc__ 

177main = Editconf.get_main(editconf, "Wrapper of the GROMACS gmx editconf module.") 

178 

179 

180if __name__ == "__main__": 

181 main()