Mercurial > repos > chemteam > biomd_neqgamma
comparison NEQGamma.py @ 0:4f3222cb5cf6 draft
"planemo upload for repository https://github.com/galaxycomputationalchemistry/galaxy-tools-compchem/ commit 79589d149a8ff2791d4f71d28b155011672db827"
author | chemteam |
---|---|
date | Fri, 11 Sep 2020 21:54:45 +0000 |
parents | |
children | afcb925def69 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4f3222cb5cf6 |
---|---|
1 #!/usr/bin/env python | |
2 | |
3 # coding: utf-8 | |
4 # This script is a modified version of a script written | |
5 # by Steffen Wolf under the GPL v3.0. | |
6 # The original version can be accessed at | |
7 # https://github.com/moldyn/dcTMD/blob/master/NEQGamma.py | |
8 | |
9 import argparse | |
10 import json | |
11 import sys | |
12 | |
13 import numpy as np | |
14 | |
15 import pandas as pd | |
16 | |
17 import scipy | |
18 import scipy.integrate | |
19 from scipy.ndimage.filters import gaussian_filter | |
20 | |
21 | |
22 def get_file_names(list_file): | |
23 with open(list_file) as f: | |
24 return [line for line in f.read().split('\n') if line] | |
25 | |
26 | |
27 def NEQGamma(file_names, output, output_frict, vel, T, av, sigma): | |
28 N = len(file_names) | |
29 RT = 0.0083144598 * T | |
30 | |
31 sys.stdout.write("reading data...\n") | |
32 | |
33 # read in initial data to get length of necessary array | |
34 test_file = pd.read_csv(file_names[0], delim_whitespace=True, | |
35 header=None, skiprows=17, dtype=float) | |
36 length_data = len(test_file[0].values) | |
37 full_force_set = np.zeros((N, length_data)) | |
38 x = np.zeros(length_data) | |
39 t = np.zeros(length_data) | |
40 t = test_file[0].values | |
41 x = test_file[0].values * vel | |
42 | |
43 # read in data | |
44 for i in range(0, N): | |
45 current_file_name = file_names[i] | |
46 sys.stdout.write("reading file {}\n".format(current_file_name)) | |
47 input_file_data = pd.read_csv(current_file_name, delim_whitespace=True, | |
48 header=None, skiprows=17, dtype=float) | |
49 full_force_set[i, :] = input_file_data[1].values | |
50 | |
51 # preprocessing | |
52 # * force average: calculate $\left< f_c (t)\right>_N$. | |
53 # **Important:** this is an ensemble average over the trajectory ensemble | |
54 # $N$, not the time average over $t$ | |
55 av_force = np.zeros(length_data) | |
56 av_forceintegral = np.zeros(length_data) | |
57 for i in range(length_data): | |
58 av_force[i] = np.mean(full_force_set[:, i]) | |
59 av_forceintegral[1:] = scipy.integrate.cumtrapz(av_force, x) | |
60 | |
61 # calculate $\delta f_c(t) = f_c(t) - \left< f_c (t) \right>_N$ for all $t$ | |
62 sys.stdout.write("calculating fluctuations...\n") | |
63 delta_force_set = np.zeros((N, length_data)) | |
64 for i in range(length_data): | |
65 delta_force_set[:, i] = full_force_set[:, i] - av_force[i] | |
66 | |
67 # evaluation | |
68 # * optimized algorithm for numerical evaluation: | |
69 # * integrate: $\int_0^t dt' \delta f_c(t')$ for all $t'$ | |
70 # * multiply by $\delta f_c(t)$ to yield | |
71 # $\int_0^t dt'\delta f_c(t) \delta f_c(t')$ for $t$ | |
72 # with all $t' \leq t$ each | |
73 # * then calculate the ensemble average | |
74 # $\left< \int_0^t dt' \delta f_c(t) \delta f_c(t') \right>$ | |
75 int_delta_force_set = np.zeros((N, length_data)) | |
76 for n in range(N): | |
77 int_delta_force_set[n, 1:] = scipy.integrate.cumtrapz( | |
78 delta_force_set[n, :], t) | |
79 | |
80 sys.stdout.write("averaging and integrating...\n") | |
81 intcorr = np.zeros((N, length_data)) | |
82 | |
83 for n in range(N): | |
84 for i in range(length_data): | |
85 intcorr[n, i] = delta_force_set[n, i] * int_delta_force_set[n, i] | |
86 if i % 1000 == 0: | |
87 sys.stdout.write("Trajectory {:2d} {:3.1f} % done\r".format( | |
88 n + 1, (i / length_data) * 100)) | |
89 | |
90 # shape of $\int_0^t dt' \delta f_c(t) \delta f_c(t')$: | |
91 sys.stdout.write("final average...\n") | |
92 av_intcorr = np.zeros(length_data) | |
93 for i in range(length_data): | |
94 av_intcorr[i] = np.mean(intcorr[:, i]) / RT | |
95 | |
96 # autocorrelation function evaluation: | |
97 # * calculate $\left< \delta f_c(t) \delta f_c(t') \right>$ | |
98 # for the last $t$ | |
99 | |
100 corr_set = np.zeros((N, length_data)) | |
101 autocorr_set = np.zeros(length_data) | |
102 | |
103 sys.stdout.write("calculating and processing ACF...\n") | |
104 for n in range(N): | |
105 for i in range(length_data): | |
106 corr_set[n, i] = delta_force_set[ | |
107 n, i] * delta_force_set[n, length_data - 1] | |
108 | |
109 for i in range(length_data): | |
110 autocorr_set[i] = np.mean(corr_set[:, i]) | |
111 | |
112 # * Gauss filter: | |
113 sys.stdout.write("applying Gauss filter...\n") | |
114 blurr = sigma | |
115 blurred = np.zeros(length_data) | |
116 blurred = gaussian_filter(av_intcorr, sigma=blurr) | |
117 | |
118 # * sliding window average: | |
119 sys.stdout.write("applying sliding window average...\n") | |
120 window = av | |
121 runn_av = np.zeros(length_data) | |
122 runn_av = np.convolve(av_intcorr, np.ones((window,)) / window, mode='same') | |
123 | |
124 # * $W_{diss}$ from integration: | |
125 wdiss = np.zeros(length_data) | |
126 wdiss[1:] = scipy.integrate.cumtrapz(av_intcorr, x) * vel | |
127 | |
128 sys.stdout.write("writing output...\n") | |
129 dist = open(output, "w") | |
130 frict = open(output_frict, "w") | |
131 | |
132 dist.write( | |
133 "#x force_integral frict_coeff wdiss corrected_force_integral\n") | |
134 for i in range(length_data): | |
135 dist.write("{:15.8f} {:20.8f} {:20.8f} {:20.8f} {:20.8f}\n".format( | |
136 x[i], av_forceintegral[i], av_intcorr[i], wdiss[i], | |
137 av_forceintegral[i] - wdiss[i])) | |
138 | |
139 frict.write("""#x ACF frict_coeff """ | |
140 """gauss_filtered_frict_coeff av_window_frict_coeff\n""") | |
141 for i in range(length_data): | |
142 frict.write("{:15.8f} {:20.8f} {:20.8f} {:20.8f} {:20.8f}\n".format( | |
143 x[i], autocorr_set[i], av_intcorr[i], blurred[i], runn_av[i])) | |
144 | |
145 dist.close() | |
146 frict.close() | |
147 | |
148 sys.stdout.write("Done!\n") | |
149 | |
150 | |
151 def main(): | |
152 parser = argparse.ArgumentParser(description="""dcTMD friciton correction | |
153 (please cite: Wolf, S., Stock, G. Targeted Molecular Dynamics | |
154 Calculations of Free Energy Profiles Using a Nonequilibrium | |
155 Friction Correction. J. Chem. Theory Comput. 2018, 14(12), 6175-6182, | |
156 DOI: 10.1021/acs.jctc.8b00835). Integrates a constraint force file via | |
157 trapezoid rule, calculates the NEQ memory friction kernel and friction | |
158 factors, and performs a friction correction. First column: reaction | |
159 coordinate in nm calculated via t * vel. Second column: force integral, | |
160 i.e. the work profile. Third column: friction factors. Fourth column: | |
161 trapezoid integral (final value) of friction work along reaction | |
162 coordinate. Fourth column: friction corrected work profile. ATTENTION: | |
163 Use with python3 or higher!""") | |
164 parser.add_argument('-i', metavar='<xvg force file>', type=str, | |
165 help="""List of xvg constraint force files prefix | |
166 as given by Gromacs mdrun -pf option before running | |
167 number.""") | |
168 parser.add_argument('-o', metavar='<combined results>', type=str, | |
169 help="""file to write x, dG(x), friction coefficeint by | |
170 integration (time resolved), and the friction-corrected | |
171 dG(x).""") | |
172 parser.add_argument('-ofrict', metavar='<combined friction results>', | |
173 type=str, | |
174 help="""file to write x, ACF, friction coefficeint by | |
175 integration (time resolved), gauss filtered friction | |
176 coefficient, and slide window averaged friction.""") | |
177 parser.add_argument('-vel', metavar='<pull velocity>', type=float, | |
178 help="""pull velocity in nm/ps for converting simulation | |
179 time t into distance x""") | |
180 parser.add_argument('-T', metavar='<temperature>', type=float, | |
181 help='temperature in K') | |
182 parser.add_argument('-av', metavar='<average window>', type=int, | |
183 help="""size of averaging window for displaying | |
184 Gamma(x) (recommended: 4 to 20 per 100 data points)""") | |
185 parser.add_argument('-sigma', metavar='<gauss blurr>', type=int, | |
186 help="""sigma value for Gauss filter for displaying | |
187 Gamma(x) (recommended: 4 per 100 data points)""") | |
188 parser.add_argument('-json', metavar='<json>', type=str, | |
189 help='JSON file defining cluster membership') | |
190 | |
191 args = parser.parse_args() | |
192 | |
193 file_names = get_file_names(args.i) | |
194 if args.json: | |
195 with open(args.json) as f: | |
196 j = json.load(f) | |
197 file_names_dct = {n: [file_names[int(m)] for m in j[n]] for n in j} | |
198 | |
199 for cluster in file_names_dct: | |
200 NEQGamma(file_names_dct[cluster], | |
201 'cluster{}_{}'.format(cluster, args.o), | |
202 'cluster{}_{}'.format(cluster, args.ofrict), | |
203 args.vel, args.T, args.av, args.sigma) | |
204 else: | |
205 NEQGamma(file_names, args.o, args.ofrict, args.vel, | |
206 args.T, args.av, args.sigma) | |
207 | |
208 | |
209 if __name__ == "__main__": | |
210 main() |