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.
- BFEE2/__init__.py +0 -0
- BFEE2/commonTools/__init__.py +0 -0
- BFEE2/commonTools/commonSlots.py +48 -0
- BFEE2/commonTools/fileParser.py +327 -0
- BFEE2/commonTools/ploter.py +218 -0
- BFEE2/doc/Doc.pdf +0 -0
- BFEE2/doc/__init__.py +1 -0
- BFEE2/gui.py +2136 -0
- BFEE2/inputGenerator.py +2857 -0
- BFEE2/postTreatment.py +502 -0
- BFEE2/templates_gromacs/000.colvars.template +37 -0
- BFEE2/templates_gromacs/000.generate_tpr_sh.template +31 -0
- BFEE2/templates_gromacs/000.mdp.template +70 -0
- BFEE2/templates_gromacs/001.colvars.template +76 -0
- BFEE2/templates_gromacs/001.generate_tpr_sh.template +31 -0
- BFEE2/templates_gromacs/001.mdp.template +70 -0
- BFEE2/templates_gromacs/001.readme.template +1 -0
- BFEE2/templates_gromacs/002.colvars.template +101 -0
- BFEE2/templates_gromacs/002.generate_tpr_sh.template +31 -0
- BFEE2/templates_gromacs/002.mdp.template +70 -0
- BFEE2/templates_gromacs/003.colvars.template +125 -0
- BFEE2/templates_gromacs/003.generate_tpr_sh.template +36 -0
- BFEE2/templates_gromacs/003.mdp.template +70 -0
- BFEE2/templates_gromacs/004.colvars.template +148 -0
- BFEE2/templates_gromacs/004.generate_tpr_sh.template +37 -0
- BFEE2/templates_gromacs/004.mdp.template +70 -0
- BFEE2/templates_gromacs/005.colvars.template +170 -0
- BFEE2/templates_gromacs/005.generate_tpr_sh.template +38 -0
- BFEE2/templates_gromacs/005.mdp.template +70 -0
- BFEE2/templates_gromacs/006.colvars.template +192 -0
- BFEE2/templates_gromacs/006.generate_tpr_sh.template +39 -0
- BFEE2/templates_gromacs/006.mdp.template +70 -0
- BFEE2/templates_gromacs/007.colvars.template +210 -0
- BFEE2/templates_gromacs/007.generate_tpr_sh.template +40 -0
- BFEE2/templates_gromacs/007.mdp.template +69 -0
- BFEE2/templates_gromacs/007_eq.colvars.template +169 -0
- BFEE2/templates_gromacs/007_eq.generate_tpr_sh.template +64 -0
- BFEE2/templates_gromacs/007_min.mdp.template +58 -0
- BFEE2/templates_gromacs/008.colvars.template +42 -0
- BFEE2/templates_gromacs/008.generate_tpr_sh.template +31 -0
- BFEE2/templates_gromacs/008.mdp.template +70 -0
- BFEE2/templates_gromacs/008_eq.generate_tpr_sh.template +31 -0
- BFEE2/templates_gromacs/BFEEGromacs.py +1244 -0
- BFEE2/templates_gromacs/__init__.py +0 -0
- BFEE2/templates_gromacs/find_min_max.awk +27 -0
- BFEE2/templates_namd/__init__.py +0 -0
- BFEE2/templates_namd/configTemplate.py +1094 -0
- BFEE2/templates_namd/fep.tcl +299 -0
- BFEE2/templates_namd/scriptTemplate.py +149 -0
- BFEE2/templates_namd/solvate.tcl +9 -0
- BFEE2/templates_namd/solvate_mem.tcl +9 -0
- BFEE2/templates_namd/updateCenters.py +311 -0
- BFEE2/templates_readme/Readme_Gromacs_Geometrical.txt +25 -0
- BFEE2/templates_readme/Readme_NAMD_Alchemical.txt +20 -0
- BFEE2/templates_readme/Readme_NAMD_Geometrical.txt +34 -0
- BFEE2/templates_readme/__init__.py +1 -0
- BFEE2/third_party/__init__.py +0 -0
- BFEE2/third_party/py_bar.py +335 -0
- BFEE2/version.py +2 -0
- bfee2-2.5.0.data/scripts/BFEE2Gui.py +18 -0
- bfee2-2.5.0.dist-info/LICENSE +677 -0
- bfee2-2.5.0.dist-info/METADATA +76 -0
- bfee2-2.5.0.dist-info/RECORD +65 -0
- bfee2-2.5.0.dist-info/WHEEL +5 -0
- 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()
|