Ejemplo n.º 1
0
    def deriv(self, t, yt):
        rho, q, p = self.unpack(yt)

        cq = np.einsum('nk,nk->n',self._c,q)
        ham_t = self.ham.sys + np.einsum('nab,n->ab',self._hamsb,cq)
        F_avg = np.einsum('nab,ba->n',self._hamsb,rho).real

        dq = p.copy()
        dp = - self._omegasq*q \
             - np.einsum('nk,n->nk',self._c,F_avg) 

        drho = -1j/const.hbar * utils.commutator(ham_t,rho)

        return self.pack(drho, dq, dp)
Ejemplo n.º 2
0
    def deriv(self, t, yt):
        rho, q, p = self.unpack(yt)

        cq = np.einsum('nk,nk->n', self._c, q)
        ham_t = np.einsum('nab,n->ab', self._hamsb, cq)
        ham_t = self.ham.to_interaction(self.ham.site2eig(ham_t), t)

        hamsb_int = list()
        for n, hamsb in enumerate(self._hamsb):
            hamsb_int_n = self.ham.to_interaction(self.ham.site2eig(hamsb), t)
            hamsb_int.append(hamsb_int_n)
        hamsb_int = np.array(hamsb_int)
        F_avg = np.einsum('nab,ba->n', hamsb_int, rho).real

        dq = p.copy()
        dp = - self._omegasq*q \
             - np.einsum('nk,n->nk',self._c,F_avg)

        drho = -1j / const.hbar * utils.commutator(ham_t, rho)

        return self.pack(drho, dq, dp)
Ejemplo n.º 3
0
    def heom_deriv(self, t, rho):
        hbar = const.hbar
        drho = []
        if self.ham.sd[0].sd_type == 'ohmic-lorentz':
            # Chen Eq. (15)
            cjk_over_gammajk = np.einsum('jk,jk->j', self.c, 1./self.gamma)
            for n, nmat in enumerate(self.nmats): 
                L = np.sum(nmat)
                rho_n = rho[n]
                drho_n = -1j/hbar * utils.commutator(self.ham.sys,rho_n)
                njk_gammajk = np.sum(nmat*self.gamma)
                for j in range(self.ham.nbath):
                    Fj = self.ham.sysbath[j]    # this is like |j><j|
                    lamdaj = self.ham.sd[j].lamda
                    omega_cj = self.ham.sd[j].omega_c
                    for k in range(self.Kmax+1):
                        if self.is_scaled:
                            scale_minus = np.sqrt(nmat[j,k]/np.abs(self.c[j,k]))
                        else:
                            scale_minus = nmat[j,k] 

                        rho_njkminus = self.rho_minus(rho,n,j,k)
                        drho_n -= ( (1j/hbar)*scale_minus
                                   *(self.c[j,k]*np.dot(Fj,rho_njkminus)
                                   -self.c[j,k].conjugate()*np.dot(rho_njkminus,Fj)) )
                    # Note: The real part is taken because the Ishizaki-Tanimura
                    # truncation yields a sum over excluded Matsubara frequencies,
                    # which are purely real; the difference between the *real*
                    # finite K expansion and 2 lamda kT / omega_c gives the
                    # neglected contribution (in Markovian "TNL" approximation).
                    if self.truncation_type == 'Ishizaki-Tanimura':
                        drho_n -= ( (2*lamdaj*const.kT/(hbar**2*omega_cj) 
                                     - cjk_over_gammajk[j]/hbar).real
                                   *utils.commutator(Fj, utils.commutator(Fj, rho_n)) )
                    if L < self.Lmax:
                        # If L == self.Lmax, then rho_nkplus = 0
                        rho_njkplus_sum = np.zeros_like(rho_n)
                        for k in range(self.Kmax+1):
                            if self.is_scaled:
                                scale_plus = np.sqrt((nmat[j,k]+1)*np.abs(self.c[j,k]))
                            else:
                                scale_plus = 1. 
                            rho_njkplus_sum += scale_plus*self.rho_plus(rho,n,j,k)
                        drho_n -= 1j*utils.commutator(Fj, rho_njkplus_sum)
                drho_n -= njk_gammajk*rho_n
                drho.append(drho_n)

#        TODO(TCB): Finish this, i.e. HEOM for single-oscillator(s) 
#        elif self.ham.sd[0].sd_type == 'oscillators':
#            # Liu App. C, Eq. (C1)
#            for m in range(len(self.nmats)):
#                mmat = self.nmats[m]
#                Lm = np.sum(mmat)
#                for n in range(len(self.nmats)): 
#                    nmat = self.nmats[n]
#                    Ln = np.sum(nmat)
#                    rho_mn = rho[m,n]
#                    drho_mn = np.zeros_like(rho_mn)
#                    drho_mn = -1j/hbar * utils.commutator(self.ham.sys,rho_mn)
#                    njk_gammajk = 0.
#
#                    # more here
#                    drho.append(drho_mn)

        return np.array(drho)
Ejemplo n.º 4
0
    def heom_deriv(self, t, rho):
        hbar = const.hbar
        drho = list()
        if self.ham.sd[0].sd_type == 'ohmic-lorentz':
            # Chen Eq. (15)
            cjk_over_gammajk = np.einsum('jk,jk->j', self.c, 1. / self.gamma)
            for n, nmat in enumerate(self.nmats):
                L = np.sum(nmat)
                rho_n = rho[n]
                drho_n = -1j / hbar * utils.commutator(self.ham.sys, rho_n)
                njk_gammajk = np.sum(nmat * self.gamma)
                for j in range(self.ham.nbath):
                    Fj = self.ham.sysbath[j]  # this is like |j><j|
                    lamdaj = self.ham.sd[j].lamda
                    omega_cj = self.ham.sd[j].omega_c
                    for k in range(self.Kmax + 1):
                        if self.is_scaled:
                            scale_minus = np.sqrt(nmat[j, k] /
                                                  np.abs(self.c[j, k]))
                        else:
                            scale_minus = nmat[j, k]

                        rho_njkminus = self.rho_minus(rho, n, j, k)
                        drho_n -= ((1j / hbar) * scale_minus *
                                   (self.c[j, k] * np.dot(Fj, rho_njkminus) -
                                    self.c[j, k].conjugate() *
                                    np.dot(rho_njkminus, Fj)))
                    # Note: The real part is taken because the Ishizaki-Tanimura
                    # truncation yields a sum over excluded Matsubara frequencies,
                    # which are purely real; the difference between the *real*
                    # finite K expansion and 2 lamda kT / omega_c gives the
                    # neglected contribution (in Markovian "TNL" approximation).
                    if self.K_truncation == 'Ishizaki-Tanimura':
                        drho_n -= (
                            (2 * lamdaj * const.kT / (hbar**2 * omega_cj) -
                             cjk_over_gammajk[j] / hbar).real *
                            utils.commutator(Fj, utils.commutator(Fj, rho_n)))
                    if L < self.Lmax:
                        # If L == self.Lmax, then rho_nkplus = 0
                        rho_njkplus_sum = np.zeros_like(rho_n)
                        for k in range(self.Kmax + 1):
                            if self.is_scaled:
                                scale_plus = np.sqrt(
                                    (nmat[j, k] + 1) * np.abs(self.c[j, k]))
                            else:
                                scale_plus = 1.
                            rho_njkplus_sum += scale_plus * self.rho_plus(
                                rho, n, j, k)
                        drho_n -= 1j * utils.commutator(Fj, rho_njkplus_sum)

                    if self.L_truncation == 'TL' and L == self.Lmax:
                        E, evec = utils.diagonalize(self.ham.sys)
                        Q_j = np.zeros((self.ham.nsite, self.ham.nsite),
                                       dtype=np.complex)
                        for a in range(self.ham.nsite):
                            aouter = np.outer(evec[:, a], evec[:, a])
                            for b in range(self.ham.nsite):
                                bouter = np.outer(evec[:, b], evec[:, b])
                                if self.is_scaled:
                                    num = np.sqrt(nmat[j, k] + 1) * self.c[
                                        j, :] * (1. - np.exp(
                                            -self.gamma[j, :] * t - 1j *
                                            self.ham.omega_diff[a, b] * t))
                                else:
                                    num = self.c[j, :] * (1. - np.exp(
                                        -self.gamma[j, :] * t -
                                        1j * self.ham.omega_diff[a, b] * t))

                                denom = self.gamma[
                                    j, :] + 1j * self.ham.omega_diff[a, b]
                                Q_j += np.sum(num / denom) * np.dot(
                                    aouter, np.dot(self.ham.sysbath[j],
                                                   bouter))

                        rho_njkplus_sum = -(1j / hbar) * (
                            np.dot(Q_j, rho_n) - np.dot(rho_n,
                                                        np.conj(Q_j).T))
                        drho_n -= 1j * utils.commutator(Fj, rho_njkplus_sum)

                #       for k in range(self.Kmax+1):
                #           if self.is_scaled:
                #               scale_plus = np.sqrt((nmat[j,k]+1)*np.abs(self.c[j,k]))
                #           else:
                #               scale_plus = 1.
                #           rho_njkplus_sum += scale_plus*self.rho_plus(rho,n,j,k)
                #
                #

                drho_n -= njk_gammajk * rho_n
                drho.append(drho_n)

#        TODO(TCB): Finish this, i.e. HEOM for single-oscillator(s)
#        elif self.ham.sd[0].sd_type == 'oscillators':
#            # Liu App. C, Eq. (C1)
#            for m in range(len(self.nmats)):
#                mmat = self.nmats[m]
#                Lm = np.sum(mmat)
#                for n in range(len(self.nmats)):
#                    nmat = self.nmats[n]
#                    Ln = np.sum(nmat)
#                    rho_mn = rho[m,n]
#                    drho_mn = np.zeros_like(rho_mn)
#                    drho_mn = -1j/hbar * utils.commutator(self.ham.sys,rho_mn)
#                    njk_gammajk = 0.
#
#                    # more here
#                    drho.append(drho_mn)

        return np.array(drho)
Ejemplo n.º 5
0
    def heom_deriv(self, t, rho):
        hbar = const.hbar
        drho = list() 
        if self.ham.sd[0].sd_type == 'ohmic-lorentz':
            # Chen Eq. (15)
            cjk_over_gammajk_re = np.einsum('jk,jk->j', self.c, 1./self.gamma).real
            for n, nmat in enumerate(self.nmats): 
                L = np.sum(nmat)
                rho_n = rho[n]
                drho_n = -1j/hbar * utils.commutator(self.ham.sys,rho_n)
                drho_n -= np.sum(nmat*self.gamma)*rho_n
                for j in range(self.ham.nbath):
                    Fj = self.ham.sysbath[j]    # this is like |j><j|
                    lamdaj = self.ham.sd[j].lamda
                    omega_cj = self.ham.sd[j].omega_c
                    if self.K_truncation == 'Ishizaki-Tanimura':
                        drho_n -= (1./hbar**2)*( 
                                (2*lamdaj*const.kT/omega_cj - cjk_over_gammajk_re[j])
                                   *utils.commutator(Fj, utils.commutator(Fj, rho_n)) )
                    if L < self.Lmax:
                        # If L == self.Lmax, then rho_nkplus = 0
                        rho_njkplus_sum = np.zeros_like(rho_n)
                        for k in range(self.Nk):
                            rho_njkplus_sum += self.rho_plus(rho,n,j,k)
                        drho_n -= 1j*utils.commutator(Fj, rho_njkplus_sum)
                    
                    if self.L_truncation == 'TL' and L==self.Lmax:
                        E, evec = utils.diagonalize(self.ham.sys)
                        Q_j=np.zeros((self.ham.nsite,self.ham.nsite),dtype=np.complex)
                        for a in range(self.ham.nsite):
                            aouter = np.outer(evec[:,a],evec[:,a])
                            for b in range(self.ham.nsite):
                                bouter = np.outer(evec[:,b],evec[:,b])
                                num = self.c[j,:]*(1.-np.exp(-self.gamma[j,:]*t
                                        -1j*self.ham.omega_diff[a,b]*t))
                                denom = self.gamma[j,:]+1j*self.ham.omega_diff[a,b]  
                                Q_j += np.sum(num/denom)*np.dot(aouter,np.dot(self.ham.sysbath[j],bouter))

                        rho_njkplus_sum = -(1j/hbar)*(np.dot(Q_j,rho_n)-np.dot(rho_n,np.conj(Q_j).T))
                        drho_n -= 1j*utils.commutator(Fj, rho_njkplus_sum)
 
                    
                    for k in range(self.Nk):
                        rho_njkminus = self.rho_minus(rho,n,j,k)
                        drho_n -= (1j/hbar**2)*( nmat[j,k]
                                   *(self.c[j,k]*np.dot(Fj,rho_njkminus)
                                    -self.c[j,k].conjugate()*np.dot(rho_njkminus,Fj)) )
                drho.append(drho_n)
        elif self.ham.sd[0].sd_type == 'ohmic-exp' or self.ham.sd[0].sd_type == 'cubic-exp':
            # Chen Eq. (15)
            beta = 1./const.kT
            cjk_over_gammajk_re = np.einsum('jk,jk->j', self.c, 1./self.gamma).real
            for nab, nabmat in enumerate(self.nmats):
                L = np.sum(nabmat)
                nmat = nabmat[:,:self.Nk]
                amat = nabmat[:,self.Nk:self.Nk+self.nlorentz]
                bmat = nabmat[:,self.Nk+self.nlorentz:self.Nk+2*self.nlorentz]
                rho_nab = rho[nab]
                drho_nab = -1j/hbar * utils.commutator(self.ham.sys,rho_nab)
                drho_nab -=    np.sum((amat+bmat)*self.Gamma)*rho_nab
                drho_nab -= 1j*np.sum((amat-bmat)*self.Omega)*rho_nab
                drho_nab -= np.sum(nmat*self.gamma)*rho_nab
                for j in range(self.ham.nbath):
                    Fj = self.ham.sysbath[j]    # this is like |j><j|
                    lamdaj = self.ham.sd[j].lamda
                    omega_cj = self.ham.sd[j].omega_c
                    #if self.truncation_type == 'Ishizaki-Tanimura':
                    #    drho_nab -= (1./hbar**2)*(
                    #            (2*lamdaj*const.kT/omega_cj - cjk_over_gammajk_re[j])
                    #               *utils.commutator(Fj, utils.commutator(Fj, rho_nab)) )
                    if L < self.Lmax:
                        # If L == self.Lmax, then rho_nabkplus = 0
                        rho_nabjkplus_sum = np.zeros_like(rho_nab)
                        for k in range(self.Nk+2*self.nlorentz):
                            rho_nabjkplus_sum += self.rho_plus(rho,nab,j,k)
                        drho_nab -= 1j*utils.commutator(Fj, rho_nabjkplus_sum)
                    
                    for k in range(self.Nk):
                        rho_nabjkminus = self.rho_minus(rho,nab,j,k)
                        drho_nab -= (1j/hbar**2)*( nmat[j,k]*self.c[j,k]
                                                  *utils.commutator(Fj, rho_nabjkminus) )
                    for l in range(self.nlorentz):
                        rho_nabjkminus = self.rho_minus(rho,nab,j,self.Nk+l)
                        drho_nab -= (1j/hbar)*( amat[j,l]
                                        * self.p[j,l]/(8*self.Omega[j,l]*self.Gamma[j,l])
                                        * (self._coth_b_OminusG[j,l] * utils.commutator(Fj, rho_nabjkminus)
                                           + utils.anticommutator(Fj, rho_nabjkminus)) )
                    for l in range(self.nlorentz):
                        rho_nabjkminus = self.rho_minus(rho,nab,j,self.Nk+self.nlorentz+l)
                        drho_nab -= (1j/hbar)*( bmat[j,l]
                                        * self.p[j,l]/(8*self.Omega[j,l]*self.Gamma[j,l])
                                        * (self._coth_b_OplusG[j,l] * utils.commutator(Fj, rho_nabjkminus)
                                           - utils.anticommutator(Fj, rho_nabjkminus)) )
                drho.append(drho_nab)

        return np.array(drho)