bfee2 2.5.0__py3-none-any.whl → 3.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of bfee2 might be problematic. Click here for more details.
- BFEE2/commonTools/commonSlots.py +1 -1
- BFEE2/gui.py +326 -12
- BFEE2/inputGenerator.py +236 -201
- BFEE2/postTreatment.py +156 -0
- BFEE2/templates_namd/configTemplate.py +10 -6
- BFEE2/templates_namd/fep_lddm.tcl +312 -0
- BFEE2/templates_namd/scriptTemplate.py +155 -0
- BFEE2/third_party/py_bar.py +251 -1
- BFEE2/version.py +2 -2
- {bfee2-2.5.0.data → bfee2-3.0.0.data}/scripts/BFEE2Gui.py +19 -18
- {bfee2-2.5.0.dist-info → bfee2-3.0.0.dist-info}/METADATA +84 -76
- {bfee2-2.5.0.dist-info → bfee2-3.0.0.dist-info}/RECORD +15 -14
- {bfee2-2.5.0.dist-info → bfee2-3.0.0.dist-info}/WHEEL +1 -1
- {bfee2-2.5.0.dist-info → bfee2-3.0.0.dist-info/licenses}/LICENSE +0 -0
- {bfee2-2.5.0.dist-info → bfee2-3.0.0.dist-info}/top_level.txt +0 -0
BFEE2/postTreatment.py
CHANGED
|
@@ -500,3 +500,159 @@ class postTreatment:
|
|
|
500
500
|
errors[5] = math.sqrt(errors[0]**2 + errors[1]**2 +errors[2]**2 + errors[3]**2 + errors[4]**2)
|
|
501
501
|
|
|
502
502
|
return contributions, errors
|
|
503
|
+
|
|
504
|
+
def _LDDMReadColvarsTmp(self, file_path):
|
|
505
|
+
""" Read an Colvars Tmp file in binding free energy calculations,
|
|
506
|
+
get the force constants and centers constants of restraints for LDDM
|
|
507
|
+
|
|
508
|
+
Args:
|
|
509
|
+
file_path (str): path to the Colvars.tmp file
|
|
510
|
+
|
|
511
|
+
Returns:
|
|
512
|
+
Tuple[List, List]: lists of force constants and centers
|
|
513
|
+
"""
|
|
514
|
+
|
|
515
|
+
force_constants = []
|
|
516
|
+
centers = []
|
|
517
|
+
|
|
518
|
+
with open(file_path, 'r') as colvars_tmp_file:
|
|
519
|
+
center_line = False
|
|
520
|
+
for line in colvars_tmp_file.readlines():
|
|
521
|
+
splited_line = line.strip().split()
|
|
522
|
+
|
|
523
|
+
if len(splited_line) < 2:
|
|
524
|
+
center_line = False
|
|
525
|
+
continue
|
|
526
|
+
|
|
527
|
+
if splited_line[1].startswith('$afc_'):
|
|
528
|
+
force_constants.append(float(splited_line[1].replace('$afc_', '')))
|
|
529
|
+
center_line = True
|
|
530
|
+
continue
|
|
531
|
+
|
|
532
|
+
if center_line:
|
|
533
|
+
centers.append(float(splited_line[1]))
|
|
534
|
+
|
|
535
|
+
continue
|
|
536
|
+
|
|
537
|
+
return force_constants, centers
|
|
538
|
+
|
|
539
|
+
def _LDDMBoundStateFreeEnergy(
|
|
540
|
+
self,
|
|
541
|
+
colvars_tmp_path,
|
|
542
|
+
cvtrj_path,
|
|
543
|
+
fepout_path,
|
|
544
|
+
steps_per_window,
|
|
545
|
+
equilbration_steps_per_window,
|
|
546
|
+
num_windows,
|
|
547
|
+
temperature = 300,
|
|
548
|
+
jobtype = 'fep'
|
|
549
|
+
):
|
|
550
|
+
""" Calculate bound state free-energy contribution and error
|
|
551
|
+
|
|
552
|
+
Args:
|
|
553
|
+
colvars_tmp_path (str): path to colvars tmp file
|
|
554
|
+
cvtrj_path (str): path to colvars.traj file
|
|
555
|
+
fepout_path (str): path to fepout file
|
|
556
|
+
steps_per_window (int): steps per FEP window
|
|
557
|
+
equilbration_steps_per_window (int): equilibration steps per FEP window
|
|
558
|
+
num_windows (int): number of windows
|
|
559
|
+
temperature (float): temperature of the simulation, defaults to 300
|
|
560
|
+
jobType (str, optional): Type of the post-treatment method. 'fep' or 'bar'.
|
|
561
|
+
Defaults to 'fep'.
|
|
562
|
+
|
|
563
|
+
Returns:
|
|
564
|
+
Tuple[float, float, float]: free-energy contribution of decoupling the molecule,
|
|
565
|
+
error, and contribution of the restraints
|
|
566
|
+
"""
|
|
567
|
+
force_contants, centers = self._LDDMReadColvarsTmp(colvars_tmp_path)
|
|
568
|
+
colvars_parser = py_bar.ColvarsParser(cvtrj_path, steps_per_window, equilbration_steps_per_window,
|
|
569
|
+
force_contants, centers,
|
|
570
|
+
np.linspace(0, 1, num_windows))
|
|
571
|
+
window, deltaU = colvars_parser.get_data()
|
|
572
|
+
b = py_bar.FEPAnalyzer(window, deltaU, temperature)
|
|
573
|
+
|
|
574
|
+
window2, deltaU2 = py_bar.NAMDParser(fepout_path).get_data()
|
|
575
|
+
success = b.MergeData(window2, deltaU2)
|
|
576
|
+
if not success:
|
|
577
|
+
raise RuntimeError('Failed in merging fepout and colvars.traj! Probably wrong number of windows or crupted simulations!')
|
|
578
|
+
|
|
579
|
+
if jobtype == 'fep':
|
|
580
|
+
result = b.FEP_free_energy()
|
|
581
|
+
else:
|
|
582
|
+
result = b.BAR_free_energy(block_size=50, n_bootstrap=20)
|
|
583
|
+
|
|
584
|
+
#windows = b.Window_boundaries()
|
|
585
|
+
#with open(fepout_path + ".convergence.data", "w") as convergence_file:
|
|
586
|
+
# convergence_file.write(f" lambda dA stdev_A \n")
|
|
587
|
+
# for window, dA, stdA in zip(windows, result[1], resul[2]):
|
|
588
|
+
# convergence_file.write(f" {window} {dA:.4f} {stdA:.4f} \n")
|
|
589
|
+
|
|
590
|
+
return -np.sum(result[1]), np.sqrt(np.sum(np.power(result[2], 2))), colvars_parser.get_restraint_contribution()
|
|
591
|
+
|
|
592
|
+
def _LDDMFreeStateFreeEnergy(self, fepout_path, temperature = 300, jobtype = 'fep'):
|
|
593
|
+
""" Calculate free state free-energy contribution and error
|
|
594
|
+
|
|
595
|
+
Args:
|
|
596
|
+
fepout_path (str): path to fepout file
|
|
597
|
+
temperature (float, optional): temperature of the simulation. Defaults to 300.
|
|
598
|
+
jobType (str, optional): Type of the post-treatment method. 'fep' or 'bar'.
|
|
599
|
+
Defaults to 'fep'.
|
|
600
|
+
|
|
601
|
+
Returns:
|
|
602
|
+
Tuple[float, float]: free-energy contribution and the error of decoupling the molecule
|
|
603
|
+
"""
|
|
604
|
+
window, deltaU = py_bar.NAMDParser(fepout_path).get_data()
|
|
605
|
+
b = py_bar.FEPAnalyzer(window, deltaU, temperature)
|
|
606
|
+
|
|
607
|
+
if jobtype == 'fep':
|
|
608
|
+
result = b.FEP_free_energy()
|
|
609
|
+
else:
|
|
610
|
+
result = b.BAR_free_energy(block_size=50, n_bootstrap=20)
|
|
611
|
+
|
|
612
|
+
# convergence file
|
|
613
|
+
#windows = b.Window_boundaries()
|
|
614
|
+
#with open(fepout_path + "convergence.data", "w") as convergence_file:
|
|
615
|
+
# convergence_file.write(f" lambda dA stdev_A \n")
|
|
616
|
+
# for window, dA, stdA in zip(windows, result_fep[1], result_fep[2]):
|
|
617
|
+
# convergence_file.write(f" {window} {dA:.4f} {stdA:.4f} \n")
|
|
618
|
+
|
|
619
|
+
return np.sum(result[1]), np.sqrt(np.sum(np.power(result[2], 2)))
|
|
620
|
+
|
|
621
|
+
def LDDMBindingFreeEnergy(
|
|
622
|
+
self,
|
|
623
|
+
colvars_tmp_path,
|
|
624
|
+
cvtrj_path,
|
|
625
|
+
step1_fepout_path,
|
|
626
|
+
steps_per_window,
|
|
627
|
+
equilbration_steps_per_window,
|
|
628
|
+
num_windows,
|
|
629
|
+
step3_fepout_path,
|
|
630
|
+
temperature = 300,
|
|
631
|
+
jobType = 'fep'):
|
|
632
|
+
"""calculate binding free energy for LDDM
|
|
633
|
+
|
|
634
|
+
Args:
|
|
635
|
+
colvars_tmp_path (str): path to colvars tmp file of step 1
|
|
636
|
+
cvtrj_path (str): path to colvars.traj file of step 1
|
|
637
|
+
step1_fepout_path (str): path to fepout file of step 1
|
|
638
|
+
steps_per_window (int): steps per FEP window of step 1
|
|
639
|
+
equilbration_steps_per_window (int): equilibration steps per FEP window of step 1
|
|
640
|
+
num_windows (int): number of windows of step 1
|
|
641
|
+
step3_fepout_path (str): path to fepout file of step 3
|
|
642
|
+
temperature (float): temperature of the simulation, defaults to 300
|
|
643
|
+
jobType (str, optional): Type of the post-treatment method. 'fep' or 'bar'.
|
|
644
|
+
Defaults to 'fep'.
|
|
645
|
+
|
|
646
|
+
Returns:
|
|
647
|
+
tuple:
|
|
648
|
+
np.array, float, 2: (contributions for step1, and step 3)
|
|
649
|
+
np.array, float, 2: errors corresponding each contribution
|
|
650
|
+
"""
|
|
651
|
+
|
|
652
|
+
step1_dG, step1_error, step3_dG_restraint = self._LDDMBoundStateFreeEnergy(
|
|
653
|
+
colvars_tmp_path, cvtrj_path, step1_fepout_path, steps_per_window, equilbration_steps_per_window,
|
|
654
|
+
num_windows, temperature, jobType
|
|
655
|
+
)
|
|
656
|
+
step3_dG_molecule, step3_error = self._LDDMFreeStateFreeEnergy(step3_fepout_path, temperature, jobType)
|
|
657
|
+
|
|
658
|
+
return np.array([step1_dG, step1_error]), np.array([step3_dG_molecule + step3_dG_restraint, step3_error])
|
|
@@ -37,7 +37,8 @@ class configTemplate:
|
|
|
37
37
|
OPLSMixingRule = False,
|
|
38
38
|
GaWTM = False,
|
|
39
39
|
CUDASOAIntegrator = False,
|
|
40
|
-
timestep = 2.0
|
|
40
|
+
timestep = 2.0,
|
|
41
|
+
LDDMStep1 = False
|
|
41
42
|
):
|
|
42
43
|
"""the namd config file template
|
|
43
44
|
|
|
@@ -68,6 +69,7 @@ class configTemplate:
|
|
|
68
69
|
GaWTM (bool, optional): Whether this is an GaWTM-eABF simulation. Default to False
|
|
69
70
|
CUDASOAIntegrator (bool, optional): Whether CUDASOA integrator is used. Default to False
|
|
70
71
|
timestep (float, optional): timestep of the simulation. Default to 2.0
|
|
72
|
+
LDDMStep1 (bool, optional): whether this is the 1st step of a LDDM simulation. Default to False.
|
|
71
73
|
|
|
72
74
|
Returns:
|
|
73
75
|
str: a NAMD config string if succeed, and empty string otherwise
|
|
@@ -259,8 +261,13 @@ run norepeat {numSteps} \n'
|
|
|
259
261
|
else:
|
|
260
262
|
# currently the alchemical route is somewhat hard-coded
|
|
261
263
|
# this will be improved in the future
|
|
264
|
+
if LDDMStep1:
|
|
265
|
+
configString += f'\
|
|
266
|
+
source ./fep_lddm.tcl \n'
|
|
267
|
+
else:
|
|
268
|
+
configString += f'\
|
|
269
|
+
source ../fep.tcl \n'
|
|
262
270
|
configString += f'\
|
|
263
|
-
source ../fep.tcl \n\
|
|
264
271
|
alch on \n\
|
|
265
272
|
alchType FEP \n\
|
|
266
273
|
alchFile {fepFile} \n\
|
|
@@ -269,6 +276,7 @@ alchOutFile {outputPrefix}.fepout \n\
|
|
|
269
276
|
alchOutFreq 50 \n\
|
|
270
277
|
alchVdwLambdaEnd 0.7 \n\
|
|
271
278
|
alchElecLambdaStart 0.5 \n\
|
|
279
|
+
alchDecouple on \n\
|
|
272
280
|
alchEquilSteps 100000 \n'
|
|
273
281
|
|
|
274
282
|
if fepForward:
|
|
@@ -566,7 +574,6 @@ colvar {{ \n\
|
|
|
566
574
|
indexGroup ligand \n\
|
|
567
575
|
centerReference on \n\
|
|
568
576
|
rotateReference on \n\
|
|
569
|
-
enableFitGradients no \n\
|
|
570
577
|
fittingGroup {{ \n\
|
|
571
578
|
indexGroup protein \n\
|
|
572
579
|
}} \n\
|
|
@@ -637,7 +644,6 @@ colvar {{ \n\
|
|
|
637
644
|
indexGroup reference \n\
|
|
638
645
|
centerReference on \n\
|
|
639
646
|
rotateReference on \n\
|
|
640
|
-
enableFitGradients no \n\
|
|
641
647
|
fittingGroup {{ \n\
|
|
642
648
|
indexGroup protein \n\
|
|
643
649
|
}} \n\
|
|
@@ -647,7 +653,6 @@ colvar {{ \n\
|
|
|
647
653
|
indexGroup ligand \n\
|
|
648
654
|
centerReference on \n\
|
|
649
655
|
rotateReference on \n\
|
|
650
|
-
enableFitGradients no \n\
|
|
651
656
|
fittingGroup {{ \n\
|
|
652
657
|
indexGroup protein \n\
|
|
653
658
|
}} \n\
|
|
@@ -707,7 +712,6 @@ colvar {{ \n\
|
|
|
707
712
|
centerReference on \n\
|
|
708
713
|
rotateReference on \n\
|
|
709
714
|
centerToOrigin on \n\
|
|
710
|
-
enableFitGradients on \n\
|
|
711
715
|
fittingGroup {{ \n\
|
|
712
716
|
indexGroup protein \n\
|
|
713
717
|
}} \n\
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
##############################################################
|
|
2
|
+
# LDDM variant FEP SCRIPT
|
|
3
|
+
# Haohao Fu <fhh2626@gmail.com>
|
|
4
|
+
# Jerome Henin <henin@ibpc.fr>
|
|
5
|
+
#
|
|
6
|
+
# Important: This version should only be used for the LDDM strategy!
|
|
7
|
+
# Use the NAMD version of fep.tcl for other simulations.
|
|
8
|
+
#
|
|
9
|
+
# Changes:
|
|
10
|
+
# 2020-05-03: added prev_lambda option to runFEP, improved doc
|
|
11
|
+
# 2018-04-18: added interleaved double-wide sampling (IDWS)
|
|
12
|
+
# 2010-04-24: added runFEPmin
|
|
13
|
+
# 2009-11-17: changed for NAMD 2.7 keywords
|
|
14
|
+
# 2008-06-25: added TI routines
|
|
15
|
+
# 2007-11-01: fixed runFEP to handle backwards transformations
|
|
16
|
+
# (i.e. dLambda < 0)
|
|
17
|
+
# 2024-11-04: support LDDM version of runFEP
|
|
18
|
+
##############################################################
|
|
19
|
+
|
|
20
|
+
##############################################################
|
|
21
|
+
## Example NAMD input: calculation with smaller windows at
|
|
22
|
+
## the ends
|
|
23
|
+
#
|
|
24
|
+
# source fep.tcl
|
|
25
|
+
#
|
|
26
|
+
# alch on
|
|
27
|
+
# alchFile system.fep
|
|
28
|
+
# alchCol B
|
|
29
|
+
# alchOutFreq 10
|
|
30
|
+
# alchOutFile system.fepout
|
|
31
|
+
# alchEquilSteps 500
|
|
32
|
+
#
|
|
33
|
+
# set nSteps 5000
|
|
34
|
+
#
|
|
35
|
+
## A) Simple schedule: 20 windows from 0 to 1, in a single run
|
|
36
|
+
#
|
|
37
|
+
# runFEP 0.0 1.0 0.05 $nSteps
|
|
38
|
+
#
|
|
39
|
+
## B) Same thing, in two NAMD separate runs with a restart
|
|
40
|
+
#
|
|
41
|
+
## First run
|
|
42
|
+
# runFEP 0.0 0.5 0.05 $nSteps
|
|
43
|
+
#
|
|
44
|
+
## Restart
|
|
45
|
+
# runFEP 0.5 1.0 0.05 $nSteps
|
|
46
|
+
#
|
|
47
|
+
## C) Lambda schedule with narrower windows at the end points
|
|
48
|
+
## Using two explicit lists of lambda points
|
|
49
|
+
#
|
|
50
|
+
# set init {0.0 0.05 0.1}
|
|
51
|
+
# set end {0.9 0.95 1.0}
|
|
52
|
+
#
|
|
53
|
+
# runFEPlist $init $nSteps
|
|
54
|
+
# runFEP 0.1 0.9 0.1 $nSteps
|
|
55
|
+
# runFEPlist $end $nSteps
|
|
56
|
+
#
|
|
57
|
+
## Alternately, in one step:
|
|
58
|
+
#
|
|
59
|
+
# runFEPlist [concat $init [FEPlist 0.1 0.9 0.1] $end] $nSteps
|
|
60
|
+
#
|
|
61
|
+
##############################################################
|
|
62
|
+
|
|
63
|
+
##############################################################
|
|
64
|
+
## Special usage for Interleaved Double-Wide sampling
|
|
65
|
+
## A) Simple schedule: 20 windows from 0 to 1, in a single run
|
|
66
|
+
#
|
|
67
|
+
# runFEP 0.0 1.0 0.05 $nSteps true
|
|
68
|
+
#
|
|
69
|
+
## B) Same thing, in two NAMD separate runs with a restart
|
|
70
|
+
#
|
|
71
|
+
## First run
|
|
72
|
+
# runFEP 0.0 0.5 0.05 $nSteps true
|
|
73
|
+
#
|
|
74
|
+
## Restart - need to tell the script the previous lambda point: 0.45
|
|
75
|
+
# runFEP 0.5 1.0 0.05 $nSteps true 0.45
|
|
76
|
+
#
|
|
77
|
+
## C) Example of a piecewise calculation with restarts
|
|
78
|
+
# and a nonlinear lambda schedule
|
|
79
|
+
#
|
|
80
|
+
## Run individual points 0, 0.05 then the series from 0.1 to 0.5
|
|
81
|
+
#
|
|
82
|
+
# runFEPlist [concat {0. 0.05} [FEPlist 0.1 0.5 0.1]] $numSteps true
|
|
83
|
+
#
|
|
84
|
+
## Continue series from 0.5 to 0.9, sampling backward dE from 0.4
|
|
85
|
+
#
|
|
86
|
+
# runFEPlist [FEPlist 0.5 0.9 0.1] $numSteps true 0.4
|
|
87
|
+
#
|
|
88
|
+
## Add two values 0.95 and 1, sampling backward dE from 0.9
|
|
89
|
+
## (automatically adds final backward window from 1. to 0.95)
|
|
90
|
+
#
|
|
91
|
+
# runFEPlist {0.95 1.} $numSteps true 0.9
|
|
92
|
+
#
|
|
93
|
+
##############################################################
|
|
94
|
+
|
|
95
|
+
##############################################################
|
|
96
|
+
# proc runFEPlist { lambdaList nSteps {IDWS} {prev_lambda} }
|
|
97
|
+
#
|
|
98
|
+
# Run n FEP windows joining (n + 1) lambda-points
|
|
99
|
+
# Provide prev_lambda value if continuing a sequential
|
|
100
|
+
# transformation and using IDWS
|
|
101
|
+
##############################################################
|
|
102
|
+
|
|
103
|
+
proc runFEPlist { lambdaList nSteps { IDWS false } { prev_lambda -1 } } {
|
|
104
|
+
set epsilon 1e-12
|
|
105
|
+
|
|
106
|
+
# Keep track of window number
|
|
107
|
+
global win
|
|
108
|
+
if {![info exists win]} {
|
|
109
|
+
set win 1
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
set l1 [lindex $lambdaList 0]
|
|
113
|
+
foreach l2 [lrange $lambdaList 1 end] {
|
|
114
|
+
print [format "Running FEP window %3s: Lambda1 %-6s Lambda2 %-6s \[dLambda %-6s\]"\
|
|
115
|
+
$win $l1 $l2 [expr $l2 - $l1]]
|
|
116
|
+
firsttimestep 0
|
|
117
|
+
alchLambda $l1
|
|
118
|
+
alchLambda2 $l2
|
|
119
|
+
|
|
120
|
+
if { $IDWS && ($prev_lambda >= 0.) } {
|
|
121
|
+
alchLambdaIDWS $prev_lambda
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
cv reset
|
|
125
|
+
cv configfile "./colvars_files/colvars_[expr $win - 1].in"
|
|
126
|
+
|
|
127
|
+
run $nSteps
|
|
128
|
+
|
|
129
|
+
# Keep track of previous value to set is as target for backward calculation in IDWS
|
|
130
|
+
set prev_lambda $l1
|
|
131
|
+
set l1 $l2
|
|
132
|
+
incr win
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if { $IDWS && ($l1 > [expr {1. - $epsilon}] || $l1 < $epsilon)} {
|
|
136
|
+
# If the list ends at 1 or zero, we add a final window, which is backward from the end point
|
|
137
|
+
# to complete double-wide sampling
|
|
138
|
+
# this will be look like "forward" sampling in the fepout file ("FepEnergy:" keyword)
|
|
139
|
+
print [format "Running FEP window %3s: Lambda1 %-6s Lambda2 %-6s \[dLambda %-6s\]"\
|
|
140
|
+
$win $l1 $l2 [expr $l2 - $l1]]
|
|
141
|
+
firsttimestep 0
|
|
142
|
+
alchLambda $l1
|
|
143
|
+
alchLambda2 $prev_lambda
|
|
144
|
+
alchLambdaIDWS -1
|
|
145
|
+
|
|
146
|
+
cv reset
|
|
147
|
+
cv configfile "./colvars_files/colvars_[expr $win - 1].in"
|
|
148
|
+
|
|
149
|
+
run $nSteps
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
##############################################################
|
|
155
|
+
# proc runFEP { start stop dLambda nSteps {IDWS} {prev_lambda} }
|
|
156
|
+
#
|
|
157
|
+
# run FEP windows of width dLambda between values start and stop
|
|
158
|
+
##############################################################
|
|
159
|
+
|
|
160
|
+
proc runFEP { start stop dLambda nSteps { IDWS false } { prev_lambda -1 } } {
|
|
161
|
+
|
|
162
|
+
runFEPlist [FEPlist $start $stop $dLambda] $nSteps $IDWS $prev_lambda
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
##############################################################
|
|
167
|
+
# proc FEPlist { start stop dLambda nSteps }
|
|
168
|
+
#
|
|
169
|
+
# Create list of FEP windows
|
|
170
|
+
##############################################################
|
|
171
|
+
|
|
172
|
+
proc FEPlist { start stop dLambda } {
|
|
173
|
+
set epsilon 1e-15
|
|
174
|
+
|
|
175
|
+
if { ($stop < $start) && ($dLambda > 0) } {
|
|
176
|
+
set dLambda [expr {-$dLambda}]
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if { $start == $stop } {
|
|
180
|
+
set ll [list $start $start]
|
|
181
|
+
} else {
|
|
182
|
+
set ll [list $start]
|
|
183
|
+
set l2 [increment $start $dLambda]
|
|
184
|
+
|
|
185
|
+
if { $dLambda > 0} {
|
|
186
|
+
# A small workaround for numerical rounding errors
|
|
187
|
+
while { [expr {$l2 <= ($stop + $epsilon) } ] } {
|
|
188
|
+
lappend ll $l2
|
|
189
|
+
set l2 [increment $l2 $dLambda]
|
|
190
|
+
}
|
|
191
|
+
} else {
|
|
192
|
+
while { [expr {$l2 >= ($stop - $epsilon) } ] } {
|
|
193
|
+
lappend ll $l2
|
|
194
|
+
set l2 [increment $l2 $dLambda]
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return $ll
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
##############################################################
|
|
204
|
+
##############################################################
|
|
205
|
+
|
|
206
|
+
proc runFEPmin { start stop dLambda nSteps nMinSteps temp} {
|
|
207
|
+
set epsilon 1e-15
|
|
208
|
+
|
|
209
|
+
if { ($stop < $start) && ($dLambda > 0) } {
|
|
210
|
+
set dLambda [expr {-$dLambda}]
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if { $start == $stop } {
|
|
214
|
+
set ll [list $start $start]
|
|
215
|
+
} else {
|
|
216
|
+
set ll [list $start]
|
|
217
|
+
set l2 [increment $start $dLambda]
|
|
218
|
+
|
|
219
|
+
if { $dLambda > 0} {
|
|
220
|
+
# A small workaround for numerical rounding errors
|
|
221
|
+
while { [expr {$l2 <= ($stop + $epsilon) } ] } {
|
|
222
|
+
lappend ll $l2
|
|
223
|
+
set l2 [increment $l2 $dLambda]
|
|
224
|
+
}
|
|
225
|
+
} else {
|
|
226
|
+
while { [expr {$l2 >= ($stop - $epsilon) } ] } {
|
|
227
|
+
lappend ll $l2
|
|
228
|
+
set l2 [increment $l2 $dLambda]
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
if { $nMinSteps > 0 } {
|
|
234
|
+
alchLambda $start
|
|
235
|
+
alchLambda2 $start
|
|
236
|
+
minimize $nMinSteps
|
|
237
|
+
reinitvels $temp
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
runFEPlist $ll $nSteps
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
##############################################################
|
|
244
|
+
##############################################################
|
|
245
|
+
|
|
246
|
+
proc runTIlist { lambdaList nSteps } {
|
|
247
|
+
# Keep track of window number
|
|
248
|
+
global win
|
|
249
|
+
if {![info exists win]} {
|
|
250
|
+
set win 1
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
foreach l $lambdaList {
|
|
254
|
+
print [format "Running TI window %3s: Lambda %-6s " $win $l ]
|
|
255
|
+
firsttimestep 0
|
|
256
|
+
alchLambda $l
|
|
257
|
+
run $nSteps
|
|
258
|
+
incr win
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
##############################################################
|
|
264
|
+
##############################################################
|
|
265
|
+
|
|
266
|
+
proc runTI { start stop dLambda nSteps } {
|
|
267
|
+
set epsilon 1e-15
|
|
268
|
+
|
|
269
|
+
if { ($stop < $start) && ($dLambda > 0) } {
|
|
270
|
+
set dLambda [expr {-$dLambda}]
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if { $start == $stop } {
|
|
274
|
+
set ll [list $start $start]
|
|
275
|
+
} else {
|
|
276
|
+
set ll [list $start]
|
|
277
|
+
set l2 [increment $start $dLambda]
|
|
278
|
+
|
|
279
|
+
if { $dLambda > 0} {
|
|
280
|
+
# A small workaround for numerical rounding errors
|
|
281
|
+
while { [expr {$l2 <= ($stop + $epsilon) } ] } {
|
|
282
|
+
lappend ll $l2
|
|
283
|
+
set l2 [increment $l2 $dLambda]
|
|
284
|
+
}
|
|
285
|
+
} else {
|
|
286
|
+
while { [expr {$l2 >= ($stop - $epsilon) } ] } {
|
|
287
|
+
lappend ll $l2
|
|
288
|
+
set l2 [increment $l2 $dLambda]
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
runTIlist $ll $nSteps
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
##############################################################
|
|
297
|
+
# Increment lambda and try to correct truncation errors around
|
|
298
|
+
# 0 and 1
|
|
299
|
+
##############################################################
|
|
300
|
+
|
|
301
|
+
proc increment { lambda dLambda } {
|
|
302
|
+
set epsilon 1e-15
|
|
303
|
+
set new [expr { $lambda + $dLambda }]
|
|
304
|
+
|
|
305
|
+
if { [expr $new > - $epsilon && $new < $epsilon] } {
|
|
306
|
+
return 0.0
|
|
307
|
+
}
|
|
308
|
+
if { [expr ($new - 1) > - $epsilon && ($new - 1) < $epsilon] } {
|
|
309
|
+
return 1.0
|
|
310
|
+
}
|
|
311
|
+
return $new
|
|
312
|
+
}
|
|
@@ -146,4 +146,159 @@ amberToGromacs(
|
|
|
146
146
|
pbcVector[0],
|
|
147
147
|
'${inputPrefix}_gmx',
|
|
148
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")
|
|
149
304
|
''')
|