def calc_Dinh(F, D, dx, dt): """Compute inhomogeneous contribution to Deff""" # compute the rate matrix rate = construct_rate_matrix_from_F_D(F, D, dx, dt) # in 1/dt # compute pseudo-inverse # symmetrize and pseudo-inverse a = np.exp(-(F - min(F)) / 2.) M = np.diag(a) #/ np.sum(a**2) M1 = np.diag(1. / a) #* np.sum(a**2) rateS = np.dot(np.dot(M1, rate), M) # symmetrized rate, in 1/dt rateS1 = np.linalg.pinv(rateS, 1.e-7) # pseudo-inverse, in dt #print "rateS",rateS[:4,:4] # gradient-like vector gradD = np.zeros(D.shape) for m in range(-1, len(gradD) - 1): gradD[m] = D[m] * a[m + 1] - D[m - 1] * a[m - 1] # in units A^2/ps #print "gradD",gradD # combine # double product is in ((A^2)/ps)**2 * dt = A^4/ps^2*dt Dinh = np.dot(np.dot(gradD, rateS1), gradD) / np.sum(a**2) Dinh *= dt # put dt in units A Dinh /= dx**2 # finally, should be divided by dx**2 to arrive at MSD/(2t) interpretation #print "Dinh",Dinh return Dinh
def calc_Dinh(F,D,dx,dt,zero): """Compute inhomogeneous contribution to Deff""" # F in units kBT, D in units A^2/ps # zero -- cutoff for the pseudo-inverse of the rate matrix # compute the rate matrix rate = construct_rate_matrix_from_F_D(F,D,dx,dt) # in 1/dt # symmetrize and pseudo-inverse a = np.exp(-(F-min(F))/2.) M = np.diag(a) #/ np.sum(a**2) M1 = np.diag(1./a) #* np.sum(a**2) rateS = np.dot(np.dot(M1,rate),M) # symmetrized rate, in 1/dt rateS1 = np.linalg.pinv(rateS,zero) # pseudo-inverse, in dt # verification numerical stability #vals,vecs = np.linalg.eigh(rateS) #vals1,vecs = np.linalg.eigh(rateS1) #vals= np.sort(vals) # okay, has highest eigenvalue equal to 1e-16 # NOOOO numerical #vals1= np.sort(abs(vals1)) # okay, has highest eigenvalue equal to 1e-16 #print "vals",vals[-2:],vals1[:2] #print "rateS",rateS[:4,:4] # gradient-like vector gradD = np.zeros(D.shape) for m in range(-1,len(gradD)-1): gradD[m] = D[m]*a[m+1] - D[m-1]*a[m-1] # in units A^2/ps #print "gradD",gradD # combine # double product is in ((A^2)/ps)**2 * dt = A^4/ps^2*dt Dinh = np.dot(np.dot(gradD,rateS1),gradD)/np.sum(a**2) Dinh *= dt # put dt in units A Dinh /= dx**2 # finally, should be divided by dx**2 to arrive at MSD/(2t) interpretation #print "Dinh",Dinh return Dinh
def calc_Dpar_logs(F, D, Drad, dz, dt, st=None, end=None, edges=None): """Compute average diffusion constant, in parallel layers, e.g. Drad Dave = sum_i D_i exp(-F_i) , where D_i is actually D_(i+1/2) not shifting F nor D to the middle of the bins using bins [st:end] = [st,st+1,...,end-1] number of used bins = end-st when st=None,end=None, then this means [:]""" # F in units kBT, D in units A^2/ps assert len(F) == len(D) #v = F[st:end] # when st=None,end=None, then this means [:] #d = D[st:end] #drad = Drad[st:end] # average Drad: #part = np.exp(-(v-min(v))) #Dave = np.sum(d*part)/np.sum(part) # a weighted sum, normalized drad = Drad[st + 1:end] # absorbing boundaries rate = construct_rate_matrix_from_F_D(F, D, dz, dt, pbc=False, st=st, end=end, side="both") # in 1/dt #rate = construct_rate_matrix_from_F_D(F,D,dz,dt,pbc=False,st=st,end=end,side=None) # in 1/dt print("rate", rate.shape) vals, U = np.linalg.eig(rate) # U contains eigenvectors as columns print(vals) U1 = np.linalg.inv(U) Ddiag = np.diag(drad) UDdiagU1 = np.dot(U, np.dot(Ddiag, U1)) "o-ow, I have three positive eigenvals?????" Dpar = 0. # first term Dpar_1 = 0. for i in range(len(vals)): Dpar_1 += 1. / vals[i] * U1[-1, i] * UDdiagU1[i, i] * U[i, 0] print("part1", Dpar_1) # second term Dpar_2 = 0. for i in range(len(vals)): for j in range(len(vals)): if i != j: term = np.log(abs(vals[i] / vals[j])) / (vals[i] - vals[j]) term *= U1[-1, i] * UDdiagU1[i, j] * U[j, 0] Dpar_2 += term print("part2", Dpar_2) Dpar = Dpar_1 + Dpar_2 print("sum", Dpar) rate1 = np.linalg.inv(rate) Dpar /= rate1[-1, 0] print("final", Dpar) return Dpar
def calc_permeability_distribution(F, D, dx, dt, st, end, figname=None): # F in units kBT, D in units A^2/ps, dx in units A rate = construct_rate_matrix_from_F_D(F, D, dx, dt) # in 1/dt, PBC rate = rate[st:end, st:end] # solve subrate*p = vec subrate = rate[1:-1, 1:-1] # rhs of equation vec = np.zeros(len(subrate), float) vec[0] = -rate[1, 0] # p = subrate^-1 * p r1 = np.linalg.inv(subrate) p = np.dot(r1, vec) # plug in vector of original size, with boundaries P = np.zeros(len(rate), float) P[1:-1] = p P[0] = 1. #print "prob",P if figname is not None: plt.figure() plt.plot(P) plt.xlabel("bins") plt.ylabel("prob") plt.savefig(figname) print "file written...", figname return P
def calc_Dinh(F, D, dx, dt, zero): """Compute inhomogeneous contribution to Deff""" # F in units kBT, D in units A^2/ps # zero -- cutoff for the pseudo-inverse of the rate matrix # compute the rate matrix rate = construct_rate_matrix_from_F_D(F, D, dx, dt) # in 1/dt # symmetrize and pseudo-inverse a = np.exp(-(F - min(F)) / 2.) M = np.diag(a) #/ np.sum(a**2) M1 = np.diag(1. / a) #* np.sum(a**2) rateS = np.dot(np.dot(M1, rate), M) # symmetrized rate, in 1/dt rateS1 = np.linalg.pinv(rateS, zero) # pseudo-inverse, in dt # verification numerical stability #vals,vecs = np.linalg.eigh(rateS) #vals1,vecs = np.linalg.eigh(rateS1) #vals= np.sort(vals) # okay, has highest eigenvalue equal to 1e-16 # NOOOO numerical #vals1= np.sort(abs(vals1)) # okay, has highest eigenvalue equal to 1e-16 #print "vals",vals[-2:],vals1[:2] #print "rateS",rateS[:4,:4] # gradient-like vector gradD = np.zeros(D.shape) for m in range(-1, len(gradD) - 1): gradD[m] = D[m] * a[m + 1] - D[m - 1] * a[m - 1] # in units A^2/ps #print "gradD",gradD # combine # double product is in ((A^2)/ps)**2 * dt = A^4/ps^2*dt Dinh = np.dot(np.dot(gradD, rateS1), gradD) / np.sum(a**2) Dinh *= dt # put dt in units A Dinh /= dx**2 # finally, should be divided by dx**2 to arrive at MSD/(2t) interpretation #print "Dinh",Dinh return Dinh
def calc_Dpar_ratios(F,D,Drad,t,dz,dt,st=None,end=None,edges=None): """Compute average diffusion constant, in parallel layers, e.g. Drad Dave = sum_i D_i percentage-time-spent-in-bin-i where D_i is actually D_(i+1/2) using bins [st:end] = [st,st+1,...,end-1] number of used bins = end-st when st=None,end=None, then this means [:]""" # F in units kBT, D in units A^2/ps assert len(F) == len(D) v = F[st:end] # when st=None,end=None, then this means [:] d = D[st:end] drad = Drad[st:end] # average Drad: #part = np.exp(-(v-min(v))) #Dave = np.sum(d*part)/np.sum(part) # a weighted sum, normalized # ow.... watch out !!! drad = Drad[st+1:end] # absorbing boundaries rate = construct_rate_matrix_from_F_D(F,D,dz,dt,pbc=False,st=st,end=end,side="both") # in 1/dt # reflective boundaries #rate = construct_rate_matrix_from_F_D(F,D,dz,dt,pbc=False,st=st,end=end,side=None) # in 1/dt #print "rate",rate.shape n = len(rate) vals,U = np.linalg.eig(rate) # U contains eigenvectors as columns #print "vals",vals U1 = np.linalg.inv(U) Ddiag = np.diag(drad) #UDdiagU1 = np.dot(U,np.dot(Ddiag,U1)) U1DdiagU = np.dot(U1,np.dot(Ddiag,U)) maxval = max(vals) exp_valt = np.exp((vals-maxval)*t) Deff_t = np.zeros((n,n),) for i in range(n): for j in range(n): # for k in range(n): # Deff_t[i,j] += drad[k] * np.sum( # summation over l # U[k,:]*U1[:,j]*U[i,:]*U1[:,k] * t * exp_valt ) Deff_t[i,j] = np.sum(U1[:,j]*U[i,:]* np.diag(U1DdiagU) * t * exp_valt ) # print Deff_t for i in range(n): for j in range(n): for l in range(n): for m in range(n): if m != l: Deff_t[i,j] += U1[l,j]*U[i,m]*U1DdiagU[m,l] * (exp_valt[l]-exp_valt[m])/(vals[l]-vals[m]) # print Deff_t import scipy.linalg Deff_t /= scipy.linalg.expm2((rate-np.diag(np.ones(n))*maxval)*t) * t print("t",t) print(Deff_t) return Deff_t
def calc_Dpar_logs(F,D,Drad,dz,dt,st=None,end=None,edges=None): """Compute average diffusion constant, in parallel layers, e.g. Drad Dave = sum_i D_i exp(-F_i) , where D_i is actually D_(i+1/2) not shifting F nor D to the middle of the bins using bins [st:end] = [st,st+1,...,end-1] number of used bins = end-st when st=None,end=None, then this means [:]""" # F in units kBT, D in units A^2/ps assert len(F) == len(D) #v = F[st:end] # when st=None,end=None, then this means [:] #d = D[st:end] #drad = Drad[st:end] # average Drad: #part = np.exp(-(v-min(v))) #Dave = np.sum(d*part)/np.sum(part) # a weighted sum, normalized drad = Drad[st+1:end] # absorbing boundaries rate = construct_rate_matrix_from_F_D(F,D,dz,dt,pbc=False,st=st,end=end,side="both") # in 1/dt #rate = construct_rate_matrix_from_F_D(F,D,dz,dt,pbc=False,st=st,end=end,side=None) # in 1/dt print("rate",rate.shape) vals,U = np.linalg.eig(rate) # U contains eigenvectors as columns print(vals) U1 = np.linalg.inv(U) Ddiag = np.diag(drad) UDdiagU1 = np.dot(U,np.dot(Ddiag,U1)) "o-ow, I have three positive eigenvals?????" Dpar = 0. # first term Dpar_1 = 0. for i in range(len(vals)): Dpar_1 += 1./vals[i]*U1[-1,i]*UDdiagU1[i,i]*U[i,0] print("part1",Dpar_1) # second term Dpar_2 = 0. for i in range(len(vals)): for j in range(len(vals)): if i != j: term = np.log(abs(vals[i]/vals[j]))/(vals[i]-vals[j]) term *= U1[-1,i]*UDdiagU1[i,j]*U[j,0] Dpar_2 += term print("part2",Dpar_2) Dpar = Dpar_1 + Dpar_2 print("sum",Dpar) rate1 = np.linalg.inv(rate) Dpar /= rate1[-1,0] print("final",Dpar) return Dpar
def calc_mfpt_othermethod(F, D, dx, dt, st, end, getmax=False): # not correct yet... this method is just wrong, probably # construct rate matrix and its pseudo-inverse #--------------------------------------------- rate = construct_rate_matrix_from_F_D( v, D, dx, dt, pbc=False) # NOPBC # in units 1/dt # cut rate_small = rate[st:end + 1, st:end + 1] rate_small1 = np.linalg.pinv(rate_small) # pseudo-inverse # in units dt # compute mfpt mfpt_small = np.zeros(rate_small.shape, float) part = np.exp(-v) # no unit, not normalized part_small = part[st:end + 1] / np.sum(part[st:end + 1]) # normalize for i in range(nbins): # fill up each row: MFPT(i,j) = starting in j, ending in i mfpt_small[i, :] = (-rate_small1[i, i] + rate_small1[i, :]) / part_small[i] mfpt_small *= dt # mfpt in ps #mfpt = np.zeros(rate.shape,float) #mfpt[a:b+1,a:b+1] = mfpt_small #tau = mfpt_small[0,-1] # the longest time #tau = mfpt[st,end] if False: plt.figure() plt.plot(mfpt_small) plt.savefig("mfpt.matrix.png") if False: x3 = np.arange(len(mfpt)) plt.figure() I = x3 #range(n) J = x3 #range(n) CS = plt.contourf(I, J, mfpt.T, 30) plt.xlabel("ending bin i") plt.ylabel("starting bin j") # starting in bin 12, then ... #plt.plot([x3[12],x3[12]],color='k',linewidth=2) plt.plot([x3[0], x3[-1]], [x3[12], x3[12]], color='k', linewidth=2) cbar = plt.colorbar(CS) cbar.ax.set_ylabel('mean first passage time (ps)') #plt.figure() #plt.plot(mfpt_small) plt.savefig("mfpt.matrix.%i.%i.png" % (st, end))
def calc_mfpt_othermethod(F,D,dx,dt,st,end,getmax=False): # not correct yet... this method is just wrong, probably # construct rate matrix and its pseudo-inverse #--------------------------------------------- rate = construct_rate_matrix_from_F_D(v,D,dx,dt,pbc=False) # NOPBC # in units 1/dt # cut rate_small = rate[st:end+1,st:end+1] rate_small1 = np.linalg.pinv(rate_small) # pseudo-inverse # in units dt # compute mfpt mfpt_small = np.zeros(rate_small.shape,float) part = np.exp(-v) # no unit, not normalized part_small = part[st:end+1]/np.sum(part[st:end+1]) # normalize for i in range(nbins): # fill up each row: MFPT(i,j) = starting in j, ending in i mfpt_small[i,:] = (-rate_small1[i,i]+rate_small1[i,:])/part_small[i] mfpt_small *= dt # mfpt in ps #mfpt = np.zeros(rate.shape,float) #mfpt[a:b+1,a:b+1] = mfpt_small #tau = mfpt_small[0,-1] # the longest time #tau = mfpt[st,end] if False: plt.figure() plt.plot(mfpt_small) plt.savefig("mfpt.matrix.png") if False: x3 = np.arange(len(mfpt)) plt.figure() I = x3 #range(n) J = x3 #range(n) CS = plt.contourf(I,J,mfpt.T,30) plt.xlabel("ending bin i") plt.ylabel("starting bin j") # starting in bin 12, then ... #plt.plot([x3[12],x3[12]],color='k',linewidth=2) plt.plot([x3[0],x3[-1]],[x3[12],x3[12]],color='k',linewidth=2) cbar = plt.colorbar(CS) cbar.ax.set_ylabel('mean first passage time (ps)') #plt.figure() #plt.plot(mfpt_small) plt.savefig("mfpt.matrix.%i.%i.png" %(st,end))
def calc_permeability_distribution(F, D, dx, dt, st, end, A, B, figname=None, ref=0, doprint=True): """Compute the permeability from the rate matrix and the steady-state solution ref -- reference bin, standard bin 0 (ASSUME BULK water) doprint -- whether to print partitioning prob[st] = A. (no units) prob[end] = B. (no units) so difference is Delta = A-B (no units) """ # F in units kBT, D in units A^2/ps, dx in units A # check assert st >= 0 assert end < len(F) assert ref > -1 and ref < len(F) #assert A!=0. or B!=0. rate = construct_rate_matrix_from_F_D(F, D, dx, dt) # in 1/dt, PBC # compute steady-state solution prob #----------------------------------- # prob (no units) is not normalized # solve subrate*p = vec subrate = rate[st + 1:end, st + 1:end] # covers bins [st+1,...,end-1] r1 = np.linalg.inv(subrate) # rhs of equation vec1 = np.zeros(len(subrate), float) vec2 = np.zeros(len(subrate), float) vec1[0] = -rate[st + 1, st] #vec[0] = -rate[1,0] vec2[-1] = -rate[end - 1, end] #vec[-1] = -rate[N,N+1] # p = subrate^-1 * vec p1 = np.dot(r1, vec1) p2 = np.dot(r1, vec2) # plug in vector of original size, with boundaries # end points of vector prob are kept constant at A and B prob1 = np.zeros(len(subrate) + 2, float) prob2 = np.zeros(len(subrate) + 2, float) prob1[1:-1] = p1 prob2[1:-1] = p2 prob1[0] = 1. prob2[-1] = 1. prob = A * prob1 + B * prob2 # compute flux (here constant) #----------------------------- flux1, fluxp1, fluxn1 = calc_flux(rate[st:, st:], prob1, dt) # in 1/ps flux2, fluxp2, fluxn2 = calc_flux(rate[st:, st:], prob2, dt) # in 1/ps flux, fluxp, fluxn = calc_flux(rate[st:, st:], prob, dt) # in 1/ps # with A,B # check flux is constant in steady-state with fixed boundaries #print np.all(flux==flux[0]) # not True, because of very small differences assert np.all( np.isclose( flux1, np.ones(len(flux1)) * flux1[0], rtol=1e-04, )) assert np.all( np.isclose( flux2, np.ones(len(flux2)) * flux2[0], rtol=1e-04, )) assert np.all(np.isclose( flux, np.ones(len(flux)) * flux[0], rtol=1e-04, )) #print "flux1 (in 1/ps)",flux1[0] #print "flux2 (in 1/ps)",flux2[0] #print "flux (in 1/ps)",flux[0] # compute permeability #--------------------- # particles/time = flux J = permeability * Delta-concentration-per-length # solve for permeability: P = flux*dx P = flux1[0] * dx # in A/ps, assume flux is constant # reference is naturally in bin st, put in bin ref P *= np.exp(F[ref] - F[st]) # # this is the same as the following: # P2 = -flux2[0]*dx # in A/ps, assume flux is constant # # reference is naturally in bin end, put in bin end # P2 *= np.exp(F[ref]-F[end]) # # verify # assert np.isclose(P,P2,rtol=1e-06,) h = dx * (len(prob) - 1 ) # membrane thickness, boundaries bin 0 and bin -1, in A R = 1. / P # resistance to permeability, in ps/A Deff = h * P # effective D, in A**2/ps if doprint: #print "permeability (in A/ps)",P print("h %7.2f P %10.5f Deff %10.5f R %10.5f" % (h, P, Deff, R)) # Now consider steady-state, but actually imitate equilibrium #------------------------------------------------------------ # by choosing A and B wisely # recalculate prob_equil for plotting # prob1: ref is st, prob2: ref is end, prob: not really ref # prob_equil: reference in bin ref, i.e. prob_equil[ref]=1. # this is a choice prob_equil = prob1 * np.exp(-F[st] + F[ref]) + prob2 * np.exp(-F[end] + F[ref]) if doprint: analyze_partitioning_steadystate( F, st, end, prob1, prob2, prob, ref, ) if figname is not None: plt.figure() #plt.subplot(2,1,1) plt.plot(prob1, label='left') plt.plot(prob2, label='right') rescale = max(max(prob1), max(prob2)) / max(prob_equil) #rescale=1. plt.plot(prob_equil * rescale, '-', color='grey', label='equil') plt.plot(prob, '--', color='k', lw='2', label="A=%.2f B=%.2f" % (A, B)) plt.xlabel("bin number") plt.ylabel("prob (no unit)") plt.legend(loc='best') plt.title("steady-state A*left+B*right") plt.savefig(figname) print("file written...", figname) plt.figure() #plt.subplot(2,1,2) plt.plot(fluxp, label='pos') plt.plot(fluxn, '--', label='neg') plt.xlabel("bin number") plt.ylabel("flux (1/ps)") plt.title("flux[0]=%.8f (1/ps)" % (flux[0])) plt.legend(loc='best') plt.savefig(figname + "flux.png") print("file written...", figname + "flux.png") return P, Deff, R, h, prob
def distribution_mfpt(F, D, dx, dt, b1, b2, trange): """Compute the mean first passage time (MFPT)""" # dx -- in angstrom # dt -- in ps # D -- in angstrom**2/ps # mfpt -- in ps # numbering of bins starts with 0 # init -- initial z-bin # b1 and b2 - absorbing bins assert b1 >= -1 and b2 <= len(F) and b1 + 1 < b2 # rate matrix v = F - min(F) # construct rate matrix and inverse subrate = construct_rate_matrix_from_F_D(v, D, dx, dt, pbc=False, st=b1, end=b2, side="both") # in 1/dt import scipy middle = len( subrate ) / 2 # this is initial bin "k", choose the middle # TODO not necessary ?? rho = [] cdf = [] for t in trange: mat = scipy.linalg.expm2(subrate * t) # needed in rho and cdf # (1) distribution rho(t) #------------------------ # compute rho(t|k), probability to exit at time t rho_t = -np.sum(np.dot(subrate, mat), 0) rho.append(rho_t[middle]) #print "t",t,"rho",rho_t[middle] # (2) cumulative distribution int(rho(t'),t'=0..t) #------------------------------------------------- # compute CDF of rho(t|k), probability to exit < time t # int( R e^Rt, 0..t) = [e^Rt]_0..t = e^Rt-1 cdf_t = np.diag(np.ones(len(subrate))) - mat cdf_t = np.sum(cdf_t, 0) cdf.append(cdf_t[middle]) #print "t",t,"cdf",cdf_t[middle] rho = np.array(rho) # rho contains rho(t|k) for all t values in trange print "trange", len(trange), "len", len( rho), "rho_t", rho_t.shape, "rho", rho.shape cdf = np.array(cdf) # cdf contains cdf(t|k) for all t values in trange print "trange", len(trange), "len", len( cdf), "cdf_t", cdf_t.shape, "cdf", cdf.shape # Writing data to file #---------------------- filename = "t_rho.dat" data = np.zeros((len(trange), 3)) data[:, 0] = trange data[:, 1] = rho data[:, 2] = cdf np.savetxt(filename, data) print "file written...", filename if True: # Plot rho(t|k) HERE k = MIDDLE #-------------------------------- plt.figure() plt.subplot(2, 1, 1) plt.title("P(exit at time t)") plt.plot(trange, rho, "o") plt.xlabel("t [ps]") plt.subplot(2, 1, 2) plt.semilogx(trange, rho, "o") plt.xlabel("t [ps]") plt.savefig("t_rho.png") if True: # Plot CDF(t|k) HERE k = MIDDLE #-------------------------------- fig = plt.figure() plt.subplot(2, 1, 1) plt.title("P(exit < time t)") plt.plot(trange, cdf, "o") plt.xlabel("t [ps]") plt.subplot(2, 1, 2) plt.semilogx(trange, cdf, "o") plt.xlabel("t [ps]") plt.savefig("t_rho_cdf.png") calc_statistics_rho(trange, rho) return rho, cdf
def calc_mfpt_hummer(F, D, dx, dt, b1, b2, init=None, doprint=True, dofig=False, t=None, side="right", weigh=False): """Compute the mean first passage time (MFPT)""" # dx -- in angstrom # dt -- in ps # D -- in angstrom**2/ps # mfpt -- in ps # side -- right (default), left, both # numbering of bins starts with 0 assert side in ["right", "left", "both"] # init -- initial z-bin # b1 and b2 - absorbing bins assert b1 >= -1 and b2 <= len(F) and b1 + 1 < b2 if init is None: init = b1 + 1 assert init > b1 and init < b2 # rate matrix: k1,k2 v = F - min(F) rate = construct_rate_matrix_from_F_D(v, D, dx, dt, pbc=True) # in 1/dt k1 = rate[ b1, b1 + 1] # at boundary b1 # if b1=-1, then b1+1=0, then k1=rate[-1,0], okay with PBC if b2 < len(F): k2 = rate[ b2, b2 - 1] # at boundary b2 # if b2=len(F), then b2-1=len(F)-1, then k2=rate[len(F),len(F)-1] elif b2 == len(F): k2 = rate[0, -1] # if b2=len(F), then b2-1=len(F)-1, # then k2=rate[len(F),len(F)-1] should be rate[0,-1] # construct rate matrix and inverse subrate = construct_rate_matrix_from_F_D(v, D, dx, dt, pbc=False, st=b1, end=b2, side="both") # in 1/dt # for global mfpt F_small = v[b1 + 1:b2] # submatrix part = np.exp(-(F_small - min(F_small))) # no unit if t is None: # mfpt #--------- mfpt1, tau1, std1 = get_mfpt_from_rate_k12( subrate, dt, 0, k2, part) # in ps # this is idential to "exit to right" mfpt2, tau2, std2 = get_mfpt_from_rate_k12( subrate, dt, k1, 0, part) # in ps # this is exit to the left mfpt3, tau3, std3 = get_mfpt_from_rate_k12( subrate, dt, k1, k2, part) # in ps # this is exit on both sides else: # t is not None if False: # mfpt median #------------ import scipy prop = scipy.linalg.expm2(subrate * t) mfpt1, tau1, std1 = get_median_from_rate_k12( subrate, prop, dt, 0, k2, part) # in ps # this is idential to "exit to right" mfpt2, tau2, std2 = get_median_from_rate_k12( subrate, prop, dt, k1, 0, part) # in ps # this is exit to the left mfpt3, tau3, std3 = get_median_from_rate_k12( subrate, prop, dt, k1, k2, part) # in ps # this is exit on both sides else: #if False: # TODO TODO TODO # mfpt before time t #------------------- import scipy prop = scipy.linalg.expm2(subrate * t) mfpt1, tau1, std1 = get_mfpt_from_rate_k12_before( subrate, prop, dt, 0, k2, part, t) # in ps # this is idential to "exit to right" mfpt2, tau2, std2 = get_mfpt_from_rate_k12_before( subrate, prop, dt, k1, 0, part, t) # in ps # this is exit to the left mfpt3, tau3, std3 = get_mfpt_from_rate_k12_before( subrate, prop, dt, k1, k2, part, t) # in ps # this is exit on both sides #print "check:",np.sum((mfpt1-mfpt3[::-1])**2) # check symmetry between profiles # selected mfpt #-------------- sel_mfpt1 = mfpt1[init - b1 - 1] # right sel_mfpt2 = mfpt2[init - b1 - 1] # left sel_mfpt3 = mfpt3[init - b1 - 1] # both sel_std1 = std1[init - b1 - 1] sel_std2 = std2[init - b1 - 1] sel_std3 = std3[init - b1 - 1] # checking #---------- if False: vals, vecs = np.linalg.eig(rate) print "vals rate (1/dt)", vals print "mfpt (ps)", mfpt if doprint: #rlb = right left both # This is nice printing! print "b1,b2,init", b1, b2, init, print "tau-rlb", tau1, tau2, tau3, print "maxmfpt-r", max(mfpt1), print "sel-rlb", sel_mfpt1, sel_mfpt2, sel_mfpt3, print "std", sel_std1, sel_std2, sel_std3 if dofig: plt.figure() binrange = np.arange(b1 + 1, b2) plt.plot(binrange, mfpt1, label="exit right") plt.plot(binrange, mfpt2, label="exit left") plt.plot(binrange, mfpt3, label="exit both sides") #plt.plot(binrange[0],[mfpt[0]],"o",) plt.xlabel("initial bin") plt.ylabel("MFPT (ps)") plt.legend(loc='best') plt.title("exit to the RIGHT: <tau>=%.1f ps, maxmfpt=%.1f ps" % (tau1, max(mfpt1))) plt.savefig("mfpt.hummer.vector.%i.%i.png" % ( b1, b2, )) plt.close() # choose side, for "return" value if side == "right": #mfpt = mfpt1 sel_mfpt = sel_mfpt1 if weigh: sel_mfpt = tau1 elif side == "left": #mfpt = mfpt2 sel_mfpt = sel_mfpt2 if weigh: sel_mfpt = tau2 elif side == "both": #mfpt = mfpt3 sel_mfpt = sel_mfpt3 if weigh: sel_mfpt = tau3 else: raise ValueError return sel_mfpt
def calc_mfpt(F, D, dx, dt, st, end, getmax=False, side=None): """Compute the mean first passage time (MFPT)""" # dx -- in angstrom # dt -- in ps # D -- in angstrom**2/ps # mfpt -- in ps # numbering of bins starts with 0 assert st >= 0 and end >= 0 and st < len(F) and end < len(F) assert side in ["both", "left", "right"] # absorbing sides, otherwize: reflective assert st < end # TODO ##################################### # mfpt vector #------------- # construct rate matrix and inverse v = F - min(F) rate = construct_rate_matrix_from_F_D(v, D, dx, dt, pbc=False, st=st, end=end, side=side) # in 1/dt print "st,end", st, end, rate.shape rate1 = np.linalg.inv(rate) # in units dt # construct mfpt vector mfpt = np.zeros(len(rate), float) for i in range(len(mfpt)): mfpt[i] = -np.sum(rate1[:, i]) # mfpt[i] is mfpt for starting position i mfpt *= dt # in unit "ps" maxmfpt = max(mfpt) # global mfpt #------------ F_small = v[st + 1:end] # submatrix part = np.exp(-F_small) # no unit tau = np.sum(part * mfpt) / np.sum(part) # normalized in interval # checking #---------- if False: vals, vecs = np.linalg.eig(rate) print "vals rate (1/dt)", vals print "mfpt (ps)", mfpt if True: print "st,end,side", st, end, side, print "tau (ps)", tau, print "maxmfpt (ps)", max(mfpt) if False: #True: plt.figure() if st < end: binrange = np.arange(st, end + 1) else: binrange = np.arange(end, st + 1) plt.plot(binrange, mfpt) plt.plot(binrange[0], [mfpt[0]], "o") plt.xlabel("bin") plt.ylabel("MFPT (ps)") plt.title("tau=%.1f ps, maxmfpt=%.1f ps" % (tau, max(mfpt))) plt.savefig("mfpt.vector.%i.%i.%s.png" % (st, end, side)) plt.close() if getmax: return maxmfpt else: return tau
def calc_Dpar_ratios(F, D, Drad, t, dz, dt, st=None, end=None, edges=None): """Compute average diffusion constant, in parallel layers, e.g. Drad Dave = sum_i D_i percentage-time-spent-in-bin-i where D_i is actually D_(i+1/2) using bins [st:end] = [st,st+1,...,end-1] number of used bins = end-st when st=None,end=None, then this means [:]""" # F in units kBT, D in units A^2/ps assert len(F) == len(D) v = F[st:end] # when st=None,end=None, then this means [:] d = D[st:end] drad = Drad[st:end] # average Drad: #part = np.exp(-(v-min(v))) #Dave = np.sum(d*part)/np.sum(part) # a weighted sum, normalized # ow.... watch out !!! drad = Drad[st + 1:end] # absorbing boundaries rate = construct_rate_matrix_from_F_D(F, D, dz, dt, pbc=False, st=st, end=end, side="both") # in 1/dt # reflective boundaries #rate = construct_rate_matrix_from_F_D(F,D,dz,dt,pbc=False,st=st,end=end,side=None) # in 1/dt #print "rate",rate.shape n = len(rate) vals, U = np.linalg.eig(rate) # U contains eigenvectors as columns #print "vals",vals U1 = np.linalg.inv(U) Ddiag = np.diag(drad) #UDdiagU1 = np.dot(U,np.dot(Ddiag,U1)) U1DdiagU = np.dot(U1, np.dot(Ddiag, U)) maxval = max(vals) exp_valt = np.exp((vals - maxval) * t) Deff_t = np.zeros((n, n), ) for i in range(n): for j in range(n): # for k in range(n): # Deff_t[i,j] += drad[k] * np.sum( # summation over l # U[k,:]*U1[:,j]*U[i,:]*U1[:,k] * t * exp_valt ) Deff_t[i, j] = np.sum(U1[:, j] * U[i, :] * np.diag(U1DdiagU) * t * exp_valt) # print Deff_t for i in range(n): for j in range(n): for l in range(n): for m in range(n): if m != l: Deff_t[i, j] += U1[l, j] * U[i, m] * U1DdiagU[m, l] * ( exp_valt[l] - exp_valt[m]) / (vals[l] - vals[m]) # print Deff_t import scipy.linalg Deff_t /= scipy.linalg.expm((rate - np.diag(np.ones(n)) * maxval) * t) * t print("t", t) print(Deff_t) return Deff_t
def distribution_mfpt(F,D,dx,dt,b1,b2,trange): """Compute the mean first passage time (MFPT)""" # dx -- in angstrom # dt -- in ps # D -- in angstrom**2/ps # mfpt -- in ps # numbering of bins starts with 0 # init -- initial z-bin # b1 and b2 - absorbing bins assert b1>=-1 and b2<=len(F) and b1+1<b2 # rate matrix v = F-min(F) # construct rate matrix and inverse subrate = construct_rate_matrix_from_F_D(v,D,dx,dt,pbc=False,st=b1,end=b2,side="both") # in 1/dt import scipy middle = len(subrate)/2 # this is initial bin "k", choose the middle # TODO not necessary ?? rho = [] cdf = [] for t in trange: mat = scipy.linalg.expm2(subrate*t) # needed in rho and cdf # (1) distribution rho(t) #------------------------ # compute rho(t|k), probability to exit at time t rho_t = -np.sum(np.dot(subrate,mat),0) rho.append(rho_t[middle]) #print "t",t,"rho",rho_t[middle] # (2) cumulative distribution int(rho(t'),t'=0..t) #------------------------------------------------- # compute CDF of rho(t|k), probability to exit < time t # int( R e^Rt, 0..t) = [e^Rt]_0..t = e^Rt-1 cdf_t = np.diag(np.ones(len(subrate)))-mat cdf_t = np.sum(cdf_t,0) cdf.append(cdf_t[middle]) #print "t",t,"cdf",cdf_t[middle] rho = np.array(rho) # rho contains rho(t|k) for all t values in trange print("trange",len(trange),"len",len(rho),"rho_t",rho_t.shape, "rho",rho.shape) cdf = np.array(cdf) # cdf contains cdf(t|k) for all t values in trange print("trange",len(trange),"len",len(cdf),"cdf_t",cdf_t.shape, "cdf",cdf.shape) # Writing data to file #---------------------- filename = "t_rho.dat" data = np.zeros((len(trange),3)) data[:,0] = trange data[:,1] = rho data[:,2] = cdf np.savetxt(filename,data) print("file written...", filename) if True: # Plot rho(t|k) HERE k = MIDDLE #-------------------------------- plt.figure() plt.subplot(2,1,1) plt.title("P(exit at time t)") plt.plot(trange,rho,"o") plt.xlabel("t [ps]") plt.subplot(2,1,2) plt.semilogx(trange,rho,"o") plt.xlabel("t [ps]") plt.savefig("t_rho.png") if True: # Plot CDF(t|k) HERE k = MIDDLE #-------------------------------- fig = plt.figure() plt.subplot(2,1,1) plt.title("P(exit < time t)") plt.plot(trange,cdf,"o") plt.xlabel("t [ps]") plt.subplot(2,1,2) plt.semilogx(trange,cdf,"o") plt.xlabel("t [ps]") plt.savefig("t_rho_cdf.png") calc_statistics_rho(trange,rho) return rho,cdf
def calc_mfpt_hummer(F,D,dx,dt,b1,b2,init=None,doprint=True,dofig=False,t=None,side="right",weigh=False): """Compute the mean first passage time (MFPT)""" # dx -- in angstrom # dt -- in ps # D -- in angstrom**2/ps # mfpt -- in ps # side -- right (default), left, both # numbering of bins starts with 0 # t -- default is None to compute mean fpt, assert side in ["right","left","both"] # init -- initial z-bin # b1 and b2 - absorbing bins assert b1>=-1 and b2<=len(F) and b1+1<b2 if init is None: init = b1+1 assert init>b1 and init<b2 # rate matrix: k1,k2 v = F-min(F) rate = construct_rate_matrix_from_F_D(v,D,dx,dt,pbc=True) # in 1/dt k1 = rate[b1,b1+1] # at boundary b1 # if b1=-1, then b1+1=0, then k1=rate[-1,0], okay with PBC if b2 < len(F): k2 = rate[b2,b2-1] # at boundary b2 # if b2=len(F), then b2-1=len(F)-1, then k2=rate[len(F),len(F)-1] elif b2 == len(F): k2 = rate[0,-1] # if b2=len(F), then b2-1=len(F)-1, # then k2=rate[len(F),len(F)-1] should be rate[0,-1] # construct rate matrix and inverse subrate = construct_rate_matrix_from_F_D(v,D,dx,dt,pbc=False,st=b1,end=b2,side="both") # in 1/dt # for global mfpt F_small = v[b1+1:b2] # submatrix part = np.exp(-(F_small-min(F_small))) # no unit if t is None: # mfpt #--------- mfpt1,tau1,std1 = get_mfpt_from_rate_k12(subrate,dt,0,k2,part) # in ps # this is idential to "exit to right" mfpt2,tau2,std2 = get_mfpt_from_rate_k12(subrate,dt,k1,0,part) # in ps # this is exit to the left mfpt3,tau3,std3 = get_mfpt_from_rate_k12(subrate,dt,k1,k2,part) # in ps # this is exit on both sides elif t == "median": # t is not None, t is not a float # mfpt median #------------ import scipy prop = scipy.linalg.expm2(subrate*t) mfpt1,tau1,std1 = get_median_from_rate_k12(subrate,prop,dt,0,k2,part) # in ps # this is idential to "exit to right" mfpt2,tau2,std2 = get_median_from_rate_k12(subrate,prop,dt,k1,0,part) # in ps # this is exit to the left mfpt3,tau3,std3 = get_median_from_rate_k12(subrate,prop,dt,k1,k2,part) # in ps # this is exit on both sides elif isinstance(t,float): # t is a float # mfpt before time t #------------------- assert t>0. # t should be a positive waiting time import scipy prop = scipy.linalg.expm2(subrate*t) mfpt1,tau1,std1 = get_mfpt_from_rate_k12_before(subrate,prop,dt,0,k2,part,t) # in ps # this is idential to "exit to right" mfpt2,tau2,std2 = get_mfpt_from_rate_k12_before(subrate,prop,dt,k1,0,part,t) # in ps # this is exit to the left mfpt3,tau3,std3 = get_mfpt_from_rate_k12_before(subrate,prop,dt,k1,k2,part,t) # in ps # this is exit on both sides #print "check:",np.sum((mfpt1-mfpt3[::-1])**2) # check symmetry between profiles # selected mfpt #-------------- sel_mfpt1 = mfpt1[init-b1-1] # right sel_mfpt2 = mfpt2[init-b1-1] # left sel_mfpt3 = mfpt3[init-b1-1] # both sel_std1 = std1[init-b1-1] sel_std2 = std2[init-b1-1] sel_std3 = std3[init-b1-1] # checking #---------- if False: vals,vecs = np.linalg.eig(rate) print("vals rate (1/dt)",vals) print("mfpt (ps)",mfpt) if doprint: #rlb = right left both # This is nice printing! print("b1,b2,init",b1,b2,init, end=' ') print("tau-rlb",tau1,tau2,tau3, end=' ') print("maxmfpt-r", max(mfpt1), end=' ') print("sel-rlb", sel_mfpt1, sel_mfpt2, sel_mfpt3, end=' ') print("std", sel_std1,sel_std2,sel_std3) if dofig: plt.figure() binrange = np.arange(b1+1,b2) plt.plot(binrange,mfpt1,label="exit right") plt.plot(binrange,mfpt2,label="exit left") plt.plot(binrange,mfpt3,label="exit both sides") #plt.plot(binrange[0],[mfpt[0]],"o",) plt.xlabel("initial bin") plt.ylabel("MFPT (ps)") plt.legend(loc='best') plt.title("exit to the RIGHT: <tau>=%.1f ps, maxmfpt=%.1f ps" %(tau1,max(mfpt1))) plt.savefig("mfpt.hummer.vector.%i.%i.png" %(b1,b2,)) plt.close() # choose side, for "return" value if side == "right": #mfpt = mfpt1 sel_mfpt = sel_mfpt1 if weigh: sel_mfpt = tau1 elif side == "left": #mfpt = mfpt2 sel_mfpt = sel_mfpt2 if weigh: sel_mfpt = tau2 elif side == "both": #mfpt = mfpt3 sel_mfpt = sel_mfpt3 if weigh: sel_mfpt = tau3 else: raise ValueError return sel_mfpt
def calc_mfpt(F,D,dx,dt,st,end,getmax=False,side=None): """Compute the mean first passage time (MFPT)""" # dx -- in angstrom # dt -- in ps # D -- in angstrom**2/ps # mfpt -- in ps # numbering of bins starts with 0 assert st>=0 and end>=0 and st<len(F) and end<len(F) assert side in ["both","left","right"] # absorbing sides, otherwize: reflective assert st < end # TODO ##################################### # mfpt vector #------------- # construct rate matrix and inverse v = F-min(F) rate = construct_rate_matrix_from_F_D(v,D,dx,dt,pbc=False,st=st,end=end,side=side) # in 1/dt print("st,end",st,end,rate.shape) rate1 = np.linalg.inv(rate) # in units dt # construct mfpt vector mfpt = np.zeros(len(rate),float) for i in range(len(mfpt)): mfpt[i] = -np.sum(rate1[:,i]) # mfpt[i] is mfpt for starting position i mfpt *= dt # in unit "ps" maxmfpt = max(mfpt) # global mfpt #------------ F_small = v[st+1:end] # submatrix part = np.exp(-F_small) # no unit tau = np.sum(part*mfpt)/np.sum(part) # normalized in interval # checking #---------- if False: vals,vecs = np.linalg.eig(rate) print("vals rate (1/dt)",vals) print("mfpt (ps)",mfpt) if True: print("st,end,side",st,end,side, end=' ') print("tau (ps)",tau, end=' ') print("maxmfpt (ps)", max(mfpt)) if False: #True: plt.figure() if st<end: binrange = np.arange(st,end+1) else: binrange = np.arange(end,st+1) plt.plot(binrange,mfpt) plt.plot(binrange[0],[mfpt[0]],"o") plt.xlabel("bin") plt.ylabel("MFPT (ps)") plt.title("tau=%.1f ps, maxmfpt=%.1f ps" %(tau,max(mfpt))) plt.savefig("mfpt.vector.%i.%i.%s.png" %(st,end,side)) plt.close() if getmax: return maxmfpt else: return tau
def calc_permeability_distribution(F,D,dx,dt,st,end,A,B,figname=None,ref=0,doprint=True): """Compute the permeability from the rate matrix and the steady-state solution ref -- reference bin, standard bin 0 (ASSUME BULK water) doprint -- whether to print partitioning prob[st] = A. (no units) prob[end] = B. (no units) so difference is Delta = A-B (no units) """ # F in units kBT, D in units A^2/ps, dx in units A # check assert st>=0 assert end<len(F) assert ref>-1 and ref<len(F) #assert A!=0. or B!=0. rate = construct_rate_matrix_from_F_D(F,D,dx,dt) # in 1/dt, PBC # compute steady-state solution prob #----------------------------------- # prob (no units) is not normalized # solve subrate*p = vec subrate = rate[st+1:end,st+1:end] # covers bins [st+1,...,end-1] r1 = np.linalg.inv(subrate) # rhs of equation vec1 = np.zeros(len(subrate),float) vec2 = np.zeros(len(subrate),float) vec1[0] = -rate[st+1,st] #vec[0] = -rate[1,0] vec2[-1] = -rate[end-1,end] #vec[-1] = -rate[N,N+1] # p = subrate^-1 * vec p1 = np.dot(r1,vec1) p2 = np.dot(r1,vec2) # plug in vector of original size, with boundaries # end points of vector prob are kept constant at A and B prob1 = np.zeros(len(subrate)+2,float) prob2 = np.zeros(len(subrate)+2,float) prob1[1:-1] = p1 prob2[1:-1] = p2 prob1[0] = 1. prob2[-1] = 1. prob = A*prob1 + B*prob2 # compute flux (here constant) #----------------------------- flux1,fluxp1,fluxn1 = calc_flux(rate[st:,st:],prob1,dt) # in 1/ps flux2,fluxp2,fluxn2 = calc_flux(rate[st:,st:],prob2,dt) # in 1/ps flux, fluxp, fluxn = calc_flux(rate[st:,st:],prob, dt) # in 1/ps # with A,B # check flux is constant in steady-state with fixed boundaries #print np.all(flux==flux[0]) # not True, because of very small differences assert np.all(np.isclose(flux1, np.ones(len(flux1))*flux1[0], rtol=1e-04,) ) assert np.all(np.isclose(flux2, np.ones(len(flux2))*flux2[0], rtol=1e-04,) ) assert np.all(np.isclose(flux, np.ones(len(flux)) *flux[0], rtol=1e-04,) ) #print "flux1 (in 1/ps)",flux1[0] #print "flux2 (in 1/ps)",flux2[0] #print "flux (in 1/ps)",flux[0] # compute permeability #--------------------- # particles/time = flux J = permeability * Delta-concentration-per-length # solve for permeability: P = flux*dx P = flux1[0]*dx # in A/ps, assume flux is constant # reference is naturally in bin st, put in bin ref P *= np.exp(F[ref]-F[st]) # # this is the same as the following: # P2 = -flux2[0]*dx # in A/ps, assume flux is constant # # reference is naturally in bin end, put in bin end # P2 *= np.exp(F[ref]-F[end]) # # verify # assert np.isclose(P,P2,rtol=1e-06,) h = dx*(len(prob)-1) # membrane thickness, boundaries bin 0 and bin -1, in A R = 1./P # resistance to permeability, in ps/A Deff = h*P # effective D, in A**2/ps if doprint: #print "permeability (in A/ps)",P print("h %7.2f P %10.5f Deff %10.5f R %10.5f"%(h,P,Deff,R)) # Now consider steady-state, but actually imitate equilibrium #------------------------------------------------------------ # by choosing A and B wisely # recalculate prob_equil for plotting # prob1: ref is st, prob2: ref is end, prob: not really ref # prob_equil: reference in bin ref, i.e. prob_equil[ref]=1. # this is a choice prob_equil = prob1*np.exp(-F[st]+F[ref]) + prob2*np.exp(-F[end]+F[ref]) if doprint: analyze_partitioning_steadystate(F,st,end,prob1,prob2,prob,ref,) if figname is not None: plt.figure() #plt.subplot(2,1,1) plt.plot(prob1,label='left') plt.plot(prob2,label='right') rescale = max(max(prob1),max(prob2))/max(prob_equil) #rescale=1. plt.plot(prob_equil*rescale,'-',color='grey',label='equil') plt.plot(prob,'--',color='k',lw='2',label="A=%.2f B=%.2f"%(A,B)) plt.xlabel("bin number") plt.ylabel("prob (no unit)") plt.legend(loc='best') plt.title("steady-state A*left+B*right") plt.savefig(figname) print("file written...",figname) plt.figure() #plt.subplot(2,1,2) plt.plot(fluxp,label='pos') plt.plot(fluxn,'--',label='neg') plt.xlabel("bin number") plt.ylabel("flux (1/ps)") plt.title("flux[0]=%f.4"%(flux[0])) plt.legend(loc='best') plt.savefig(figname+"flux.png") print("file written...",figname+"flux.png") return P,Deff,R,h,prob