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

60 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-03-05 08:26 +0000

1#!/usr/bin/env python3 

2 

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

4import shutil 

5from typing import Optional 

6from pathlib import Path 

7from biobb_common.generic.biobb_object import BiobbObject 

8from biobb_common.tools import file_utils as fu 

9from biobb_common.tools.file_utils import launchlogger 

10from biobb_gromacs.gromacs.common import get_gromacs_version 

11 

12 

13class Solvate(BiobbObject): 

14 """ 

15 | biobb_gromacs Solvate 

16 | Wrapper of the `GROMACS solvate <http://manual.gromacs.org/current/onlinehelp/gmx-solvate.html>`_ module. 

17 | The GROMACS solvate module, generates a box of solvent around the selected structure. 

18 

19 Args: 

20 input_solute_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/solvate.gro>`_. Accepted formats: gro (edam:format_2033), pdb (edam:format_1476). 

21 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_solvate.gro>`_. Accepted formats: gro (edam:format_2033), pdb (edam:format_1476). 

22 input_top_zip_path (str): Path the input TOP topology in zip format. File type: input. `Sample file <https://github.com/bioexcel/biobb_gromacs/raw/master/biobb_gromacs/test/data/gromacs/solvate.zip>`_. Accepted formats: zip (edam:format_3987). 

23 output_top_zip_path (str): Path the output topology in zip format. File type: output. `Sample file <https://github.com/bioexcel/biobb_gromacs/raw/master/biobb_gromacs/test/reference/gromacs/ref_solvate.zip>`_. Accepted formats: zip (edam:format_3987). 

24 input_solvent_gro_path (str) (Optional): (spc216.gro) Path to the GRO file containing the structure of the solvent. File type: input. Accepted formats: gro (edam:format_2033). 

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

26 * **shell** (*float*) - (0.0) [0~100|0.1] Thickness in nanometers of optional water layer around solute. 

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

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

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

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

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

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

33 * **container_image** (*str*) - ("gromacs/gromacs:latest") Container Image identifier. 

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

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

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

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

38 

39 Examples: 

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

41 

42 from biobb_gromacs.gromacs.solvate import Solvate 

43 prop = { 'shell': 1.0 } 

44 solvate(input_solute_gro_path='/path/to/myStructure.gro', 

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

46 input_top_zip_path='/path/to/myTopology.zip', 

47 output_top_zip_path='/path/to/newTopology.zip', 

48 properties=prop) 

49 

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__(self, input_solute_gro_path: str, output_gro_path: str, input_top_zip_path: str, 

62 output_top_zip_path: str, input_solvent_gro_path: Optional[str] = None, properties: Optional[dict] = None, **kwargs) -> None: 

63 properties = properties or {} 

64 

65 # Call parent class constructor 

66 super().__init__(properties) 

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

68 

69 # Input/Output files 

70 self.io_dict = { 

71 "in": {"input_solute_gro_path": input_solute_gro_path, "input_solvent_gro_path": input_solvent_gro_path}, 

72 "out": {"output_gro_path": output_gro_path, "output_top_zip_path": output_top_zip_path} 

73 } 

74 

75 # Should not be copied inside container 

76 self.input_top_zip_path = input_top_zip_path 

77 

78 # Properties specific for BB 

79 self.shell = properties.get('shell') 

80 if not self.io_dict["in"].get('input_solvent_gro_path'): 

81 self.io_dict["in"]['input_solvent_gro_path'] = 'spc216.gro' 

82 

83 # Properties common in all GROMACS BB 

84 self.gmx_lib = properties.get('gmx_lib', None) 

85 self.binary_path = properties.get('binary_path', 'gmx') 

86 self.gmx_nobackup = properties.get('gmx_nobackup', True) 

87 self.gmx_nocopyright = properties.get('gmx_nocopyright', True) 

88 if self.gmx_nobackup: 

89 self.binary_path += ' -nobackup' 

90 if self.gmx_nocopyright: 

91 self.binary_path += ' -nocopyright' 

92 if not self.container_path: 

93 self.gmx_version = get_gromacs_version(self.binary_path) 

94 

95 # Check the properties 

96 self.check_properties(properties) 

97 self.check_arguments() 

98 

99 @launchlogger 

100 def launch(self) -> int: 

101 """Execute the :class:`Solvate <gromacs.solvate.Solvate>` object.""" 

102 

103 # Setup Biobb 

104 if self.check_restart(): 

105 return 0 

106 self.stage_files() 

107 

108 # Unzip topology to topology_out 

109 top_file = fu.unzip_top(zip_file=self.input_top_zip_path, out_log=self.out_log) 

110 top_dir = str(Path(top_file).parent) 

111 

112 if self.container_path: 

113 shutil.copytree(top_dir, str(Path(self.stage_io_dict.get("unique_dir", "")).joinpath(Path(top_dir).name))) 

114 top_file = str(Path(self.container_volume_path).joinpath(Path(top_dir).name, Path(top_file).name)) 

115 

116 self.cmd = [self.binary_path, 'solvate', 

117 '-cp', self.stage_io_dict["in"]["input_solute_gro_path"], 

118 '-cs', self.stage_io_dict["in"]["input_solvent_gro_path"], 

119 '-o', self.stage_io_dict["out"]["output_gro_path"], 

120 '-p', top_file] 

121 

122 if self.shell: 

123 self.cmd.append("-shell") 

124 self.cmd.append(str(self.shell)) 

125 

126 if self.gmx_lib: 

127 self.env_vars_dict['GMXLIB'] = self.gmx_lib 

128 

129 # Run Biobb block 

130 self.run_biobb() 

131 

132 # Copy files to host 

133 self.copy_to_host() 

134 

135 if self.container_path: 

136 top_file = str(Path(self.stage_io_dict.get("unique_dir", "")).joinpath(Path(top_dir).name, Path(top_file).name)) 

137 

138 # zip topology 

139 fu.log('Compressing topology to: %s' % self.stage_io_dict["out"]["output_top_zip_path"], self.out_log, 

140 self.global_log) 

141 fu.zip_top(zip_file=self.io_dict["out"]["output_top_zip_path"], top_file=top_file, out_log=self.out_log, remove_original_files=self.remove_tmp) 

142 

143 # Remove temporal files 

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 solvate(input_solute_gro_path: str, output_gro_path: str, input_top_zip_path: str, 

151 output_top_zip_path: str, input_solvent_gro_path: Optional[str] = None, properties: Optional[dict] = None, **kwargs) -> int: 

152 """Create :class:`Solvate <gromacs.solvate.Solvate>` class and 

153 execute the :meth:`launch() <gromacs.solvate.Solvate.launch>` method.""" 

154 return Solvate(**dict(locals())).launch() 

155 

156 

157solvate.__doc__ = Solvate.__doc__ 

158main = Solvate.get_main(solvate, "Wrapper for the GROMACS solvate module.") 

159 

160 

161if __name__ == '__main__': 

162 main()