Mercurial > repos > chemteam > biomd_neqgamma
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NEQGamma.py Fri Sep 11 21:54:45 2020 +0000 @@ -0,0 +1,210 @@ +#!/usr/bin/env python + +# coding: utf-8 +# This script is a modified version of a script written +# by Steffen Wolf under the GPL v3.0. +# The original version can be accessed at +# https://github.com/moldyn/dcTMD/blob/master/NEQGamma.py + +import argparse +import json +import sys + +import numpy as np + +import pandas as pd + +import scipy +import scipy.integrate +from scipy.ndimage.filters import gaussian_filter + + +def get_file_names(list_file): + with open(list_file) as f: + return [line for line in f.read().split('\n') if line] + + +def NEQGamma(file_names, output, output_frict, vel, T, av, sigma): + N = len(file_names) + RT = 0.0083144598 * T + + sys.stdout.write("reading data...\n") + + # read in initial data to get length of necessary array + test_file = pd.read_csv(file_names[0], delim_whitespace=True, + header=None, skiprows=17, dtype=float) + length_data = len(test_file[0].values) + full_force_set = np.zeros((N, length_data)) + x = np.zeros(length_data) + t = np.zeros(length_data) + t = test_file[0].values + x = test_file[0].values * vel + + # read in data + for i in range(0, N): + current_file_name = file_names[i] + sys.stdout.write("reading file {}\n".format(current_file_name)) + input_file_data = pd.read_csv(current_file_name, delim_whitespace=True, + header=None, skiprows=17, dtype=float) + full_force_set[i, :] = input_file_data[1].values + + # preprocessing + # * force average: calculate $\left< f_c (t)\right>_N$. + # **Important:** this is an ensemble average over the trajectory ensemble + # $N$, not the time average over $t$ + av_force = np.zeros(length_data) + av_forceintegral = np.zeros(length_data) + for i in range(length_data): + av_force[i] = np.mean(full_force_set[:, i]) + av_forceintegral[1:] = scipy.integrate.cumtrapz(av_force, x) + + # calculate $\delta f_c(t) = f_c(t) - \left< f_c (t) \right>_N$ for all $t$ + sys.stdout.write("calculating fluctuations...\n") + delta_force_set = np.zeros((N, length_data)) + for i in range(length_data): + delta_force_set[:, i] = full_force_set[:, i] - av_force[i] + + # evaluation + # * optimized algorithm for numerical evaluation: + # * integrate: $\int_0^t dt' \delta f_c(t')$ for all $t'$ + # * multiply by $\delta f_c(t)$ to yield + # $\int_0^t dt'\delta f_c(t) \delta f_c(t')$ for $t$ + # with all $t' \leq t$ each + # * then calculate the ensemble average + # $\left< \int_0^t dt' \delta f_c(t) \delta f_c(t') \right>$ + int_delta_force_set = np.zeros((N, length_data)) + for n in range(N): + int_delta_force_set[n, 1:] = scipy.integrate.cumtrapz( + delta_force_set[n, :], t) + + sys.stdout.write("averaging and integrating...\n") + intcorr = np.zeros((N, length_data)) + + for n in range(N): + for i in range(length_data): + intcorr[n, i] = delta_force_set[n, i] * int_delta_force_set[n, i] + if i % 1000 == 0: + sys.stdout.write("Trajectory {:2d} {:3.1f} % done\r".format( + n + 1, (i / length_data) * 100)) + + # shape of $\int_0^t dt' \delta f_c(t) \delta f_c(t')$: + sys.stdout.write("final average...\n") + av_intcorr = np.zeros(length_data) + for i in range(length_data): + av_intcorr[i] = np.mean(intcorr[:, i]) / RT + + # autocorrelation function evaluation: + # * calculate $\left< \delta f_c(t) \delta f_c(t') \right>$ + # for the last $t$ + + corr_set = np.zeros((N, length_data)) + autocorr_set = np.zeros(length_data) + + sys.stdout.write("calculating and processing ACF...\n") + for n in range(N): + for i in range(length_data): + corr_set[n, i] = delta_force_set[ + n, i] * delta_force_set[n, length_data - 1] + + for i in range(length_data): + autocorr_set[i] = np.mean(corr_set[:, i]) + + # * Gauss filter: + sys.stdout.write("applying Gauss filter...\n") + blurr = sigma + blurred = np.zeros(length_data) + blurred = gaussian_filter(av_intcorr, sigma=blurr) + + # * sliding window average: + sys.stdout.write("applying sliding window average...\n") + window = av + runn_av = np.zeros(length_data) + runn_av = np.convolve(av_intcorr, np.ones((window,)) / window, mode='same') + + # * $W_{diss}$ from integration: + wdiss = np.zeros(length_data) + wdiss[1:] = scipy.integrate.cumtrapz(av_intcorr, x) * vel + + sys.stdout.write("writing output...\n") + dist = open(output, "w") + frict = open(output_frict, "w") + + dist.write( + "#x force_integral frict_coeff wdiss corrected_force_integral\n") + for i in range(length_data): + dist.write("{:15.8f} {:20.8f} {:20.8f} {:20.8f} {:20.8f}\n".format( + x[i], av_forceintegral[i], av_intcorr[i], wdiss[i], + av_forceintegral[i] - wdiss[i])) + + frict.write("""#x ACF frict_coeff """ + """gauss_filtered_frict_coeff av_window_frict_coeff\n""") + for i in range(length_data): + frict.write("{:15.8f} {:20.8f} {:20.8f} {:20.8f} {:20.8f}\n".format( + x[i], autocorr_set[i], av_intcorr[i], blurred[i], runn_av[i])) + + dist.close() + frict.close() + + sys.stdout.write("Done!\n") + + +def main(): + parser = argparse.ArgumentParser(description="""dcTMD friciton correction + (please cite: Wolf, S., Stock, G. Targeted Molecular Dynamics + Calculations of Free Energy Profiles Using a Nonequilibrium + Friction Correction. J. Chem. Theory Comput. 2018, 14(12), 6175-6182, + DOI: 10.1021/acs.jctc.8b00835). Integrates a constraint force file via + trapezoid rule, calculates the NEQ memory friction kernel and friction + factors, and performs a friction correction. First column: reaction + coordinate in nm calculated via t * vel. Second column: force integral, + i.e. the work profile. Third column: friction factors. Fourth column: + trapezoid integral (final value) of friction work along reaction + coordinate. Fourth column: friction corrected work profile. ATTENTION: + Use with python3 or higher!""") + parser.add_argument('-i', metavar='<xvg force file>', type=str, + help="""List of xvg constraint force files prefix + as given by Gromacs mdrun -pf option before running + number.""") + parser.add_argument('-o', metavar='<combined results>', type=str, + help="""file to write x, dG(x), friction coefficeint by + integration (time resolved), and the friction-corrected + dG(x).""") + parser.add_argument('-ofrict', metavar='<combined friction results>', + type=str, + help="""file to write x, ACF, friction coefficeint by + integration (time resolved), gauss filtered friction + coefficient, and slide window averaged friction.""") + parser.add_argument('-vel', metavar='<pull velocity>', type=float, + help="""pull velocity in nm/ps for converting simulation + time t into distance x""") + parser.add_argument('-T', metavar='<temperature>', type=float, + help='temperature in K') + parser.add_argument('-av', metavar='<average window>', type=int, + help="""size of averaging window for displaying + Gamma(x) (recommended: 4 to 20 per 100 data points)""") + parser.add_argument('-sigma', metavar='<gauss blurr>', type=int, + help="""sigma value for Gauss filter for displaying + Gamma(x) (recommended: 4 per 100 data points)""") + parser.add_argument('-json', metavar='<json>', type=str, + help='JSON file defining cluster membership') + + args = parser.parse_args() + + file_names = get_file_names(args.i) + if args.json: + with open(args.json) as f: + j = json.load(f) + file_names_dct = {n: [file_names[int(m)] for m in j[n]] for n in j} + + for cluster in file_names_dct: + NEQGamma(file_names_dct[cluster], + 'cluster{}_{}'.format(cluster, args.o), + 'cluster{}_{}'.format(cluster, args.ofrict), + args.vel, args.T, args.av, args.sigma) + else: + NEQGamma(file_names, args.o, args.ofrict, args.vel, + args.T, args.av, args.sigma) + + +if __name__ == "__main__": + main()