bfee2 3.1.1.post1__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.
Files changed (68) 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 +2785 -0
  9. BFEE2/inputGenerator.py +2949 -0
  10. BFEE2/postTreatment.py +676 -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 +74 -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 +73 -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 +73 -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 +73 -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 +74 -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 +74 -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 +74 -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 +73 -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 +62 -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 +74 -0
  42. BFEE2/templates_gromacs/008_eq.colvars.template +14 -0
  43. BFEE2/templates_gromacs/008_eq.generate_tpr_sh.template +31 -0
  44. BFEE2/templates_gromacs/BFEEGromacs.py +1268 -0
  45. BFEE2/templates_gromacs/__init__.py +0 -0
  46. BFEE2/templates_gromacs/find_min_max.awk +27 -0
  47. BFEE2/templates_namd/__init__.py +0 -0
  48. BFEE2/templates_namd/configTemplate.py +1152 -0
  49. BFEE2/templates_namd/fep.tcl +299 -0
  50. BFEE2/templates_namd/fep_lddm.tcl +312 -0
  51. BFEE2/templates_namd/scriptTemplate.py +304 -0
  52. BFEE2/templates_namd/solvate.tcl +9 -0
  53. BFEE2/templates_namd/solvate_mem.tcl +9 -0
  54. BFEE2/templates_namd/updateCenters.py +312 -0
  55. BFEE2/templates_readme/Readme_Gromacs_Geometrical.txt +25 -0
  56. BFEE2/templates_readme/Readme_NAMD_Alchemical.txt +20 -0
  57. BFEE2/templates_readme/Readme_NAMD_Geometrical.txt +34 -0
  58. BFEE2/templates_readme/__init__.py +1 -0
  59. BFEE2/templates_readme/rags.py +187 -0
  60. BFEE2/third_party/__init__.py +0 -0
  61. BFEE2/third_party/py_bar.py +585 -0
  62. BFEE2/version.py +4 -0
  63. bfee2-3.1.1.post1.data/scripts/BFEE2Gui.py +19 -0
  64. bfee2-3.1.1.post1.dist-info/METADATA +86 -0
  65. bfee2-3.1.1.post1.dist-info/RECORD +68 -0
  66. bfee2-3.1.1.post1.dist-info/WHEEL +5 -0
  67. bfee2-3.1.1.post1.dist-info/licenses/LICENSE +677 -0
  68. bfee2-3.1.1.post1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,304 @@
1
+ import string
2
+
3
+ removeProteinTemplate = string.Template('''
4
+ mol new ${path}.psf
5
+ mol addfile ${path}.pdb
6
+ set aa [atomselect top "not $selectionPro"]
7
+ $$aa writepsf ${outputPath}.psf
8
+ $$aa writepdb ${outputPath}.pdb
9
+ exit
10
+ ''')
11
+
12
+ removeMemProteinTemplate = string.Template('''
13
+ mol new ${path}.psf
14
+ mol addfile ${path}.pdb
15
+ set aa [atomselect top "$selectionLig"]
16
+ $$aa writepsf ${outputPath}_base.psf
17
+ $$aa writepdb ${outputPath}_base.pdb
18
+ mol delete top
19
+ package require solvate
20
+ solvate ${outputPath}_base.psf ${outputPath}_base.pdb -x 20 -y 20 -z 20 +x 20 +y 20 +z 20 -o ${outputPath} -s WT -b 2.2
21
+ mol delete top
22
+ mol new ${outputPath}.psf
23
+ mol addfile ${outputPath}.pdb
24
+ set aa [atomselect top all]
25
+ $$aa writexyz ${outputPath}.xyz
26
+ exit
27
+ ''')
28
+
29
+ removeMemProteinFepTemplate = string.Template('''
30
+ package require autoionize
31
+ mol new ${path}.psf
32
+ mol addfile ${path}.pdb
33
+ set aa [atomselect top "$selectionLig"]
34
+ $$aa writepsf ${outputPath}_base.psf
35
+ $$aa writepdb ${outputPath}_base.pdb
36
+ mol delete top
37
+ package require solvate
38
+ solvate ${outputPath}_base.psf ${outputPath}_base.pdb -x 20 -y 20 -z 20 +x 20 +y 20 +z 20 -o ${outputPath} -s WT -b 2.2
39
+ mol delete top
40
+ mol new ${outputPath}.psf
41
+ mol addfile ${outputPath}.pdb
42
+ set aa [atomselect top all]
43
+ $$aa writexyz ${outputPath}.xyz
44
+ $$aa set beta 0
45
+ set solute [atomselect top "not water"]
46
+ $$solute set beta 1
47
+ $$aa writepdb ${outputFepPath}.pdb
48
+ exit
49
+ ''')
50
+
51
+ removeProteinAmberTemplate = string.Template('''
52
+ parm ${path}.parm7
53
+ trajin ${path}.pdb
54
+ strip :$residueNum parmout ${outputPath}.parm7
55
+ trajout ${outputPath}.pdb
56
+ go
57
+ ''')
58
+
59
+ neutralizeSystempTemplate = string.Template('''
60
+ package require autoionize
61
+ autoionize -psf ${path}.psf -pdb ${path}.pdb -neutralize -cation ${cationName} -anion ${anionName} -seg IO2 -o ${path}
62
+ mol new ${path}.psf
63
+ mol addfile ${path}.pdb
64
+ set aa [atomselect top all]
65
+ $$aa set beta 0
66
+ set solute [atomselect top "not water and not ion"]
67
+ $$solute set beta 1
68
+ $$aa writexyz ${path}.xyz
69
+ ${extraCommand}
70
+ exit
71
+ ''')
72
+
73
+ def charmmToGromacsTemplate(inputPrefix, forceFieldList):
74
+ return f'''
75
+ import numpy as np
76
+ import parmed, MDAnalysis
77
+ from MDAnalysis import transformations
78
+ def measurePBC(uObject):
79
+ atoms = uObject.select_atoms('all')
80
+ atomPositions = atoms.positions
81
+ xyz_array = np.transpose(atomPositions)
82
+ min_x = np.min(xyz_array[0])
83
+ max_x = np.max(xyz_array[0])
84
+ min_y = np.min(xyz_array[1])
85
+ max_y = np.max(xyz_array[1])
86
+ min_z = np.min(xyz_array[2])
87
+ max_z = np.max(xyz_array[2])
88
+ return [
89
+ np.array([max_x, max_y, max_z]) - np.array([min_x, min_y, min_z]),
90
+ (np.array([min_x, min_y, min_z]) + np.array([max_x, max_y, max_z])) / 2
91
+ ]
92
+ def charmmToGromacs(psfFile, pdbFile, prmFiles, PBC, outputPrefix):
93
+ struct = parmed.load_file(psfFile)
94
+ struct.load_parameters(
95
+ parmed.charmm.CharmmParameterSet(*prmFiles)
96
+ )
97
+ struct.coordinates = parmed.load_file(pdbFile).coordinates
98
+ struct.box = [PBC[0], PBC[1], PBC[2], 90, 90, 90]
99
+ struct.save(f'{{outputPrefix}}.top', format='gromacs')
100
+ struct.save(f'{{outputPrefix}}.gro')
101
+ uObject = MDAnalysis.Universe('{inputPrefix}.psf', '{inputPrefix}.pdb')
102
+ pbcVector = measurePBC(uObject)
103
+ allAtoms = uObject.select_atoms('all')
104
+ transformations.translate((-pbcVector[1] + pbcVector[0] / 2))(allAtoms)
105
+ allAtoms.write('{inputPrefix}.pdb', 'pdb', bonds=None)
106
+ charmmToGromacs(
107
+ '{inputPrefix}.psf',
108
+ '{inputPrefix}.pdb',
109
+ {forceFieldList},
110
+ pbcVector[0],
111
+ '{inputPrefix}_gmx'
112
+ )'''
113
+
114
+ amberToGromacsTemplate = string.Template('''
115
+ import numpy as np
116
+ import parmed, MDAnalysis
117
+ from MDAnalysis import transformations
118
+ def measurePBC(uObject):
119
+ atoms = uObject.select_atoms('all')
120
+ atomPositions = atoms.positions
121
+ xyz_array = np.transpose(atomPositions)
122
+ min_x = np.min(xyz_array[0])
123
+ max_x = np.max(xyz_array[0])
124
+ min_y = np.min(xyz_array[1])
125
+ max_y = np.max(xyz_array[1])
126
+ min_z = np.min(xyz_array[2])
127
+ max_z = np.max(xyz_array[2])
128
+ return [
129
+ np.array([max_x, max_y, max_z]) - np.array([min_x, min_y, min_z]),
130
+ (np.array([min_x, min_y, min_z]) + np.array([max_x, max_y, max_z])) / 2
131
+ ]
132
+ def amberToGromacs(parmFile, rstFile, PBC, outputPrefix):
133
+ struct = parmed.load_file(parmFile, xyz=rstFile)
134
+ struct.coordinates = parmed.load_file(rstFile).coordinates
135
+ struct.box = [PBC[0], PBC[1], PBC[2], 90, 90, 90]
136
+ struct.save(f'{outputPrefix}.top', format='gromacs')
137
+ struct.save(f'{outputPrefix}.gro')
138
+ uObject = MDAnalysis.Universe('${inputPrefix}.parm7', '${inputPrefix}.pdb')
139
+ pbcVector = measurePBC(uObject)
140
+ allAtoms = uObject.select_atoms('all')
141
+ transformations.translate((-pbcVector[1] + pbcVector[0] / 2))(allAtoms)
142
+ allAtoms.write('${inputPrefix}.pdb', 'pdb', bonds=None)
143
+ amberToGromacs(
144
+ '${inputPrefix}.parm7',
145
+ '${inputPrefix}.pdb',
146
+ pbcVector[0],
147
+ '${inputPrefix}_gmx',
148
+ )
149
+ ''')
150
+
151
+ genarateLDDMFilesTemplate = string.Template('''
152
+ import numpy as np
153
+ import os, sys
154
+
155
+ TEMPERATURE = ${temperature}
156
+ WINDOWS = ${windows}
157
+ BOLTZMANN = 0.0019872041
158
+
159
+ def parseDat(filename, temperature=300.0):
160
+ """Parse a dat (histogram) file, return the most probable CV value
161
+ and the corresponding force constant for restraints
162
+
163
+ Args:
164
+ filename (str): the dat file to be parsed with
165
+ temperature (float): the temperature of the simulation
166
+
167
+ Returns:
168
+ Tuple(float, float): the most probable CV value and the force constant
169
+ """
170
+
171
+ data = np.loadtxt(filename)
172
+ CVs = data[:,0]
173
+ counts = data[:,1]
174
+
175
+ beta = 1 / (-BOLTZMANN * temperature)
176
+
177
+ maxCV = -1
178
+ maxCount = -1
179
+ maxIndex = -1
180
+ for index, (i, j) in enumerate(zip(CVs, counts)):
181
+ if j > maxCount:
182
+ maxCV = i
183
+ maxCount = j
184
+ maxIndex = index
185
+
186
+ # fitting
187
+ assert (maxIndex - 2 >=0 and maxIndex + 2 < len(counts)), f"maxIndex is: {maxIndex}, length is: {len(counts)}"
188
+ X = [CVs[maxIndex - 2], CVs[maxIndex], CVs[maxIndex + 2]]
189
+ y = [beta * np.log(counts[maxIndex - 2]), beta * np.log(counts[maxIndex]), beta * np.log(counts[maxIndex + 2])]
190
+
191
+ forceConstant = np.polyfit(X, y, 2)
192
+
193
+ return maxCV, forceConstant[0]
194
+
195
+ def showForceConstant(temperature=300):
196
+ """ Print force constants obtained from histogram.dat files
197
+
198
+ Args:
199
+ temperature (int, optional): _description_. Defaults to 300.
200
+ """
201
+ #print(parseDat("eq.histogram1.dat", temperature))
202
+ print(parseDat("../000_eq/output/eq.histogram2.dat", temperature))
203
+ print(parseDat("../000_eq/output/eq.histogram3.dat", temperature))
204
+ print(parseDat("../000_eq/output/eq.histogram4.dat", temperature))
205
+ print(parseDat("../000_eq/output/eq.histogram5.dat", temperature))
206
+ print(parseDat("../000_eq/output/eq.histogram6.dat", temperature))
207
+ print(parseDat("../000_eq/output/eq.histogram7.dat", temperature))
208
+
209
+ def updateForceConstant(filename, CVs, newForceConstants):
210
+ """ Update force constant of the CVs in a colvars file named filename.
211
+ Generates a new files named filename.tmp.
212
+
213
+ Args:
214
+ filename (str): path to the colvars files
215
+ CVs (list[str]): list of CVs
216
+ newForceConstants (List[float]): new force constants
217
+ """
218
+ # whether parsing a harmonic block
219
+ # either None or the index of the corresponding CV
220
+ inBlock = None
221
+ with open(filename, 'r') as oldColvarsFile:
222
+ # Python cannot modify text file in place
223
+ with open(filename + '.tmp', 'w') as newColvarsFile:
224
+ for line in oldColvarsFile.readlines():
225
+ if line.strip().lower().startswith('colvarstrajfrequency'):
226
+ newColvarsFile.write(f'colvarsTrajFrequency 50\\n')
227
+ continue
228
+
229
+ splitedLine = line.strip().split()
230
+
231
+ if inBlock is None:
232
+ newColvarsFile.write(line)
233
+ else:
234
+ if not line.strip().lower().startswith('forceconstant'):
235
+ newColvarsFile.write(line)
236
+ else:
237
+ # 'colvars' not in CVs
238
+ if inBlock == -1:
239
+ newColvarsFile.write(line)
240
+ else:
241
+ newColvarsFile.write(f' ForceConstant $$afc_{newForceConstants[inBlock]}\\n')
242
+
243
+ if len(splitedLine) > 0:
244
+ if splitedLine[0] == '}':
245
+ inBlock = None
246
+
247
+ if line.strip().lower().startswith('harmonic'):
248
+ inBlock = -1
249
+
250
+ if line.strip().lower().startswith('colvars'):
251
+ for index, CV in enumerate(CVs):
252
+ if splitedLine[1].lower() == CV.lower():
253
+ inBlock = index
254
+
255
+ def updateAllForceConstants(temperature=300):
256
+ """ update all the force constants of the colvars.in file,
257
+ based on histogram.dat files
258
+
259
+ Args:
260
+ temperature (int, optional): temperature. Defaults to 300.
261
+ """
262
+ newForceConstants = []
263
+ newForceConstants.append(parseDat("../000_eq/output/eq.histogram2.dat", temperature)[1])
264
+ newForceConstants.append(parseDat("../000_eq/output/eq.histogram3.dat", temperature)[1])
265
+ newForceConstants.append(parseDat("../000_eq/output/eq.histogram4.dat", temperature)[1])
266
+ newForceConstants.append(parseDat("../000_eq/output/eq.histogram5.dat", temperature)[1])
267
+ newForceConstants.append(parseDat("../000_eq/output/eq.histogram6.dat", temperature)[1])
268
+ newForceConstants.append(parseDat("../000_eq/output/eq.histogram7.dat", temperature)[1])
269
+
270
+ updateForceConstant("./colvars.in",
271
+ ["eulerTheta", "eulerPhi", "eulerPsi", "polarTheta", "polarPhi", "r"],
272
+ newForceConstants)
273
+
274
+ def generateColvarsFiles(template_file, windows, prefix):
275
+
276
+ if os.path.exists(f"./{prefix}"):
277
+ print(f"Error, ./{prefix} exists!")
278
+ sys.exit(1)
279
+
280
+ os.mkdir(prefix)
281
+
282
+ with open(template_file, "r") as inputFile:
283
+ lines = inputFile.readlines()
284
+
285
+ for i in range(windows):
286
+ with open(f"./{prefix}/colvars_{i}.in", "w") as new_colvars_file:
287
+ for j in range(len(lines)):
288
+ splitedLine = lines[j].strip().split()
289
+ if len(splitedLine) < 2 or (not splitedLine[1].startswith("$$afc_")):
290
+ new_colvars_file.write(lines[j])
291
+ else:
292
+ new_colvars_file.write(f" forceConstant {float(splitedLine[1].split('_')[1]) * (float(i) / windows)}\\n")
293
+
294
+ with open(f"./{prefix}/colvars_{windows}.in", "w") as new_colvars_file:
295
+ for j in range(len(lines)):
296
+ splitedLine = lines[j].strip().split()
297
+ if len(splitedLine) < 2 or (not splitedLine[1].startswith("$$afc_")):
298
+ new_colvars_file.write(lines[j])
299
+ else:
300
+ new_colvars_file.write(f" forceConstant {float(splitedLine[1].split('_')[1])}\\n")
301
+
302
+ updateAllForceConstants(TEMPERATURE)
303
+ generateColvarsFiles("colvars.in.tmp", WINDOWS, "colvars_files")
304
+ ''')
@@ -0,0 +1,9 @@
1
+ package require solvate
2
+ solvate ../complex.psf ../complex.pdb -x 12 -y 12 -z 12 +x 12 +y 12 +z 12 -o complex_largeBox -s W2 -b 2.2
3
+ mol addfile complex_largeBox.psf
4
+ mol addfile complex_largeBox.pdb
5
+ set all [atomselect top "all"]
6
+ $all writexyz complex_largeBox.xyz
7
+ $all delete
8
+ mol delete top
9
+ exit
@@ -0,0 +1,9 @@
1
+ package require solvate
2
+ solvate ../complex.psf ../complex.pdb -x 0 -y 0 -z 16 +x 0 +y 0 +z 16 -o complex_largeBox -s W2 -b 2.2
3
+ mol addfile complex_largeBox.psf
4
+ mol addfile complex_largeBox.pdb
5
+ set all [atomselect top "all"]
6
+ $all writexyz complex_largeBox.xyz
7
+ $all delete
8
+ mol delete top
9
+ exit
@@ -0,0 +1,312 @@
1
+ # Read eq.histogramX.dat and update Centers in *.in files
2
+ # This step is optional but may improve the convergence
3
+
4
+ import os, sys, re
5
+ import numpy as np
6
+
7
+ def isGeometric():
8
+ """Check the route of the simulation, True for geometric,
9
+ False for alchemical.
10
+
11
+ Returns:
12
+ bool: the route of the free-energy calculation. True for geometric,
13
+ False for alchemical
14
+ """
15
+
16
+ if os.path.exists('../fep.tcl'):
17
+ return False
18
+ else:
19
+ return True
20
+
21
+
22
+ def parseDat(filename):
23
+ """Parse a dat (histogram) file and return the most probable CV value
24
+
25
+ Args:
26
+ filename (str): the dat file to be parsed with
27
+
28
+ Returns:
29
+ float: the most probable CV value
30
+ """
31
+
32
+ data = np.loadtxt(filename)
33
+ CVs = data[:,0]
34
+ counts = data[:,1]
35
+
36
+ maxCV = -1
37
+ maxCount = -1
38
+ for i, j in zip(CVs, counts):
39
+ if j > maxCount:
40
+ maxCV = i
41
+ maxCount = j
42
+ return maxCV
43
+
44
+ def findOptimalCVs():
45
+ """ read *.dat files generated through equilibration
46
+ and find out the most probable values of CVs
47
+
48
+ Returns:
49
+ list[Float]: the most probable values of RMSD, eulerTheta, eulerPhi, eulerPsi, polarTheta, polarPhi, r
50
+ """
51
+
52
+ optimalCVs = []
53
+ files = [
54
+ 'output/eq.histogram1.dat',
55
+ 'output/eq.histogram2.dat',
56
+ 'output/eq.histogram3.dat',
57
+ 'output/eq.histogram4.dat',
58
+ 'output/eq.histogram5.dat',
59
+ 'output/eq.histogram6.dat',
60
+ 'output/eq.histogram7.dat'
61
+ ]
62
+
63
+ for file in files:
64
+ optimalCVs.append(parseDat(file))
65
+
66
+ return optimalCVs
67
+
68
+ def readCenters(filename, CVs):
69
+ """ find the value of centers of provided CVs in a *.in file
70
+
71
+ Args:
72
+ filename (str): a Colvars config file
73
+ CVs (List[str]): a list, showing the CVs whose centers are to be get
74
+
75
+ Returns:
76
+ List[float]: centers of the provided CVs
77
+ """
78
+
79
+ # whether parsing a harmonic block
80
+ # either None or the index of the corresponding CV
81
+ inBlock = None
82
+
83
+ # the CV values
84
+ CVValues = [0 for i in range(len(CVs))]
85
+
86
+ with open(filename, 'r') as colvarsFile:
87
+ for line in colvarsFile.readlines():
88
+ splitedLine = line.strip().split()
89
+
90
+ if inBlock is not None:
91
+ if line.strip().lower().startswith('centers'):
92
+ if inBlock != -1:
93
+ CVValues[inBlock] = float(splitedLine[1])
94
+
95
+ if splitedLine[0] == '}':
96
+ inBlock = None
97
+
98
+ if line.strip().lower().startswith('harmonic'):
99
+ inBlock = -1
100
+
101
+ if line.strip().lower().startswith('colvars'):
102
+ for index, CV in enumerate(CVs):
103
+ if splitedLine[1].lower() == CV.lower():
104
+ inBlock = index
105
+
106
+ return CVValues
107
+
108
+ def changeCenters(filename, CVs, newCenters):
109
+ """ change Centers of harmonic restraints in a *.in file
110
+
111
+ Args:
112
+ filename (str): a Colvars config file
113
+ CVs (List[str]): a list, showing the Centers of which harmonic blocks are to be replaced
114
+ newCenters (List[float]): a list, containing the new values of Centers
115
+ """
116
+
117
+ # whether parsing a harmonic block
118
+ # either None or the index of the corresponding CV
119
+ inBlock = None
120
+ with open(filename, 'r') as oldColvarsFile:
121
+ # Python cannot modify text file in place
122
+ with open(filename + '.tmp', 'w') as newColvarsFile:
123
+ for line in oldColvarsFile.readlines():
124
+ splitedLine = line.strip().split()
125
+
126
+ if inBlock is None:
127
+ newColvarsFile.write(line)
128
+ else:
129
+ if not line.strip().lower().startswith('centers'):
130
+ newColvarsFile.write(line)
131
+ else:
132
+ # 'colvars' not in CVs
133
+ if inBlock == -1:
134
+ newColvarsFile.write(line)
135
+ else:
136
+ newColvarsFile.write(f' Centers {newCenters[inBlock]}\n')
137
+
138
+ if len(splitedLine) > 0:
139
+ if splitedLine[0] == '}':
140
+ inBlock = None
141
+
142
+ if line.strip().lower().startswith('harmonic'):
143
+ inBlock = -1
144
+
145
+ if line.strip().lower().startswith('colvars'):
146
+ for index, CV in enumerate(CVs):
147
+ if splitedLine[1].lower() == CV.lower():
148
+ inBlock = index
149
+
150
+ os.remove(filename)
151
+ os.rename(filename + '.tmp', filename)
152
+
153
+ def changeABFRange(filename, CVs, newCenters, originalCenters):
154
+ """ change lowerboundary, upperboundary, lowerWalls, upperWalls of ABF in a *.in file
155
+
156
+ Args:
157
+ filename (str): a Colvars config file
158
+ CVs (List[str]): a list, showing the corresponding options of which CV blocks are to be replaced
159
+ newCenters (List[float]): a list, containing the new values of Centers of these CVs
160
+ originalCenters (List[float]): a list, containing the original values of Centers of these CVs
161
+ """
162
+
163
+ # whether parsing a harmonic block
164
+ # either None or the index of the corresponding CV
165
+ inBlock = None
166
+ with open(filename, 'r') as oldColvarsFile:
167
+ # Python cannot modify text file in place
168
+ with open(filename + '.tmp', 'w') as newColvarsFile:
169
+ for line in oldColvarsFile.readlines():
170
+ splitedLine = line.strip().split()
171
+
172
+ if inBlock is None:
173
+ newColvarsFile.write(line)
174
+ else:
175
+ if (not line.strip().lower().startswith('lowerboundary')) and \
176
+ (not line.strip().lower().startswith('upperboundary')) and \
177
+ (not line.strip().lower().startswith('lowerwalls')) and \
178
+ (not line.strip().lower().startswith('upperwalls')):
179
+ newColvarsFile.write(line)
180
+ else:
181
+ # 'name' not in CVs
182
+ if inBlock == -1:
183
+ newColvarsFile.write(line)
184
+ else:
185
+ if line.strip().lower().startswith('lowerboundary'):
186
+ newColvarsFile.write(
187
+ f' Lowerboundary {float(splitedLine[1]) + newCenters[inBlock] - originalCenters[inBlock]}\n'
188
+ )
189
+ elif line.strip().lower().startswith('upperboundary'):
190
+ newColvarsFile.write(
191
+ f' Upperboundary {float(splitedLine[1]) + newCenters[inBlock] - originalCenters[inBlock]}\n'
192
+ )
193
+ elif line.strip().lower().startswith('lowerwalls'):
194
+ newColvarsFile.write(
195
+ f' LowerWalls {float(splitedLine[1]) + newCenters[inBlock] - originalCenters[inBlock]}\n'
196
+ )
197
+ elif line.strip().lower().startswith('upperwalls'):
198
+ newColvarsFile.write(
199
+ f' UpperWalls {float(splitedLine[1]) + newCenters[inBlock] - originalCenters[inBlock]}\n'
200
+ )
201
+ else:
202
+ print("Selected CV(s) not for free-energy calculation!")
203
+
204
+ if len(splitedLine) > 0:
205
+ if splitedLine[0] == '}':
206
+ inBlock = None
207
+
208
+ if len(splitedLine) > 0:
209
+ if splitedLine[0].lower() == 'colvar' or line.strip().lower().startswith('harmonicwalls'):
210
+ inBlock = -1
211
+
212
+ if line.strip().lower().startswith('name') or splitedLine[0].lower() == 'colvars':
213
+ for index, CV in enumerate(CVs):
214
+ if splitedLine[1].lower() == CV.lower():
215
+ inBlock = index
216
+
217
+ os.remove(filename)
218
+ os.rename(filename + '.tmp', filename)
219
+
220
+ def updateAlchemicalFiles():
221
+ """Update the Centers of *.in files based on equilibration
222
+ """
223
+
224
+ files = [
225
+ './colvars2.in',
226
+ '../001_MoleculeBound/colvars.in',
227
+ '../002_RestraintBound/colvars_forward.in',
228
+ '../002_RestraintBound/colvars_backward.in'
229
+ ]
230
+
231
+ for file in files:
232
+ if not os.path.exists(file):
233
+ print(f'File {file} does not exist!')
234
+ continue
235
+ changeCenters(
236
+ file,
237
+ [
238
+ 'eulerTheta', 'eulerPhi', 'eulerPsi', 'polarTheta', 'polarPhi', 'r'
239
+ ],
240
+ findOptimalCVs()[1:]
241
+ )
242
+ print(f'File {file} updated!')
243
+
244
+ # if re-eqilibrated
245
+ if os.path.exists('./000.1_eq2_re-eq.conf'):
246
+ confFiles = [
247
+ '../001_MoleculeBound/001.1_fep_backward.conf',
248
+ '../001_MoleculeBound/001_fep_doubleWide.conf',
249
+ '../001_MoleculeBound/001_lambdaABF.conf',
250
+ '../002_RestraintBound/002.1_ti_backward.conf',
251
+ ]
252
+ for confFile in confFiles:
253
+ if not os.path.exists(confFile):
254
+ print(f'File {confFile} does not exist!')
255
+ continue
256
+ with open(confFile,'r') as readFile:
257
+ data=readFile.read()
258
+ data = re.sub('../000_eq/output/eq.coor', '../000_eq/output/eq2.coor', data)
259
+ data = re.sub('../000_eq/output/eq.vel', '../000_eq/output/eq2.vel', data)
260
+ data = re.sub('../000_eq/output/eq.xsc', '../000_eq/output/eq2.xsc', data)
261
+ with open(confFile,'w') as writeFile:
262
+ writeFile.write(data)
263
+ print(f'File {confFile} updated!')
264
+
265
+ def updateGeometricFiles():
266
+ """Update the Centers of *.in files based on equilibration
267
+ """
268
+
269
+ CVNames = ['eulerTheta', 'eulerPhi', 'eulerPsi', 'polarTheta', 'polarPhi']
270
+ optimalCVValues = findOptimalCVs()[1:6]
271
+ originalCVValues = readCenters('../007_r/colvars_eq.in', CVNames)
272
+
273
+ # in geometrical route, there may be many windows
274
+ folders = [
275
+ '../002_EulerTheta',
276
+ '../003_EulerPhi',
277
+ '../004_EulerPsi',
278
+ '../005_PolarTheta',
279
+ '../006_PolarPhi',
280
+ '../007_r'
281
+ ]
282
+
283
+ for fIndex, folder in enumerate(folders):
284
+ # *.in in folder
285
+ files = []
286
+ for file in os.listdir(folder):
287
+ if file.endswith('.in') or file.endswith('.in.amd'):
288
+ files.append(os.path.join(folder, file))
289
+
290
+ for inFile in files:
291
+ changeCenters(
292
+ inFile,
293
+ CVNames[:fIndex],
294
+ optimalCVValues[:fIndex]
295
+ )
296
+
297
+ changeABFRange(
298
+ inFile,
299
+ CVNames[:fIndex+1],
300
+ optimalCVValues[:fIndex+1],
301
+ originalCVValues[:fIndex+1]
302
+ )
303
+ print(f'File {inFile} updated!')
304
+
305
+ if __name__ == '__main__':
306
+
307
+ if isGeometric():
308
+ updateGeometricFiles()
309
+ print('All the *.in files updated for the Geometrical route!')
310
+ else:
311
+ updateAlchemicalFiles()
312
+ print('All the *.in files updated for the Alchemical route!')
@@ -0,0 +1,25 @@
1
+ To calculate the binding free energy:
2
+
3
+ 1.1. run 000_eq/000_generate_tpr.sh
4
+ 1.2. run 000_eq/000_eq.tpr
5
+ 2.1. run 001_RMSD_bound/001_generate_tpr.sh
6
+ 2.2. run 001_RMSD_bound/001_RMSD_bound.tpr
7
+ 3.1. run 002_euler_theta/002_generate_tpr.sh
8
+ 3.2. run 002_euler_theta/002_euler_theta.tpr
9
+ 4.1. run 003_euler_phi/003_generate_tpr.sh
10
+ 4.2. run 003_euler_phi/003_euler_phi.tpr
11
+ 5.1. run 004_euler_psi/004_generate_tpr.sh
12
+ 5.2. run 004_euler_psi/004_euler_psi.tpr
13
+ 6.1. run 005_polar_theta/005_generate_tpr.sh
14
+ 6.2. run 005_polar_theta/005_polar_theta.tpr
15
+ 7.1. run 006_polar_phi/006_generate_tpr.sh
16
+ 7.2. run 006_polar_phi/006_polar_phi.tpr
17
+ 8.1. run 007_r/007.1_generate_eq_tpr.sh
18
+ 8.2. run 007_r/007_r.eq.tpr
19
+ 8.3. run 007_r/007.2_generate_tpr.sh
20
+ 8.4 run 007_r/007_r.tpr
21
+ 9.1. run 008_RMSD_unbound/008.1_generate_eq_tpr.sh
22
+ 9.2. run 008_RMSD_unbound/008_RMSD_unbound.eq.tpr
23
+ 9.3. run 008_RMSD_unbound/008.2_generate_tpr.sh
24
+ 9.4. run 008_RMSD_unbound/008_RMSD_unbound.tpr
25
+ 10. do post-treatment using BFEE
@@ -0,0 +1,20 @@
1
+ To calculate the binding free energy:
2
+
3
+ 1.1. run 000_eq/000.1_eq.conf
4
+ 1.2. (optionally) run 000_eq/000.3_updateCenters.py
5
+ 2.1. run 001_MoleculeBound/001.1_fep_backward.conf
6
+ 2.2. run 001_MoleculeBound/001.2_fep_forward.conf
7
+ 3.1. run 002_RestraintBound/002.1_ti_backward.conf
8
+ 3.2. run 002_RestraintBound/002.2_ti_forward.conf
9
+ 4.1. CHARMM user:
10
+ (if you didn't link BFEE with VMD before generating inputs)
11
+ run 002.3_removeProtein.tcl using VMD
12
+ Amber user:
13
+ run 002.3_removeProtein.cpptraj using cpptraj
14
+ 4.2 run 000_eq/000.2_eq_ligandOnly.conf
15
+ 4.3. run 003_MoleculeUnbound/003.1_fep_backward.conf
16
+ 4.4. run 003_MoleculeUnbound/003.2_fep_forward.conf
17
+ 5.1. run 004_RestraintUnbound/004.1_ti_backward.conf
18
+ 5.2. run 004_RestraintUnbound/004.2_ti_forward.conf
19
+ (steps 2-5 can be done in parallel)
20
+ 6. do post-treatment using BFEE