Coverage for biobb_amber/leap/leap_solvate.py: 71%

160 statements  

« prev     ^ index     » next       coverage.py v7.16.2, created at 2026-10-06 14:11 +0000

1#!/usr/bin/env python3 

2 

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

4 

5import os 

6import re 

7from pathlib import PurePath 

8from typing import List, Optional 

9 

10from biobb_common.generic.biobb_object import BiobbObject 

11from biobb_common.tools import file_utils as fu 

12from biobb_common.tools.file_utils import launchlogger 

13 

14from biobb_amber.leap.common import _from_string_to_list 

15 

16 

17class LeapSolvate(BiobbObject): 

18 """ 

19 | biobb_amber LeapSolvate 

20 | Wrapper of the `AmberTools (AMBER MD Package) leap tool <https://ambermd.org/AmberTools.php>`_ module. 

21 | Creates and solvates a system box for an AMBER MD system using tLeap tool from the AmberTools MD package. 

22 

23 Args: 

24 input_pdb_path (str): Input 3D structure PDB file. File type: input. `Sample file <https://github.com/bioexcel/biobb_amber/raw/master/biobb_amber/test/data/leap/structure.leap.pdb>`_. Accepted formats: pdb (edam:format_1476). 

25 input_lib_path (str) (Optional): Input ligand library parameters file. File type: input. `Sample file <https://github.com/bioexcel/biobb_amber/raw/master/biobb_amber/test/data/leap/ligand.lib>`_. Accepted formats: lib (edam:format_3889), zip (edam:format_3987). 

26 input_frcmod_path (str) (Optional): Input ligand frcmod parameters file. File type: input. `Sample file <https://github.com/bioexcel/biobb_amber/raw/master/biobb_amber/test/data/leap/ligand.frcmod>`_. Accepted formats: frcmod (edam:format_3888), zip (edam:format_3987). 

27 input_params_path (str) (Optional): Additional leap parameter files to load with loadAmberParams Leap command. File type: input. `Sample file <https://github.com/bioexcel/biobb_amber/raw/master/biobb_amber/test/data/leap/frcmod.ionsdang_spce.txt>`_. Accepted formats: in (edam:format_2330), leapin (edam:format_2330), txt (edam:format_2330), zip (edam:format_3987). 

28 input_prep_path (str) (Optional): Additional leap parameter files to load with loadAmberPrep Leap command. File type: input. Accepted formats: in (edam:format_2330), leapin (edam:format_2330), txt (edam:format_2330), zip (edam:format_3987). 

29 input_source_path (str) (Optional): Additional leap command files to load with source Leap command. File type: input. `Sample file <https://github.com/bioexcel/biobb_amber/raw/master/biobb_amber/test/data/leap/leaprc.water.spce.txt>`_. Accepted formats: in (edam:format_2330), leapin (edam:format_2330), txt (edam:format_2330), zip (edam:format_3987). 

30 output_pdb_path (str): Output 3D structure PDB file matching the topology file. File type: output. `Sample file <https://github.com/bioexcel/biobb_amber/raw/master/biobb_amber/test/reference/leap/structure.solv.pdb>`_. Accepted formats: pdb (edam:format_1476). 

31 output_top_path (str): Output topology file (AMBER ParmTop). File type: output. `Sample file <https://github.com/bioexcel/biobb_amber/raw/master/biobb_amber/test/reference/leap/structure.solv.top>`_. Accepted formats: top (edam:format_3881), parmtop (edam:format_3881), prmtop (edam:format_3881). 

32 output_crd_path (str): Output coordinates file (AMBER crd). File type: output. `Sample file <https://github.com/bioexcel/biobb_amber/raw/master/biobb_amber/test/reference/leap/structure.solv.crd>`_. Accepted formats: crd (edam:format_3878), mdcrd (edam:format_3878), inpcrd (edam:format_3878). 

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

34 * **forcefield** (*list*) - (["protein.ff14SB","DNA.bsc1","gaff"]) Forcefields to be used for the structure generation. Each item should be either a path to a leaprc file or a string with the leaprc file name if the force field is included with Amber (e.g. "/path/to/leaprc.protein.ff14SB" or "protein.ff14SB"). Default values: ["protein.ff14SB","DNA.bsc1","gaff"]. 

35 * **water_type** (*str*) - ("TIP3PBOX") Water molecule parameters to be used for the topology. Values: POL3BOX, QSPCFWBOX, SPCBOX, SPCFWBOX, TIP3PBOX, TIP3PFBOX, TIP4PBOX, TIP4PEWBOX, OPCBOX, OPC3BOX, TIP5PBOX. 

36 * **box_type** (*str*) - ("truncated_octahedron") Type for the MD system box. Values: cubic, truncated_octahedron. 

37 * **ions_type** (*str*) - ("ionsjc_tip3p") Ions type. Values: ionsjc_tip3p, ionsjc_spce, ionsff99_tip3p, ions_charmm22, ionsjc_tip4pew, None. 

38 * **neutralise** (*bool*) - ("False") Energetically neutralise the system adding the necessary counterions. 

39 * **iso** (*bool*) - ("False") Make the box isometric. 

40 * **positive_ions_number** (*int*) - (0) Number of additional positive ions to include in the system box. 

41 * **negative_ions_number** (*int*) - (0) Number of additional negative ions to include in the system box. 

42 * **positive_ions_type** (*str*) - ("Na+") Type of additional positive ions to include in the system box. Values: Na+,K+. 

43 * **negative_ions_type** (*str*) - ("Cl-") Type of additional negative ions to include in the system box. Values: Cl-. 

44 * **distance_to_molecule** (*float*) - ("8.0") Size for the MD system box -in Angstroms-, defined such as the minimum distance between any atom originally present in solute and the edge of the periodic box is given by this distance parameter. 

45 * **closeness** (*float*) - ("1.0") How close, in Å, solvent ATOMs may come to solute ATOMs. 

46 * **binary_path** (*str*) - ("tleap") Path to the tleap executable binary. 

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

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

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

50 * **container_path** (*str*) - (None) Container path definition. 

51 * **container_image** (*str*) - ('afandiadib/ambertools:serial') Container image definition. 

52 * **container_volume_path** (*str*) - ('/tmp') Container volume path definition. 

53 * **container_working_dir** (*str*) - (None) Container working directory definition. 

54 * **container_user_id** (*str*) - (None) Container user_id definition. 

55 * **container_shell_path** (*str*) - ('/bin/bash') Path to default shell inside the container. 

56 

57 Examples: 

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

59 from biobb_amber.leap.leap_solvate import leap_solvate 

60 prop = { 

61 'forcefield': ['protein.ff14SB'], 

62 'water_type': 'TIP3PBOX', 

63 'box_type': 'truncated_octahedron', 

64 'neutralise' : True 

65 } 

66 leap_solvate(input_pdb_path='/path/to/structure.pdb', 

67 output_pdb_path='/path/to/newStructure.pdb', 

68 output_top_path='/path/to/newTopology.top', 

69 output_crd_path='/path/to/newCoordinates.crd', 

70 properties=prop) 

71 

72 Info: 

73 * wrapped_software: 

74 * name: AmberTools tLeap 

75 * version: >20.9 

76 * license: LGPL 2.1 

77 * ontology: 

78 * name: EDAM 

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

80 

81 """ 

82 

83 def __init__( 

84 self, 

85 input_pdb_path: str, 

86 output_pdb_path: str, 

87 output_top_path: str, 

88 output_crd_path: str, 

89 input_lib_path: Optional[str] = None, 

90 input_frcmod_path: Optional[str] = None, 

91 input_params_path: Optional[str] = None, 

92 input_prep_path: Optional[str] = None, 

93 input_source_path: Optional[str] = None, 

94 properties: Optional[dict] = None, 

95 **kwargs, 

96 ): 

97 properties = properties or {} 

98 

99 # Call parent class constructor 

100 super().__init__(properties) 

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

102 

103 # Input/Output files 

104 self.io_dict = { 

105 "in": { 

106 "input_pdb_path": input_pdb_path, 

107 "input_lib_path": input_lib_path, 

108 "input_frcmod_path": input_frcmod_path, 

109 "input_params_path": input_params_path, 

110 "input_prep_path": input_prep_path, 

111 "input_source_path": input_source_path, 

112 }, 

113 "out": { 

114 "output_pdb_path": output_pdb_path, 

115 "output_top_path": output_top_path, 

116 "output_crd_path": output_crd_path, 

117 }, 

118 } 

119 

120 # # Ligand Parameter lists 

121 # self.ligands_lib_list = [] 

122 # if input_lib_path: 

123 # self.ligands_lib_list.append(input_lib_path) 

124 # 

125 # self.ligands_frcmod_list = [] 

126 # if input_frcmod_path: 

127 # self.ligands_frcmod_list.append(input_frcmod_path) 

128 

129 # Properties specific for BB 

130 self.properties = properties 

131 

132 # Set default forcefields 

133 if self.container_path: 

134 self.forcefield = _from_string_to_list( 

135 properties.get("forcefield", ['leaprc.protein.ff14SB', 'leaprc.DNA.bsc1', 'leaprc.gaff']) 

136 ) 

137 else: 

138 amber_home_path = os.getenv("AMBERHOME") 

139 protein_ff14SB_path = os.path.join(amber_home_path, 'dat', 'leap', 'cmd', 'leaprc.protein.ff14SB') 

140 dna_bsc1_path = os.path.join(amber_home_path, 'dat', 'leap', 'cmd', 'leaprc.DNA.bsc1') 

141 gaff_path = os.path.join(amber_home_path, 'dat', 'leap', 'cmd', 'leaprc.gaff') 

142 

143 self.forcefield = _from_string_to_list( 

144 properties.get("forcefield", [protein_ff14SB_path, dna_bsc1_path, gaff_path]) 

145 ) 

146 

147 # Find the paths of the leaprc files if only the force field names are provided 

148 self.forcefield = self.find_leaprc_paths(self.forcefield) 

149 

150 self.water_type = properties.get("water_type", "TIP3PBOX") 

151 self.box_type = properties.get("box_type", "truncated_octahedron") 

152 self.ions_type = properties.get("ions_type", "ionsjc_tip3p") 

153 self.neutralise = properties.get("neutralise", False) 

154 self.iso = properties.get("iso", False) 

155 self.positive_ions_number = properties.get("positive_ions_number", 0) 

156 self.positive_ions_type = properties.get("positive_ions_type", "Na+") 

157 self.negative_ions_number = properties.get("negative_ions_number", 0) 

158 self.negative_ions_type = properties.get("negative_ions_type", "Cl-") 

159 self.distance_to_molecule = properties.get("distance_to_molecule", 8.0) 

160 self.closeness = properties.get("closeness", 1.0) 

161 self.binary_path = properties.get("binary_path", "tleap") 

162 

163 # Check the properties 

164 self.check_properties(properties) 

165 self.check_arguments() 

166 

167 def find_leaprc_paths(self, forcefields: List[str]) -> List[str]: 

168 """ 

169 Find the leaprc paths for the force fields provided. 

170 

171 For each item in the forcefields list, the function checks if the str is a path to an existing file. 

172 If not, it tries to find the file in the $AMBERHOME/dat/leap/cmd/ directory or the $AMBERHOME/dat/leap/cmd/oldff/ 

173 directory with and without the leaprc prefix. 

174 

175 Args: 

176 forcefields (List[str]): List of force fields to find the leaprc files for. 

177 

178 Returns: 

179 List[str]: List of leaprc file paths. 

180 """ 

181 

182 leaprc_paths = [] 

183 

184 for forcefield in forcefields: 

185 

186 num_paths = len(leaprc_paths) 

187 

188 # Check if the forcefield is a path to an existing file 

189 if os.path.exists(forcefield): 

190 leaprc_paths.append(forcefield) 

191 continue 

192 

193 # Check if the forcefield is in the leaprc directory 

194 leaprc_path = os.path.join(os.environ.get('AMBERHOME', ''), 'dat', 'leap', 'cmd', f"leaprc.{forcefield}") 

195 if os.path.exists(leaprc_path): 

196 leaprc_paths.append(leaprc_path) 

197 continue 

198 

199 # Check if the forcefield is in the oldff directory 

200 leaprc_path = os.path.join(os.environ.get('AMBERHOME', ''), 'dat', 'leap', 'cmd', 'oldff', f"leaprc.{forcefield}") 

201 if os.path.exists(leaprc_path): 

202 leaprc_paths.append(leaprc_path) 

203 continue 

204 

205 # Check if the forcefield is in the leaprc directory without the leaprc prefix 

206 leaprc_path = os.path.join(os.environ.get('AMBERHOME', ''), 'dat', 'leap', 'cmd', f"{forcefield}") 

207 if os.path.exists(leaprc_path): 

208 leaprc_paths.append(leaprc_path) 

209 continue 

210 

211 # Check if the forcefield is in the oldff directory without the leaprc prefix 

212 leaprc_path = os.path.join(os.environ.get('AMBERHOME', ''), 'dat', 'leap', 'cmd', 'oldff', f"{forcefield}") 

213 if os.path.exists(leaprc_path): 

214 leaprc_paths.append(leaprc_path) 

215 continue 

216 

217 new_num_paths = len(leaprc_paths) 

218 

219 if new_num_paths == num_paths: 

220 raise ValueError(f"Force field {forcefield} not found. Check the $AMBERHOME/dat/leap/cmd/ directory for available force fields or provide the path to an existing leaprc file.") 

221 

222 return leaprc_paths 

223 

224 # def check_data_params(self, out_log, err_log): 

225 # """ Checks input/output paths correctness """ 

226 

227 # # Check input(s) 

228 # self.io_dict["in"]["input_pdb_path"] = check_input_path(self.io_dict["in"]["input_pdb_path"], "input_pdb_path", False, out_log, self.__class__.__name__) 

229 # self.io_dict["in"]["input_lib_path"] = check_input_path(self.io_dict["in"]["input_lib_path"], "input_lib_path", True, out_log, self.__class__.__name__) 

230 # self.io_dict["in"]["input_frcmod_path"] = check_input_path(self.io_dict["in"]["input_frcmod_path"], "input_frcmod_path", True, out_log, self.__class__.__name__) 

231 # # self.io_dict["in"]["input_params_path"] = check_input_path(self.io_dict["in"]["input_params_path"], "input_params_path", True, out_log, self.__class__.__name__) 

232 # # self.io_dict["in"]["input_source_path"] = check_input_path(self.io_dict["in"]["input_source_path"], "input_source_path", True, out_log, self.__class__.__name__) 

233 

234 # # Check output(s) 

235 # self.io_dict["out"]["output_pdb_path"] = check_output_path(self.io_dict["out"]["output_pdb_path"], "output_pdb_path", False, out_log, self.__class__.__name__) 

236 # self.io_dict["out"]["output_top_path"] = check_output_path(self.io_dict["out"]["output_top_path"], "output_top_path", False, out_log, self.__class__.__name__) 

237 # self.io_dict["out"]["output_crd_path"] = check_output_path(self.io_dict["out"]["output_crd_path"], "output_crd_path", False, out_log, self.__class__.__name__) 

238 

239 def _resolve_input_files(self, io_key: str, tmp_folder: Optional[str]) -> List[str]: 

240 """Resolve an optional input (zip or single file) to the list of paths the tleap 

241 script must load. 

242 

243 In container mode the zipball is staged into the host sandbox (unique_dir), which is 

244 bind-mounted at ``container_volume_path``; it is unpacked on the host and the entries 

245 are referenced by their container path. In local mode the zipball is unpacked into a 

246 temporary folder and referenced by its host path. 

247 """ 

248 file_path = self.io_dict["in"][io_key] 

249 if file_path is None: 

250 return [] 

251 if not file_path.endswith(".zip"): 

252 return [self.stage_io_dict["in"][io_key]] 

253 if self.container_path: 

254 unique_dir = self.stage_io_dict["unique_dir"] 

255 host_zip = os.path.join(unique_dir, os.path.basename(file_path)) 

256 extracted = fu.unzip_list(host_zip, dest_dir=unique_dir, out_log=self.out_log) 

257 return [ 

258 os.path.join(self.container_volume_path, os.path.relpath(p, unique_dir)) 

259 for p in extracted 

260 ] 

261 return fu.unzip_list( 

262 self.stage_io_dict["in"][io_key], dest_dir=tmp_folder, out_log=self.out_log 

263 ) 

264 

265 @launchlogger 

266 def launch(self): 

267 """Launches the execution of the LeapSolvate module.""" 

268 

269 # check input/output paths and parameters 

270 # self.check_data_params(self.out_log, self.err_log) 

271 

272 # Setup Biobb 

273 if self.check_restart(): 

274 return 0 

275 self.stage_files() 

276 

277 box_command = "solvateOct" 

278 if self.box_type == "cubic": 

279 box_command = "solvateBox" 

280 

281 # Forcefield 

282 # source_ff_command = "source leaprc." + self.forcefield 

283 

284 # Water Type 

285 # leaprc.water.tip4pew, tip4pd, tip3p, spceb, spce, opc, fb4, fb3 

286 # Values: POL3BOX, QSPCFWBOX, SPCBOX, SPCFWBOX, TIP3PBOX, TIP3PFBOX, TIP4PBOX, TIP4PEWBOX, OPCBOX, OPC3BOX, TIP5PBOX. 

287 source_wat_command = "source leaprc.water.tip3p" 

288 if self.water_type == "TIP4PEWBOX": 

289 source_wat_command = "leaprc.water.tip4pew" 

290 if self.water_type == "TIP4PBOX": 

291 source_wat_command = "leaprc.water.tip4pd" 

292 if re.match(r"SPC", self.water_type): 

293 source_wat_command = "source leaprc.water.spce" 

294 if re.match(r"OPC", self.water_type): 

295 source_wat_command = "source leaprc.water.opc" 

296 

297 # Counterions 

298 ions_command = "" 

299 if self.neutralise: 

300 ions_command = ( 

301 ions_command + "addions mol " + self.negative_ions_type + " 0 \n" 

302 ) 

303 ions_command = ( 

304 ions_command + "addions mol " + self.positive_ions_type + " 0 \n" 

305 ) 

306 

307 if self.negative_ions_number != 0: 

308 ions_command = ( 

309 ions_command + "addions mol " + self.negative_ions_type + " " + str(self.negative_ions_number) + " \n" 

310 ) 

311 if self.positive_ions_number != 0: 

312 ions_command = ( 

313 ions_command + "addions mol " + self.positive_ions_type + " " + str(self.positive_ions_number) + " \n" 

314 ) 

315 

316 # Creating temporary folder & Leap configuration (instructions) file 

317 if self.container_path: 

318 instructions_file = str( 

319 PurePath(self.stage_io_dict["unique_dir"]).joinpath("leap.in") 

320 ) 

321 instructions_file_path = str( 

322 PurePath(self.container_volume_path).joinpath("leap.in") 

323 ) 

324 tmp_folder = None 

325 else: 

326 tmp_folder = fu.create_unique_dir() 

327 instructions_file = str(PurePath(tmp_folder).joinpath("leap.in")) 

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

329 instructions_file_path = instructions_file 

330 

331 ligands_lib_list = self._resolve_input_files("input_lib_path", tmp_folder) 

332 ligands_frcmod_list = self._resolve_input_files("input_frcmod_path", tmp_folder) 

333 amber_params_list = self._resolve_input_files("input_params_path", tmp_folder) 

334 amber_prep_list = self._resolve_input_files("input_prep_path", tmp_folder) 

335 leap_source_list = self._resolve_input_files("input_source_path", tmp_folder) 

336 

337 with open(instructions_file, "w") as leapin: 

338 # Forcefields loaded by default: 

339 # Protein: ff14SB (PARM99 + frcmod.ff99SB + frcmod.parmbsc0 + OL3 for RNA) 

340 # leapin.write("source leaprc.protein.ff14SB \n") 

341 # DNA: parmBSC1 (ParmBSC1 (ff99 + bsc0 + bsc1) for DNA. Ivani et al. Nature Methods 13: 55, 2016) 

342 # leapin.write("source leaprc.DNA.bsc1 \n") 

343 # Ligands: GAFF (General Amber Force field, J. Comput. Chem. 2004 Jul 15;25(9):1157-74) 

344 # leapin.write("source leaprc.gaff \n") 

345 

346 # Forcefields loaded from input forcefield property 

347 for t in self.forcefield: 

348 if self.container_path: 

349 leapin.write("source leaprc.{}\n".format(t)) 

350 else: 

351 leapin.write("source {}\n".format(t)) 

352 

353 # Additional Leap commands 

354 for leap_commands in leap_source_list: 

355 leapin.write("source " + leap_commands + "\n") 

356 

357 # Ions Type 

358 if self.ions_type != "None": 

359 leapin.write("loadamberparams frcmod." + self.ions_type + "\n") 

360 

361 # Additional Amber parameters 

362 for amber_params in amber_params_list: 

363 leapin.write("loadamberparams " + amber_params + "\n") 

364 

365 # Additional Amber prep files 

366 for amber_prep in amber_prep_list: 

367 leapin.write("loadamberprep " + amber_prep + "\n") 

368 

369 # Water Model loaded from input water_model property 

370 leapin.write(source_wat_command + " \n") 

371 

372 # Ligand(s) libraries (if any) 

373 for amber_lib in ligands_lib_list: 

374 leapin.write("loadOff " + amber_lib + "\n") 

375 for amber_frcmod in ligands_frcmod_list: 

376 leapin.write("loadamberparams " + amber_frcmod + "\n") 

377 

378 # Loading PDB file 

379 leapin.write( 

380 "mol = loadpdb " + self.stage_io_dict["in"]["input_pdb_path"] + " \n" 

381 ) 

382 

383 # Generating box + adding water molecules 

384 leapin.write( 

385 box_command + " mol " + self.water_type + " " + str(self.distance_to_molecule) 

386 ) 

387 leapin.write( 

388 " iso " + str(self.closeness) + "\n" 

389 ) if self.iso else leapin.write(" " + str(self.closeness) + "\n") 

390 

391 # Adding counterions 

392 leapin.write(ions_command) 

393 

394 # Saving output PDB file, coordinates and topology 

395 leapin.write( 

396 "savepdb mol " + self.stage_io_dict["out"]["output_pdb_path"] + " \n" 

397 ) 

398 leapin.write( 

399 "saveAmberParm mol " + self.stage_io_dict["out"]["output_top_path"] + " " + self.stage_io_dict["out"]["output_crd_path"] + "\n" 

400 ) 

401 leapin.write("quit \n") 

402 

403 # Command line 

404 self.cmd = [self.binary_path, "-f", instructions_file_path] 

405 

406 # Run Biobb block 

407 self.run_biobb() 

408 

409 # Copy files to host 

410 self.copy_to_host() 

411 

412 # Saving octahedron box with all decimals in PDB file. Needed for the add_ions BB. 

413 

414 # Getting octahedron box from generated crd file 

415 with open(self.io_dict["out"]["output_crd_path"], "r") as file: 

416 for line in file: 

417 pass 

418 

419 # Adding box as a first line in the generated pdb file with OCTBOX tag 

420 octbox = "OCTBOX " + line 

421 with open(self.io_dict["out"]["output_pdb_path"], "r+") as f: 

422 content = f.read() 

423 f.seek(0, 0) 

424 f.write(octbox + content) 

425 

426 # remove temporary folder(s) 

427 self.tmp_files.extend([str(tmp_folder), "leap.log"]) 

428 self.remove_tmp_files() 

429 

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

431 

432 return self.return_code 

433 

434 

435def leap_solvate( 

436 input_pdb_path: str, 

437 output_pdb_path: str, 

438 output_top_path: str, 

439 output_crd_path: str, 

440 input_lib_path: Optional[str] = None, 

441 input_frcmod_path: Optional[str] = None, 

442 input_params_path: Optional[str] = None, 

443 input_prep_path: Optional[str] = None, 

444 input_source_path: Optional[str] = None, 

445 properties: Optional[dict] = None, 

446 **kwargs, 

447) -> int: 

448 """Create the :class:`LeapSolvate <leap.leap_solvate.LeapSolvate>` class and 

449 execute the :meth:`launch() <leap.leap_solvate.LeapSolvate.launch>` method.""" 

450 return LeapSolvate(**dict(locals())).launch() 

451 

452 

453leap_solvate.__doc__ = LeapSolvate.__doc__ 

454main = LeapSolvate.get_main(leap_solvate, "Generating and solvating a system box for an AMBER MD system. using tLeap program from AmberTools MD package.") 

455 

456if __name__ == "__main__": 

457 main()