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
BFEE2/postTreatment.py ADDED
@@ -0,0 +1,502 @@
1
+ # post-treatment of BFEE
2
+
3
+ import math
4
+
5
+ import numpy as np
6
+
7
+ from BFEE2.third_party import py_bar
8
+
9
+ # Boltazann constant for NAMD unit convention
10
+ BOLTZMANN = 0.0019872041
11
+ BOLTZMANN_GMX = 0.0019872041 * 4.184
12
+
13
+ # standard concentration
14
+ CSTAR = 1661
15
+ CSTAR_GMX = 1.661
16
+
17
+ # an runtime error
18
+ # r* > r(pmf)
19
+ class RStarTooLargeError(RuntimeError):
20
+ def __init__(self, arg):
21
+ self.args = arg
22
+
23
+ class postTreatment:
24
+ """the post-treatment of BFEE outputs
25
+ """
26
+
27
+ def __init__(self, temperature, unit, jobType='geometric'):
28
+ """do post treatment, internally, all the unit should be converted into
29
+ the NAMD/Colvars unit
30
+
31
+ Args:
32
+ temperature (float): temperature of the simulation
33
+ unit (str): unit convention used by MD engine, 'namd' or 'gromacs'
34
+ jobType (str): 'geometric' or 'alchemical'. Actually this arg is not used yet. Default to geometric.
35
+ """
36
+
37
+ if unit == 'namd':
38
+ self.BOLTZMANN = BOLTZMANN
39
+ self.CSTAR = CSTAR
40
+ elif unit == 'gromacs':
41
+ self.BOLTZMANN = BOLTZMANN_GMX
42
+ self.CSTAR = CSTAR_GMX
43
+
44
+ self.unit = unit
45
+ self.beta = 1 / (self.BOLTZMANN * temperature)
46
+ self.temperature = float(temperature)
47
+
48
+ def _readPMF(self, filePath):
49
+ """read a 1D PMF file
50
+
51
+ Args:
52
+ filePath (str): the path of the PMF file
53
+
54
+ Returns:
55
+ np.array (float, 2*N): ((x0,x1,x2, ...), (y0, y1, y2, ...))
56
+ """
57
+
58
+ data = np.loadtxt(filePath)
59
+ x = data[:,0]
60
+ y = data[:,1]
61
+
62
+ return np.array((x, y))
63
+
64
+ def _geometricRestraintContribution(self, pmf, forceConstant, rmsd=False, unbound=False):
65
+ """calculate the contribution of RMSD and angle restraints
66
+
67
+ Args:
68
+ pmf (np.array, float, 2*N): ((x0,x1,x2, ...), (y0, y1, y2, ...))
69
+ forceConstant (float): the force constant of the restraint
70
+ rmsd (bool): whether the contribution of RMSD is being calculated. Defaults to False.
71
+ unbound (bool, optional): whether unbound-state contribution is being calculated. Defaults to False.
72
+
73
+ Returns:
74
+ float: contribution of the geometric restraint
75
+ """
76
+
77
+ width = pmf[0][1] - pmf[0][0]
78
+
79
+ if rmsd:
80
+ # for RMSD, the restraintCenter is zero
81
+ restraintCenter = 0
82
+ else:
83
+ # the minimum of pmf
84
+ restraintCenter = pmf[0][np.argmin(pmf[1])]
85
+
86
+ # integration
87
+ numerator = 0
88
+ denominator = 0
89
+ for x, y in zip(pmf[0], pmf[1]):
90
+ numerator += math.exp(-self.beta * y)
91
+ denominator += math.exp((-self.beta) * (y + 0.5 * forceConstant * ((x - restraintCenter)**2)))
92
+
93
+ contribution = math.log(numerator / denominator) / self.beta
94
+
95
+ if unbound:
96
+ return contribution
97
+ else:
98
+ return -contribution
99
+
100
+ def _geometricRestraintContributionBulk(
101
+ self, theta, forceConstantTheta, forceConstantPhi, forceConstantPsi
102
+ ):
103
+ """contribution of rotational restraints in the unbounded state
104
+
105
+ Args:
106
+ theta (float): restraining center of the theta angle
107
+ forceConstantTheta (float): restraining force constant for Theta
108
+ forceConstantPhi (float): restraining force constant for Phi
109
+ forceConstantPsi (float): restraining force constant for Psi
110
+
111
+ Returns:
112
+ float: contribution of the geometric restraint in the unbound state
113
+ """
114
+
115
+ # all the units in radian
116
+ theta0 = math.radians(theta)
117
+ # periodic CV then the u(phi) and u(psi) should be the same in all cases
118
+ phi0 = math.radians(180)
119
+ psi0 = math.radians(180)
120
+
121
+ forceConstantTheta *= (180 / math.pi)**2
122
+ forceConstantPhi *= (180 / math.pi)**2
123
+ forceConstantPsi *= (180 / math.pi)**2
124
+
125
+ contributionTheta = 0
126
+ contributionPhi = 0
127
+ contributionPsi = 0
128
+ # integration
129
+ for i in range(1000):
130
+ theta = i / 1000.0 * math.pi - math.pi / 2
131
+ contributionTheta += 1.0/1000.0 * math.pi * math.sin(theta + math.pi / 2) * \
132
+ math.exp(-self.beta * 0.5 * forceConstantTheta * ((theta - theta0)**2))
133
+
134
+ phi = i / 1000.0 * 2 * math.pi
135
+ contributionPhi += 1.0/1000.0 * 2 * math.pi * \
136
+ math.exp(-self.beta * 0.5 * forceConstantPhi* ((phi - phi0)**2))
137
+
138
+ psi = i / 1000.0 * 2 * math.pi
139
+ contributionPsi += 1.0/1000.0 * 2 * math.pi * \
140
+ math.exp(-self.beta * 0.5 * forceConstantPsi* ((psi - psi0)**2))
141
+
142
+ return -math.log((contributionTheta * contributionPhi * contributionPsi) / 8 / math.pi**2) / self.beta
143
+
144
+ def _geometricJacobianCorrection(self, pmf):
145
+ """correct the Jacobian contribution of separation pmf
146
+
147
+ Args:
148
+ pmf (np.array, float, 2*N): ((x0,x1,x2, ...), (y0, y1, y2, ...)), separation pmf
149
+ """
150
+
151
+ for i in range(len(pmf[0])):
152
+ pmf[1][i] += 2 * self.BOLTZMANN * self.temperature * math.log(pmf[0][i])
153
+
154
+ pmf[1] -= np.min(pmf[1])
155
+
156
+ def _geometricCalculateSI(
157
+ self, rStar, pmf, polarTheta, polarPhi, forceConstantPolarTheta, forceConstantPolarPhi):
158
+ """calculation the contribution of S* and I* in the separation simulation
159
+
160
+ Args:
161
+ rStar (float): r* in integration
162
+ pmf (np.array, float, 2*N): ((x0,x1,x2, ...), (y0, y1, y2, ...)), separation pmf
163
+ polarTheta0 (float): restraining center of polarTheta
164
+ polarPhi0 (float): restraining center of polarPhi
165
+ forceConstantPolarTheta (float): restraining force constant for polarTheta
166
+ forceConstantPolarPhi (float): restraining force constant for polarPhi
167
+
168
+ Returns:
169
+ float: contribution of S* and I* in the separation simulation
170
+ """
171
+
172
+ if rStar > pmf[0][-1]:
173
+ raise RStarTooLargeError('r_star cannot be larger than r_max of step 7!')
174
+
175
+ polarTheta0 = math.radians(polarTheta)
176
+ polarPhi0 = math.radians(polarPhi)
177
+
178
+ forceConstantPolarTheta *= (180 / math.pi)**2
179
+ forceConstantPolarPhi *= (180 / math.pi)**2
180
+
181
+ contributionPolarTheta = 0
182
+ contributionPolarPhi = 0
183
+ # integration
184
+ for i in range(1000):
185
+ polarTheta = i / 1000.0 * math.pi
186
+ contributionPolarTheta += 1.0 / 1000.0 * math.pi * math.sin(polarTheta) * \
187
+ math.exp(-self.beta * 0.5 * forceConstantPolarTheta * (polarTheta - polarTheta0)**2)
188
+
189
+ polarPhi = i / 1000.0 * 2 * math.pi - math.pi
190
+ contributionPolarPhi += 1.0 / 1000.0 * 2 * math.pi * \
191
+ math.exp(-self.beta * 0.5 * forceConstantPolarPhi * (polarPhi - polarPhi0)**2)
192
+
193
+ S = rStar**2 * contributionPolarTheta * contributionPolarPhi
194
+
195
+ # w(r*)
196
+ wrStar = pmf[1][0]
197
+ for x, y in zip(pmf[0], pmf[1]):
198
+ if x >= rStar:
199
+ wrStar = y
200
+ break
201
+
202
+ # integration
203
+ width = pmf[0][1] - pmf[0][0]
204
+ I = 0
205
+ for x, y in zip(pmf[0], pmf[1]):
206
+ I += width * math.exp(-self.beta * (y - wrStar))
207
+ if x >= rStar:
208
+ break
209
+
210
+ return -1 / self.beta * math.log(S * I / self.CSTAR)
211
+
212
+ def geometricBindingFreeEnergy(self, filePathes, parameters):
213
+ """calculate binding free energy for geometric route
214
+
215
+ Args:
216
+ filePathes (list of strings, 8): pathes of PMF files for step1 - step8.
217
+ PMFs for steps 1 and 8 can be omitted, which
218
+ indicates the investication of a rigid ligand.
219
+ parameters (np.array, floats, 8): (forceConstant1, FC2, FC3, FC4, FC5, FC6, r*, FC8)
220
+
221
+ Returns:
222
+ np.array, float, 10: (contributions for step1, 2, 3, 4 ... 8, bulk restraining contribution, free energy)
223
+ """
224
+
225
+ assert len(parameters) == 8
226
+ assert len(filePathes) == 8
227
+
228
+ pmfs = []
229
+ rigid_ligand = False
230
+ for index, path in enumerate(filePathes):
231
+ if (index == 0 or index == 7) and path == '':
232
+ rigid_ligand = True
233
+ pmfs.append(None)
234
+ else:
235
+ pmfs.append(self._readPMF(path))
236
+ self._geometricJacobianCorrection(pmfs[6])
237
+
238
+ contributions = np.zeros(10)
239
+ if not rigid_ligand:
240
+ contributions[0] = self._geometricRestraintContribution(pmfs[0], parameters[0], True, False)
241
+ else:
242
+ contributions[0] = 0.0
243
+ contributions[1] = self._geometricRestraintContribution(pmfs[1], parameters[1], False, False)
244
+ contributions[2] = self._geometricRestraintContribution(pmfs[2], parameters[2], False, False)
245
+ contributions[3] = self._geometricRestraintContribution(pmfs[3], parameters[3], False, False)
246
+ contributions[4] = self._geometricRestraintContribution(pmfs[4], parameters[4], False, False)
247
+ contributions[5] = self._geometricRestraintContribution(pmfs[5], parameters[5], False, False)
248
+ contributions[6] = self._geometricCalculateSI(
249
+ parameters[6], pmfs[6], pmfs[4][0][np.argmin(pmfs[4][1])], pmfs[5][0][np.argmin(pmfs[5][1])],
250
+ parameters[4], parameters[5]
251
+ )
252
+ if not rigid_ligand:
253
+ contributions[7] = self._geometricRestraintContribution(pmfs[7], parameters[7], True, True)
254
+ else:
255
+ contributions[7] = 0.0
256
+ contributions[8] = self._geometricRestraintContributionBulk(
257
+ pmfs[1][0][np.argmin(pmfs[1][1])], parameters[1], parameters[2], parameters[3]
258
+ )
259
+
260
+ contributions[9] = np.sum(contributions[:9])
261
+
262
+ if self.unit == 'namd':
263
+ return contributions
264
+ elif self.unit == 'gromacs':
265
+ return contributions / 4.184
266
+
267
+ def _alchemicalRestraintContributionBulk(
268
+ self, eulerTheta, polarTheta, R,
269
+ forceConstantTheta=0.1, forceConstantPhi=0.1, forceConstantPsi=0.1,
270
+ forceConstanttheta=0.1, forceConstantphi=0.1, forceConstantR=10
271
+ ):
272
+ """contribution of (standard concentration corrected) rotational
273
+ and orienetational restraints in the unbounded state
274
+
275
+ Args:
276
+ eulerTheta (float): restraining center of the Euler angle theta
277
+ polarTheta (float): restraining center of the polar angle theta
278
+ R (float): restraining center of anger R
279
+ forceConstantTheta (float): restraining force constant for euler Theta. Defaults to 0.1.
280
+ forceConstantPhi (float, optional): restraining force constant for euler Phi. Defaults to 0.1.
281
+ forceConstantPsi (float, optional): restraining force constant for euler Psi. Defaults to 0.1.
282
+ forceConstanttheta (float, optional): restraining force constant for polar theta. Defaults to 0.1.
283
+ forceConstantphi (float, optional): restraining force constant for polar phi. Defaults to 0.1.
284
+ forceConstantR (int, optional): restraining force constant for distance R. Defaults to 10.
285
+
286
+ Returns:
287
+ float: contribution of the geometric restraint in the unbound state
288
+ """
289
+
290
+ # degrees to rad
291
+ eulerTheta = math.radians(eulerTheta + 90)
292
+ polarTheta = math.radians(polarTheta)
293
+ forceConstantTheta *= (180 / math.pi)**2
294
+ forceConstantPhi *= (180 / math.pi)**2
295
+ forceConstantPsi *= (180 / math.pi)**2
296
+ forceConstanttheta *= (180 / math.pi)**2
297
+ forceConstantphi *= (180 / math.pi)**2
298
+
299
+ contribution = self.BOLTZMANN * self.temperature * math.log(
300
+ 8 * (math.pi**2) * self.CSTAR / ((R**2) * math.sin(eulerTheta) * math.sin(polarTheta)) * \
301
+ math.sqrt(forceConstantTheta * forceConstantPhi * forceConstantPsi * forceConstanttheta * \
302
+ forceConstantphi * forceConstantR ) / ((2 * math.pi * self.BOLTZMANN * self.temperature)**3)
303
+ )
304
+ return contribution
305
+
306
+ def _fepoutFile(self, filePath):
307
+ """parse a fepout file and return the lambda-free energy relationship
308
+
309
+ Args:
310
+ filePath (str): path of the fepout file
311
+
312
+ Returns:
313
+ tuple (2D np.array): lambda-free energy relationship
314
+ """
315
+
316
+ Lambda = []
317
+ dA_dLambda = []
318
+
319
+ with open(filePath, 'r', encoding='utf-8') as fepoutFile:
320
+ for line in fepoutFile.readlines():
321
+ if not line.startswith('#Free energy'):
322
+ continue
323
+ splitedLine = line.strip().split()
324
+ Lambda.append((float(splitedLine[7]) + float(splitedLine[8])) / 2)
325
+ dA_dLambda.append(float(splitedLine[11]))
326
+
327
+ if Lambda[0] > Lambda[1]:
328
+ Lambda.reverse()
329
+ dA_dLambda.reverse()
330
+
331
+ return np.array((Lambda, np.cumsum(dA_dLambda)))
332
+
333
+
334
+ def _tiLogFile(self, filePath, rigidLigand = False):
335
+ """parse a ti log file and return the lambda-free energy relationship
336
+
337
+ Args:
338
+ filePath (str): path of the fepout file
339
+ rigidLigand (bool): whether dealing with a rigid ligand. Default to False.
340
+
341
+ Returns:
342
+ tuple (2D np.array): lambda-free energy relationship
343
+ """
344
+
345
+ Lambda = []
346
+ dA_dLambda = []
347
+
348
+ if rigidLigand:
349
+ numCVs = 6
350
+ else:
351
+ numCVs = 7
352
+
353
+ with open(filePath, 'r', encoding='utf-8') as fepoutFile:
354
+ for line in fepoutFile.readlines():
355
+ if not ('dA/dLambda' in line):
356
+ continue
357
+ splitedLine = line.strip().split()
358
+ Lambda.append(float(splitedLine[4]))
359
+ dA_dLambda.append(float(splitedLine[6]))
360
+
361
+ # seven CVs in total with the same Lambda in the step 2
362
+ if Lambda[0] == Lambda[1]:
363
+ correctedLambda = []
364
+ correctedDA_dLambda = []
365
+
366
+ for i in range(0, len(Lambda), numCVs):
367
+ correctedLambda.append(Lambda[i])
368
+ totalDA_dLambda = 0
369
+ for j in range(numCVs):
370
+ totalDA_dLambda += dA_dLambda[i+j]
371
+ correctedDA_dLambda.append(totalDA_dLambda)
372
+
373
+ Lambda = correctedLambda
374
+ dA_dLambda = correctedDA_dLambda
375
+
376
+ if Lambda[0] > Lambda[1]:
377
+ Lambda.reverse()
378
+ dA_dLambda.reverse()
379
+
380
+ for i in range(1, len(Lambda)):
381
+ dA_dLambda[i] = (Lambda[i] - Lambda[i-1]) * dA_dLambda[i]
382
+
383
+ return np.array((Lambda, np.cumsum(dA_dLambda)))
384
+
385
+ def _alchemicalFepoutFile(self, filePath, fileType = 'fepout', rigidLigand = False):
386
+ """parse a fepout/log file and return the total free energy change
387
+
388
+ Args:
389
+ filePath (str): path of the fepout file
390
+ fileType (str): 'fepout' (decouping atoms) or 'log' (decoupling restraints). Defaults to 'fepout'.
391
+ rigidLigand (bool): whether dealing with a rigid ligand. Default to False.
392
+
393
+ Returns:
394
+ float: free-energy change
395
+ """
396
+
397
+ if fileType == 'fepout':
398
+ _, freeEnergyProfile = self._fepoutFile(filePath)
399
+
400
+ if fileType == 'log':
401
+ _, freeEnergyProfile = self._tiLogFile(filePath, rigidLigand)
402
+
403
+ return freeEnergyProfile[-1]
404
+
405
+ def alchemicalFreeEnergy(self, forwardFilePath, backwardFilePath = '', temperature = 300, jobType = 'fep'):
406
+ """ parse a pair of fepout file, or a single double-wide file using the py_bar library
407
+
408
+ Args:
409
+ forwardFilePath (str): path to the forward fepout file
410
+ backwardFilePath (str): path to the backward fepout file. Empty string
411
+ corresponds to a double-wide simulation
412
+ temperature (float): temperature of the simulation
413
+ jobType (str, optional): Type of the post-treatment method. 'fep' or 'bar'.
414
+ Defaults to 'fep'.
415
+ Returns:
416
+ tuple[float, float]: free-energy change, error
417
+ """
418
+ window, deltaU = py_bar.NAMDParser(forwardFilePath, backwardFilePath).get_data()
419
+ analyzer = py_bar.FEPAnalyzer(window, deltaU, temperature)
420
+
421
+ if jobType == 'bar':
422
+ result = analyzer.BAR_free_energy(block_size=50, n_bootstrap=20)
423
+ else:
424
+ result = analyzer.FEP_free_energy()
425
+
426
+ freeEnergy = np.sum(result[1])
427
+ error = np.sqrt(np.sum(np.power(result[2], 2)))
428
+
429
+ return freeEnergy, error
430
+
431
+ def alchemicalBindingFreeEnergy(self, filePathes, parameters, temperature = 300, jobType = 'fep', rigidLigand = False):
432
+ """calculate binding free energy for alchemical route
433
+
434
+ Args:
435
+ filePathes (list of strings, 8): pathes of alchemical output files
436
+ (step1-forward, step1-backward, step2-forward ...)
437
+ parameters (np.array, floats, 9): (eulerTheta, polarTheta, r, forceConstant1, FC2, FC3, FC4, FC5, FC6)
438
+ temperature (float): temperature of the simulation
439
+ jobType (str, optional): Type of the post-treatment method. 'fep' or 'bar'.
440
+ Defaults to 'fep'.
441
+ rigidLigand (bool): whether dealing with a rigid ligand. Default to False.
442
+
443
+ Returns:
444
+ tuple:
445
+ np.array, float, 6: (contributions for step1, 2, 3, 4, bulk restraining contribution, free energy)
446
+ np.array, float, 6: errors corresponding each contribution
447
+ """
448
+
449
+ assert len(parameters) == 9
450
+ assert len(filePathes) == 8
451
+
452
+ rigid_ligand = False
453
+ if (filePathes[6] == ''):
454
+ rigid_ligand = True
455
+
456
+ # get free energies from fep outputs
457
+ freeEnergies = []
458
+ for i in range(len(filePathes)):
459
+ if filePathes[i] != '':
460
+ if (i // 2) % 2 == 0:
461
+ # just a dirty solution
462
+ freeEnergies.append(None)
463
+ #freeEnergies.append(self._alchemicalFepoutFile(filePathes[i], 'fepout'))
464
+ else:
465
+ freeEnergies.append(self._alchemicalFepoutFile(filePathes[i], 'log', rigidLigand))
466
+ else:
467
+ # backward file can be empty
468
+ freeEnergies.append(None)
469
+
470
+ contributions = np.zeros(6)
471
+ errors = np.zeros(6)
472
+
473
+ contributions[0], errors[0] = self.alchemicalFreeEnergy(filePathes[0], filePathes[1], temperature, jobType)
474
+
475
+ if freeEnergies[3] is not None:
476
+ contributions[1] = -(freeEnergies[2] + freeEnergies[3]) / 2
477
+ errors[1] = abs((freeEnergies[2] - freeEnergies[3]) / 1.414)
478
+ else:
479
+ contributions[1] = -freeEnergies[2]
480
+ errors[1] = 99999
481
+
482
+ contributions[2], errors[2] = self.alchemicalFreeEnergy(filePathes[4], filePathes[5], temperature, jobType)
483
+ contributions[2] = -contributions[2]
484
+
485
+ if not rigid_ligand:
486
+ if freeEnergies[7] is not None:
487
+ contributions[3] = (freeEnergies[6] + freeEnergies[7]) / 2
488
+ errors[3] = abs((freeEnergies[6] - freeEnergies[7]) / 1.414)
489
+ else:
490
+ contributions[3] = freeEnergies[6]
491
+ errors[3] = 99999
492
+ else:
493
+ contributions[3] = 0
494
+ errors[3] = 0
495
+
496
+ contributions[4] = self._alchemicalRestraintContributionBulk(*parameters)
497
+ errors[4] = 0
498
+
499
+ contributions[5] = contributions[0] + contributions[1] + contributions[2] + contributions[3] + contributions[4]
500
+ errors[5] = math.sqrt(errors[0]**2 + errors[1]**2 +errors[2]**2 + errors[3]**2 + errors[4]**2)
501
+
502
+ return contributions, errors
@@ -0,0 +1,37 @@
1
+ colvarsTrajFrequency 500
2
+ colvarsRestartFrequency 50000
3
+ indexFile colvars.ndx
4
+
5
+ colvar {
6
+ name translation
7
+ distance {
8
+ group1 {
9
+ indexGroup $protein_selection
10
+ }
11
+ group2 {
12
+ dummyAtom $protein_center
13
+ }
14
+ }
15
+ }
16
+
17
+ harmonic {
18
+ colvars translation
19
+ centers 0.0
20
+ forceConstant 4184
21
+ }
22
+
23
+ colvar {
24
+ name orientation
25
+ orientation {
26
+ atoms {
27
+ indexGroup $protein_selection
28
+ }
29
+ refPositionsfile reference.xyz
30
+ }
31
+ }
32
+
33
+ harmonic {
34
+ colvars orientation
35
+ centers (1.0, 0.0, 0.0, 0.0)
36
+ forceConstant 836.8
37
+ }
@@ -0,0 +1,31 @@
1
+ #!/bin/sh
2
+
3
+ # define the binary of gromacs
4
+ if which gmx_mpi &> /dev/null; then
5
+ GMX_BIN=$(which gmx_mpi)
6
+ else which gmx &> /dev/null;
7
+ GMX_BIN=$(which gmx)
8
+ fi
9
+ echo "Will use the gromacs executable binary at $GMX_BIN"
10
+
11
+ # input (.gro, .top and .mdp) and output (.tpr)
12
+ # MDP_FILE: running parameters
13
+ # GRO_FILE: atom positions
14
+ # TOP_FILE: topology
15
+ MDP_FILE=$MDP_FILE_TEMPLATE
16
+ GRO_FILE=$GRO_FILE_TEMPLATE
17
+ TOP_FILE=$TOP_FILE_TEMPLATE
18
+
19
+ # generate the tpr file
20
+ OUTPUT_BASENAME=$(basename "$(pwd)")
21
+ TPR_FILE="$OUTPUT_BASENAME.tpr"
22
+ NEW_MDP_FILE="$OUTPUT_BASENAME.mdp"
23
+ echo "Making gromacs tpr file ($TPR_FILE)..."
24
+ $GMX_BIN grompp -f $MDP_FILE -c $GRO_FILE -p $TOP_FILE -o $TPR_FILE -po $NEW_MDP_FILE
25
+
26
+ # run the PMF calculation
27
+ mkdir -p output
28
+ DEFAULT_OUTPUT_FILENAME="output/$OUTPUT_BASENAME.out"
29
+ # $GMX_BIN mdrun -ntmpi 1 -ntomp 4 -nb gpu -pme gpu -gpu_id 0 -s $TPR_FILE -deffnm $DEFAULT_OUTPUT_FILENAME -colvars colvar.dat
30
+ echo "You can now run gromacs by the following example:"
31
+ echo "$GMX_BIN mdrun -ntmpi 1 -ntomp 4 -nb gpu -pme gpu -gpu_id 0 -s $TPR_FILE -deffnm $DEFAULT_OUTPUT_FILENAME -colvars $COLVARS_INPUT_TEMPLATE"
@@ -0,0 +1,70 @@
1
+ ;equilibration of p41-abl
2
+
3
+ ;Run control
4
+ integrator = md
5
+ dt = $dt
6
+ tinit = 0
7
+ nsteps = $nsteps
8
+ comm-mode = Linear
9
+ nstcomm = 1000
10
+
11
+ ;Langevin dynamics
12
+ bd-fric = 0
13
+ ld-seed = -1
14
+
15
+ ;Energy minimization
16
+ ;emtol = 10
17
+ ;emstep = 0.01
18
+
19
+ ;Output control
20
+ nstxout = 5000
21
+ nstvout = 5000
22
+ nstfout = 5000
23
+ nstlog = 5000
24
+ nstcalcenergy = 1000
25
+ nstenergy = 5000
26
+
27
+ ;Neighbor searching
28
+ cutoff-scheme = Verlet
29
+ ns-type = grid
30
+ pbc = xyz
31
+ periodic-molecules = no
32
+
33
+ ;Electrostatics
34
+ coulombtype = PME
35
+ coulomb-modifier = Potential-shift-Verlet
36
+ rcoulomb = 1.2
37
+
38
+ ;VdW
39
+ vdwtype = Cut-off
40
+ vdw-modifier = force-switch
41
+ rvdw = 1.2
42
+ rvdw-switch = 1.0
43
+ DispCorr = no
44
+
45
+ ;Bonds (for minimization)
46
+ constraint-algorithm = LINCS
47
+ constraints = h-bonds
48
+ continuation = yes
49
+ morse = no
50
+
51
+ ;Implicit solvent
52
+ implicit-solvent = no
53
+
54
+ ;Pressure coupling
55
+ ;Pressure coupling
56
+ pcoupl = C-rescale
57
+ pcoupltype = Isotropic
58
+ nstpcouple = -1
59
+ tau-p = 2
60
+ compressibility = 4.5e-5
61
+ ref-p = $pressure
62
+
63
+ ;Temperature coupling
64
+ tcoupl = v-rescale
65
+ tc-grps = System
66
+ tau_t = 0.1
67
+ ref_t = $temperature
68
+
69
+ ;Velocity generation
70
+ gen-vel = no