//  [python]
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.cumulative_trapezoid(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.cumulative_trapezoid(
                                        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.cumulative_trapezoid(av_intcorr, x) * vel

    sys.stdout.write("writing output...\n")
    dist = open(output, "w")
    frict = open(output_frict, "w")

    dist.write('\t'.join(('#x', 'force_integral',  'frict_coeff',
                         'wdiss', 'corrected_force_integral\n')))
    for i in range(length_data):
        dist.write("{:.8f}\t{:.8f}\t{:.8f}\t{:.8f}\t{:.8f}\n".format(
            x[i], av_forceintegral[i], av_intcorr[i], wdiss[i],
            av_forceintegral[i] - wdiss[i]))

    frict.write('\t'.join(('#x', 'ACF', 'frict_coeff',
                           'gauss_filtered_frict_coeff',
                           'av_window_frict_coeff\n')))
    for i in range(length_data):
        frict.write("{:.8f}\t{:.8f}\t{:.8f}\t{:.8f}\t{:.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")