Coverage for biobb_flexdyn/flexdyn/concoord_dist.py: 86%

78 statements  

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

1#!/usr/bin/env python3 

2 

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

4from typing import Optional 

5import os 

6import shutil 

7from pathlib import Path, PurePath 

8from biobb_common.tools import file_utils as fu 

9from biobb_common.generic.biobb_object import BiobbObject 

10from biobb_common.tools.file_utils import launchlogger 

11 

12 

13class ConcoordDist(BiobbObject): 

14 """ 

15 | biobb_flexdyn ConcoordDist 

16 | Wrapper of the Dist tool from the Concoord package. 

17 | Structure interpretation and bond definitions from a PDB/GRO file. 

18 

19 Args: 

20 input_structure_path (str): Input structure file. File type: input. `Sample file <https://github.com/bioexcel/biobb_flexdyn/raw/master/biobb_flexdyn/test/data/flexdyn/structure.pdb>`_. Accepted formats: pdb (edam:format_1476), gro (edam:format_2033). 

21 output_pdb_path (str): Output pdb file. File type: output. `Sample file <https://github.com/bioexcel/biobb_flexdyn/raw/master/biobb_flexdyn/test/reference/flexdyn/dist.pdb>`_. Accepted formats: pdb (edam:format_1476). 

22 output_gro_path (str): Output gro file. File type: output. `Sample file <https://github.com/bioexcel/biobb_flexdyn/raw/master/biobb_flexdyn/test/reference/flexdyn/dist.gro>`_. Accepted formats: gro (edam:format_2033). 

23 output_dat_path (str): Output dat with structure interpretation and bond definitions. File type: output. `Sample file <https://github.com/bioexcel/biobb_flexdyn/raw/master/biobb_flexdyn/test/reference/flexdyn/dist.dat>`_. Accepted formats: dat (edam:format_1637), txt (edam:format_2330). 

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

25 * **binary_path** (*str*) - ("dist") Concoord dist binary path to be used. 

26 * **vdw** (*int*) - (1) Select a set of Van der Waals parameters. Values: 1 (OPLS-UA -united atoms- parameters), 2 (OPLS-AA -all atoms- parameters), 3 (PROLSQ repel parameters), 4 (Yamber2 parameters), 5 (Li et al. parameters), 6 (OPLS-X parameters -recommended for NMR structure determination-). 

27 * **concoord_lib_path** (*str*) - (None) Path to Concoord library files. If not specified will look for CONCOORDLIB conda environment variable. 

28 * **bond_angle** (*int*) - (1) Select a set of bond/angle parameters. Values: 1 (Concoord default parameters), 2 (Engh-Huber parameters). 

29 * **retain_hydrogens** (*bool*) - (False) Retain hydrogen atoms 

30 * **nb_interactions** (*bool*) - (False) Try to find alternatives for non-bonded interactions (by default the native contacts will be preserved) 

31 * **cutoff** (*float*) - (4.0) cut-off radius (Angstroms) for non-bonded interacting pairs (the cut-off distances are additional to the sum of VDW radii) 

32 * **min_distances** (*int*) - (50) Minimum number of distances to be defined for each atom 

33 * **damp** (*float*) - (1.0) Multiply each distance margin by this value 

34 * **fixed_atoms** (*bool*) - (False) Interpret zero occupancy as atoms to keep fixed 

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

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

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

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

39 * **container_image** (*str*) - ("cmip/cmip:latest") Container Image identifier. 

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

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

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

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

44 

45 Examples: 

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

47 

48 from biobb_flexdyn.flexdyn.concoord_dist import concoord_dist 

49 prop = { 

50 'vdw' : 4, 

51 'bond_angle' : 1 

52 } 

53 concoord_dist( input_structure_path='/path/to/structure.pdb', 

54 output_pdb_path='/path/to/output.pdb', 

55 output_gro_path='/path/to/output.gro', 

56 output_dat_path='/path/to/output.dat', 

57 properties=prop) 

58 

59 Info: 

60 * wrapped_software: 

61 * name: Concoord 

62 * version: >=2.1.2 

63 * license: other 

64 * ontology: 

65 * name: EDAM 

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

67 

68 """ 

69 

70 def __init__(self, input_structure_path: str, output_pdb_path: str, 

71 output_gro_path: str, output_dat_path: str, properties: Optional[dict] = None, **kwargs) -> None: 

72 

73 properties = properties or {} 

74 

75 # Call parent class constructor 

76 super().__init__(properties) 

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

78 

79 # Input/Output files 

80 self.io_dict = { 

81 'in': {'input_structure_path': input_structure_path}, 

82 'out': {'output_pdb_path': output_pdb_path, 

83 'output_gro_path': output_gro_path, 

84 'output_dat_path': output_dat_path} 

85 } 

86 

87 # Properties specific for BB 

88 self.properties = properties 

89 self.binary_path = properties.get('binary_path', 'dist') 

90 self.retain_hydrogens = properties.get('retain_hydrogens', False) 

91 self.nb_interactions = properties.get('nb_interactions', False) 

92 self.cutoff = properties.get('cutoff', 4.0) 

93 self.min_distances = properties.get('min_distances', 50) 

94 self.damp = properties.get('damp', 1.0) 

95 self.fixed_atoms = properties.get('fixed_atoms', False) 

96 

97 self.vdw = properties.get('vdw', 1) 

98 self.concoord_lib_path = properties.get('concoord_lib_path', None) 

99 self.bond_angle = properties.get('bond_angle', 1) 

100 

101 # Check the properties 

102 self.check_properties(properties) 

103 self.check_arguments() 

104 

105 @launchlogger 

106 def launch(self): 

107 """Launches the execution of the FlexDyn ConcoordDist module.""" 

108 

109 # Set input params 

110 self.io_dict['in']['stdin_file_path'] = fu.create_stdin_file(f'{self.vdw}\n{self.bond_angle}\n') 

111 

112 # Setup Biobb 

113 if self.check_restart(): 

114 return 0 

115 self.stage_files() 

116 

117 # Copy auxiliary file (HBONDS) to the working dir 

118 if self.concoord_lib_path is None: 

119 concoord_lib = os.getenv("CONCOORDLIB") 

120 else: 

121 concoord_lib = self.concoord_lib_path 

122 

123 hbonds_file = str(concoord_lib) + "/HBONDS.DAT" 

124 shutil.copy2(hbonds_file, self.stage_io_dict.get("unique_dir", "")) 

125 

126 # Determine working directory (host unique_dir or container volume path) 

127 if self.container_path: 

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

129 else: 

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

131 

132 # Command line 

133 # (concoord) OROZCO67:biobb_flexdyn hospital$ dist -p biobb_flexdyn/test/data/flexdyn/structure.pdb 

134 # -op dist.pdb -og dist.gro -od dist.dat 

135 # Select a set of Van der Waals parameters: 

136 # 1: OPLS-UA (united atoms) parameters 

137 # 2: OPLS-AA (all atoms) parameters 

138 # 3: PROLSQ repel parameters 

139 # 4: Yamber2 parameters 

140 # 5: Li et al. parameters 

141 # 6: OPLS-X parameters (recommended for NMR structure determination) 

142 # 2 

143 # Selected parameter set 2 

144 # copying /opt/anaconda3/envs/concoord/share/concoord/lib/ATOMS_oplsaa.DAT to ATOMS.DAT in current working directory 

145 # copying /opt/anaconda3/envs/concoord/share/concoord/lib/MARGINS_oplsaa.DAT to MARGINS.DAT in current working directory 

146 # Select a set of bond/angle parameters: 

147 # 1: Concoord default parameters 

148 # 2: Engh-Huber parameters 

149 # 1 

150 # Selected parameter set 1 

151 # copying /opt/anaconda3/envs/concoord/share/concoord/lib/BONDS.DAT.noeh to BONDS.DAT in current working directory 

152 

153 self.cmd = [ 

154 "cd", working_dir, ";", self.binary_path, 

155 "-op", PurePath(self.stage_io_dict["out"]["output_pdb_path"]).name, 

156 "-og", PurePath(self.stage_io_dict["out"]["output_gro_path"]).name, 

157 "-od", PurePath(self.stage_io_dict["out"]["output_dat_path"]).name 

158 ] 

159 # If input structure in pdb format: 

160 file_extension = Path(self.stage_io_dict["in"]["input_structure_path"]).suffix 

161 if file_extension == ".pdb": 

162 self.cmd.append('-p') 

163 self.cmd.append(PurePath(self.stage_io_dict["in"]["input_structure_path"]).name) 

164 

165 elif file_extension == ".gro": 

166 self.cmd.append('-g') 

167 self.cmd.append(PurePath(self.stage_io_dict["in"]["input_structure_path"]).name) 

168 

169 else: 

170 fu.log("ERROR: input_structure_path ({}) must be a PDB or a GRO formatted file ({})".format(self.io_dict["in"]["input_structure_path"], file_extension), self.out_log, self.global_log) 

171 

172 if self.retain_hydrogens: 

173 self.cmd.append('-r') 

174 

175 if self.nb_interactions: 

176 self.cmd.append('-nb') 

177 

178 if self.fixed_atoms: 

179 self.cmd.append('-q') 

180 

181 if self.cutoff: 

182 self.cmd.append('-c') 

183 self.cmd.append(str(self.cutoff)) 

184 

185 if self.min_distances: 

186 self.cmd.append('-m') 

187 self.cmd.append(str(self.min_distances)) 

188 

189 if self.damp: 

190 self.cmd.append('-damp') 

191 self.cmd.append(str(self.damp)) 

192 

193 # Add stdin input file 

194 self.cmd.append('<') 

195 self.cmd.append(PurePath(self.stage_io_dict["in"]["stdin_file_path"]).name) 

196 

197 # Run Biobb block 

198 self.run_biobb() 

199 

200 # Copy files to host 

201 self.copy_to_host() 

202 

203 # remove temporary folder(s) 

204 self.tmp_files.append(self.io_dict['in'].get("stdin_file_path", "")) 

205 self.remove_tmp_files() 

206 

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

208 

209 return self.return_code 

210 

211 

212def concoord_dist(input_structure_path: str, 

213 output_pdb_path: str, output_gro_path: str, output_dat_path: str, 

214 properties: Optional[dict] = None, **kwargs) -> int: 

215 """Create :class:`ConcoordDist <flexdyn.concoord_dist.ConcoordDist>`flexdyn.concoord_dist.ConcoordDist class and 

216 execute :meth:`launch() <flexdyn.concoord_dist.ConcoordDist.launch>` method""" 

217 return ConcoordDist(**dict(locals())).launch() 

218 

219 

220concoord_dist.__doc__ = ConcoordDist.__doc__ 

221main = ConcoordDist.get_main(concoord_dist, "Structure interpretation and bond definitions from a PDB/GRO file.") 

222 

223if __name__ == '__main__': 

224 main()