-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathumbr_int.py
174 lines (137 loc) · 5.48 KB
/
umbr_int.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
import numpy as np
import math
import toml
import sys
from pathlib import Path
sqrt_two_pi = math.sqrt(math.tau)
class Window:
def __init__(self, x0, k, filename, options):
self.x0 = x0
self.k = k
self.filename = filename
self.mean = 0
self.std = 0
self.num = 0
self.read_data(options)
def get_interval(self,interval,Nintervals):
if Nintervals>0 and interval>=0:
interval_sz = len(self.data)/Nintervals
b = int(interval_sz*interval)
e = int(interval_sz*(interval+1))
self.mean = np.mean(self.data[b:e])
self.std = np.std(self.data[b:e])
self.num = len(self.data[b:e])
else:
self.mean = np.mean(self.data)
self.std = np.std(self.data)
self.num = len(self.data)
def read_data(self, options):
print(f'Reading data file {self.filename} starting time: {options.first_time}...')
data = [] # List to store filtered data
with open(self.filename, 'r') as file:
for line in file:
if line.startswith(('#', '@')):
continue # Skip comments and header lines
time, x = map(float, line.strip().split()[:2])
if time >= options.first_time:
data.append(x) # Add x value if time >= first_time
self.data = np.array(data) # Convert list to NumPy array and store
print(f'{len(data)} values read after filtering')
class Options:
def __init__(self, config):
self.Nbin = config['Nbin']
# Compute min and max
minval = 1.0e6
maxval = -1.0e6
for w in config['windows']:
if w["pos"] > maxval:
maxval = w["pos"]
if w["pos"] < minval:
minval = w["pos"]
self.bin_min = minval
self.bin_max = maxval
self.Nwin = len(config['windows'])
self.Temperature = config['Temperature']
self.first_time = config['first_time']
self.Nintervals = config['Nintervals']
self.out_file = config['out_file']
self.kt_units = config['kt_units']
self.zero_point = config['zero_point']
self.bin_sz = (self.bin_max - self.bin_min) / self.Nbin
def read_parameters(config):
options = Options(config)
windows = []
for window_config in config['windows']:
windows.append(Window(window_config['pos'], window_config['k'], window_config['file'], options))
return options, windows
def Pb(x, mean, std):
return 1 / (std * sqrt_two_pi) * np.exp(-0.5 * ((x - mean) / std)**2)
def umb_int_init(param_file_path):
with open(param_file_path, 'r') as f:
config = toml.load(f)
options,windows = read_parameters(config)
return options,windows
def compute_interval(options,windows,interval):
if interval>=0:
print(f'Computing PMF for interval {interval}...')
else:
print(f'Computing PMF for whole duration...')
kb = 0.0083144621 # Boltzmann constant in kJ/(mol*K)
kbT = kb * options.Temperature
dAu = np.zeros((options.Nwin, options.Nbin))
dAfinal = np.zeros(options.Nbin)
Afinal = np.zeros(options.Nbin)
for i, window in enumerate(windows):
# Get averages for given interval
window.get_interval(interval,options.Nintervals)
# Compute dAu
for j in range(options.Nbin):
x = options.bin_min + options.bin_sz * (j + 0.5)
dAu[i, j] = kbT * ((x - window.mean) / (window.std**2)) - window.k * (x - window.x0)
for j in range(options.Nbin):
x = options.bin_min + options.bin_sz * (j + 0.5)
weights = np.array([window.num * Pb(x, window.mean, window.std) for i, window in enumerate(windows)])
dAfinal[j] = np.sum(weights * dAu[:, j]) / np.sum(weights)
Afinal[0] = 0
for j in range(1, options.Nbin):
Afinal[j] = Afinal[j-1] + options.bin_sz * 0.5 * (dAfinal[j-1] + dAfinal[j])
# Set zero as asked
if options.zero_point == 'min':
Afinal -= np.min(Afinal)
elif options.zero_point == 'left':
Afinal -= Afinal[0]
elif options.zero_point == 'right':
Afinal -= Afinal[-1]
# Convert to kT if asked
if options.kt_units:
Afinal /= kbT
return Afinal
def write_pmf(outfile,pmf,options,errors):
with open(outfile, 'w') as f:
for i in range(options.Nbin):
bin_center = options.bin_min + options.bin_sz * (i + 0.5)
if len(errors) == 0:
f.write(f'{bin_center:10.5f} {pmf[i]:10.5f}\n')
else:
f.write(f'{bin_center:10.5f} {pmf[i]:10.5f} {errors[i]:10.5f}\n')
####################
# Run
####################
options,windows = umb_int_init(sys.argv[1])
if options.Nintervals>1:
pmfs = np.zeros((options.Nbin, options.Nintervals))
for interval in range(options.Nintervals):
pmfs[:,interval] = compute_interval(options,windows,interval)
# Writing output
fname = Path(options.out_file).stem
ext = Path(options.out_file).suffix
outfile = f'{fname}_{interval}{ext}'
write_pmf(outfile,pmfs[:,interval],options,errors=[])
# Compute errors in each point
errs = np.zeros(options.Nbin)
for i in range(options.Nbin):
errs[i] = np.std(pmfs[i,:])
# Compute whole
whole_pmf = compute_interval(options,windows,-1)
# Writing output
write_pmf(options.out_file,whole_pmf,options,errs)