Exemple #1
0
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
Exemple #2
0
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
Exemple #3
0
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
Exemple #4
0
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
Exemple #5
0
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
Exemple #6
0
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
Exemple #7
0
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
Exemple #8
0
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))
Exemple #9
0
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))
Exemple #10
0
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
Exemple #11
0
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
Exemple #12
0
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
Exemple #13
0
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
Exemple #14
0
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
Exemple #15
0
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
Exemple #16
0
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
Exemple #17
0
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
Exemple #18
0
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