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.
- 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 +2785 -0
- BFEE2/inputGenerator.py +2949 -0
- BFEE2/postTreatment.py +676 -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 +74 -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 +73 -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 +73 -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 +73 -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 +74 -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 +74 -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 +74 -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 +73 -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 +62 -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 +74 -0
- BFEE2/templates_gromacs/008_eq.colvars.template +14 -0
- BFEE2/templates_gromacs/008_eq.generate_tpr_sh.template +31 -0
- BFEE2/templates_gromacs/BFEEGromacs.py +1268 -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 +1152 -0
- BFEE2/templates_namd/fep.tcl +299 -0
- BFEE2/templates_namd/fep_lddm.tcl +312 -0
- BFEE2/templates_namd/scriptTemplate.py +304 -0
- BFEE2/templates_namd/solvate.tcl +9 -0
- BFEE2/templates_namd/solvate_mem.tcl +9 -0
- BFEE2/templates_namd/updateCenters.py +312 -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/templates_readme/rags.py +187 -0
- BFEE2/third_party/__init__.py +0 -0
- BFEE2/third_party/py_bar.py +585 -0
- BFEE2/version.py +4 -0
- bfee2-3.1.1.post1.data/scripts/BFEE2Gui.py +19 -0
- bfee2-3.1.1.post1.dist-info/METADATA +86 -0
- bfee2-3.1.1.post1.dist-info/RECORD +68 -0
- bfee2-3.1.1.post1.dist-info/WHEEL +5 -0
- bfee2-3.1.1.post1.dist-info/licenses/LICENSE +677 -0
- 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
|