bfee2 2.5.0__py3-none-any.whl

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

Potentially problematic release.


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

Files changed (65) hide show
  1. BFEE2/__init__.py +0 -0
  2. BFEE2/commonTools/__init__.py +0 -0
  3. BFEE2/commonTools/commonSlots.py +48 -0
  4. BFEE2/commonTools/fileParser.py +327 -0
  5. BFEE2/commonTools/ploter.py +218 -0
  6. BFEE2/doc/Doc.pdf +0 -0
  7. BFEE2/doc/__init__.py +1 -0
  8. BFEE2/gui.py +2136 -0
  9. BFEE2/inputGenerator.py +2857 -0
  10. BFEE2/postTreatment.py +502 -0
  11. BFEE2/templates_gromacs/000.colvars.template +37 -0
  12. BFEE2/templates_gromacs/000.generate_tpr_sh.template +31 -0
  13. BFEE2/templates_gromacs/000.mdp.template +70 -0
  14. BFEE2/templates_gromacs/001.colvars.template +76 -0
  15. BFEE2/templates_gromacs/001.generate_tpr_sh.template +31 -0
  16. BFEE2/templates_gromacs/001.mdp.template +70 -0
  17. BFEE2/templates_gromacs/001.readme.template +1 -0
  18. BFEE2/templates_gromacs/002.colvars.template +101 -0
  19. BFEE2/templates_gromacs/002.generate_tpr_sh.template +31 -0
  20. BFEE2/templates_gromacs/002.mdp.template +70 -0
  21. BFEE2/templates_gromacs/003.colvars.template +125 -0
  22. BFEE2/templates_gromacs/003.generate_tpr_sh.template +36 -0
  23. BFEE2/templates_gromacs/003.mdp.template +70 -0
  24. BFEE2/templates_gromacs/004.colvars.template +148 -0
  25. BFEE2/templates_gromacs/004.generate_tpr_sh.template +37 -0
  26. BFEE2/templates_gromacs/004.mdp.template +70 -0
  27. BFEE2/templates_gromacs/005.colvars.template +170 -0
  28. BFEE2/templates_gromacs/005.generate_tpr_sh.template +38 -0
  29. BFEE2/templates_gromacs/005.mdp.template +70 -0
  30. BFEE2/templates_gromacs/006.colvars.template +192 -0
  31. BFEE2/templates_gromacs/006.generate_tpr_sh.template +39 -0
  32. BFEE2/templates_gromacs/006.mdp.template +70 -0
  33. BFEE2/templates_gromacs/007.colvars.template +210 -0
  34. BFEE2/templates_gromacs/007.generate_tpr_sh.template +40 -0
  35. BFEE2/templates_gromacs/007.mdp.template +69 -0
  36. BFEE2/templates_gromacs/007_eq.colvars.template +169 -0
  37. BFEE2/templates_gromacs/007_eq.generate_tpr_sh.template +64 -0
  38. BFEE2/templates_gromacs/007_min.mdp.template +58 -0
  39. BFEE2/templates_gromacs/008.colvars.template +42 -0
  40. BFEE2/templates_gromacs/008.generate_tpr_sh.template +31 -0
  41. BFEE2/templates_gromacs/008.mdp.template +70 -0
  42. BFEE2/templates_gromacs/008_eq.generate_tpr_sh.template +31 -0
  43. BFEE2/templates_gromacs/BFEEGromacs.py +1244 -0
  44. BFEE2/templates_gromacs/__init__.py +0 -0
  45. BFEE2/templates_gromacs/find_min_max.awk +27 -0
  46. BFEE2/templates_namd/__init__.py +0 -0
  47. BFEE2/templates_namd/configTemplate.py +1094 -0
  48. BFEE2/templates_namd/fep.tcl +299 -0
  49. BFEE2/templates_namd/scriptTemplate.py +149 -0
  50. BFEE2/templates_namd/solvate.tcl +9 -0
  51. BFEE2/templates_namd/solvate_mem.tcl +9 -0
  52. BFEE2/templates_namd/updateCenters.py +311 -0
  53. BFEE2/templates_readme/Readme_Gromacs_Geometrical.txt +25 -0
  54. BFEE2/templates_readme/Readme_NAMD_Alchemical.txt +20 -0
  55. BFEE2/templates_readme/Readme_NAMD_Geometrical.txt +34 -0
  56. BFEE2/templates_readme/__init__.py +1 -0
  57. BFEE2/third_party/__init__.py +0 -0
  58. BFEE2/third_party/py_bar.py +335 -0
  59. BFEE2/version.py +2 -0
  60. bfee2-2.5.0.data/scripts/BFEE2Gui.py +18 -0
  61. bfee2-2.5.0.dist-info/LICENSE +677 -0
  62. bfee2-2.5.0.dist-info/METADATA +76 -0
  63. bfee2-2.5.0.dist-info/RECORD +65 -0
  64. bfee2-2.5.0.dist-info/WHEEL +5 -0
  65. bfee2-2.5.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,335 @@
1
+ from typing import List, Literal, Optional, Tuple
2
+
3
+ import numpy as np
4
+ from numpy.typing import NDArray
5
+
6
+ # boltzmann constant
7
+ BOLTZMANN = 0.0019872041
8
+
9
+ # type of FEP files
10
+ fep_type = Literal['forward', 'backward', 'double-wide']
11
+
12
+ class NAMDParser:
13
+ """ parse NAMD .fepout files and get the necessary data
14
+ """
15
+
16
+ def __init__(self, forward_file: str, backward_file: Optional[str] = '') -> None:
17
+ """ Read NAMD .fepout files. The end-user can either provide the bidirectional
18
+ .fepout files, or provide an .fepout file of the double-wide FEP simulation
19
+
20
+ Args:
21
+ forward_file (str): the fepout file for forward or double-wide simulation
22
+ backward_file (Optional[str], optional): the fepout file for backward simulation.
23
+ Defaults to ''.
24
+ """
25
+
26
+ self._double_wide = False
27
+ if (backward_file == '') or (backward_file is None):
28
+ self._double_wide = True
29
+
30
+ # List[Tuple[float, float]], recording the boundaries of each window
31
+ # List[Tuple[NDArray, NDArray]], recording the deltaU of forward of
32
+ # backward simulations of each window
33
+ if not self._double_wide:
34
+ self._windows, self._deltaU_data = self._pair_bidirectionalData(
35
+ self._read_fepout(forward_file),
36
+ self._read_fepout(backward_file)
37
+ )
38
+ else:
39
+ self._windows, self._deltaU_data = self._read_double_wide_fepout(forward_file)
40
+
41
+ if len(self._windows) != len(self._deltaU_data):
42
+ raise RuntimeError('Internal numbers of windows and deltaU do not match! This is a bug!')
43
+
44
+ def _read_fepout(self, fepout_file: str) -> Tuple[List[Tuple[float, float]], List[NDArray]]:
45
+ """ Read an NAMD fepout file. Return the window and deltaU information
46
+
47
+ Args:
48
+ fepout_file (str): the path of the fepout file
49
+
50
+ Returns:
51
+ Tuple[List[Tuple[float, float]], List[NDArray]]: List[Tuple[float, float]], recording
52
+ the boundaries of each window, and
53
+ List[NDArray], recording the deltaU
54
+ """
55
+
56
+ windows = []
57
+ deltaU = []
58
+ with open(fepout_file, 'r') as input_fepout:
59
+ while True:
60
+ line = input_fepout.readline()
61
+ if not line:
62
+ break
63
+
64
+ if line.startswith('#NEW FEP WINDOW:'):
65
+ splitedLine = line.strip().split()
66
+ windows.append((float(splitedLine[6]), float(splitedLine[8])))
67
+ continue
68
+
69
+ if line.startswith('#STARTING COLLECTION'):
70
+ # collecting deltaU
71
+ deltaU_per_window = []
72
+ while True:
73
+ line = input_fepout.readline()
74
+ if line.startswith('FepEnergy:'):
75
+ splitedLine = line.strip().split()
76
+ deltaU_per_window.append(float(splitedLine[6]))
77
+ else:
78
+ deltaU.append(np.array(deltaU_per_window))
79
+ break
80
+
81
+ return windows, deltaU
82
+
83
+ def _read_double_wide_fepout(self, fepout_file: str) -> Tuple[List[Tuple[float, float]], List[Tuple[NDArray, NDArray]]]:
84
+ """ Read an NAMD double-wide fepout file. Return the window and bidirectional deltaU information
85
+
86
+ Args:
87
+ fepout_file (str): the path of the fepout file
88
+
89
+ Returns:
90
+ Tuple[List[Tuple[float, float]], List[Tuple[NDArray, NDArray]]]: recording the boundary and
91
+ deltaU of each window of
92
+ bidirectional simulations
93
+ """
94
+
95
+ windows = []
96
+ deltaU_forward = []
97
+ deltaU_backward = []
98
+ with open(fepout_file, 'r') as input_fepout:
99
+ # The first window samples forward only, the last window backward only
100
+ first_window = True
101
+ last_window = False
102
+ while True:
103
+ line = input_fepout.readline()
104
+ if not line:
105
+ break
106
+
107
+ if line.startswith('#NEW FEP WINDOW: LAMBDA SET TO 1') and windows != []:
108
+ last_window = True
109
+ if line.startswith('#NEW FEP WINDOW: LAMBDA SET TO 0 ') and windows != []:
110
+ last_window = True
111
+
112
+ if not last_window:
113
+ if line.startswith('#NEW FEP WINDOW:'):
114
+ splitedLine = line.strip().split()
115
+ windows.append((float(splitedLine[6]), float(splitedLine[8])))
116
+ continue
117
+
118
+ if line.startswith('#STARTING COLLECTION'):
119
+ # collecting deltaU
120
+ deltaU_forward_per_window = []
121
+ deltaU_backward_per_window = []
122
+ while True:
123
+ line = input_fepout.readline()
124
+ if line.startswith('FepEnergy:'):
125
+ splitedLine = line.strip().split()
126
+ if not last_window:
127
+ deltaU_forward_per_window.append(float(splitedLine[6]))
128
+ else:
129
+ deltaU_backward_per_window.append(float(splitedLine[6]))
130
+ elif line.startswith('FepE_back:'):
131
+ splitedLine = line.strip().split()
132
+ deltaU_backward_per_window.append(float(splitedLine[6]))
133
+ else:
134
+ if deltaU_forward_per_window != []:
135
+ deltaU_forward.append(np.array(deltaU_forward_per_window))
136
+ if deltaU_backward_per_window != []:
137
+ deltaU_backward.append(np.array(deltaU_backward_per_window))
138
+ break
139
+
140
+ if line.startswith('#Free energy change for lambda window'):
141
+ first_window = False
142
+ last_window = False
143
+
144
+ if len(deltaU_forward) != len(deltaU_backward):
145
+ raise RuntimeError('Forward and backward data do not match!')
146
+
147
+ deltaU = []
148
+ for i in range(len(deltaU_forward)):
149
+ deltaU.append((np.array(deltaU_forward[i]), np.array(deltaU_backward[i])))
150
+
151
+ return windows, deltaU
152
+
153
+ def _pair_bidirectionalData(
154
+ self,
155
+ forward_data: Tuple[List[Tuple[float, float]], List[NDArray]],
156
+ backward_data: Tuple[List[Tuple[float, float]], List[NDArray]]
157
+ ) -> Tuple[List[Tuple[float, float]], List[Tuple[NDArray, NDArray]]]:
158
+ """ pair data from bidirectional simulations
159
+
160
+ Args:
161
+ forward_data (Tuple[List[Tuple[float, float]], List[NDArray]]): data from forward simulation
162
+ backward_data (Tuple[List[Tuple[float, float]], List[NDArray]]): data from backward simulation
163
+
164
+ Returns:
165
+ Tuple[List[Tuple[float, float]], List[Tuple[NDArray, NDArray]]]: recording the boundary and
166
+ deltaU of each window of
167
+ bidirectional simulations
168
+ """
169
+
170
+ merged_data = []
171
+
172
+ for i in range(len(forward_data[0])):
173
+ for j in range(len(backward_data[0])):
174
+ if forward_data[0][i][0] == backward_data[0][j][1] and \
175
+ forward_data[0][i][1] == backward_data[0][j][0]:
176
+ merged_data.append((forward_data[1][i], backward_data[1][j]))
177
+ break
178
+ else:
179
+ raise RuntimeError('Error! the forward and backward files do not match!')
180
+
181
+ return forward_data[0], merged_data
182
+
183
+ def get_data(self) -> Tuple[List[Tuple[float, float]], List[Tuple[NDArray, NDArray]]]:
184
+ """ return the boundary and deltaU of each window
185
+
186
+ Returns:
187
+ Tuple[List[Tuple[float, float]], List[Tuple[NDArray, NDArray]]]: recording the boundary and
188
+ deltaU of each window of
189
+ bidirectional simulations
190
+ """
191
+
192
+ return self._windows, self._deltaU_data
193
+
194
+ class FEPAnalyzer:
195
+ """ Analyze FEP simulations
196
+ """
197
+
198
+ def __init__(
199
+ self,
200
+ window_boundaries: List[Tuple[float, float]],
201
+ deltaU_data: List[Tuple[NDArray, NDArray]],
202
+ temperature: float,
203
+ ) -> None:
204
+ """_summary_
205
+
206
+ Args:
207
+ window_boundaries (List[Tuple[float, float]]): boundaries of each window
208
+ deltaU_data (List[Tuple[NDArray, NDArray]]): deltaU for forward and backward simulations
209
+ of each window. The two deltaU should be opposite
210
+ numbers.
211
+ temperature (float): temperature of the simulation
212
+ """
213
+ self._windows, self._deltaU_data = window_boundaries, deltaU_data
214
+ self._temperature = temperature
215
+ if len(self._windows) != len(self._deltaU_data):
216
+ raise RuntimeError('Internal numbers of windows and deltaU do not match! This is a bug!')
217
+
218
+ def FEP_free_energy(self) -> Tuple[List[Tuple[float, float]], List[NDArray], List[NDArray]]:
219
+ """ Calculate and return the free-energy change using the FEP equation
220
+
221
+ Returns:
222
+ Tuple[List[Tuple[float, float]], List[NDArray], List[NDArray]]: window boundaries, free energies and errors
223
+ """
224
+
225
+ free_energies = []
226
+ errors = []
227
+ for i in range(len(self._windows)):
228
+ forward_free_energy = -BOLTZMANN * self._temperature * \
229
+ np.log(np.mean(np.exp(-self._deltaU_data[i][0] / (BOLTZMANN * self._temperature))))
230
+ backward_free_energy = -BOLTZMANN * self._temperature * \
231
+ np.log(np.mean(np.exp(-self._deltaU_data[i][1] / (BOLTZMANN * self._temperature))))
232
+ free_energies.append((forward_free_energy - backward_free_energy) / 2)
233
+ errors.append((forward_free_energy + backward_free_energy) / np.sqrt(2))
234
+ return self._windows, free_energies, errors
235
+
236
+ def BAR_free_energy(
237
+ self,
238
+ tolerance: float = 1e-6,
239
+ block_size: int = 20,
240
+ n_bootstrap: int = 20,
241
+ ) -> Tuple[List[Tuple[float, float]], List[NDArray], List[NDArray]]:
242
+ """ Calculate and return the free-energy change using the BAR estimator
243
+
244
+ Args:
245
+ tolerance (float): tolerance of the SCF. Default to 1e-6.
246
+ block_size (int): the size of the block in block bootstrap. Default to 10.
247
+ n_bootstrap (int): number of bootstrap samples. Default to 20.
248
+
249
+ Returns:
250
+ Tuple[List[Tuple[float, float]], List[NDArray], List[NDArray]]: window boundaries, free energies and errors
251
+ """
252
+
253
+ free_energies = []
254
+ errors = []
255
+ for i in range(len(self._windows)):
256
+ dA = self._BAR_estimator(self._deltaU_data[i], tolerance)
257
+ err = self._BAR_error_estimator(self._deltaU_data[i], tolerance, block_size, n_bootstrap)
258
+
259
+ free_energies.append(dA)
260
+ errors.append(err)
261
+ return self._windows, free_energies, errors
262
+
263
+ def _BAR_estimator(self, deltaU: Tuple[NDArray, NDArray], tolerance: float = 1e-6) -> float:
264
+ """ Estimate the free energy of a window using the BAR estimator
265
+
266
+ Args:
267
+ Tuple[NDArray, NDArray]: deltaU data of forward and backward simulations
268
+ tolerance (float): tolerance of the SCF. Default to 1e-6.
269
+
270
+ Returns:
271
+ float: free energy change
272
+ """
273
+
274
+ def fermi(x):
275
+ return 1 / (1 + np.exp(x))
276
+
277
+ beta = 1 / (BOLTZMANN * self._temperature)
278
+ c = 0
279
+ # BAR estimator
280
+ exp_beta_dA = np.mean(fermi(beta * (deltaU[0] - c))) / np.mean(fermi(beta * (deltaU[1] + c)))
281
+ dA = np.log(exp_beta_dA) / (-beta) + c
282
+
283
+ while np.abs(c - dA) > tolerance:
284
+ c = dA
285
+ # BAR estimator
286
+ exp_beta_dA = np.mean(fermi(beta * (deltaU[0] - c))) / np.mean(fermi(beta * (deltaU[1] + c)))
287
+ dA = np.log(exp_beta_dA) / (-beta) + c
288
+
289
+ return dA
290
+
291
+ def _BAR_error_estimator(
292
+ self,
293
+ deltaU: Tuple[NDArray, NDArray],
294
+ tolerance: float = 1e-6,
295
+ block_size: int = 20,
296
+ n_bootstrap: int = 20
297
+ ) -> float:
298
+ """ Estimate the error of the free energy estimate of a window
299
+ using the BAR estimator and block bootstrap method
300
+
301
+ Args:
302
+ Tuple[NDArray, NDArray]: deltaU data of forward and backward simulations
303
+ tolerance (float): tolerance of the SCF. Default to 1e-6.
304
+ block_size (int): the size of the block in block bootstrap. Default to 10.
305
+ n_bootstrap (int): number of bootstrap samples. Default to 20.
306
+
307
+ Returns:
308
+ float: error of the free-energy estimator
309
+ """
310
+
311
+ forward_size = len(deltaU[0])
312
+ backward_size = len(deltaU[1])
313
+ bootstrap_samples = int(np.max((forward_size, backward_size)) / block_size)
314
+
315
+ if bootstrap_samples < 1:
316
+ raise RuntimeError('Error! block_size larger than sample size!')
317
+
318
+ # block bootstrap
319
+ estimates = np.zeros(n_bootstrap)
320
+
321
+ for i in range(n_bootstrap):
322
+ forward_bootstrap = np.zeros(bootstrap_samples * block_size, dtype=int)
323
+ for idx, j in enumerate(np.random.randint(0, forward_size - block_size - 1, bootstrap_samples)):
324
+ forward_bootstrap[idx*block_size:idx*block_size+block_size] = j + np.arange(block_size)
325
+
326
+ backward_bootstrap = np.zeros(bootstrap_samples * block_size, dtype=int)
327
+ for idx, j in enumerate(np.random.randint(0, backward_size - block_size - 1, bootstrap_samples)):
328
+ backward_bootstrap[idx*block_size:idx*block_size+block_size] = j + np.arange(block_size)
329
+
330
+ estimates[i] = self._BAR_estimator(
331
+ (deltaU[0][forward_bootstrap], deltaU[1][backward_bootstrap]),
332
+ tolerance
333
+ )
334
+
335
+ return np.std(estimates)
BFEE2/version.py ADDED
@@ -0,0 +1,2 @@
1
+ __VERSION__ = '2.5.0'
2
+ __NAMD_VERSION__ = '3.0b5'
@@ -0,0 +1,18 @@
1
+ #!python
2
+ ###################################################
3
+ ## binding free energy estimator (BFEE) v2.x
4
+ ## by Haohao Fu (fhh2626_at_gmail.com)
5
+ ##
6
+ ## this is a completely rewritten version of BFEE
7
+ ##
8
+ ###################################################
9
+
10
+ import sys
11
+ from PySide2.QtWidgets import QApplication
12
+ import BFEE2.gui as gui
13
+
14
+ if __name__ == '__main__':
15
+
16
+ app = QApplication(sys.argv)
17
+ ex = gui.mainUI()
18
+ sys.exit(app.exec_())