bfee2 2.5.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of bfee2 might be problematic. Click here for more details.

Files changed (65) hide show
  1. BFEE2/__init__.py +0 -0
  2. BFEE2/commonTools/__init__.py +0 -0
  3. BFEE2/commonTools/commonSlots.py +48 -0
  4. BFEE2/commonTools/fileParser.py +327 -0
  5. BFEE2/commonTools/ploter.py +218 -0
  6. BFEE2/doc/Doc.pdf +0 -0
  7. BFEE2/doc/__init__.py +1 -0
  8. BFEE2/gui.py +2136 -0
  9. BFEE2/inputGenerator.py +2857 -0
  10. BFEE2/postTreatment.py +502 -0
  11. BFEE2/templates_gromacs/000.colvars.template +37 -0
  12. BFEE2/templates_gromacs/000.generate_tpr_sh.template +31 -0
  13. BFEE2/templates_gromacs/000.mdp.template +70 -0
  14. BFEE2/templates_gromacs/001.colvars.template +76 -0
  15. BFEE2/templates_gromacs/001.generate_tpr_sh.template +31 -0
  16. BFEE2/templates_gromacs/001.mdp.template +70 -0
  17. BFEE2/templates_gromacs/001.readme.template +1 -0
  18. BFEE2/templates_gromacs/002.colvars.template +101 -0
  19. BFEE2/templates_gromacs/002.generate_tpr_sh.template +31 -0
  20. BFEE2/templates_gromacs/002.mdp.template +70 -0
  21. BFEE2/templates_gromacs/003.colvars.template +125 -0
  22. BFEE2/templates_gromacs/003.generate_tpr_sh.template +36 -0
  23. BFEE2/templates_gromacs/003.mdp.template +70 -0
  24. BFEE2/templates_gromacs/004.colvars.template +148 -0
  25. BFEE2/templates_gromacs/004.generate_tpr_sh.template +37 -0
  26. BFEE2/templates_gromacs/004.mdp.template +70 -0
  27. BFEE2/templates_gromacs/005.colvars.template +170 -0
  28. BFEE2/templates_gromacs/005.generate_tpr_sh.template +38 -0
  29. BFEE2/templates_gromacs/005.mdp.template +70 -0
  30. BFEE2/templates_gromacs/006.colvars.template +192 -0
  31. BFEE2/templates_gromacs/006.generate_tpr_sh.template +39 -0
  32. BFEE2/templates_gromacs/006.mdp.template +70 -0
  33. BFEE2/templates_gromacs/007.colvars.template +210 -0
  34. BFEE2/templates_gromacs/007.generate_tpr_sh.template +40 -0
  35. BFEE2/templates_gromacs/007.mdp.template +69 -0
  36. BFEE2/templates_gromacs/007_eq.colvars.template +169 -0
  37. BFEE2/templates_gromacs/007_eq.generate_tpr_sh.template +64 -0
  38. BFEE2/templates_gromacs/007_min.mdp.template +58 -0
  39. BFEE2/templates_gromacs/008.colvars.template +42 -0
  40. BFEE2/templates_gromacs/008.generate_tpr_sh.template +31 -0
  41. BFEE2/templates_gromacs/008.mdp.template +70 -0
  42. BFEE2/templates_gromacs/008_eq.generate_tpr_sh.template +31 -0
  43. BFEE2/templates_gromacs/BFEEGromacs.py +1244 -0
  44. BFEE2/templates_gromacs/__init__.py +0 -0
  45. BFEE2/templates_gromacs/find_min_max.awk +27 -0
  46. BFEE2/templates_namd/__init__.py +0 -0
  47. BFEE2/templates_namd/configTemplate.py +1094 -0
  48. BFEE2/templates_namd/fep.tcl +299 -0
  49. BFEE2/templates_namd/scriptTemplate.py +149 -0
  50. BFEE2/templates_namd/solvate.tcl +9 -0
  51. BFEE2/templates_namd/solvate_mem.tcl +9 -0
  52. BFEE2/templates_namd/updateCenters.py +311 -0
  53. BFEE2/templates_readme/Readme_Gromacs_Geometrical.txt +25 -0
  54. BFEE2/templates_readme/Readme_NAMD_Alchemical.txt +20 -0
  55. BFEE2/templates_readme/Readme_NAMD_Geometrical.txt +34 -0
  56. BFEE2/templates_readme/__init__.py +1 -0
  57. BFEE2/third_party/__init__.py +0 -0
  58. BFEE2/third_party/py_bar.py +335 -0
  59. BFEE2/version.py +2 -0
  60. bfee2-2.5.0.data/scripts/BFEE2Gui.py +18 -0
  61. bfee2-2.5.0.dist-info/LICENSE +677 -0
  62. bfee2-2.5.0.dist-info/METADATA +76 -0
  63. bfee2-2.5.0.dist-info/RECORD +65 -0
  64. bfee2-2.5.0.dist-info/WHEEL +5 -0
  65. bfee2-2.5.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1244 @@
1
+ #!/usr/bin/env python3
2
+ import numpy as np
3
+ import os
4
+ import sys
5
+ import posixpath
6
+ import string
7
+ import logging
8
+ import shutil
9
+ from MDAnalysis import Universe
10
+ from MDAnalysis.units import convert
11
+ from MDAnalysis import transformations
12
+ from math import isclose
13
+
14
+ try:
15
+ import importlib.resources as pkg_resources
16
+ except ImportError:
17
+ # Try backported to PY<37 `importlib_resources`.
18
+ import importlib_resources as pkg_resources
19
+
20
+ from BFEE2 import templates_gromacs
21
+
22
+ # an runtime error
23
+ # selection corresponding to nothing
24
+ class SelectionError(RuntimeError):
25
+ def __init__(self, arg):
26
+ self.args = arg
27
+
28
+ def scanGromacsTopologyInclude(gmxTopFile, logger=None):
29
+ """scan the files included by a gromacs topology file
30
+
31
+ Args:
32
+ gmxTopFile (str): filename of the gromacs topology file
33
+ logger (Logging.logger, optional): logger for debugging. Defaults to None.
34
+
35
+ Returns:
36
+ tuple:
37
+ tuple:
38
+ a (list, list) tuple.
39
+ The first list contains the absolute pathnames of included files.
40
+ The second list contains the strings in the quotation marks for handling
41
+ relative paths.
42
+ Logging.logger:
43
+ logger for debugging
44
+ """
45
+
46
+ topology_dirpath = os.path.dirname(os.path.abspath(gmxTopFile))
47
+ include_files = []
48
+ include_strings = []
49
+ with open(gmxTopFile, 'r') as finput:
50
+ for line in finput:
51
+ line = line.strip()
52
+ if line.startswith('#include'):
53
+ # this is an include line
54
+ # find the first quote
55
+ first_quote = line.find('"')
56
+ # find the second quote
57
+ second_quote = line.find('"', first_quote+1)
58
+ # save the string of include
59
+ include_str = line[first_quote+1:second_quote]
60
+ # find the absolute path and save it to the list
61
+ include_filename = os.path.join(topology_dirpath, include_str).replace('\\', '/')
62
+ if (posixpath.exists(include_filename)):
63
+ include_files.append(include_filename)
64
+ include_strings.append(include_str)
65
+ else:
66
+ if logger is None:
67
+ print(f'Warning: {include_filename} does not exists.')
68
+ else:
69
+ logger.warning(f'{include_filename} does not exists.')
70
+ return include_files, include_strings
71
+
72
+
73
+ def measure_minmax(atom_positions):
74
+ """mimic the VMD command "measure minmax"
75
+
76
+ Args:
77
+ atom_positions (numpy.array): a numpy array containing the XYZ coordinates of N atoms. The shape
78
+ should be (N, 3).
79
+
80
+ Returns:
81
+ Numpy.array: a shape of (2, 3) array, where the first subarray has the minimum
82
+ values in XYZ directions, and the second subarray has the maximum
83
+ values in XYZ directions.
84
+ """
85
+
86
+ xyz_array = np.transpose(atom_positions)
87
+ min_x = np.min(xyz_array[0])
88
+ max_x = np.max(xyz_array[0])
89
+ min_y = np.min(xyz_array[1])
90
+ max_y = np.max(xyz_array[1])
91
+ min_z = np.min(xyz_array[2])
92
+ max_z = np.max(xyz_array[2])
93
+ return np.array([[min_x, min_y, min_z],[max_x, max_y, max_z]])
94
+
95
+
96
+ def measure_center(atom_positions):
97
+ """mimic the VMD command "measure center"
98
+
99
+ Args:
100
+ atom_positions (numpy.array): a numpy array containing the XYZ coordinates of N atoms. The shape should be (N, 3).
101
+
102
+ Returns:
103
+ Numpy.array: a shape of (3,) array contains the geometric center
104
+ """
105
+
106
+ xyz_array = np.transpose(atom_positions)
107
+ center_x = np.average(xyz_array[0])
108
+ center_y = np.average(xyz_array[1])
109
+ center_z = np.average(xyz_array[2])
110
+ return np.array([center_x, center_y, center_z])
111
+
112
+
113
+ def get_cell(atom_positions):
114
+ """mimic the VMD script get_cell.tcl to calculate the cell units
115
+
116
+ Args:
117
+ atom_positions (numpy.array): a numpy array containing the XYZ coordinates of N atoms. The shape should be (N, 3).
118
+
119
+ Returns:
120
+ Numpy.array: a shape of (3,3) array contains periodic cell information
121
+ """
122
+
123
+ minmax_array = measure_minmax(atom_positions)
124
+ vec = minmax_array[1] - minmax_array[0]
125
+ cell_basis_vector1 = np.array([vec[0], 0, 0])
126
+ cell_basis_vector2 = np.array([0, vec[1], 0])
127
+ cell_basis_vector3 = np.array([0, 0, vec[2]])
128
+ return np.array([cell_basis_vector1,
129
+ cell_basis_vector2,
130
+ cell_basis_vector3])
131
+
132
+
133
+ def generateMDP(MDPTemplate, outputPrefix, timeStep, numSteps, temperature, pressure, logger=None):
134
+ """generate a GROMACS mdp file from a template
135
+
136
+ Args:
137
+ MDPTemplate (str): template MDP file with $dt and $nsteps
138
+ outputPrefix (str): prefix (no .mdp extension) of the output MDP file
139
+ timeStep (float): timestep for running the simulation
140
+ numSteps (int): number of steps for running the simulation
141
+ temperature (float): simulation temperature
142
+ pressure (float): simulation pressure
143
+ logger (Logging.logger, optional): logger for debugging. Defaults to None.
144
+ """
145
+
146
+ #if logger is None:
147
+ #print(f'generateMDP: Generating {outputPrefix + ".mdp"} from template {MDPTemplate}...')
148
+ #print(f'Timestep (dt): {timeStep}')
149
+ #print(f'Number of simulation steps (nsteps): {numSteps}')
150
+ #print(f'Temperature: {temperature}')
151
+ #print(f'Pressure: {pressure}')
152
+ #else:
153
+ #logger.info(f'generateMDP: Generating {outputPrefix + ".mdp"} from template {MDPTemplate}...')
154
+ #logger.info(f'Timestep (dt): {timeStep}')
155
+ #logger.info(f'Number of simulation steps (nsteps): {numSteps}')
156
+ #logger.info(f'Temperature: {temperature}')
157
+ #logger.info(f'Pressure: {pressure}')
158
+ #with open(MDPTemplate, 'r', newline='\n') as finput:
159
+ MDP_content = string.Template(MDPTemplate)
160
+ MDP_content = MDP_content.safe_substitute(dt=timeStep,
161
+ nsteps=numSteps,
162
+ temperature=temperature,
163
+ pressure=pressure)
164
+ with open(outputPrefix + '.mdp', 'w', newline='\n') as foutput:
165
+ foutput.write(MDP_content)
166
+
167
+ def generateColvars(colvarsTemplate, outputPrefix, logger=None, **kwargs):
168
+ """generate a Colvars configuration file from a template suffixed with '.dat'
169
+
170
+ Args:
171
+ colvarsTemplate (str): path to a colvars template
172
+ outputPrefix (str): (no .dat extension) of the output Colvars configuration file
173
+ logger (Logging.logger, optional): logger for debugging. Defaults to None.
174
+ **kwargs: additional arguments passed to safe_substitute()
175
+ """
176
+
177
+ #if logger is None:
178
+ #print(f'generateColvars: Generating {outputPrefix + ".dat"} from template {colvarsTemplate}...')
179
+ #print('Colvars parameters:')
180
+ #else:
181
+ #logger.info(f'generateColvars: Generating {outputPrefix + ".dat"} from template {colvarsTemplate}...')
182
+ #logger.info('Colvars parameters:')
183
+ for key, val in kwargs.items():
184
+ if logger is None:
185
+ print(f'{key} = {val}')
186
+ else:
187
+ logger.info(f'{key} = {val}')
188
+ #with open(colvarsTemplate, 'r', newline='\n') as finput:
189
+ content = string.Template(colvarsTemplate)
190
+ content = content.safe_substitute(**kwargs)
191
+ with open(outputPrefix + '.dat', 'w', newline='\n') as foutput:
192
+ foutput.write(content)
193
+
194
+ def generateShellScript(shellTemplate, outputPrefix, logger=None, **kwargs):
195
+ """generate a shell script from a template
196
+
197
+ Args:
198
+ shellTemplate (str): path to a shell template
199
+ outputPrefix (str): prefix (no .sh extension) of the output Colvars configuration file
200
+ logger (Logging.logger, optional): logger for debugging. Defaults to None.
201
+ **kwargs: additional arguments passed to safe_substitute()
202
+ """
203
+
204
+ #if logger is None:
205
+ #print(f'generateShellScript: Generating {outputPrefix + ".sh"} from template {shellTemplate}...')
206
+ #else:
207
+ #logger.info(f'generateShellScript: Generating {outputPrefix + ".sh"} from template {shellTemplate}...')
208
+ #with open(shellTemplate, 'r', newline='\n') as finput:
209
+ content = string.Template(shellTemplate)
210
+ content = content.safe_substitute(**kwargs)
211
+ with open(outputPrefix + '.sh', 'w', newline='\n') as foutput:
212
+ foutput.write(content)
213
+
214
+
215
+ def mearsurePolarAngles(proteinCenter, ligandCenter):
216
+ """measure the polar angles between the protein and the ligand
217
+
218
+ Args:
219
+ proteinCenter (numpy.array): center-of-mass of the protein
220
+ ligandCenter (numpy.array): center-of-mass of the ligand
221
+
222
+ Returns:
223
+ tuple: a (theta, phi) tuple where theta and phi are measured in degrees
224
+ """
225
+
226
+ vector = ligandCenter - proteinCenter
227
+ vector /= np.linalg.norm(vector)
228
+ return (np.degrees(np.arccos(vector[2])),
229
+ np.degrees(np.arctan2(vector[1], vector[0])))
230
+
231
+
232
+ class BFEEGromacs:
233
+ """The entry class for handling gromacs inputs in BFEE.
234
+
235
+ Attributes:
236
+ logger (logging.Logger): logger object for debugging
237
+ handler (logging.StreamHandler): output stream of the debug output
238
+ baseDirectory (str): output directory of the generated files
239
+ structureFile (str): filename of the structure file (either in PDB or GRO format) of the
240
+ protein-ligand binding complex
241
+ topologyFile (str): filename of the GROMACS topology file of the protein-ligand binding
242
+ complex
243
+ ligandOnlyStructureFile (str): filename of the structure file (either in PDB or GRO format) of the
244
+ ligand-only system
245
+ system (MDAnalysis.core.universe): MDAnalysis universe of the protein-ligand binding system
246
+ ligandOnlySystem (MDAnalysis.core.universe): MDAnalysis universe of the ligand-only system
247
+ basenames (str): subdirectory names of all eight steps
248
+ ligand (MDAnalysis.core.groups.AtomGroup): selected HEAVY ATOMS of the ligand in the protein-ligand binding
249
+ complex. This attribute does not exist until the call of
250
+ setLigandHeavyAtomsGroup.
251
+ ligandOnly (MDAnalysis.core.groups.AtomGroup): selected HEAVY ATOMS of the ligand in the ligand-only system.
252
+ This attribute does not exist until the call of
253
+ setLigandHeavyAtomsGroup.
254
+ protein (MDAnalysis.core.groups.AtomGroup): selected HEAVY ATOMS of the protein in the protein-ligand binding
255
+ complex. This attribute does not exist until the call of
256
+ setProteinHeavyAtomsGroup.
257
+ solvent (MDAnalysis.core.groups.AtomGroup): selected atoms of the solvents in the protein-ligand binding complex.
258
+ This attribute does not exist until the call of setSolventAtomsGroup.
259
+ temperature (float): the temperature of simulations (default : 300.0)
260
+ """
261
+
262
+ def __init__(self, structureFile, topologyFile, ligandOnlyStructureFile, ligandOnlyTopologyFile, baseDirectory=None, structureFormat='pdb', ligandOnlyStructureFileFormat='pdb'):
263
+ # setup the logger
264
+ self.logger = logging.getLogger()
265
+ self.logger.handlers.clear()
266
+ self.handler = logging.StreamHandler(sys.stdout)
267
+ self.handler.setFormatter(logging.Formatter('%(asctime)s [BFEEGromacs][%(levelname)s]:%(message)s'))
268
+ self.logger.addHandler(self.handler)
269
+ self.logger.setLevel(logging.INFO)
270
+ self.logger.info('Initializing BFEEGromacs...')
271
+ # setup class attributes
272
+ self.structureFile = structureFile
273
+ self.topologyFile = topologyFile
274
+ if baseDirectory is None:
275
+ self.baseDirectory = os.getcwd()
276
+ else:
277
+ self.baseDirectory = baseDirectory
278
+ self.ligandOnlyStructureFile = ligandOnlyStructureFile
279
+ self.ligandOnlyTopologyFile = ligandOnlyTopologyFile
280
+
281
+ # start to load data into MDAnalysis
282
+ self.logger.info(f'Calling MDAnalysis to load structure {self.structureFile} (format {structureFormat}).')
283
+ self.system = Universe(self.structureFile, format=structureFormat)
284
+ self.ligandOnlySystem = Universe(self.ligandOnlyStructureFile, format=structureFormat)
285
+
286
+ # some PDB files do not have cell info
287
+ # so we reset the cell by an estimation
288
+ all_atoms = self.system.select_atoms("all")
289
+ all_atoms_ligandOnly = self.ligandOnlySystem.select_atoms("all")
290
+ self.system.trajectory[0].triclinic_dimensions = get_cell(all_atoms.positions)
291
+ self.ligandOnlySystem.trajectory[0].triclinic_dimensions = get_cell(all_atoms_ligandOnly.positions)
292
+ dim = self.system.dimensions
293
+ ligandOnly_dim = self.ligandOnlySystem.dimensions
294
+ # measure the cell
295
+ volume = dim[0] * dim[1] * dim[2]
296
+ self.logger.info(f'The volume of the simulation box is {volume} Å^3.')
297
+
298
+ # set default temperature to 300.0 K
299
+ self.temperature = 300.0
300
+ self.logger.info(f'You have specified a new base directory at {self.baseDirectory}')
301
+ if not posixpath.exists(self.baseDirectory):
302
+ os.makedirs(self.baseDirectory)
303
+ if not posixpath.exists(posixpath.join(self.baseDirectory, 'Protein')):
304
+ os.makedirs(posixpath.join(self.baseDirectory, 'Protein'))
305
+ if not posixpath.exists(posixpath.join(self.baseDirectory, 'Ligand')):
306
+ os.makedirs(posixpath.join(self.baseDirectory, 'Ligand'))
307
+
308
+ # check if the topologies have other itp files included
309
+ topologyIncludeFiles, topologyIncludeStrings = scanGromacsTopologyInclude(self.topologyFile)
310
+ for includeFile, includeString in zip(topologyIncludeFiles, topologyIncludeStrings):
311
+ # handle something like "#include "toppar/xxx.itp""
312
+ # in this case we need to create the directory named "toppar" in the base directory
313
+ dest_dirname = posixpath.dirname(includeString)
314
+ if dest_dirname:
315
+ # if dest_dirname is not empty
316
+ if not posixpath.exists(posixpath.join(self.baseDirectory, 'Protein', dest_dirname)):
317
+ # if the destination directory does not exist
318
+ os.makedirs(posixpath.join(self.baseDirectory, 'Protein', dest_dirname))
319
+ shutil.copy(includeFile, posixpath.join(self.baseDirectory, 'Protein', dest_dirname))
320
+ # do the same thing to the ligand topology
321
+ topologyIncludeFiles, topologyIncludeStrings = scanGromacsTopologyInclude(self.ligandOnlyTopologyFile)
322
+ for includeFile, includeString in zip(topologyIncludeFiles, topologyIncludeStrings):
323
+ # handle something like "#include "toppar/xxx.itp""
324
+ # in this case we need to create the directory named "toppar" in the base directory
325
+ dest_dirname = posixpath.dirname(includeString)
326
+ if dest_dirname:
327
+ # if dest_dirname is not empty
328
+ if not posixpath.exists(posixpath.join(self.baseDirectory, 'Ligand', dest_dirname)):
329
+ # if the destination directory does not exist
330
+ os.makedirs(posixpath.join(self.baseDirectory, 'Ligand', dest_dirname))
331
+ shutil.copy(includeFile, posixpath.join(self.baseDirectory, 'Ligand', dest_dirname))
332
+
333
+ #self.structureFile = shutil.copy(self.structureFile, self.baseDirectory)
334
+ self.topologyFile = shutil.copy(self.topologyFile, posixpath.join(self.baseDirectory, 'Protein'))
335
+ self.ligandOnlyStructureFile = shutil.copy(self.ligandOnlyStructureFile, posixpath.join(self.baseDirectory, 'Ligand'))
336
+ self.ligandOnlyTopologyFile = shutil.copy(self.ligandOnlyTopologyFile, posixpath.join(self.baseDirectory, 'Ligand'))
337
+
338
+ # move the system, so that the complex is at the center of the simulation box
339
+ all_center = measure_center(all_atoms.positions)
340
+ moveVector = (-all_center[0], -all_center[1], -all_center[2])
341
+ transformations.translate(moveVector)(all_atoms)
342
+ all_center = measure_center(all_atoms.positions)
343
+ moveVector = (dim[0]/2, dim[1]/2, dim[2]/2)
344
+ transformations.translate(moveVector)(all_atoms)
345
+ all_center = measure_center(all_atoms.positions)
346
+
347
+ ligandOnly_center = measure_center(all_atoms_ligandOnly.positions)
348
+ moveVector = (-ligandOnly_center[0], -ligandOnly_center[1], -ligandOnly_center[2])
349
+ transformations.translate(moveVector)(all_atoms_ligandOnly)
350
+ ligandOnly_center = measure_center(all_atoms_ligandOnly.positions)
351
+ moveVector = (ligandOnly_dim[0]/2, ligandOnly_dim[1]/2, ligandOnly_dim[2]/2)
352
+ transformations.translate(moveVector)(all_atoms_ligandOnly)
353
+ ligandOnly_center = measure_center(all_atoms_ligandOnly.positions)
354
+
355
+ _, fileName = os.path.split(self.structureFile)
356
+ all_atoms.write(self.baseDirectory + '/Protein/' + fileName)
357
+
358
+ _, ligandOnly_fileName = os.path.split(self.ligandOnlyStructureFile)
359
+ all_atoms_ligandOnly.write(self.baseDirectory + '/' + ligandOnly_fileName)
360
+
361
+ #if isclose(volume, 0.0):
362
+ #self.logger.warning(f'The volume is too small. Maybe the structure file is a PDB file without the unit cell.')
363
+ #all_atoms = self.system.select_atoms("all")
364
+ #self.logger.warning(f'The unit cell has been reset to {dim[0]:12.5f} {dim[1]:12.5f} {dim[2]:12.5f} .')
365
+ newBasename = posixpath.splitext(fileName)[0]
366
+ self.structureFile = self.baseDirectory + '/Protein/' + fileName + '.new.gro'
367
+ #self.saveStructure(self.structureFile)
368
+ all_atoms.write(self.structureFile)
369
+ # measure the cell of the ligand-only system
370
+ #dim = self.ligandOnlySystem.dimensions
371
+ #volume = dim[0] * dim[1] * dim[2]
372
+ #self.logger.info(f'The volume of the simulation box (ligand-only system) is {volume} Å^3.')
373
+ #if isclose(volume, 0.0):
374
+ #self.logger.warning(f'The volume is too small. Maybe the structure file is a PDB file without the unit cell.')
375
+ #all_atoms = self.ligandOnlySystem.select_atoms("all")
376
+ #self.ligandOnlySystem.trajectory[0].triclinic_dimensions = get_cell(all_atoms.positions)
377
+ #dim = self.ligandOnlySystem.dimensions
378
+ #self.logger.warning(f'The unit cell has been reset to {dim[0]:12.5f} {dim[1]:12.5f} {dim[2]:12.5f} .')
379
+ newBasename = posixpath.splitext(ligandOnly_fileName)[0]
380
+ self.ligandOnlyStructureFile = self.baseDirectory + '/' + ligandOnly_fileName + '.new.gro'
381
+ #self.saveStructure(self.ligandOnlyStructureFile)
382
+ all_atoms_ligandOnly.write(self.ligandOnlyStructureFile)
383
+
384
+ self.basenames = [
385
+ '000_eq',
386
+ '001_RMSD_bound',
387
+ '002_euler_theta',
388
+ '003_euler_phi',
389
+ '004_euler_psi',
390
+ '005_polar_theta',
391
+ '006_polar_phi',
392
+ '007_r',
393
+ '008_RMSD_unbound'
394
+ ]
395
+ self.stepnames = self.basenames.copy()
396
+ self.basenames = [posixpath.join(self.baseDirectory, basename) for basename in self.basenames]
397
+ self.logger.info('Initialization done.')
398
+
399
+ def saveStructure(self, outputFile, selection='all'):
400
+ """a helper method for selecting a group of atoms and save it
401
+
402
+ Args:
403
+ outputFile (str): filename of the output file
404
+ selection (str, optional): MDAnalysis atom selection string. Defaults to 'all'.
405
+
406
+ Raises:
407
+ SelectionError: if the selection corresponds to nothing
408
+ """
409
+
410
+ self.logger.info(f'Saving a new structure file at {outputFile} with selection ({selection}).')
411
+ selected_atoms = self.system.select_atoms(selection)
412
+ if len(selected_atoms) == 0:
413
+ raise SelectionError('Empty selection!')
414
+ selected_atoms.write(outputFile)
415
+
416
+ def setProteinHeavyAtomsGroup(self, selection):
417
+ """select the heavy atoms of the protein
418
+
419
+ Args:
420
+ selection (str): MDAnalysis atom selection string
421
+
422
+ Raises:
423
+ SelectionError: if the selection corresponds to nothing
424
+ """
425
+
426
+ self.logger.info(f'Setup the atoms group of the protein by selection: {selection}')
427
+ self.protein = self.system.select_atoms(selection)
428
+ if len(self.protein) == 0:
429
+ raise SelectionError('Empty selection!')
430
+
431
+ def setLigandHeavyAtomsGroup(self, selection):
432
+ """select the heavy atoms of the ligand in both the protein-ligand complex
433
+ and the ligand-only systems
434
+
435
+ Args:
436
+ selection (str): MDAnalysis atom selection string
437
+
438
+ Raises:
439
+ SelectionError: if the selection corresponds to nothing
440
+ """
441
+
442
+ self.logger.info(f'Setup the atoms group of the ligand by selection: {selection}')
443
+ self.ligand = self.system.select_atoms(selection)
444
+ if len(self.ligand) == 0:
445
+ raise SelectionError('Empty selection!')
446
+ self.ligandOnly = self.ligandOnlySystem.select_atoms(selection)
447
+ if len(self.ligandOnly) == 0:
448
+ raise SelectionError('Empty selection!')
449
+
450
+ def setSolventAtomsGroup(self, selection):
451
+ """select the solvent atoms
452
+
453
+ Args:
454
+ selection (str): MDAnalysis atom selection string
455
+
456
+ Raises:
457
+ SelectionError: if the selection corresponds nothing
458
+ """
459
+
460
+ self.logger.info(f'Setup the atoms group of the solvent molecule by selection: {selection}')
461
+ self.solvent = self.system.select_atoms(selection)
462
+ if len(self.solvent) == 0:
463
+ raise SelectionError('Empty selection!')
464
+
465
+ def setTemperature(self, newTemperature):
466
+ """set the temperature
467
+
468
+ Args:
469
+ newTemperature (float): new value of the temperature
470
+ """
471
+ self.temperature = newTemperature
472
+
473
+ def generateGromacsIndex(self, outputFile):
474
+ """generate a GROMACS index file for atom selection in Colvars
475
+ """
476
+
477
+ self.system.select_atoms('all').write(outputFile, name='BFEE_all')
478
+ if hasattr(self, 'ligand'):
479
+ self.ligand.write(outputFile, name='BFEE_Ligand', mode='a')
480
+ if hasattr(self, 'protein'):
481
+ self.protein.write(outputFile, name='BFEE_Protein', mode='a')
482
+ if hasattr(self, 'solvent'):
483
+ self.solvent.write(outputFile, name='BFEE_Solvent', mode='a')
484
+
485
+ def generate000(self):
486
+ """generate files for running an equilibrium simulation
487
+ """
488
+
489
+ self.handler.setFormatter(logging.Formatter('%(asctime)s [BFEEGromacs][000][%(levelname)s]:%(message)s'))
490
+ generate_basename = self.basenames[0]
491
+ self.logger.info('=' * 80)
492
+ self.logger.info(f'Generating simulation files for {generate_basename}...')
493
+ if not posixpath.exists(generate_basename):
494
+ self.logger.info(f'Making directory {os.path.abspath(generate_basename)}...')
495
+ os.makedirs(generate_basename)
496
+ # generate the MDP file
497
+ generateMDP(pkg_resources.read_text(templates_gromacs, '000.mdp.template'),
498
+ posixpath.join(generate_basename, '000_eq'),
499
+ logger=self.logger,
500
+ timeStep=0.002,
501
+ numSteps=4000000,
502
+ temperature=self.temperature,
503
+ pressure=1.01325)
504
+ # check if the ligand and protein is selected
505
+ if not hasattr(self, 'ligand'):
506
+ raise RuntimeError('The atoms of the ligand have not been selected.')
507
+ if not hasattr(self, 'protein'):
508
+ raise RuntimeError('The atoms of the protein have not been selected.')
509
+ # measure the COM of the protein
510
+ protein_center = measure_center(self.protein.positions)
511
+ # convert angstrom to nanometer and format the string
512
+ protein_center = convert(protein_center, "angstrom", "nm")
513
+ protein_center_str = f'({protein_center[0]}, {protein_center[1]}, {protein_center[2]})'
514
+ self.logger.info('COM of the protein: ' + protein_center_str + '.')
515
+ # generate the index file
516
+ self.generateGromacsIndex(posixpath.join(generate_basename, 'colvars.ndx'))
517
+ # generate the colvars configuration
518
+ colvars_inputfile_basename = posixpath.join(generate_basename, '000_colvars')
519
+ generateColvars(pkg_resources.read_text(templates_gromacs, '000.colvars.template'),
520
+ colvars_inputfile_basename,
521
+ protein_selection='BFEE_Protein',
522
+ protein_center=protein_center_str,
523
+ logger=self.logger)
524
+ # generate the reference file
525
+ self.system.select_atoms('all').write(posixpath.join(generate_basename, 'reference.xyz'))
526
+ # generate the shell script for making the tpr file
527
+ generateShellScript(pkg_resources.read_text(templates_gromacs, '000.generate_tpr_sh.template'),
528
+ posixpath.join(generate_basename, '000_generate_tpr'),
529
+ logger=self.logger,
530
+ MDP_FILE_TEMPLATE=os.path.relpath(os.path.abspath(posixpath.join(generate_basename,
531
+ '000_eq.mdp')),
532
+ os.path.abspath(generate_basename)).replace('\\', '/'),
533
+ GRO_FILE_TEMPLATE=os.path.relpath(os.path.abspath(self.structureFile),
534
+ os.path.abspath(generate_basename)).replace('\\', '/'),
535
+ TOP_FILE_TEMPLATE=os.path.relpath(os.path.abspath(self.topologyFile),
536
+ os.path.abspath(generate_basename)).replace('\\', '/'),
537
+ COLVARS_INPUT_TEMPLATE=os.path.relpath(os.path.abspath(colvars_inputfile_basename + '.dat'),
538
+ os.path.abspath(generate_basename)).replace('\\', '/'))
539
+ if not posixpath.exists(posixpath.join(generate_basename, 'output')):
540
+ os.makedirs(posixpath.join(generate_basename, 'output'))
541
+ self.logger.info(f"Generation of {generate_basename} done.")
542
+ self.logger.info('=' * 80)
543
+
544
+
545
+ def generate001(self):
546
+ """generate files for determining the PMF along the RMSD of the ligand
547
+ with respect to its bound state
548
+ """
549
+
550
+ self.handler.setFormatter(logging.Formatter('%(asctime)s [BFEEGromacs][001][%(levelname)s]:%(message)s'))
551
+ generate_basename = self.basenames[1]
552
+ self.logger.info('=' * 80)
553
+ self.logger.info(f'Generating simulation files for {generate_basename}...')
554
+ if not posixpath.exists(generate_basename):
555
+ self.logger.info(f'Making directory {os.path.abspath(generate_basename)}...')
556
+ os.makedirs(generate_basename)
557
+ # generate the MDP file
558
+ generateMDP(pkg_resources.read_text(templates_gromacs, '001.mdp.template'),
559
+ posixpath.join(generate_basename, '001_PMF'),
560
+ logger=self.logger,
561
+ timeStep=0.002,
562
+ numSteps=4000000,
563
+ temperature=self.temperature,
564
+ pressure=1.01325)
565
+ # check if the ligand and protein is selected
566
+ if not hasattr(self, 'ligand'):
567
+ raise RuntimeError('The atoms of the ligand have not been selected.')
568
+ if not hasattr(self, 'protein'):
569
+ raise RuntimeError('The atoms of the protein have not been selected.')
570
+ # measure the COM of the protein
571
+ protein_center = measure_center(self.protein.positions)
572
+ # convert angstrom to nanometer and format the string
573
+ protein_center = convert(protein_center, "angstrom", "nm")
574
+ protein_center_str = f'({protein_center[0]}, {protein_center[1]}, {protein_center[2]})'
575
+ self.logger.info('COM of the protein: ' + protein_center_str + '.')
576
+ # generate the index file
577
+ self.generateGromacsIndex(posixpath.join(generate_basename, 'colvars.ndx'))
578
+ # generate the colvars configuration
579
+ colvars_inputfile_basename = posixpath.join(generate_basename, '001_colvars')
580
+ generateColvars(pkg_resources.read_text(templates_gromacs, '001.colvars.template'),
581
+ colvars_inputfile_basename,
582
+ rmsd_bin_width=0.005,
583
+ rmsd_lower_boundary=0.0,
584
+ rmsd_upper_boundary=0.5,
585
+ rmsd_wall_constant=0.8368,
586
+ ligand_selection='BFEE_Ligand',
587
+ protein_selection='BFEE_Protein',
588
+ protein_center=protein_center_str,
589
+ logger=self.logger)
590
+ # generate the reference file
591
+ self.system.select_atoms('all').write(posixpath.join(generate_basename, 'reference.xyz'))
592
+ # generate the shell script for making the tpr file
593
+ generateShellScript(pkg_resources.read_text(templates_gromacs, '001.generate_tpr_sh.template'),
594
+ posixpath.join(generate_basename, '001_generate_tpr'),
595
+ logger=self.logger,
596
+ MDP_FILE_TEMPLATE=os.path.relpath(os.path.abspath(posixpath.join(generate_basename,
597
+ '001_PMF.mdp')),
598
+ os.path.abspath(generate_basename)).replace('\\', '/'),
599
+ GRO_FILE_TEMPLATE=os.path.relpath(os.path.abspath(f'{self.baseDirectory}/000_eq/output/000_eq.out.gro'),
600
+ os.path.abspath(generate_basename)).replace('\\', '/'),
601
+ TOP_FILE_TEMPLATE=os.path.relpath(os.path.abspath(self.topologyFile),
602
+ os.path.abspath(generate_basename)).replace('\\', '/'),
603
+ COLVARS_INPUT_TEMPLATE=os.path.relpath(os.path.abspath(colvars_inputfile_basename + '.dat'),
604
+ os.path.abspath(generate_basename)).replace('\\', '/'))
605
+ if not posixpath.exists(posixpath.join(generate_basename, 'output')):
606
+ os.makedirs(posixpath.join(generate_basename, 'output'))
607
+ self.logger.info(f"Generation of {generate_basename} done.")
608
+ self.logger.info('=' * 80)
609
+
610
+ def generate002(self):
611
+ """generate files for determining the PMF along the pitch (theta) angle of
612
+ the ligand
613
+ """
614
+
615
+ self.handler.setFormatter(logging.Formatter('%(asctime)s [BFEEGromacs][002][%(levelname)s]:%(message)s'))
616
+ generate_basename = self.basenames[2]
617
+ self.logger.info('=' * 80)
618
+ self.logger.info(f'Generating simulation files for {generate_basename}...')
619
+ if not posixpath.exists(generate_basename):
620
+ self.logger.info(f'Making directory {os.path.abspath(generate_basename)}...')
621
+ os.makedirs(generate_basename)
622
+ # generate the MDP file
623
+ generateMDP(pkg_resources.read_text(templates_gromacs, '002.mdp.template'),
624
+ posixpath.join(generate_basename, '002_PMF'),
625
+ timeStep=0.002,
626
+ numSteps=4000000,
627
+ temperature=self.temperature,
628
+ pressure=1.01325,
629
+ logger=self.logger)
630
+ # check if the ligand and protein is selected
631
+ if not hasattr(self, 'ligand'):
632
+ raise RuntimeError('The atoms of the ligand have not been selected.')
633
+ if not hasattr(self, 'protein'):
634
+ raise RuntimeError('The atoms of the protein have not been selected.')
635
+ # measure the COM of the protein
636
+ protein_center = measure_center(self.protein.positions)
637
+ # convert angstrom to nanometer and format the string
638
+ protein_center = convert(protein_center, "angstrom", "nm")
639
+ protein_center_str = f'({protein_center[0]}, {protein_center[1]}, {protein_center[2]})'
640
+ self.logger.info('COM of the protein: ' + protein_center_str + '.')
641
+ # generate the index file
642
+ self.generateGromacsIndex(posixpath.join(generate_basename, 'colvars.ndx'))
643
+ # generate the colvars configuration
644
+ colvars_inputfile_basename = posixpath.join(generate_basename, '002_colvars')
645
+ generateColvars(pkg_resources.read_text(templates_gromacs, '002.colvars.template'),
646
+ colvars_inputfile_basename,
647
+ logger=self.logger,
648
+ eulerTheta_width=1,
649
+ eulerTheta_lower_boundary=-10.0,
650
+ eulerTheta_upper_boundary=10.0,
651
+ eulerTheta_wall_constant=0.8368,
652
+ ligand_selection='BFEE_Ligand',
653
+ protein_selection='BFEE_Protein',
654
+ protein_center=protein_center_str)
655
+ # generate the reference file
656
+ self.system.select_atoms('all').write(posixpath.join(generate_basename, 'reference.xyz'))
657
+ # generate the shell script for making the tpr file
658
+ generateShellScript(pkg_resources.read_text(templates_gromacs, '002.generate_tpr_sh.template'),
659
+ posixpath.join(generate_basename, '002_generate_tpr'),
660
+ logger=self.logger,
661
+ MDP_FILE_TEMPLATE=os.path.relpath(os.path.abspath(posixpath.join(generate_basename,
662
+ '002_PMF.mdp')),
663
+ os.path.abspath(generate_basename)).replace('\\', '/'),
664
+ GRO_FILE_TEMPLATE=os.path.relpath(os.path.abspath(f'{self.baseDirectory}/000_eq/output/000_eq.out.gro'),
665
+ os.path.abspath(generate_basename)).replace('\\', '/'),
666
+ TOP_FILE_TEMPLATE=os.path.relpath(os.path.abspath(self.topologyFile),
667
+ os.path.abspath(generate_basename)).replace('\\', '/'),
668
+ COLVARS_INPUT_TEMPLATE=os.path.relpath(os.path.abspath(colvars_inputfile_basename + '.dat'),
669
+ os.path.abspath(generate_basename)).replace('\\', '/'))
670
+ # also copy the awk script to modify the colvars configuration according to the PMF minima in previous stages
671
+ with pkg_resources.path(templates_gromacs, 'find_min_max.awk') as p:
672
+ shutil.copyfile(p, posixpath.join(generate_basename, 'find_min_max.awk'))
673
+ if not posixpath.exists(posixpath.join(generate_basename, 'output')):
674
+ os.makedirs(posixpath.join(generate_basename, 'output'))
675
+ self.logger.info(f"Generation of {generate_basename} done.")
676
+ self.logger.info('=' * 80)
677
+
678
+ def generate003(self):
679
+ """generate files for determining the PMF along the roll (phi) angle of
680
+ the ligand
681
+ """
682
+
683
+ self.handler.setFormatter(logging.Formatter('%(asctime)s [BFEEGromacs][003][%(levelname)s]:%(message)s'))
684
+ generate_basename = self.basenames[3]
685
+ self.logger.info('=' * 80)
686
+ self.logger.info(f'Generating simulation files for {generate_basename}...')
687
+ if not posixpath.exists(generate_basename):
688
+ self.logger.info(f'Making directory {os.path.abspath(generate_basename)}...')
689
+ os.makedirs(generate_basename)
690
+ # generate the MDP file
691
+ generateMDP(pkg_resources.read_text(templates_gromacs, '003.mdp.template'),
692
+ posixpath.join(generate_basename, '003_PMF'),
693
+ timeStep=0.002,
694
+ numSteps=4000000,
695
+ temperature=self.temperature,
696
+ pressure=1.01325,
697
+ logger=self.logger)
698
+ # check if the ligand and protein is selected
699
+ if not hasattr(self, 'ligand'):
700
+ raise RuntimeError('The atoms of the ligand have not been selected.')
701
+ if not hasattr(self, 'protein'):
702
+ raise RuntimeError('The atoms of the protein have not been selected.')
703
+ # measure the COM of the protein
704
+ protein_center = measure_center(self.protein.positions)
705
+ # convert angstrom to nanometer and format the string
706
+ protein_center = convert(protein_center, "angstrom", "nm")
707
+ protein_center_str = f'({protein_center[0]}, {protein_center[1]}, {protein_center[2]})'
708
+ self.logger.info('COM of the protein: ' + protein_center_str + '.')
709
+ # generate the index file
710
+ self.generateGromacsIndex(posixpath.join(generate_basename, 'colvars.ndx'))
711
+ # generate the colvars configuration
712
+ colvars_inputfile_basename = posixpath.join(generate_basename, '003_colvars')
713
+ generateColvars(pkg_resources.read_text(templates_gromacs, '003.colvars.template'),
714
+ colvars_inputfile_basename,
715
+ logger=self.logger,
716
+ eulerPhi_width=1,
717
+ eulerPhi_lower_boundary=-10.0,
718
+ eulerPhi_upper_boundary=10.0,
719
+ eulerPhi_wall_constant=0.8368,
720
+ ligand_selection='BFEE_Ligand',
721
+ protein_selection='BFEE_Protein',
722
+ protein_center=protein_center_str)
723
+ # generate the reference file
724
+ self.system.select_atoms('all').write(posixpath.join(generate_basename, 'reference.xyz'))
725
+ # generate the shell script for making the tpr file
726
+ generateShellScript(pkg_resources.read_text(templates_gromacs, '003.generate_tpr_sh.template'),
727
+ posixpath.join(generate_basename, '003_generate_tpr'),
728
+ logger=self.logger,
729
+ BASENAME_002=self.stepnames[2],
730
+ MDP_FILE_TEMPLATE=os.path.relpath(os.path.abspath(posixpath.join(generate_basename,
731
+ '003_PMF.mdp')),
732
+ os.path.abspath(generate_basename)).replace('\\', '/'),
733
+ GRO_FILE_TEMPLATE=os.path.relpath(os.path.abspath(f'{self.baseDirectory}/000_eq/output/000_eq.out.gro'),
734
+ os.path.abspath(generate_basename)).replace('\\', '/'),
735
+ TOP_FILE_TEMPLATE=os.path.relpath(os.path.abspath(self.topologyFile),
736
+ os.path.abspath(generate_basename)).replace('\\', '/'),
737
+ COLVARS_INPUT_TEMPLATE=os.path.relpath(os.path.abspath(colvars_inputfile_basename + '.dat'),
738
+ os.path.abspath(generate_basename)).replace('\\', '/'))
739
+ # also copy the awk script to modify the colvars configuration according to the PMF minima in previous stages
740
+ with pkg_resources.path(templates_gromacs, 'find_min_max.awk') as p:
741
+ shutil.copyfile(p, posixpath.join(generate_basename, 'find_min_max.awk'))
742
+ if not posixpath.exists(posixpath.join(generate_basename, 'output')):
743
+ os.makedirs(posixpath.join(generate_basename, 'output'))
744
+ self.logger.info(f"Generation of {generate_basename} done.")
745
+ self.logger.info('=' * 80)
746
+
747
+ def generate004(self):
748
+ """generate files for determining the PMF along the yaw (psi) angle of
749
+ the ligand
750
+ """
751
+
752
+ self.handler.setFormatter(logging.Formatter('%(asctime)s [BFEEGromacs][004][%(levelname)s]:%(message)s'))
753
+ generate_basename = self.basenames[4]
754
+ self.logger.info('=' * 80)
755
+ self.logger.info(f'Generating simulation files for {generate_basename}...')
756
+ if not posixpath.exists(generate_basename):
757
+ self.logger.info(f'Making directory {os.path.abspath(generate_basename)}...')
758
+ os.makedirs(generate_basename)
759
+ # generate the MDP file
760
+ generateMDP(pkg_resources.read_text(templates_gromacs, '004.mdp.template'),
761
+ posixpath.join(generate_basename, '004_PMF'),
762
+ timeStep=0.002,
763
+ numSteps=4000000,
764
+ temperature=self.temperature,
765
+ pressure=1.01325,
766
+ logger=self.logger)
767
+ # check if the ligand and protein is selected
768
+ if not hasattr(self, 'ligand'):
769
+ raise RuntimeError('The atoms of the ligand have not been selected.')
770
+ if not hasattr(self, 'protein'):
771
+ raise RuntimeError('The atoms of the protein have not been selected.')
772
+ # measure the COM of the protein
773
+ protein_center = measure_center(self.protein.positions)
774
+ # convert angstrom to nanometer and format the string
775
+ protein_center = convert(protein_center, "angstrom", "nm")
776
+ protein_center_str = f'({protein_center[0]}, {protein_center[1]}, {protein_center[2]})'
777
+ self.logger.info('COM of the protein: ' + protein_center_str + '.')
778
+ # generate the index file
779
+ self.generateGromacsIndex(posixpath.join(generate_basename, 'colvars.ndx'))
780
+ # generate the colvars configuration
781
+ colvars_inputfile_basename = posixpath.join(generate_basename, '004_colvars')
782
+ generateColvars(pkg_resources.read_text(templates_gromacs, '004.colvars.template'),
783
+ colvars_inputfile_basename,
784
+ logger=self.logger,
785
+ eulerPsi_width=1,
786
+ eulerPsi_lower_boundary=-10.0,
787
+ eulerPsi_upper_boundary=10.0,
788
+ eulerPsi_wall_constant=0.8368,
789
+ ligand_selection='BFEE_Ligand',
790
+ protein_selection='BFEE_Protein',
791
+ protein_center=protein_center_str)
792
+ # generate the reference file
793
+ self.system.select_atoms('all').write(posixpath.join(generate_basename, 'reference.xyz'))
794
+ # generate the shell script for making the tpr file
795
+ generateShellScript(pkg_resources.read_text(templates_gromacs, '004.generate_tpr_sh.template'),
796
+ posixpath.join(generate_basename, '004_generate_tpr'),
797
+ logger=self.logger,
798
+ BASENAME_002=self.stepnames[2],
799
+ BASENAME_003=self.stepnames[3],
800
+ MDP_FILE_TEMPLATE=os.path.relpath(os.path.abspath(posixpath.join(generate_basename,
801
+ '004_PMF.mdp')),
802
+ os.path.abspath(generate_basename)).replace('\\', '/'),
803
+ GRO_FILE_TEMPLATE=os.path.relpath(os.path.abspath(f'{self.baseDirectory}/000_eq/output/000_eq.out.gro'),
804
+ os.path.abspath(generate_basename)).replace('\\', '/'),
805
+ TOP_FILE_TEMPLATE=os.path.relpath(os.path.abspath(self.topologyFile),
806
+ os.path.abspath(generate_basename)).replace('\\', '/'),
807
+ COLVARS_INPUT_TEMPLATE=os.path.relpath(os.path.abspath(colvars_inputfile_basename + '.dat'),
808
+ os.path.abspath(generate_basename)).replace('\\', '/'))
809
+ # also copy the awk script to modify the colvars configuration according to the PMF minima in previous stages
810
+ with pkg_resources.path(templates_gromacs, 'find_min_max.awk') as p:
811
+ shutil.copyfile(p, posixpath.join(generate_basename, 'find_min_max.awk'))
812
+ if not posixpath.exists(posixpath.join(generate_basename, 'output')):
813
+ os.makedirs(posixpath.join(generate_basename, 'output'))
814
+ self.logger.info(f"Generation of {generate_basename} done.")
815
+ self.logger.info('=' * 80)
816
+
817
+ def generate005(self):
818
+ """generate files for determining the PMF along the polar theta angle of
819
+ the ligand relative to the protein
820
+ """
821
+
822
+ self.handler.setFormatter(logging.Formatter('%(asctime)s [BFEEGromacs][005][%(levelname)s]:%(message)s'))
823
+ generate_basename = self.basenames[5]
824
+ self.logger.info('=' * 80)
825
+ self.logger.info(f'Generating simulation files for {generate_basename}...')
826
+ if not posixpath.exists(generate_basename):
827
+ self.logger.info(f'Making directory {os.path.abspath(generate_basename)}...')
828
+ os.makedirs(generate_basename)
829
+ # generate the MDP file
830
+ generateMDP(pkg_resources.read_text(templates_gromacs, '005.mdp.template'),
831
+ posixpath.join(generate_basename, '005_PMF'),
832
+ timeStep=0.002,
833
+ numSteps=4000000,
834
+ temperature=self.temperature,
835
+ pressure=1.01325,
836
+ logger=self.logger)
837
+ # check if the ligand and protein is selected
838
+ if not hasattr(self, 'ligand'):
839
+ raise RuntimeError('The atoms of the ligand have not been selected.')
840
+ if not hasattr(self, 'protein'):
841
+ raise RuntimeError('The atoms of the protein have not been selected.')
842
+ # measure the COM of the protein
843
+ protein_center = measure_center(self.protein.positions)
844
+ # convert angstrom to nanometer and format the string
845
+ protein_center = convert(protein_center, "angstrom", "nm")
846
+ protein_center_str = f'({protein_center[0]}, {protein_center[1]}, {protein_center[2]})'
847
+ self.logger.info('COM of the protein: ' + protein_center_str + '.')
848
+ # generate the index file
849
+ self.generateGromacsIndex(posixpath.join(generate_basename, 'colvars.ndx'))
850
+ # generate the colvars configuration
851
+ colvars_inputfile_basename = posixpath.join(generate_basename, '005_colvars')
852
+ # measure the current polar theta angles
853
+ ligand_center = measure_center(self.ligand.positions)
854
+ ligand_center = convert(ligand_center, "angstrom", "nm")
855
+ ligand_center_str = f'({ligand_center[0]}, {ligand_center[1]}, {ligand_center[2]})'
856
+ polar_theta, polar_phi = mearsurePolarAngles(protein_center, ligand_center)
857
+ polar_theta_center = np.around(polar_theta, 1)
858
+ self.logger.info(f'Measured polar angles: theta = {polar_theta:12.5f} ; phi = {polar_phi:12.5f}')
859
+ polar_theta_width = 1
860
+ polar_theta_lower = polar_theta_center - polar_theta_width * np.ceil(10 / polar_theta_width)
861
+ polar_theta_upper = polar_theta_center + polar_theta_width * np.ceil(10 / polar_theta_width)
862
+ generateColvars(pkg_resources.read_text(templates_gromacs, '005.colvars.template'),
863
+ colvars_inputfile_basename,
864
+ logger=self.logger,
865
+ polarTheta_width=polar_theta_width,
866
+ polarTheta_lower_boundary=np.around(polar_theta_lower, 2),
867
+ polarTheta_upper_boundary=np.around(polar_theta_upper, 2),
868
+ polarTheta_wall_constant=0.8368,
869
+ ligand_selection='BFEE_Ligand',
870
+ protein_selection='BFEE_Protein',
871
+ protein_center=protein_center_str)
872
+ # generate the reference file
873
+ self.system.select_atoms('all').write(posixpath.join(generate_basename, 'reference.xyz'))
874
+ # generate the shell script for making the tpr file
875
+ generateShellScript(pkg_resources.read_text(templates_gromacs, '005.generate_tpr_sh.template'),
876
+ posixpath.join(generate_basename, '005_generate_tpr'),
877
+ logger=self.logger,
878
+ BASENAME_002=self.stepnames[2],
879
+ BASENAME_003=self.stepnames[3],
880
+ BASENAME_004=self.stepnames[4],
881
+ MDP_FILE_TEMPLATE=os.path.relpath(os.path.abspath(posixpath.join(generate_basename,
882
+ '005_PMF.mdp')),
883
+ os.path.abspath(generate_basename)).replace('\\', '/'),
884
+ GRO_FILE_TEMPLATE=os.path.relpath(os.path.abspath(f'{self.baseDirectory}/000_eq/output/000_eq.out.gro'),
885
+ os.path.abspath(generate_basename)).replace('\\', '/'),
886
+ TOP_FILE_TEMPLATE=os.path.relpath(os.path.abspath(self.topologyFile),
887
+ os.path.abspath(generate_basename)).replace('\\', '/'),
888
+ COLVARS_INPUT_TEMPLATE=os.path.relpath(os.path.abspath(colvars_inputfile_basename + '.dat'),
889
+ os.path.abspath(generate_basename)).replace('\\', '/'))
890
+ # also copy the awk script to modify the colvars configuration according to the PMF minima in previous stages
891
+ with pkg_resources.path(templates_gromacs, 'find_min_max.awk') as p:
892
+ shutil.copyfile(p, posixpath.join(generate_basename, 'find_min_max.awk'))
893
+ if not posixpath.exists(posixpath.join(generate_basename, 'output')):
894
+ os.makedirs(posixpath.join(generate_basename, 'output'))
895
+ self.logger.info(f"Generation of {generate_basename} done.")
896
+ self.logger.info('=' * 80)
897
+
898
+ def generate006(self):
899
+ """generate files for determining the PMF along the polar phi angle of
900
+ the ligand relative to the protein
901
+ """
902
+
903
+ self.handler.setFormatter(logging.Formatter('%(asctime)s [BFEEGromacs][006][%(levelname)s]:%(message)s'))
904
+ generate_basename = self.basenames[6]
905
+ self.logger.info('=' * 80)
906
+ self.logger.info(f'Generating simulation files for {generate_basename}...')
907
+ if not posixpath.exists(generate_basename):
908
+ self.logger.info(f'Making directory {os.path.abspath(generate_basename)}...')
909
+ os.makedirs(generate_basename)
910
+ # generate the MDP file
911
+ generateMDP(pkg_resources.read_text(templates_gromacs, '006.mdp.template'),
912
+ posixpath.join(generate_basename, '006_PMF'),
913
+ timeStep=0.002,
914
+ numSteps=4000000,
915
+ temperature=self.temperature,
916
+ pressure=1.01325,
917
+ logger=self.logger)
918
+ # check if the ligand and protein is selected
919
+ if not hasattr(self, 'ligand'):
920
+ raise RuntimeError('The atoms of the ligand have not been selected.')
921
+ if not hasattr(self, 'protein'):
922
+ raise RuntimeError('The atoms of the protein have not been selected.')
923
+ # measure the COM of the protein
924
+ protein_center = measure_center(self.protein.positions)
925
+ # convert angstrom to nanometer and format the string
926
+ protein_center = convert(protein_center, "angstrom", "nm")
927
+ protein_center_str = f'({protein_center[0]}, {protein_center[1]}, {protein_center[2]})'
928
+ self.logger.info('COM of the protein: ' + protein_center_str + '.')
929
+ # generate the index file
930
+ self.generateGromacsIndex(posixpath.join(generate_basename, 'colvars.ndx'))
931
+ # generate the colvars configuration
932
+ colvars_inputfile_basename = posixpath.join(generate_basename, '006_colvars')
933
+ # measure the current polar theta angles
934
+ ligand_center = measure_center(self.ligand.positions)
935
+ ligand_center = convert(ligand_center, "angstrom", "nm")
936
+ ligand_center_str = f'({ligand_center[0]}, {ligand_center[1]}, {ligand_center[2]})'
937
+ polar_theta, polar_phi = mearsurePolarAngles(protein_center, ligand_center)
938
+ polar_phi_center = np.around(polar_phi, 1)
939
+ self.logger.info(f'Measured polar angles: theta = {polar_theta:12.5f} ; phi = {polar_phi:12.5f}')
940
+ polar_phi_width = 1
941
+ polar_phi_lower = polar_phi_center - polar_phi_width * np.ceil(10 / polar_phi_width)
942
+ polar_phi_upper = polar_phi_center + polar_phi_width * np.ceil(10 / polar_phi_width)
943
+ generateColvars(pkg_resources.read_text(templates_gromacs, '006.colvars.template'),
944
+ colvars_inputfile_basename,
945
+ logger=self.logger,
946
+ polarPhi_width=polar_phi_width,
947
+ polarPhi_lower_boundary=np.around(polar_phi_lower, 2),
948
+ polarPhi_upper_boundary=np.around(polar_phi_upper, 2),
949
+ polarPhi_wall_constant=0.8368,
950
+ ligand_selection='BFEE_Ligand',
951
+ protein_selection='BFEE_Protein',
952
+ protein_center=protein_center_str)
953
+ # generate the reference file
954
+ self.system.select_atoms('all').write(posixpath.join(generate_basename, 'reference.xyz'))
955
+ # generate the shell script for making the tpr file
956
+ generateShellScript(pkg_resources.read_text(templates_gromacs, '006.generate_tpr_sh.template'),
957
+ posixpath.join(generate_basename, '006_generate_tpr'),
958
+ logger=self.logger,
959
+ BASENAME_002=self.stepnames[2],
960
+ BASENAME_003=self.stepnames[3],
961
+ BASENAME_004=self.stepnames[4],
962
+ BASENAME_005=self.stepnames[5],
963
+ MDP_FILE_TEMPLATE=os.path.relpath(os.path.abspath(posixpath.join(generate_basename,
964
+ '006_PMF.mdp')),
965
+ os.path.abspath(generate_basename)).replace('\\', '/'),
966
+ GRO_FILE_TEMPLATE=os.path.relpath(os.path.abspath(f'{self.baseDirectory}/000_eq/output/000_eq.out.gro'),
967
+ os.path.abspath(generate_basename)).replace('\\', '/'),
968
+ TOP_FILE_TEMPLATE=os.path.relpath(os.path.abspath(self.topologyFile),
969
+ os.path.abspath(generate_basename)).replace('\\', '/'),
970
+ COLVARS_INPUT_TEMPLATE=os.path.relpath(os.path.abspath(colvars_inputfile_basename + '.dat'),
971
+ os.path.abspath(generate_basename)).replace('\\', '/'))
972
+ # also copy the awk script to modify the colvars configuration according to the PMF minima in previous stages
973
+ with pkg_resources.path(templates_gromacs, 'find_min_max.awk') as p:
974
+ shutil.copyfile(p, posixpath.join(generate_basename, 'find_min_max.awk'))
975
+ if not posixpath.exists(posixpath.join(generate_basename, 'output')):
976
+ os.makedirs(posixpath.join(generate_basename, 'output'))
977
+ self.logger.info(f"Generation of {generate_basename} done.")
978
+ self.logger.info('=' * 80)
979
+
980
+ def generate007(self):
981
+ """generate files for determining the PMF along the distance between the
982
+ the ligand and the protein
983
+ """
984
+
985
+ self.handler.setFormatter(logging.Formatter('%(asctime)s [BFEEGromacs][007][%(levelname)s]:%(message)s'))
986
+ generate_basename = self.basenames[7]
987
+ self.logger.info('=' * 80)
988
+ self.logger.info(f'Generating simulation files for {generate_basename}...')
989
+ if not posixpath.exists(generate_basename):
990
+ self.logger.info(f'Making directory {os.path.abspath(generate_basename)}...')
991
+ os.makedirs(generate_basename)
992
+ # check if the topologies have other itp files included
993
+ topologyIncludeFiles, topologyIncludeStrings = scanGromacsTopologyInclude(self.topologyFile)
994
+ for includeFile, includeString in zip(topologyIncludeFiles, topologyIncludeStrings):
995
+ # handle something like "#include "toppar/xxx.itp""
996
+ # in this case we need to create the directory named "toppar" in the base directory
997
+ dest_dirname = posixpath.dirname(includeString)
998
+ if dest_dirname:
999
+ # if dest_dirname is not empty
1000
+ if not posixpath.exists(posixpath.join(self.baseDirectory, generate_basename, dest_dirname)):
1001
+ # if the destination directory does not exist
1002
+ os.makedirs(posixpath.join(self.baseDirectory, generate_basename, dest_dirname))
1003
+ shutil.copy(includeFile, posixpath.join(self.baseDirectory, generate_basename, dest_dirname))
1004
+ # generate the MDP file
1005
+ generateMDP(pkg_resources.read_text(templates_gromacs, '007_min.mdp.template'),
1006
+ posixpath.join(generate_basename, '007_Minimize'),
1007
+ timeStep=0.002,
1008
+ numSteps=5000,
1009
+ temperature=self.temperature,
1010
+ pressure=1.01325,
1011
+ logger=self.logger)
1012
+ # equilibration
1013
+ generateMDP(pkg_resources.read_text(templates_gromacs, '007.mdp.template'),
1014
+ posixpath.join(generate_basename, '007_Equilibration'),
1015
+ timeStep=0.002,
1016
+ numSteps=5000000,
1017
+ temperature=self.temperature,
1018
+ pressure=1.01325,
1019
+ logger=self.logger)
1020
+ # free-energy calculation
1021
+ generateMDP(pkg_resources.read_text(templates_gromacs, '007.mdp.template'),
1022
+ posixpath.join(generate_basename, '007_PMF'),
1023
+ timeStep=0.002,
1024
+ numSteps=80000000,
1025
+ temperature=self.temperature,
1026
+ pressure=1.01325,
1027
+ logger=self.logger)
1028
+ # check if the ligand, protein and solvent is selected
1029
+ if not hasattr(self, 'ligand'):
1030
+ raise RuntimeError('The atoms of the ligand have not been selected.')
1031
+ if not hasattr(self, 'protein'):
1032
+ raise RuntimeError('The atoms of the protein have not been selected.')
1033
+ if not hasattr(self, 'solvent'):
1034
+ raise RuntimeError('The atoms of the solvent have not been selected.')
1035
+ # measure the COM of the protein
1036
+ protein_center = measure_center(self.protein.positions)
1037
+ # convert angstrom to nanometer and format the string
1038
+ protein_center = convert(protein_center, "angstrom", "nm")
1039
+ protein_center_str = f'({protein_center[0]}, {protein_center[1]}, {protein_center[2]})'
1040
+ self.logger.info('COM of the protein: ' + protein_center_str + '.')
1041
+ # generate the index file
1042
+ self.generateGromacsIndex(posixpath.join(generate_basename, 'colvars.ndx'))
1043
+ # generate the colvars configuration
1044
+ colvars_inputfile_basename_eq = posixpath.join(generate_basename, '007_eq_colvars')
1045
+ colvars_inputfile_basename = posixpath.join(generate_basename, '007_colvars')
1046
+ # measure the current COM distance from the ligand to protein
1047
+ ligand_center = measure_center(self.ligand.positions)
1048
+ ligand_center = convert(ligand_center, "angstrom", "nm")
1049
+ ligand_center_str = f'({ligand_center[0]}, {ligand_center[1]}, {ligand_center[2]})'
1050
+ self.logger.info('COM of the ligand: ' + ligand_center_str + '.')
1051
+ r_center = np.sqrt(np.dot(ligand_center - protein_center, ligand_center - protein_center))
1052
+ # round r_center
1053
+ r_center = np.around(r_center, 2)
1054
+ self.logger.info('Distance of protein and ligand: ' + str(r_center) + ' nm.')
1055
+ r_width = 0.01
1056
+ # r_lower_boundary = r_center - r_lower_shift
1057
+ # r_lower_shift is default to 0.2 nm
1058
+ r_lower_shift = 0.2
1059
+ r_lower_boundary = r_center - r_lower_shift
1060
+ if r_lower_boundary < 0:
1061
+ r_lower_boundary = 0.0
1062
+ # r_upper_boundary = r_center + r_upper_shift
1063
+ # r_upper_shift is default to 2.1 nm
1064
+ # also we will need r_upper_shift to enlarge the solvent box
1065
+ r_upper_shift = 2.1
1066
+ r_upper_boundary = r_center + r_upper_shift
1067
+ # colvars file for equilibration
1068
+ generateColvars(pkg_resources.read_text(templates_gromacs, '007_eq.colvars.template'),
1069
+ colvars_inputfile_basename_eq,
1070
+ logger=self.logger,
1071
+ ligand_selection='BFEE_Ligand',
1072
+ protein_selection='BFEE_Protein',
1073
+ protein_center=protein_center_str)
1074
+ # colvars file for free-energy calculation
1075
+ generateColvars(pkg_resources.read_text(templates_gromacs, '007.colvars.template'),
1076
+ colvars_inputfile_basename,
1077
+ logger=self.logger,
1078
+ r_width=r_width,
1079
+ r_lower_boundary=r_lower_boundary,
1080
+ r_upper_boundary=r_upper_boundary,
1081
+ r_wall_constant=0.5*4.184,
1082
+ ligand_selection='BFEE_Ligand',
1083
+ protein_selection='BFEE_Protein',
1084
+ protein_center=protein_center_str)
1085
+ # generate the reference file
1086
+ self.system.select_atoms('all').write(posixpath.join(generate_basename, 'reference.xyz'))
1087
+ # write the solvent molecules
1088
+ self.solvent.write(posixpath.join(generate_basename, 'solvent.gro'))
1089
+ # generate the shell script for making the tpr file
1090
+ # further enlarge the water box by 10% since the size of box may be compressed under NPT
1091
+ new_box_x = np.around(convert(self.system.dimensions[0], 'angstrom', 'nm'), 2) + r_upper_shift * 1.1
1092
+ new_box_y = np.around(convert(self.system.dimensions[1], 'angstrom', 'nm'), 2) + r_upper_shift * 1.1
1093
+ new_box_z = np.around(convert(self.system.dimensions[2], 'angstrom', 'nm'), 2) + r_upper_shift * 1.1
1094
+ # generate shell script for equlibration
1095
+ generateShellScript(pkg_resources.read_text(templates_gromacs, '007_eq.generate_tpr_sh.template'),
1096
+ posixpath.join(generate_basename, '007.1_generate_eq_tpr'),
1097
+ logger=self.logger,
1098
+ BASENAME_002=self.stepnames[2],
1099
+ BASENAME_003=self.stepnames[3],
1100
+ BASENAME_004=self.stepnames[4],
1101
+ BASENAME_005=self.stepnames[5],
1102
+ BASENAME_006=self.stepnames[6],
1103
+ BOX_MODIFIED_GRO_TEMPLATE=os.path.relpath(os.path.abspath(posixpath.join(generate_basename,
1104
+ 'box_modified.gro')),
1105
+ os.path.abspath(generate_basename)).replace('\\', '/'),
1106
+ MODIFIED_TOP_TEMPLATE=os.path.relpath(os.path.abspath(posixpath.join(generate_basename,
1107
+ 'solvated.top')),
1108
+ os.path.abspath(generate_basename)).replace('\\', '/'),
1109
+ MODIFIED_GRO_TEMPLATE=os.path.relpath(os.path.abspath(posixpath.join(generate_basename,
1110
+ 'solvated.gro')),
1111
+ os.path.abspath(generate_basename)).replace('\\', '/'),
1112
+ NEW_BOX_X_TEMPLATE=f'{new_box_x:.5f}',
1113
+ NEW_BOX_Y_TEMPLATE=f'{new_box_y:.5f}',
1114
+ NEW_BOX_Z_TEMPLATE=f'{new_box_z:.5f}',
1115
+ MIN_MDP_FILE_TEMPLATE=os.path.relpath(os.path.abspath(posixpath.join(generate_basename,
1116
+ '007_Minimize.mdp')),
1117
+ os.path.abspath(generate_basename)).replace('\\', '/'),
1118
+ MDP_FILE_TEMPLATE=os.path.relpath(os.path.abspath(posixpath.join(generate_basename,
1119
+ '007_Equilibration.mdp')),
1120
+ os.path.abspath(generate_basename)).replace('\\', '/'),
1121
+ GRO_FILE_TEMPLATE=os.path.relpath(os.path.abspath(self.structureFile),
1122
+ os.path.abspath(generate_basename)).replace('\\', '/'),
1123
+ TOP_FILE_TEMPLATE=os.path.relpath(os.path.abspath(self.topologyFile),
1124
+ os.path.abspath(generate_basename)).replace('\\', '/'),
1125
+ COLVARS_INPUT_TEMPLATE=os.path.relpath(os.path.abspath(colvars_inputfile_basename_eq + '.dat'),
1126
+ os.path.abspath(generate_basename)).replace('\\', '/'))
1127
+ # generate shell script for free-energy calculation
1128
+ generateShellScript(pkg_resources.read_text(templates_gromacs, '007.generate_tpr_sh.template'),
1129
+ posixpath.join(generate_basename, '007.2_generate_tpr'),
1130
+ logger=self.logger,
1131
+ BASENAME_002=self.stepnames[2],
1132
+ BASENAME_003=self.stepnames[3],
1133
+ BASENAME_004=self.stepnames[4],
1134
+ BASENAME_005=self.stepnames[5],
1135
+ BASENAME_006=self.stepnames[6],
1136
+ MDP_FILE_TEMPLATE=os.path.relpath(os.path.abspath(posixpath.join(generate_basename,
1137
+ '007_PMF.mdp')),
1138
+ os.path.abspath(generate_basename)).replace('\\', '/'),
1139
+ GRO_FILE_TEMPLATE=os.path.relpath(os.path.abspath(f'{self.baseDirectory}/007_r/output/007_r_eq.out.gro'),
1140
+ os.path.abspath(generate_basename)).replace('\\', '/'),
1141
+ TOP_FILE_TEMPLATE=os.path.relpath(os.path.abspath(f'{self.baseDirectory}/007_r/solvated.top'),
1142
+ os.path.abspath(generate_basename)).replace('\\', '/'),
1143
+ COLVARS_INPUT_TEMPLATE=os.path.relpath(os.path.abspath(colvars_inputfile_basename + '.dat'),
1144
+ os.path.abspath(generate_basename)).replace('\\', '/'))
1145
+ # also copy the awk script to modify the colvars configuration according to the PMF minima in previous stages
1146
+ with pkg_resources.path(templates_gromacs, 'find_min_max.awk') as p:
1147
+ shutil.copyfile(p, posixpath.join(generate_basename, 'find_min_max.awk'))
1148
+ if not posixpath.exists(posixpath.join(generate_basename, 'output')):
1149
+ os.makedirs(posixpath.join(generate_basename, 'output'))
1150
+ self.logger.info(f"Generation of {generate_basename} done.")
1151
+ self.logger.info('=' * 80)
1152
+
1153
+ def generate008(self):
1154
+ """generate files for determining the PMF along the RMSD of the ligand
1155
+ with respect to its unbound state
1156
+ """
1157
+
1158
+ self.handler.setFormatter(logging.Formatter('%(asctime)s [BFEEGromacs][008][%(levelname)s]:%(message)s'))
1159
+ generate_basename = self.basenames[8]
1160
+ self.logger.info('=' * 80)
1161
+ self.logger.info(f'Generating simulation files for {generate_basename}...')
1162
+ if not posixpath.exists(generate_basename):
1163
+ self.logger.info(f'Making directory {os.path.abspath(generate_basename)}...')
1164
+ os.makedirs(generate_basename)
1165
+ # # generate the MDP file for equlibration
1166
+ generateMDP(pkg_resources.read_text(templates_gromacs, '008.mdp.template'),
1167
+ posixpath.join(generate_basename, '008_Equilibration'),
1168
+ logger=self.logger,
1169
+ timeStep=0.002,
1170
+ numSteps=1000000,
1171
+ temperature=self.temperature,
1172
+ pressure=1.01325)
1173
+ # generate the MDP file
1174
+ generateMDP(pkg_resources.read_text(templates_gromacs, '008.mdp.template'),
1175
+ posixpath.join(generate_basename, '008_PMF'),
1176
+ logger=self.logger,
1177
+ timeStep=0.002,
1178
+ numSteps=4000000,
1179
+ temperature=self.temperature,
1180
+ pressure=1.01325)
1181
+ # generate the index file
1182
+ if hasattr(self, 'ligandOnly'):
1183
+ self.ligandOnly.write(posixpath.join(generate_basename, 'colvars_ligand_only.ndx'), name='BFEE_Ligand_Only')
1184
+ # generate the colvars configuration
1185
+ colvars_inputfile_basename = posixpath.join(generate_basename, '008_colvars')
1186
+ generateColvars(pkg_resources.read_text(templates_gromacs, '008.colvars.template'),
1187
+ colvars_inputfile_basename,
1188
+ rmsd_bin_width=0.005,
1189
+ rmsd_lower_boundary=0.0,
1190
+ rmsd_upper_boundary=0.5,
1191
+ rmsd_wall_constant=0.8368,
1192
+ ligand_selection='BFEE_Ligand_Only',
1193
+ logger=self.logger)
1194
+ # generate the reference file for ligand only
1195
+ # extract the positions from the host-guest binding system
1196
+ ligand_position_in_system = self.ligand.positions
1197
+ # modify positions in the ligand-only system
1198
+ self.ligandOnly.positions = ligand_position_in_system
1199
+ # write out the whole ligand-only system as reference
1200
+ self.ligandOnlySystem.select_atoms('all').write(posixpath.join(generate_basename, 'reference_ligand_only.xyz'))
1201
+ # generate the shell script for making the tpr file for equilibration
1202
+ generateShellScript(pkg_resources.read_text(templates_gromacs, '008_eq.generate_tpr_sh.template'),
1203
+ posixpath.join(generate_basename, '008.1_generate_eq_tpr'),
1204
+ logger=self.logger,
1205
+ MDP_FILE_TEMPLATE=os.path.relpath(os.path.abspath(posixpath.join(generate_basename,
1206
+ '008_Equilibration.mdp')),
1207
+ os.path.abspath(generate_basename)).replace('\\', '/'),
1208
+ GRO_FILE_TEMPLATE=os.path.relpath(os.path.abspath(self.ligandOnlyStructureFile),
1209
+ os.path.abspath(generate_basename)).replace('\\', '/'),
1210
+ TOP_FILE_TEMPLATE=os.path.relpath(os.path.abspath(self.ligandOnlyTopologyFile),
1211
+ os.path.abspath(generate_basename)).replace('\\', '/'),)
1212
+ # generate the shell script for making the tpr file for free-energy calculation
1213
+ generateShellScript(pkg_resources.read_text(templates_gromacs, '008.generate_tpr_sh.template'),
1214
+ posixpath.join(generate_basename, '008.2_generate_tpr'),
1215
+ logger=self.logger,
1216
+ MDP_FILE_TEMPLATE=os.path.relpath(os.path.abspath(posixpath.join(generate_basename,
1217
+ '008_PMF.mdp')),
1218
+ os.path.abspath(generate_basename)).replace('\\', '/'),
1219
+ GRO_FILE_TEMPLATE=os.path.relpath(os.path.abspath(f'{self.baseDirectory}/008_RMSD_unbound/output/008_RMSD_unbound_eq.out.gro'),
1220
+ os.path.abspath(generate_basename)).replace('\\', '/'),
1221
+ TOP_FILE_TEMPLATE=os.path.relpath(os.path.abspath(self.ligandOnlyTopologyFile),
1222
+ os.path.abspath(generate_basename)).replace('\\', '/'),
1223
+ COLVARS_INPUT_TEMPLATE=os.path.relpath(os.path.abspath(colvars_inputfile_basename + '.dat'),
1224
+ os.path.abspath(generate_basename)).replace('\\', '/'))
1225
+ if not posixpath.exists(posixpath.join(generate_basename, 'output')):
1226
+ os.makedirs(posixpath.join(generate_basename, 'output'))
1227
+ self.logger.info(f"Generation of {generate_basename} done.")
1228
+ self.logger.info('=' * 80)
1229
+
1230
+ if __name__ == "__main__":
1231
+ bfee = BFEEGromacs('p41-abl.pdb', 'p41-abl.top', 'ligand-only.pdb', 'ligand-only.top', 'p41-abl-test/abc/def')
1232
+ bfee.setProteinHeavyAtomsGroup('segid SH3D and not (name H*)')
1233
+ bfee.setLigandHeavyAtomsGroup('segid PPRO and not (name H*)')
1234
+ bfee.setSolventAtomsGroup('resname TIP3*')
1235
+ bfee.setTemperature(350.0)
1236
+ bfee.generate000()
1237
+ bfee.generate001()
1238
+ bfee.generate002()
1239
+ bfee.generate003()
1240
+ bfee.generate004()
1241
+ bfee.generate005()
1242
+ bfee.generate006()
1243
+ bfee.generate007()
1244
+ bfee.generate008()