Пример #1
0
def _exact_pmf(system_type, pmf_bin_edges):
    if system_type == "symmetric":
        U0 = U0_sym
    elif system_type == "asymmetric":
        U0 = U0_asym
    else:
        raise ValueError("Unknown system_type: " + system_type)

    centers = bin_centers(pmf_bin_edges)
    exact_pmf = U0(centers)

    return centers, exact_pmf
def _exact_pmf(system_type, pmf_bin_edges):
    if system_type == "symmetric":
        U0 = U0_sym
    elif system_type == "asymmetric":
        U0 = U0_asym

    centers = bin_centers(pmf_bin_edges)
    exact_pmf = U0(centers)

    pmf = {}
    pmf["pmf_bin_edges"] = pmf_bin_edges
    pmf["pmf"] = exact_pmf

    return pmf
Пример #3
0
def uni_pmf(z_t, w_t, lambda_t, V, ks, bin_edges):
    """
    unidirectional estimator for PMF

    :param z_t: ndarray with shape (N, number_of_steps)
                the (fluctuating) coordinate pulled by a protocol
    :param w_t: ndarray with shape (N, number_of_steps)
                works done in forward direction, in unit of kT
    :param lambda_t: ndarray of shape (number_of_steps)
                    coordinate controlled by the pulling procedure
    :param V: a python function, pulling harmonic potential, e.g., 0.5 * ks * (z - lambda)**2
    :param ks: float, harmonic force constant of V, the unit of ks is such that V is in unit of kT
    :param bin_edges: ndarray with shape ( nbins+1, ), same distance unit as zF_t and zR_t

    :return: (centers, pmf)
                centers : ndarray with shape (bin_edges.shape[0]-1 ), bin centers
                pmf : ndarray with shape (bin_edges.shape[0]-1 ) potential of mean force
    """
    assert z_t.ndim == w_t.ndim == 2, "z_t and w_t must be 2d array"
    assert z_t.shape == w_t.shape, "z_t and w_t must have the same shape"
    assert lambda_t.ndim == 1, "lambda_t  must be 1d array"
    assert z_t.shape[1] == lambda_t.shape[0], "z_t.shape[1], lambda_t.shape[0] must be the same"
    assert bin_edges.ndim == 1, "bin_edges must be 1d array"

    df_t = uni_df_t(w_t)

    N = z_t.shape[0]
    weights = np.exp(-w_t) / N
    histograms = hist_counts(z_t, bin_edges, weights)

    centers = bin_centers(bin_edges)
    denominator = np.exp( -V( centers[None,:], ks, lambda_t[:,None] ) + df_t[:,None] )
    denominator = denominator.sum(axis=0)

    numerator = histograms * np.exp(df_t[:,None])
    numerator = numerator.sum(axis=0)
    pmf = -np.log(numerator / denominator)

    return centers, pmf
           xlimits=xlimits_fe,
           ylimits=ylimits_fe,
           lw=1.0,
           markersize=4,
           alpha=1.,
           n_xtics=8,
           n_ytics=8)

# plot pmf rmse
start_pmf_ind = args.bin_ind_to_start_to_plot

xs = []
ys = []
yerrs = []
for label in data_estimator_pairs:
    x = bin_centers(all_data[label]["pmfs"]["pmf_bin_edges"])

    end_pmf_ind = len(x) - start_pmf_ind
    xs.append(x[start_pmf_ind:end_pmf_ind])
    ys.append(pmf_rmse[label][start_pmf_ind:end_pmf_ind])
    yerrs.append(pmf_rmse_std_error[label][start_pmf_ind:end_pmf_ind] / 2)

if args.xlimits_pmf.lower() != "none":
    xlimits_pmf = [float(s) for s in args.xlimits_pmf.split()]
else:
    xlimits_pmf = None

if args.ylimits_pmf.lower() != "none":
    ylimits_pmf = [float(s) for s in args.ylimits_pmf.split()]
else:
    ylimits_pmf = None
Пример #5
0
def sym_est_pmf_v2(z_t, w_t, lambda_t, V, ks, bin_edges, symmetrize_pmf):
    """
    Version 2 of symmetric estimator for PMF
    The symmetric estimator of path ensemble average is
    <F> = (1/N) * sum{ ( F[x_n] + F[xr_n] * exp( -w_tau[x_n] ) ) / ( 1 + exp( -w_tau[x_n] ) ) }
    where xr_n is the time reversal of x_n

    Substitute the symmetric estimator (v2) of path ensemble average defined above into Eq. (9) in
    Minh and Adib, Phys. Rev. Lett. 100, 180602 (2008)

    :param z_t: np.ndarray with shape (N, number_of_steps),
                the (fluctuating) coordinate pulled by a symmetric protocol or in a symmetric
    :param w_t: np.ndarray with shape (N, number_of_steps),
                works done in forward direction, in unit of kT
    :param lambda_t: np.ndarray of shape (number_of_steps)
                    coordinate controlled by the pulling procedure
    :param V: a python function, pulling harmonic potential
                    e.g., 0.5 * ks * (z - lambda)**2
    :param ks: float, harmonic force constant of V
                    the unit of ks is such that V is in unit of kT
    :param bin_edges: np.ndarray with shape ( nbins+1, )
                    same distance unit as zF_t and zR_t
    :param symmetrize_pmf: bool
                         should set to True when both system and protocol are symmetric

    :return: (centers, pmf)
                centers : np.ndarray with shape (bin_edges.shape[0]-1 )
                            bin centers
                pmf : np.ndarray with shape (bin_edges.shape[0]-1 )
                    potential of mean force
    """
    assert z_t.ndim == w_t.ndim == 2, "z_t and w_t must be 2d array"
    assert z_t.shape == w_t.shape, "z_t and w_t must have the same shape"
    assert lambda_t.ndim == 1, "lambda_t  must be 1d array"
    assert z_t.shape[1] == lambda_t.shape[0], "z_t.shape[1] and lambda_t.shape[0] must be the same"
    assert bin_edges.ndim == 1, "bin_edges must be 1d array"

    df_t  = sym_est_df_t_v2(w_t)

    wTR_t = time_reversal_of_work(w_t)
    zTR_t = time_reversal_of_trajectory(z_t)

    if symmetrize_pmf:
        symm_center = (lambda_t[0] + lambda_t[-1])/2.
        zTR_t = center_reflection(zTR_t, symm_center)

    centers = bin_centers(bin_edges)
    outer_denominator = np.exp( -V( centers[None,:], ks, lambda_t[:,None] ) + df_t[:,None] )
    outer_denominator = outer_denominator.sum(axis=0)

    w_tau = w_t[:, -1]
    N = w_tau.shape[0]

    weights_1    = np.exp(-w_t) / (1 + np.exp(-w_tau[:,None])) / N
    histograms_1 = hist_counts(z_t, bin_edges, weights_1)

    weights_2 = np.exp(-wTR_t) * np.exp(-w_tau[:,None] ) / (1 + np.exp(-w_tau[:,None])) / N
    histograms_2 = hist_counts(zTR_t, bin_edges, weights_2)

    numerator = (histograms_1 + histograms_2) * np.exp(df_t[:,None])
    numerator = numerator.sum(axis=0)
    pmf = -np.log(numerator / outer_denominator)

    return centers, pmf
Пример #6
0
def bi_pmf(zF_t, wF_t, zR_t, wR_t, lambda_t, V, ks, bin_edges):
    """
    Bidirectional estimator for PMF

    Implement the PMF which is resulted from substituting Eq (17) in Minh and Chodera into
    Eq (9) in Minh and Adib

    Refs:
    Minh and Abid, Optimized Free Energies from Bidirectional Single-Molecule Force Spectroscopy,
                Phys. Rev. Lett. 100, 180602 (2008)
    Minh and Chodera, Optimal estimators and asymptotic variances for nonequilibrium path-ensemble averages,
                J. Chem. Phys. 131, 134110 (2009)

    -----------------------

    :param zF_t: ndarray with shape (NF, number_of_steps),
            the (fluctuating) coordinate pulled in forward direction
    :param wF_t: ndarray with shape (NF, number_of_steps),
                works done in forward direction, in unit of kT
    :param zR_t: ndarray with shape (NR, number_of_steps)
                the (fluctuating) coordinate pulled in reverse direction
    :param wR_t: ndarray with shape (NR, number_of_steps)
                the (fluctuating) coordinate pulled in reverse direction
    :param lambda_t: ndarray of shape (number_of_steps)
                    coordinate controlled by the pulling procedure
    :param V: a python function, pulling harmonic potential
                e.g., 0.5 * ks * (z - lambda)**2
    :param ks: float, harmonic force constant of V
                the unit of ks is such that V is in unit of kT
    :param bin_edges: ndarray with shape ( nbins+1, )
                    same distance unit as zF_t and zR_t

    :return: (centers, pmf)
                centers :   ndarray with shape (bin_edges.shape[0]-1 ) bin centers
                pmf :   ndarray with shape (bin_edges.shape[0]-1 ) potential of mean force
    """
    assert zF_t.ndim == zR_t.ndim == wF_t.ndim == wR_t.ndim == 2, " zF_t, wF_t, zR_t, wR_t must be 2D array"
    assert zF_t.shape == wF_t.shape, "zF_t and wF_t must have the same shape"
    assert zR_t.shape == wR_t.shape, "zR_t and wR_t must have the same shape"
    assert lambda_t.ndim == 1, "lambda_t must be 1d array"
    assert zF_t.shape[1] == zR_t.shape[1] == lambda_t.shape[0], "zF_t.shape[1], zR_t.shape[1], lambda_t.shape[0] must be the same"
    assert bin_edges.ndim == 1, "bin_edges must be 1d array"

    df_t = bi_df_t(wF_t, wR_t)

    wR_t = time_reversal_of_work(wR_t)
    zR_t = time_reversal_of_trajectory(zR_t)

    NF = wF_t.shape[0]
    NR = wR_t.shape[0]

    wF_tau = wF_t[:, -1]
    wR_tau = wR_t[:, -1]
    dt_tau = df_t[-1]

    centers = bin_centers(bin_edges)

    denominator = np.exp(-V(centers[None, :], ks, lambda_t[:, None]) + df_t[:, None])
    denominator = denominator.sum(axis=0)

    weights_F = np.exp(-wF_t) / (NF + NR * np.exp(dt_tau - wF_tau[:, None]))
    histograms_F = hist_counts(zF_t, bin_edges, weights_F)

    weights_R = np.exp(-wR_t) / (NF + NR * np.exp(dt_tau - wR_tau[:, None]))
    histograms_R = hist_counts(zR_t, bin_edges, weights_R)

    numerator = (histograms_F + histograms_R) * np.exp(df_t[:, None])
    numerator = numerator.sum(axis=0)

    pmf = -np.log(numerator / denominator)
    return centers, pmf
            print("Right replicate for", label)
            data = replicate_data_cuc7_da(data, args.system_type)

    # put first of fes to zero
    data = put_first_of_fe_to_zero(data)

    # put argmin of pmf to pmf_exact["pmf"]
    data = put_argmin_of_pmf_to_target(data, pmf_us["pmf"])

    fe_x = data["free_energies"]["lambdas"]
    fe_ys = np.array(data["free_energies"]["main_estimates"].values())
    fe_y = fe_ys.mean(axis=0)
    fe_error = fe_ys.std(axis=0)
    free_energies[label] = {"x": fe_x, "y": fe_y, "error": fe_error}

    pmf_x = bin_centers(data["pmfs"]["pmf_bin_edges"])
    pmf_ys = np.array(data["pmfs"]["main_estimates"].values())
    pmf_y = pmf_ys.mean(axis=0)
    pmf_error = pmf_ys.std(axis=0)

    pmfs[label] = {"x": pmf_x, "y": pmf_y, "error": pmf_error}

# plot free energies
xs = []
ys = []
yerrs = []
for label in data_estimator_pairs:
    x = free_energies[label]["x"]
    y = free_energies[label]["y"]
    yerr = free_energies[label]["error"] / 2  # error bars are one std