Ejemplo n.º 1
0
 def density_fit(self, auxbasis=None, with_df=None):
     from pyscf.mp import dfmp2
     mymp = dfmp2.DFMP2(self._scf, self.frozen, self.mo_coeff, self.mo_occ)
     if with_df is not None:
         mymp.with_df = with_df
     if mymp.with_df.auxbasis != auxbasis:
         mymp.with_df = copy.copy(mymp.with_df)
         mymp.with_df.auxbasis = auxbasis
     return mymp
Ejemplo n.º 2
0
def RMP2(mf, frozen=0, mo_coeff=None, mo_occ=None):
    __doc__ = mp2.RMP2.__doc__
    from pyscf import lib
    from pyscf.soscf import newton_ah

    if isinstance(mf, scf.uhf.UHF):
        raise RuntimeError('RMP2 cannot be used with UHF method.')
    elif isinstance(mf, scf.rohf.ROHF):
        lib.logger.warn(mf, 'RMP2 method does not support ROHF method. ROHF object '
                        'is converted to UHF object and UMP2 method is called.')
        return UMP2(mf, frozen, mo_coeff, mo_occ)

    if isinstance(mf, newton_ah._CIAH_SOSCF) or not isinstance(mf, scf.hf.RHF):
        mf = mf.to_rhf()

    if getattr(mf, 'with_df', None):
        return dfmp2.DFMP2(mf, frozen, mo_coeff, mo_occ)
    else:
        return mp2.RMP2(mf, frozen, mo_coeff, mo_occ)
Ejemplo n.º 3
0
def solve (mol, nel, cf_core, cf_gs, ImpOrbs, chempot=0., n_orth=0, FrozenPot=None, mf_tot=None):
    # cf_core : core orbitals (in AO basis, assumed orthonormal)
    # cf_gs   : guess orbitals (in AO basis)
    # ImpOrbs : cf_gs -> impurity orbitals transformation
    # n_orth  : number of orthonormal orbitals in cf_gs [1..n_orth]

    mol_ = gto.Mole()
    mol_.build (verbose=0)
    mol_.nelectron = nel
    mol_.incore_anyway = True

    cfx = cf_gs
    print("cfx shape", cfx.shape)
    Sf  = mol.intor_symmetric('cint1e_ovlp_sph')
    Hc  = mol.intor_symmetric('cint1e_kin_sph') \
        + mol.intor_symmetric('cint1e_nuc_sph') \
        + FrozenPot

    occ = np.zeros((cfx.shape[1],))
    occ[:nel//2] = 2.

    # core contributions
    dm_core = np.dot(cf_core, cf_core.T)*2
    jk_core = scf.hf.get_veff (mol, dm_core)
    e_core  =     np.trace(np.dot(Hc, dm_core)) \
            + 0.5*np.trace(np.dot(jk_core, dm_core))

    # transform integrals
    Sp = np.dot(cfx.T, np.dot(Sf, cfx))
    Hp = np.dot(cfx.T, np.dot(Hc, cfx))
    jkp = np.dot(cfx.T, np.dot(jk_core, cfx))


    # density fitting ============================================================
    # mf = scf.RHF(mol).density_fit()     # this should be moved out of to the parent directory, to avoid repetition
    # mf.with_df._cderi_to_save = 'saved_cderi.h5' # rank-3 decomposition
    # mf.kernel()                    ### moved these three lines to orbital_selection_fc

    auxmol = df.incore.format_aux_basis(mol, auxbasis='weigend')
    j3c    = df.incore.aux_e2(mol, auxmol, intor='cint3c2e_sph', aosym='s1')
    nao    = mol.nao_nr()
    naoaux = auxmol.nao_nr()
    j3c    = j3c.reshape(nao,nao,naoaux) # (ij|L)
    print("j3c shape", j3c.shape)
    j2c    = df.incore.fill_2c2e(mol, auxmol) #(L|M) overlap matrix between auxiliary basis functions

    #the eri is (ij|kl) = \sum_LM (ij|L) (L|M) (M|kl)
    omega = sla.inv(j2c)
    eps,U = sla.eigh(omega)
    #after this transformation the eri is (ij|kl) = \sum_L (ij|L) (L|kl)
    j3c   = np.dot(np.dot(j3c,U),np.diag(np.sqrt(eps)))

    #this part is slow, as we again store the whole eri_df
    # conv = np.einsum('prl,pi,rj->ijl', j3c, cfx, cfx)
    conv = np.einsum('prl,pi->irl',j3c,cfx)
    conv = np.einsum('irl,rj->ijl',conv,cfx)
    df_eri = np.einsum('ijm,klm->ijkl',conv,conv)

    intsp_df = ao2mo.restore(4, df_eri, cfx.shape[1])
    print("DF instp", intsp_df.shape)
    # =============================================================================

    # intsp = ao2mo.outcore.full_iofree (mol, cfx)    #TODO: this we need to calculate on the fly using generator f'n
    # print("intsp shape", intsp.shape)

    # orthogonalize cf [virtuals]
    cf  = np.zeros((cfx.shape[1],)*2,)
    if n_orth > 0:
        assert (n_orth <= cfx.shape[1])
        assert (np.allclose(np.eye(n_orth), Sp[:n_orth,:n_orth]))
    else:
        n_orth = 0

    cf[:n_orth,:n_orth] = np.eye(n_orth)
    if n_orth < cfx.shape[1]:
        val, vec = sla.eigh(-Sp[n_orth:,n_orth:])
        idx = -val > 1.e-12
        U = np.dot(vec[:,idx]*1./(np.sqrt(-val[idx])), \
                   vec[:,idx].T)
        cf[n_orth:,n_orth:] = U

    # define ImpOrbs projection
    Xp = np.dot(ImpOrbs, ImpOrbs.T)

    # Si = np.dot(ImpOrbs.T, np.dot(Sp, ImpOrbs))
    # Mp = np.dot(ImpOrbs, np.dot(sla.inv(Si), ImpOrbs.T))
    Np = np.dot(Sp, Xp)
    # print np.allclose(Np, np.dot(Np, np.dot(Mp, Np)))

    # HF calculation
    mol_.energy_nuc = lambda *args: mol.energy_nuc() + e_core
    mf1 = scf.RHF(mol_) #.density_fit()
    #mf.verbose = 4
    mf1.mo_coeff  = cf
    mf1.mo_occ    = occ
    mf1.get_ovlp  = lambda *args: Sp
    mf1.get_hcore = lambda *args: Hp + jkp - 0.5*chempot*(Np + Np.T)
    mf1._eri = ao2mo.restore (8, intsp_df, cfx.shape[1]) #trying something

    nt = scf.newton(mf1)
    #nt.verbose = 4
    nt.max_cycle_inner = 1
    nt.max_stepsize = 0.25
    nt.ah_max_cycle = 32
    nt.ah_start_tol = 1.0e-12
    nt.ah_grad_trust_region = 1.0e8
    nt.conv_tol_grad = 1.0e-6

    nt.kernel()
    cf = nt.mo_coeff
    if not nt.converged:
       raise RuntimeError ('hf failed to converge')
    mo_coeff  = nt.mo_coeff
    mo_energy = nt.mo_energy
    mo_occ    = nt.mo_occ
    print("mo_coeff", mo_coeff)

    # dfMP2 solution
    nocc = nel//2
    # mp2solver = dfmp2_testing.MP2(mf_tot) #(work)  #we just pass the mf for the full molecule to dfmp2
    mp2solver = dfmp2.DFMP2(mf_tot) #(work)  #we just pass the mf for the full molecule to dfmp2
    # mp2solver = dfmp2.MP2(mf)  #(home)
    mp2solver.verbose = 5
    mp2solver.kernel(mo_energy=mo_energy, mo_coeff=mo_coeff, nocc=nocc)
    mp2solver.mo_occ=mo_occ.copy()   # this is DIRTY


    def get_t2(mp):
        '''basically identical to the DFMP2 kernel, returns t2'''
        from pyscf.mp import mp2
        mo_coeff  = mp2._mo_without_core(mp, mp.mo_coeff)
        # print("mo_coeff rdms", mo_coeff)
        mo_energy = mp2._mo_energy_without_core(mp, mp.mo_energy)
        nocc = mp.nocc
        nvir = mp.nmo - nocc
        eia  = mo_energy[:nocc,None] - mo_energy[None,nocc:]
        emp2 = 0
        t2   = []
        for istep, qov in enumerate(mp.loop_ao2mo(mo_coeff, nocc)):
            for i in range(nocc):
                buf = np.dot(qov[:,i*nvir:(i+1)*nvir].T,qov).reshape(nvir,nocc,nvir)
                gi  = np.array(buf,copy=False)
                gi  = gi.reshape(nvir,nocc,nvir).transpose(1,0,2)
                t2i = gi.conj()/lib.direct_sum('jb+a->jba',eia,eia[i])
                t2.append(t2i)
                emp2 += np.einsum('jab,jab',t2i,gi) * 2
                emp2 -= np.einsum('jab,jba',t2i,gi)
        return emp2,t2

    def make_rdm1(mp2solver):
        '''rdm1 in the MO basis'''
        from pyscf.cc import ccsd_rdm
        doo, dvv = _gamma1_intermediates(mp2solver)
        nocc = doo.shape[0]
        nvir = dvv.shape[0]
        print('nocc', nocc)
        print('nvir', nvir)
        dov  = np.zeros((nocc,nvir), dtype=doo.dtype)
        dvo  = dov.T
        return ccsd_rdm._make_rdm1(mp,(doo,dov,dvo,dvv),with_frozen=False)

    def _gamma1_intermediates(mp,t2=None):
        nmo  = mp.nmo
        nocc = mp.nocc
        nvir = nmo - nocc
        from pyscf.mp import mp2
        mo_coeff  = mp2._mo_without_core(mp, mp.mo_coeff)
        print("mo coeff rdms", mo_coeff)
        print('nmo, nocc, nvir, mo_coeff shape')
        print(nmo, nocc, nvir, mp.mo_coeff.shape)
        mo_energy = mp2._mo_energy_without_core(mp, mp.mo_energy)
        eia = mo_energy[:nocc,None] - mo_energy[None,nocc:]
        if(t2 is None):
            for istep, qov in enumerate(mp.loop_ao2mo(mo_coeff, nocc)):
                if(istep==0):
                    dtype = qov.dtype
                    dm1occ = np.zeros((nocc,nocc), dtype=dtype)
                    dm1vir = np.zeros((nvir,nvir), dtype=dtype)
                for i in range(nocc):
                    buf = np.dot(qov[:,i*nvir:(i+1)*nvir].T,
                                   qov).reshape(nvir,nocc,nvir)
                    gi = np.array(buf, copy=False)
                    gi = gi.reshape(nvir,nocc,nvir).transpose(1,0,2)
                    t2i = gi/lib.direct_sum('jb+a->jba', eia, eia[i])
                    l2i = t2i.conj()
                    dm1vir += np.einsum('jca,jcb->ba', l2i, t2i) * 2 \
                           - np.einsum('jca,jbc->ba', l2i, t2i)
                    dm1occ += np.einsum('iab,jab->ij', l2i, t2i) * 2 \
                           - np.einsum('iab,jba->ij', l2i, t2i)
        else:
            dtype = t2[0].dtype
            dm1occ = np.zeros((nocc,nocc), dtype=dtype)
            dm1vir = np.zeros((nvir,nvir), dtype=dtype)
            for i in range(nocc):
                t2i = t2[i]
                l2i = t2i.conj()
                dm1vir += np.einsum('jca,jcb->ba', l2i, t2i) * 2 \
                      - np.einsum('jca,jbc->ba', l2i, t2i)
                dm1occ += np.einsum('iab,jab->ij', l2i, t2i) * 2 \
                      - np.einsum('iab,jba->ij', l2i, t2i)
        return -dm1occ, dm1vir

    def make_rdm2(mp2solver):
        nmo  = nmo0  = mp2solver.nmo
        nocc = nocc0 = mp2solver.nocc
        nvir = nmo - nocc
        from pyscf.mp import mp2
        mo_coeff  = mp2._mo_without_core(mp2solver, mp2solver.mo_coeff)
        mo_energy = mp2._mo_energy_without_core(mp2solver, mp2solver.mo_energy)
        eia       = mo_energy[:nocc,None] - mo_energy[None,nocc:]

        moidx = oidx = vidx = None
        dm1   = make_rdm1(mp2solver)
        dm1[np.diag_indices(nocc0)] -= 2
        dm2   = np.zeros((nmo0,nmo0,nmo0,nmo0), dtype=dm1.dtype)

        if(t2 is None):
            for istep, qov in enumerate(mp2solver.loop_ao2mo(mo_coeff, nocc)):
                for i in range(nocc):
                    buf = np.dot(qov[:,i*nvir:(i+1)*nvir].T,qov).reshape(nvir,nocc,nvir)
                    gi  = np.array(buf,copy=False)
                    gi  = gi.reshape(nvir,nocc,nvir).transpose(1,0,2)
                    t2i = gi.conj()/lib.direct_sum('jb+a->jba',eia,eia[i])
                    dovov = t2i.transpose(1,0,2)*2 - t2i.transpose(2,0,1)
                    dovov *= 2
                    if moidx is None:
                        dm2[i,nocc:,:nocc,nocc:] = dovov
                        dm2[nocc:,i,nocc:,:nocc] = dovov.conj().transpose(0,2,1)
                    else:
                        dm2[oidx[i],vidx[:,None,None],oidx[:,None],vidx] = dovov
                        dm2[vidx[:,None,None],oidx[i],vidx[:,None],oidx] = dovov.conj().transpose(0,2,1)

        else:
            for i in range(nocc):
                t2i = t2[i]
                dovov = t2i.transpose(1,0,2)*2 - t2i.transpose(2,0,1)
                dovov *= 2
                if moidx is None:
                    dm2[i,nocc:,:nocc,nocc:] = dovov
                    dm2[nocc:,i,nocc:,:nocc] = dovov.conj().transpose(0,2,1)
                else:
                    dm2[oidx[i],vidx[:,None,None],oidx[:,None],vidx] = dovov
                    dm2[vidx[:,None,None],oidx[i],vidx[:,None],oidx] = dovov.conj().transpose(0,2,1)

        for i in range(nocc0):
            dm2[i,i,:,:] += dm1.T * 2
            dm2[:,:,i,i] += dm1.T * 2
            dm2[:,i,i,:] -= dm1.T
            dm2[i,:,:,i] -= dm1

        for i in range(nocc0):
            for j in range(nocc0):
                dm2[i,i,j,j] += 4
                dm2[i,j,j,i] -= 2

        return dm2


    t2 = None
    rdm1 = make_rdm1(mp2solver)
    rdm2 = make_rdm2(mp2solver)

#  # -------------------------------------
 # TEST: compare rdm dmet with dfmp2 rdms
    # atoms_test=\
    # [['C',( 0.0000, 0.0000, 0.7680)],\
    #  ['C',( 0.0000, 0.0000,-0.7680)],\
    #  ['H',(-1.0192, 0.0000, 1.1573)],\
    #  ['H',( 0.5096, 0.8826, 1.1573)],\
    #  ['H',( 0.5096,-0.8826, 1.1573)],\
    #  ['H',( 1.0192, 0.0000,-1.1573)],\
    #  ['H',(-0.5096,-0.8826,-1.1573)],\
    #  ['H',(-0.5096, 0.8826,-1.1573)]]

    atoms_test = [
    ['O' , (0. , 0. , 0.)],\
    ['H' , (0. , -0.757 , 0.587)],\
    ['H' , (0. , 0.757  , 0.587)]]

    mol_test = gto.M(atom=atoms_test,basis='cc-pvdz')
    m_test = scf.RHF(mol_test).density_fit()
    m_test.kernel()

    mm_test = dfmp2.DFMP2(m_test)
    mm_test.kernel()
    from pyscf.mp import mp2
    rdm1_test = mp2.make_rdm1(mm_test)
    rdm2_test = mp2.make_rdm2(mm_test)

    # Plot sorted rdm1 values
    x1 = rdm1
    y1 = x1.flatten()
    y1 = np.sort(y1)
    import matplotlib.pyplot as plt
    plt.plot(y1, 'r', label='rdm1 from dmet')
    plt.ylabel('rdm1')
    x2 = rdm1_test
    y2 = x2.flatten()
    print("rdm1", y2)
    print(type(y2))
    y2 = np.sort(y2)
    plt.plot(y2, 'b', label='rdm1 for dfmp2')
    plt.ylabel('rdm1 sorted values')
    # Place a legend above this subplot, expanding itself to
    # fully use the given bounding box.
    plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3,
               ncol=2, mode="expand", borderaxespad=0.)
    plt.show()
    plt.close()
    print("deviations between sorted 1rdm in MO basis ")
    print(np.abs(y1-y2).max())

    # Plot sorted rdm2 values
    x1 = rdm2
    y1 = x1.flatten()
    y1 = np.sort(y1)
    import matplotlib.pyplot as plt
    plt.plot(y1, 'r', label='rdm2 from dmet')
    plt.ylabel('rdm2')
    x2 = rdm2_test
    y2 = x2.flatten()
    print("rdm1", y2)
    print(type(y2))
    y2 = np.sort(y2)
    plt.plot(y2, 'b', label='rdm2 for dfmp2')
    plt.ylabel('rdm1 sorted values')
    # Place a legend above this subplot, expanding itself to
    # fully use the given bounding box.
    plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3,
               ncol=2, mode="expand", borderaxespad=0.)
    plt.show()
    plt.close()
    print("deviations between sorted 1rdm in MO basis ")
    print(np.abs(y1-y2).max())

    print("deviations between 1rdm,2rdm in MO basis ")
    print(np.abs(rdm1-rdm1_test).max())
    print(np.abs(rdm2-rdm2_test).max())
# # ----------------------------------

    # transform rdm's to original basis
    tei  = ao2mo.restore(1, intsp_df, cfx.shape[1])
    print("tei shape", tei.shape)
    rdm1 = np.dot(cf, np.dot(rdm1, cf.T))
    rdm2 = np.einsum('ai,ijkl->ajkl', cf, rdm2)
    rdm2 = np.einsum('bj,ajkl->abkl', cf, rdm2)
    rdm2 = np.einsum('ck,abkl->abcl', cf, rdm2)
    rdm2 = np.einsum('dl,abcl->abcd', cf, rdm2)

    ImpEnergy = +0.25 *np.einsum('ij,jk,ki->', 2*Hp+jkp, rdm1, Xp) \
                +0.25 *np.einsum('ij,jk,ki->', 2*Hp+jkp, Xp, rdm1) \
                +0.125*np.einsum('ijkl,ijkm,ml->', tei, rdm2, Xp) \
                +0.125*np.einsum('ijkl,ijml,mk->', tei, rdm2, Xp) \
                +0.125*np.einsum('ijkl,imkl,mj->', tei, rdm2, Xp) \
                +0.125*np.einsum('ijkl,mjkl,mi->', tei, rdm2, Xp)

    Nel = np.trace(np.dot(np.dot(rdm1, Sp), Xp))

    return Nel, ImpEnergy
Ejemplo n.º 4
0
N = 4
atoms = []
for i in range(N):
    atoms.append(['H', (i * R, 0, 0)])

mol = gto.M(atom=atoms, basis='sto-6g', verbose=2)
m = scf.RHF(mol).density_fit()
EhfDF = m.kernel()
print("DFHF energy ")
print(EhfDF)

mo_coeff = m.mo_coeff

mo_energy = m.mo_energy
nocc = mol.nelectron // 2
mm = dfmp2.DFMP2(m)
EmmDF, t2DF = mm.kernel()
print("DFMP2 energy")
print(EmmDF)

EmmDFb, t2 = get_t2(mm, mo_coeff, mo_energy, nocc)
print("DFMP2 energy (from get t2)")
print(EmmDFb)

mp2solver = mm

t2 = None
g1 = make_rdm1(mp2solver, t2, mo_coeff, mo_energy, nocc)
g2 = make_rdm2(mp2solver, t2, mo_coeff, mo_energy, nocc)
print("||||||||||| df mp2 complete ||||||||||||||||||||||||||||||")
Ejemplo n.º 5
0
 ['H',( 0.5096,-0.8826, 1.1573)],\
 ['H',( 1.0192, 0.0000,-1.1573)],\
 ['H',(-0.5096,-0.8826,-1.1573)],\
 ['H',(-0.5096, 0.8826,-1.1573)]]

mol = gto.M(atom=atoms, basis='cc-pvdz')
m   = scf.RHF(mol)
m.kernel()
# mm  = cc.CCSD(m)
# mm = mp.MP2(m)
# mm.kernel()

mdf = scf.RHF(mol).density_fit()
mdf.kernel()

mp2_df = dfmp2.DFMP2(mdf)
mp2_df.kernel()
del mol, m,  mp2_df #,mm

print()
print("Starting DMET")

bs     = 'dz'
basis  = {'C': 'cc-pv'+bs, 'H': 'cc-pv'+bs}
shells = {'C': ['sto-6g','cc-pv'+bs], 'H': ['sto-6g','cc-pv'+bs]}
charge = 0
spin   = 0

fragments = [[0,2,3,4],[1,5,6,7]]
fragment_spins = [1,-1]
# fragments = [[0,2,3,4,1,5,6,7]]
Ejemplo n.º 6
0
def solve (mol, nel, cf_core, cf_gs, ImpOrbs, chempot=0., n_orth=0, FrozenPot=None, mf_tot=None):
    # cf_core : core orbitals (in AO basis, assumed orthonormal)
    # cf_gs   : guess orbitals (in AO basis)
    # ImpOrbs : cf_gs -> impurity orbitals transformation
    # n_orth  : number of orthonormal orbitals in cf_gs [1..n_orth]

    mol_ = gto.Mole()
    mol_.build (verbose=0)
    mol_.nelectron = nel
    mol_.incore_anyway = True

    cfx = cf_gs
    print("cfx shape", cfx.shape)
    Sf  = mol.intor_symmetric('cint1e_ovlp_sph')
    Hc  = mol.intor_symmetric('cint1e_kin_sph') \
        + mol.intor_symmetric('cint1e_nuc_sph') \
        + FrozenPot

    occ = np.zeros((cfx.shape[1],))
    occ[:nel//2] = 2.

    # core contributions
    dm_core = np.dot(cf_core, cf_core.T)*2
    jk_core = scf.hf.get_veff (mol, dm_core)
    e_core  =     np.trace(np.dot(Hc, dm_core)) \
            + 0.5*np.trace(np.dot(jk_core, dm_core))

    # transform integrals
    Sp = np.dot(cfx.T, np.dot(Sf, cfx))
    Hp = np.dot(cfx.T, np.dot(Hc, cfx))
    jkp = np.dot(cfx.T, np.dot(jk_core, cfx))


    # density fitting ============================================================
    # mf = scf.RHF(mol).density_fit()     # this should be moved out of to the parent directory, to avoid repetition
    # mf.with_df._cderi_to_save = 'saved_cderi.h5' # rank-3 decomposition
    # mf.kernel()                    ### moved these three lines to orbital_selection_fc

    auxmol = df.incore.format_aux_basis(mol, auxbasis='weigend')
    j3c    = df.incore.aux_e2(mol, auxmol, intor='cint3c2e_sph', aosym='s1')
    nao    = mol.nao_nr()
    naoaux = auxmol.nao_nr()
    j3c    = j3c.reshape(nao,nao,naoaux) # (ij|L)
    print("j3c shape", j3c.shape)
    j2c    = df.incore.fill_2c2e(mol, auxmol) #(L|M) overlap matrix between auxiliary basis functions

    #the eri is (ij|kl) = \sum_LM (ij|L) (L|M) (M|kl)
    omega = sla.inv(j2c)
    eps,U = sla.eigh(omega)
    #after this transformation the eri is (ij|kl) = \sum_L (ij|L) (L|kl)
    j3c   = np.dot(np.dot(j3c,U),np.diag(np.sqrt(eps)))

    #this part is slow, as we again store the whole eri_df
    # conv = np.einsum('prl,pi,rj->ijl', j3c, cfx, cfx)
    conv = np.einsum('prl,pi->irl',j3c,cfx)
    conv = np.einsum('irl,rj->ijl',conv,cfx)
    df_eri = np.einsum('ijm,klm->ijkl',conv,conv)

    intsp_df = ao2mo.restore(4, df_eri, cfx.shape[1])
    print("DF instp", intsp_df.shape)
    # =============================================================================

    # intsp = ao2mo.outcore.full_iofree (mol, cfx)    #TODO: this we need to calculate on the fly using generator f'n
    # print("intsp shape", intsp.shape)

    # orthogonalize cf [virtuals]
    cf  = np.zeros((cfx.shape[1],)*2,)
    if n_orth > 0:
        assert (n_orth <= cfx.shape[1])
        assert (np.allclose(np.eye(n_orth), Sp[:n_orth,:n_orth]))
    else:
        n_orth = 0

    cf[:n_orth,:n_orth] = np.eye(n_orth)
    if n_orth < cfx.shape[1]:
        val, vec = sla.eigh(-Sp[n_orth:,n_orth:])
        idx = -val > 1.e-12
        U = np.dot(vec[:,idx]*1./(np.sqrt(-val[idx])), \
                   vec[:,idx].T)
        cf[n_orth:,n_orth:] = U

    # define ImpOrbs projection
    Xp = np.dot(ImpOrbs, ImpOrbs.T)

    # Si = np.dot(ImpOrbs.T, np.dot(Sp, ImpOrbs))
    # Mp = np.dot(ImpOrbs, np.dot(sla.inv(Si), ImpOrbs.T))
    Np = np.dot(Sp, Xp)
    # print np.allclose(Np, np.dot(Np, np.dot(Mp, Np)))

    # HF calculation
    mol_.energy_nuc = lambda *args: mol.energy_nuc() + e_core
    mf1 = scf.RHF(mol_) #.density_fit()
    #mf.verbose = 4
    mf1.mo_coeff  = cf
    mf1.mo_occ    = occ
    mf1.get_ovlp  = lambda *args: Sp
    mf1.get_hcore = lambda *args: Hp + jkp - 0.5*chempot*(Np + Np.T)
    mf1._eri = ao2mo.restore (8, intsp_df, cfx.shape[1]) #trying something

    nt = scf.newton(mf1)
    #nt.verbose = 4
    nt.max_cycle_inner = 1
    nt.max_stepsize = 0.25
    nt.ah_max_cycle = 32
    nt.ah_start_tol = 1.0e-12
    nt.ah_grad_trust_region = 1.0e8
    nt.conv_tol_grad = 1.0e-6

    nt.kernel()
    cf = nt.mo_coeff
    if not nt.converged:
       raise RuntimeError ('hf failed to converge')
    mo_coeff  = nt.mo_coeff
    mo_energy = nt.mo_energy
    mo_occ    = nt.mo_occ

    # dfMP2 solution
    nocc = nel//2
    # mp2solver = dfmp2_testing.MP2(mf_tot) #(work)  #we just pass the mf for the full molecule to dfmp2
    mp2solver = dfmp2.DFMP2(mf_tot) #(work)  #we just pass the mf for the full molecule to dfmp2
    # mp2solver = dfmp2.MP2(mf)  #(home)
    mp2solver.verbose = 5
    mp2solver.kernel(mo_energy=mo_energy, mo_coeff=mo_coeff, nocc=nocc)
    # exit()

    ''' Try generating j3c for the whole molecule, on the fly, then use that for rdms
    '''

    def make_rdm1(mp2solver, t2, mo_coeff, mo_energy, nocc):
        '''1-particle density matrix in MO basis.  The off-diagonal blocks due to
        the orbital response contribution are not included.
        '''
        mo = np.asarray(mo_coeff, order='F')
        nmo = mo.shape[1]
        nvir = nmo - nocc
        dm1occ = np.zeros((nocc,nocc))
        dm1vir = np.zeros((nvir,nvir))
        for i in range(nocc):
            dm1vir += np.einsum('jca,jcb->ab', t2[i], t2[i]) * 2 \
                    - np.einsum('jca,jbc->ab', t2[i], t2[i])
            dm1occ += np.einsum('iab,jab->ij', t2[i], t2[i]) * 2 \
                    - np.einsum('iab,jba->ij', t2[i], t2[i])
        rdm1 = np.zeros((nmo,nmo))
    # *2 for beta electron
        rdm1[:nocc,:nocc] =-dm1occ * 2
        rdm1[nocc:,nocc:] = dm1vir * 2
        for i in range(nocc):
            rdm1[i,i] += 2
        return rdm1

    def make_rdm2(mp2solver, t2, mo_coeff, mo_energy, nocc):
        '''2-RDM in MO basis'''
        mo = np.asarray(mo_coeff, order='F')
        nmo = mo.shape[1]
        nvir = nmo - nocc
        dm2 = np.zeros((nmo,nmo,nmo,nmo)) # Chemist notation
        #dm2[:nocc,nocc:,:nocc,nocc:] = t2.transpose(0,3,1,2)*2 - t2.transpose(0,2,1,3)
        #dm2[nocc:,:nocc,nocc:,:nocc] = t2.transpose(3,0,2,1)*2 - t2.transpose(2,0,3,1)
        for i in range(nocc):
            t2i = t2[i]
            dm2[i,nocc:,:nocc,nocc:] = t2i.transpose(1,0,2)*2 - t2i.transpose(2,0,1)
            dm2[nocc:,i,nocc:,:nocc] = dm2[i,nocc:,:nocc,nocc:].transpose(0,2,1)

        for i in range(nocc):
            for j in range(nocc):
                dm2[i,i,j,j] += 4
                dm2[i,j,j,i] -= 2
        return dm2

    mo = np.asarray(mo_coeff, order='F')
    nmo = mo.shape[1]
    nvir = nmo - nocc
    co = mo_coeff[:,:nocc]
    cv = mo_coeff[:,nocc:]
    # eri = mol_.intor('cint2e_sph', aosym='s8')
    _scf = mf1
    eri = _scf._eri
    eri = ao2mo.incore.general(eri, (co,cv,co,cv))
    print("eri shape", eri.shape)
    eri = ao2mo.load(eri)

    t2 = np.empty((nocc,nocc,nvir,nvir))
    eia = mo_energy[:nocc,None] - mo_energy[None,nocc:]
    with eri as ovov:
        print("ovov", ovov)
        for i in range(nocc):
            gi = np.asarray(ovov[i*nvir:(i+1)*nvir])
            gi = gi.reshape(nvir, nocc, nvir).transpose(1,0,2)
            t2[i] = gi/lib.direct_sum('jb+a->jba', eia, eia[i])

    rdm1 = make_rdm1(mp2solver, t2, mo_coeff, mo_energy, nocc)

    from scipy.linalg import eigh
    print("hermitian?", np.allclose(rdm1,rdm1.T))
    w,v = eigh(rdm1)
    print(w)
    print(np.trace(rdm1))
    print("rm1 shape", rdm1.shape)
    rdm2 = make_rdm2(mp2solver, t2, mo_coeff, mo_energy, nocc)
    print("rmd2 shape", rdm2.shape)
    print("cfx shape", cfx.shape)

# #  # -------------------------------------
#  # TEST: compare rdm dmet with dfmp2 rdms
#     # atoms_test=\
#     # [['C',( 0.0000, 0.0000, 0.7680)],\
#     #  ['C',( 0.0000, 0.0000,-0.7680)],\
#     #  ['H',(-1.0192, 0.0000, 1.1573)],\
#     #  ['H',( 0.5096, 0.8826, 1.1573)],\
#     #  ['H',( 0.5096,-0.8826, 1.1573)],\
#     #  ['H',( 1.0192, 0.0000,-1.1573)],\
#     #  ['H',(-0.5096,-0.8826,-1.1573)],\
#     #  ['H',(-0.5096, 0.8826,-1.1573)]]
#
#     atoms_test = [
#     ['O' , (0. , 0. , 0.)],\
#     ['H' , (0. , -0.757 , 0.587)],\
#     ['H' , (0. , 0.757  , 0.587)]]
#
#     mol_test = gto.M(atom=atoms_test,basis='cc-pvdz')
#     m_test = scf.RHF(mol_test).density_fit()
#     m_test.kernel()
#
#     mm_test = dfmp2.DFMP2(m_test)
#     mm_test.kernel()
#     from pyscf.mp import mp2
#     rdm1_test = mp2.make_rdm1(mm_test)
#     rdm2_test = mp2.make_rdm2(mm_test)
#
# # --------------plots ------------------------
#     # Plot sorted rdm1 values
#     x1 = rdm1
#     y1 = x1.flatten()
#     y1 = np.sort(y1)
#     import matplotlib.pyplot as plt
#     plt.plot(y1, 'r', label='rdm1 from dmet')
#     plt.ylabel('rdm1')
#     x2 = rdm1_test
#     y2 = x2.flatten()
#     y2 = np.sort(y2)
#     plt.plot(y2, 'b', label='rdm1 for dfmp2')
#     plt.ylabel('rdm1 sorted values')
#     # Place a legend above this subplot, expanding itself to
#     # fully use the given bounding box.
#     plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3,
#                ncol=2, mode="expand", borderaxespad=0.)
#     # plt.show()
#
#     print("deviations between sorted 1rdm in MO basis ")
#     print(np.abs(y1-y2).max())
#
#     # Plot sorted rdm2 values
#     x1 = rdm2
#     y1 = x1.flatten()
#     y1 = np.sort(y1)
#     import matplotlib.pyplot as plt
#     plt.plot(y1, 'r', label='rdm2 from dmet')
#     plt.ylabel('rdm2')
#     x2 = rdm2_test
#     y2 = x2.flatten()
#     y2 = np.sort(y2)
#     plt.plot(y2, 'b', label='rdm2 for dfmp2')
#     plt.ylabel('rdm1 sorted values')
#     # Place a legend above this subplot, expanding itself to
#     # fully use the given bounding box.
#     plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3,
#                ncol=2, mode="expand", borderaxespad=0.)
#     # plt.show()
#     print("deviations between sorted 1rdm in MO basis ")
#     print(np.abs(y1-y2).max())
#
#
#     print("deviations between 1rdm,2rdm in MO basis ")
#     print(np.abs(rdm1-rdm1_test).max())
#     print(np.abs(rdm2-rdm2_test).max())
# # ------------------------------------------------------------


    # transform rdm's to original basis
    tei  = ao2mo.restore(1, intsp_df, cfx.shape[1])
    rdm1 = np.dot(cf, np.dot(rdm1, cf.T))
    rdm2 = np.einsum('ai,ijkl->ajkl', cf, rdm2)
    rdm2 = np.einsum('bj,ajkl->abkl', cf, rdm2)
    rdm2 = np.einsum('ck,abkl->abcl', cf, rdm2)
    rdm2 = np.einsum('dl,abcl->abcd', cf, rdm2)

    ImpEnergy = +0.25 *np.einsum('ij,jk,ki->', 2*Hp+jkp, rdm1, Xp) \
                +0.25 *np.einsum('ij,jk,ki->', 2*Hp+jkp, Xp, rdm1) \
                +0.125*np.einsum('ijkl,ijkm,ml->', tei, rdm2, Xp) \
                +0.125*np.einsum('ijkl,ijml,mk->', tei, rdm2, Xp) \
                +0.125*np.einsum('ijkl,imkl,mj->', tei, rdm2, Xp) \
                +0.125*np.einsum('ijkl,mjkl,mi->', tei, rdm2, Xp)

    Nel = np.trace(np.dot(np.dot(rdm1, Sp), Xp))

    return Nel, ImpEnergy
Ejemplo n.º 7
0
treated with standard MP2.
'''

# define a molecule, and treat it with DFMP2

R = 1.5
atoms = [['O', (0, 0, 0)], ['H', (R, 0, 0)],
         ['H', (-R * sqrt(3) / 2, R / 2, 0)]]
mol = gto.M(atom=atoms, basis='cc-pvdz', verbose=2)
m = scf.RHF(mol).density_fit().run()
# m.kernel()
mo_coeff = m.mo_coeff
mo_energy = m.mo_energy
nocc = mol.nelectron // 2

mm = dfmp2.DFMP2(m).run()
mp2solver = mm


def make_rdm1(mp2solver, t2, mo_coeff, mo_energy, nocc):
    '''1-particle density matrix in MO basis.  The off-diagonal blocks due to
    the orbital response contribution are not included.
    '''
    nmo = mo_coeff.shape[1]
    nvir = nmo - nocc
    dm1occ = np.zeros((nocc, nocc))
    dm1vir = np.zeros((nvir, nvir))
    for i in range(nocc):
        dm1vir += np.einsum('jca,jcb->ab', t2[i], t2[i]) * 2 \
                - np.einsum('jca,jbc->ab', t2[i], t2[i])
        dm1occ += np.einsum('iab,jab->ij', t2[i], t2[i]) * 2 \
Ejemplo n.º 8
0
def solve(mol,
          nel,
          cf_core,
          cf_gs,
          ImpOrbs,
          chempot=0.,
          n_orth=0,
          FrozenPot=None,
          mf_tot=None):
    # cf_core : core orbitals (in AO basis, assumed orthonormal)
    # cf_gs   : guess orbitals (in AO basis)
    # ImpOrbs : cf_gs -> impurity orbitals transformation
    # n_orth  : number of orthonormal orbitals in cf_gs [1..n_orth]

    mol_ = gto.Mole()
    mol_.build(verbose=0)
    mol_.nelectron = nel
    mol_.incore_anyway = True
    print("shapes in solver")
    print("cf_core, cf_gs, imporbs", cf_core.shape, cf_gs.shape, ImpOrbs.shape)

    cfx = cf_gs
    Sf = mol.intor_symmetric('cint1e_ovlp_sph')
    Hc  = mol.intor_symmetric('cint1e_kin_sph') \
        + mol.intor_symmetric('cint1e_nuc_sph') \
        + FrozenPot

    occ = np.zeros((cfx.shape[1], ))
    occ[:nel // 2] = 2.

    # core contributions
    dm_core = np.dot(cf_core, cf_core.T) * 2
    jk_core = scf.hf.get_veff(mol, dm_core)
    e_core  =     np.trace(np.dot(Hc, dm_core)) \
            + 0.5*np.trace(np.dot(jk_core, dm_core))

    # transform integrals
    Sp = np.dot(cfx.T, np.dot(Sf, cfx))
    Hp = np.dot(cfx.T, np.dot(Hc, cfx))
    jkp = np.dot(cfx.T, np.dot(jk_core, cfx))

    # density fitting =========================================================
    # mf = scf.RHF(mol).density_fit()     #moved out of to orbital_selection_fc, to avoid repetition
    # mf.with_df._cderi_to_save = 'saved_cderi.h5' # rank-3 decomposition
    # print("cderi shape", (mf_tot.with_df._cderi.shape))
    # cderi = mf_tot.with_df._cderi.transpose()

    # # convert cholesky-dimention c3eri to incore.aux_e2 eri
    # #cderi = df.incore.cholesky_eri(mol, auxbasis='cc-pvdz-jkfit').transpose()
    # nao    = mol.nao_nr()
    # il = np.tril_indices(nao)
    # naux = cderi.shape[1]
    # print ('naux',naux)
    # c3eri = np.zeros((nao,nao,naux))
    # c3eri[il] = cderi.copy()
    # c3eri = c3eri+np.triu(c3eri.transpose(2,1,0),k=1).transpose(1,2,0)
    # #c3eri = einsum('ji,jkQ,kl->ilQ',mo_coeff,c3eri,mo_coeff)
    # print("c3eri shape", c3eri.shape)

    auxmol = df.incore.format_aux_basis(mol, auxbasis='weigend')
    j3c = df.incore.aux_e2(mol, auxmol, intor='cint3c2e_sph', aosym='s1')

    nao = mol.nao_nr()
    naoaux = auxmol.nao_nr()
    j3c = j3c.reshape(nao, nao, naoaux)  # (ij|L)

    # import time
    # start = time.time()
    # print("Starting the clock for solver")
    j2c = df.incore.fill_2c2e(
        mol, auxmol)  #(L|M) overlap matrix between auxiliary basis functions
    # t3 = time.time()
    # print("time for j3c conv", t3 - start)

    #the eri is (ij|kl) = \sum_LM (ij|L) (L|M) (M|kl)
    omega = sla.inv(j2c)
    eps, U = sla.eigh(omega)
    #after this transformation the eri is (ij|kl) = \sum_L (ij|L) (L|kl)
    j3c = np.dot(np.dot(j3c, U), np.diag(np.sqrt(eps)))

    #this part is slow, as we again store the whole eri_df
    conv = np.einsum('prl,pi,rj->ijl', j3c, cfx, cfx)
    conv = np.einsum('prl,pi->irl', j3c, cfx)
    conv = np.einsum('irl,rj->ijl', conv, cfx)
    df_eri = np.einsum('ijm,klm->ijkl', conv, conv)
    intsp_df = ao2mo.restore(4, df_eri, cfx.shape[1])
    # =========================================================================

    # print("deviations between sorted j3c and cderi")
    # print(np.abs(j3c-c3eri).max())
    # exit()

    # orthogonalize cf [virtuals]
    cf = np.zeros((cfx.shape[1], ) * 2, )
    if n_orth > 0:
        assert (n_orth <= cfx.shape[1])
        assert (np.allclose(np.eye(n_orth), Sp[:n_orth, :n_orth]))
    else:
        n_orth = 0

    cf[:n_orth, :n_orth] = np.eye(n_orth)
    if n_orth < cfx.shape[1]:
        val, vec = sla.eigh(-Sp[n_orth:, n_orth:])
        idx = -val > 1.e-12
        U = np.dot(vec[:,idx]*1./(np.sqrt(-val[idx])), \
                   vec[:,idx].T)
        cf[n_orth:, n_orth:] = U

    # define ImpOrbs projection
    Xp = np.dot(ImpOrbs, ImpOrbs.T)

    # Si = np.dot(ImpOrbs.T, np.dot(Sp, ImpOrbs))
    # Mp = np.dot(ImpOrbs, np.dot(sla.inv(Si), ImpOrbs.T))
    Np = np.dot(Sp, Xp)
    # print np.allclose(Np, np.dot(Np, np.dot(Mp, Np)))

    # HF calculation
    mol_.energy_nuc = lambda *args: mol.energy_nuc() + e_core
    mf1 = scf.RHF(mol_)  #.density_fit()
    #mf.verbose = 4
    mf1.mo_coeff = cf
    mf1.mo_occ = occ
    mf1.get_ovlp = lambda *args: Sp
    mf1.get_hcore = lambda *args: Hp + jkp - 0.5 * chempot * (Np + Np.T)
    mf1._eri = ao2mo.restore(8, intsp_df, cfx.shape[1])  #trying something
    # print("mf1.eri shape", mf1._eri.shape)
    # print("cfx shape", cfx.shape)
    # print("intsp_df shape", intsp_df.shape)

    nt = scf.newton(mf1)
    #nt.verbose = 4
    nt.max_cycle_inner = 1
    nt.max_stepsize = 0.25
    nt.ah_max_cycle = 32
    nt.ah_start_tol = 1.0e-12
    nt.ah_grad_trust_region = 1.0e8
    nt.conv_tol_grad = 1.0e-6

    nt.kernel()
    cf = nt.mo_coeff
    if not nt.converged:
        raise RuntimeError('hf failed to converge')
    mo_coeff = nt.mo_coeff
    mo_energy = nt.mo_energy
    mo_occ = nt.mo_occ

    #transform mo_coeff from iAO to MO basis
    mo_coeff = np.einsum('iI, Ip -> ip', cfx, mo_coeff)

    # dfMP2 solution
    nocc = nel // 2
    mp2solver = dfmp2.DFMP2(
        mf_tot)  #(work) #Pass the mf for the full molecule to dfmp2
    # mp2solver = dfmp2.MP2(mf)  #(home)
    mp2solver.verbose = 5
    mp2solver.kernel(mo_energy=mo_energy, mo_coeff=mo_coeff, nocc=nocc)
    mp2solver.mo_occ = mo_occ.copy()  # this is DIRTY

    # print("mo_coeff", mo_coeff)
    # mo_coeff = mp2solver.mo_coeff
    # print("mo_coeff mp2solver ", mo_coeff)
    # print("mf_tot mo coeff =", mf_tot.mo_coeff)
    # print("mf_tot mo-energy", mf_tot.mo_energy)

    # -------------------------------------------------------------------------------
    def make_rdm1(mp2solver, t2, mo_coeff, mo_energy, nocc):
        '''rdm1 in the MO basis'''
        from pyscf.cc import ccsd_rdm
        doo, dvv = _gamma1_intermediates(mp2solver,
                                         mo_coeff,
                                         mo_energy,
                                         nocc,
                                         t2=None)
        nocc = doo.shape[0]
        nvir = dvv.shape[0]
        dov = np.zeros((nocc, nvir), dtype=doo.dtype)
        dvo = dov.T
        return ccsd_rdm._make_rdm1(mp, (doo, dov, dvo, dvv), with_frozen=False)

    def _gamma1_intermediates(mp, mo_coeff, mo_energy, nocc, t2=None):
        nmo = mo_coeff.shape[1]
        nvir = nmo - nocc
        eia = mo_energy[:nocc, None] - mo_energy[None, nocc:]

        if (t2 is None):
            t2 = []
            for istep, qov in enumerate(mp.loop_ao2mo(mo_coeff, nocc)):
                if (istep == 0):
                    dtype = qov.dtype
                    dm1occ = np.zeros((nocc, nocc), dtype=dtype)
                    dm1vir = np.zeros((nvir, nvir), dtype=dtype)
                for i in range(nocc):
                    buf = np.dot(qov[:, i * nvir:(i + 1) * nvir].T,
                                 qov).reshape(nvir, nocc, nvir)
                    gi = np.array(buf, copy=False)
                    gi = gi.reshape(nvir, nocc, nvir).transpose(1, 0, 2)
                    t2i = gi.conj() / lib.direct_sum('jb+a->jba', eia, eia[i])
                    t2.append(t2i)
                    l2i = t2i.conj()
                    dm1vir += np.einsum('jca,jcb->ba', l2i, t2i) * 2 \
                           - np.einsum('jca,jbc->ba', l2i, t2i)
                    dm1occ += np.einsum('iab,jab->ij', l2i, t2i) * 2 \
                           - np.einsum('iab,jba->ij', l2i, t2i)
        else:
            dtype = t2[0].dtype
            dm1occ = np.zeros((nocc, nocc), dtype=dtype)
            dm1vir = np.zeros((nvir, nvir), dtype=dtype)
            for i in range(nocc):
                t2i = t2[i]
                l2i = t2i.conj()
                dm1vir += np.einsum('jca,jcb->ba', l2i, t2i) * 2 \
                      - np.einsum('jca,jbc->ba', l2i, t2i)
                dm1occ += np.einsum('iab,jab->ij', l2i, t2i) * 2 \
                      - np.einsum('iab,jba->ij', l2i, t2i)
        return -dm1occ, dm1vir

    def make_rdm2(mp2solver, t2, mo_coeff, mo_energy, nocc):
        nmo = nmo0 = mo_coeff.shape[1]
        nocc0 = nocc
        nvir = nmo - nocc
        eia = mo_energy[:nocc, None] - mo_energy[None, nocc:]
        moidx = oidx = vidx = None
        dm1 = make_rdm1(mp2solver, t2, mo_coeff, mo_energy, nocc)
        dm1[np.diag_indices(nocc0)] -= 2
        dm2 = np.zeros((nmo0, nmo0, nmo0, nmo0), dtype=dm1.dtype)

        if (t2 is None):
            for istep, qov in enumerate(mp2solver.loop_ao2mo(mo_coeff, nocc)):
                for i in range(nocc):
                    buf = np.dot(qov[:, i * nvir:(i + 1) * nvir].T,
                                 qov).reshape(nvir, nocc, nvir)
                    gi = np.array(buf, copy=False)
                    gi = gi.reshape(nvir, nocc, nvir).transpose(1, 0, 2)
                    t2i = gi.conj() / lib.direct_sum('jb+a->jba', eia, eia[i])
                    dovov = t2i.transpose(1, 0, 2) * 2 - t2i.transpose(2, 0, 1)
                    dovov *= 2
                    if moidx is None:
                        dm2[i, nocc:, :nocc, nocc:] = dovov
                        dm2[nocc:, i,
                            nocc:, :nocc] = dovov.conj().transpose(0, 2, 1)
                    else:
                        dm2[oidx[i], vidx[:, None, None], oidx[:, None],
                            vidx] = dovov
                        dm2[vidx[:, None, None], oidx[i], vidx[:, None],
                            oidx] = dovov.conj().transpose(0, 2, 1)
        else:
            for i in range(nocc):
                t2i = t2[i]
                dovov = t2i.transpose(1, 0, 2) * 2 - t2i.transpose(2, 0, 1)
                dovov *= 2
                if moidx is None:
                    dm2[i, nocc:, :nocc, nocc:] = dovov
                    dm2[nocc:, i,
                        nocc:, :nocc] = dovov.conj().transpose(0, 2, 1)
                else:
                    dm2[oidx[i], vidx[:, None, None], oidx[:, None],
                        vidx] = dovov
                    dm2[vidx[:, None, None], oidx[i], vidx[:, None],
                        oidx] = dovov.conj().transpose(0, 2, 1)
        for i in range(nocc0):
            dm2[i, i, :, :] += dm1.T * 2
            dm2[:, :, i, i] += dm1.T * 2
            dm2[:, i, i, :] -= dm1.T
            dm2[i, :, :, i] -= dm1
        for i in range(nocc0):
            for j in range(nocc0):
                dm2[i, i, j, j] += 4
                dm2[i, j, j, i] -= 2
        return dm2

    t2 = None
    rdm1 = make_rdm1(mp2solver, t2, mo_coeff, mo_energy, nocc)
    rdm2 = make_rdm2(mp2solver, t2, mo_coeff, mo_energy, nocc)

    # print("BEGINNING MP2")
    # ---- mp2 -----------------------------------------------------------------
    # intsp = ao2mo.outcore.full_iofree (mol, cfx)
    # # print("MP2 INTSP OBTAINED")
    #
    # HF calculation
    # mol_.energy_nuc = lambda *args: mol.energy_nuc() + e_core
    # mf = scf.RHF(mol_)
    # mf.mo_coeff  = cf
    # mf.mo_occ    = occ
    # mf.get_ovlp  = lambda *args: Sp
    # mf.get_hcore = lambda *args: Hp + jkp - 0.5*chempot*(Np + Np.T)
    # mf._eri = ao2mo.restore (8, intsp, cfx.shape[1])
    #
    # nt = scf.newton(mf)
    # nt.max_cycle_inner = 1
    # nt.max_stepsize = 0.25
    # nt.ah_max_cycle = 32
    # nt.ah_start_tol = 1.0e-12
    # nt.ah_grad_trust_region = 1.0e8
    # nt.conv_tol_grad = 1.0e-6
    #
    # nt.kernel()
    # cf = nt.mo_coeff
    # if not nt.converged:
    #     raise RuntimeError ('hf failed to converge')
    # mf.mo_coeff  = nt.mo_coeff
    # mf.mo_energy = nt.mo_energy
    # mf.mo_occ    = nt.mo_occ
    #
    # # MP2 solution
    # mp2solver = mp.MP2(mf)
    # mp2solver.verbose = 5
    # mp2solver.kernel()
    #
    # nbas = Sp.shape[0]
    # rdm1_mp = mp2solver.make_rdm1()
    # rdm2_mp = mp2solver.make_rdm2()
    #
    # print("deviation between intsp and intsp_df ")
    # print(np.abs(intsp-intsp_df).max())
    # ------- end mp2 ---------------------------------------------
    # exit()

    # #  # -------------------------------------
    #  # TEST: compare rdm dmet with dfmp2 rdms
    #     # atoms_test=\
    #     # [['C',( 0.0000, 0.0000, 0.7680)],\
    #     #  ['C',( 0.0000, 0.0000,-0.7680)],\
    #     #  ['H',(-1.0192, 0.0000, 1.1573)],\
    #     #  ['H',( 0.5096, 0.8826, 1.1573)],\
    #     #  ['H',( 0.5096,-0.8826, 1.1573)],\
    #     #  ['H',( 1.0192, 0.0000,-1.1573)],\
    #     #  ['H',(-0.5096,-0.8826,-1.1573)],\
    #     #  ['H',(-0.5096, 0.8826,-1.1573)]]
    #
    #     atoms_test = [
    #     ['O' , (0. , 0. , 0.)],\
    #     ['H' , (0. , -0.757 , 0.587)],\
    #     ['H' , (0. , 0.757  , 0.587)]]
    #
    #     # R = 1.8 # Bonr units
    #     # N = 4
    #     # atoms_test = []
    #     # for i in range(N):
    #     #     atoms_test.append(['H', (i*R,0,0)])
    #
    #     mol_test = gto.M(atom=atoms_test,basis='cc-pvdz')
    #     m_test = scf.RHF(mol_test).density_fit()
    #     m_test.kernel()
    #
    #     mm_test = dfmp2.DFMP2(m_test)
    #     mm_test.kernel()
    #     from pyscf.mp import mp2
    #     rdm1_test = mp2.make_rdm1(mm_test)
    #     rdm2_test = mp2.make_rdm2(mm_test)
    #
    # # --------------plots ------------------------
    #     # Plot sorted rdm1 values
    #     x1 = rdm1
    #     y1 = x1.flatten()
    #     y1 = np.sort(y1)
    #     import matplotlib.pyplot as plt
    #     plt.plot(y1, 'r', label='rdm1 from dmet')
    #     plt.ylabel('rdm1')
    #     x2 = rdm1_test
    #     y2 = x2.flatten()
    #     y2 = np.sort(y2)
    #     plt.plot(y2, 'b', label='rdm1 for dfmp2')
    #     plt.ylabel('rdm1 sorted values')
    #     plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3,
    #                ncol=2, mode="expand", borderaxespad=0.)
    #     plt.show()
    #     print("deviations between sorted 1rdm in MO basis ")
    #     print(np.abs(y1-y2).max())
    #
    #     # Plot sorted rdm2 values
    #     x1 = rdm2
    #     y1 = x1.flatten()
    #     y1 = np.sort(y1)
    #     import matplotlib.pyplot as plt
    #     plt.plot(y1, 'r', label='rdm2 from dmet')
    #     plt.ylabel('rdm2')
    #     x2 = rdm2_test
    #     y2 = x2.flatten()
    #     y2 = np.sort(y2)
    #     plt.plot(y2, 'b', label='rdm2 for dfmp2')
    #     plt.ylabel('rdm1 sorted values')
    #     plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3,
    #                ncol=2, mode="expand", borderaxespad=0.)
    #     plt.show()
    #     print("deviations between sorted 2rdm in MO basis ")
    #     print(np.abs(y1-y2).max())
    # # # ------------------------------------------------------------

    # transform rdm's to original basis
    tei = ao2mo.restore(1, intsp_df, cfx.shape[1])
    rdm1 = np.dot(cf, np.dot(rdm1, cf.T))
    rdm2 = np.einsum('ai,ijkl->ajkl', cf, rdm2)
    rdm2 = np.einsum('bj,ajkl->abkl', cf, rdm2)
    rdm2 = np.einsum('ck,abkl->abcl', cf, rdm2)
    rdm2 = np.einsum('dl,abcl->abcd', cf, rdm2)

    ImpEnergy = +0.25 *np.einsum('ij,jk,ki->', 2*Hp+jkp, rdm1, Xp) \
                +0.25 *np.einsum('ij,jk,ki->', 2*Hp+jkp, Xp, rdm1) \
                +0.125*np.einsum('ijkl,ijkm,ml->', tei, rdm2, Xp) \
                +0.125*np.einsum('ijkl,ijml,mk->', tei, rdm2, Xp) \
                +0.125*np.einsum('ijkl,imkl,mj->', tei, rdm2, Xp) \
                +0.125*np.einsum('ijkl,mjkl,mi->', tei, rdm2, Xp)
    print("imp energy = ", ImpEnergy)

    Nel = np.trace(np.dot(np.dot(rdm1, Sp), Xp))

    return Nel, ImpEnergy
Ejemplo n.º 9
0
def solve(mol,
          nel,
          cf_core,
          cf_gs,
          ImpOrbs,
          chempot=0.,
          n_orth=0,
          FrozenPot=None,
          mf_tot=None):
    # cf_core : core orbitals (in AO basis, assumed orthonormal)
    # cf_gs   : guess orbitals (in AO basis)
    # ImpOrbs : cf_gs -> impurity orbitals transformation
    # n_orth  : number of orthonormal orbitals in cf_gs [1..n_orth]

    mol_ = gto.Mole()
    mol_.build(verbose=0)
    mol_.nelectron = nel
    mol_.incore_anyway = True

    cfx = cf_gs
    Sf = mol.intor_symmetric('cint1e_ovlp_sph')
    Hc  = mol.intor_symmetric('cint1e_kin_sph') \
        + mol.intor_symmetric('cint1e_nuc_sph') \
        + FrozenPot

    occ = np.zeros((cfx.shape[1], ))
    occ[:nel // 2] = 2.

    # core contributions
    dm_core = np.dot(cf_core, cf_core.T) * 2
    jk_core = scf.hf.get_veff(mol, dm_core)
    e_core  =     np.trace(np.dot(Hc, dm_core)) \
            + 0.5*np.trace(np.dot(jk_core, dm_core))

    # transform integrals
    Sp = np.dot(cfx.T, np.dot(Sf, cfx))
    Hp = np.dot(cfx.T, np.dot(Hc, cfx))
    jkp = np.dot(cfx.T, np.dot(jk_core, cfx))

    # density fitting =========================================================
    # mf = scf.RHF(mol).density_fit()     #moved out of to orbital_selection_fc, to avoid repetition
    # mf.with_df._cderi_to_save = 'saved_cderi.h5' # rank-3 decomposition

    auxmol = df.incore.format_aux_basis(mol, auxbasis='weigend')
    j3c = df.incore.aux_e2(mol, auxmol, intor='cint3c2e_sph', aosym='s1')
    nao = mol.nao_nr()
    naoaux = auxmol.nao_nr()
    j3c = j3c.reshape(nao, nao, naoaux)  # (ij|L)
    j2c = df.incore.fill_2c2e(
        mol, auxmol)  #(L|M) overlap matrix between auxiliary basis functions

    #the eri is (ij|kl) = \sum_LM (ij|L) (L|M) (M|kl)
    omega = sla.inv(j2c)
    eps, U = sla.eigh(omega)
    #after this transformation the eri is (ij|kl) = \sum_L (ij|L) (L|kl)
    j3c = np.dot(np.dot(j3c, U), np.diag(np.sqrt(eps)))

    #this part is slow, as we again store the whole eri_df
    conv = np.einsum('prl,pi,rj->ijl', j3c, cfx, cfx)
    conv = np.einsum('prl,pi->irl', j3c, cfx)
    conv = np.einsum('irl,rj->ijl', conv, cfx)
    df_eri = np.einsum('ijm,klm->ijkl', conv, conv)
    intsp_df = ao2mo.restore(4, df_eri, cfx.shape[1])
    # =========================================================================

    # orthogonalize cf [virtuals]
    cf = np.zeros((cfx.shape[1], ) * 2, )
    if n_orth > 0:
        assert (n_orth <= cfx.shape[1])
        assert (np.allclose(np.eye(n_orth), Sp[:n_orth, :n_orth]))
    else:
        n_orth = 0

    cf[:n_orth, :n_orth] = np.eye(n_orth)
    if n_orth < cfx.shape[1]:
        val, vec = sla.eigh(-Sp[n_orth:, n_orth:])
        idx = -val > 1.e-12
        U = np.dot(vec[:,idx]*1./(np.sqrt(-val[idx])), \
                   vec[:,idx].T)
        cf[n_orth:, n_orth:] = U

    # define ImpOrbs projection
    Xp = np.dot(ImpOrbs, ImpOrbs.T)

    # Si = np.dot(ImpOrbs.T, np.dot(Sp, ImpOrbs))
    # Mp = np.dot(ImpOrbs, np.dot(sla.inv(Si), ImpOrbs.T))
    Np = np.dot(Sp, Xp)
    # print np.allclose(Np, np.dot(Np, np.dot(Mp, Np)))

    # HF calculation
    mol_.energy_nuc = lambda *args: mol.energy_nuc() + e_core
    mf1 = scf.RHF(mol_)  #.density_fit()
    #mf.verbose = 4
    mf1.mo_coeff = cf
    mf1.mo_occ = occ
    mf1.get_ovlp = lambda *args: Sp
    mf1.get_hcore = lambda *args: Hp + jkp - 0.5 * chempot * (Np + Np.T)
    mf1._eri = ao2mo.restore(8, intsp_df, cfx.shape[1])  #trying something
    print("mf1.eri shape", mf1._eri.shape)
    print("cfx shape", cfx.shape)
    print("intsp_df shape", intsp_df.shape)

    nt = scf.newton(mf1)
    #nt.verbose = 4
    nt.max_cycle_inner = 1
    nt.max_stepsize = 0.25
    nt.ah_max_cycle = 32
    nt.ah_start_tol = 1.0e-12
    nt.ah_grad_trust_region = 1.0e8
    nt.conv_tol_grad = 1.0e-6

    nt.kernel()
    cf = nt.mo_coeff
    if not nt.converged:
        raise RuntimeError('hf failed to converge')
    mo_coeff = nt.mo_coeff
    mo_energy = nt.mo_energy
    mo_occ = nt.mo_occ

    #transform mo_coeff from iAO to MO basis
    mo_coeff = np.einsum('iI, Ip -> ip', cfx, mo_coeff)

    # dfMP2 solution
    nocc = nel // 2
    mp2solver = dfmp2.DFMP2(
        mf_tot)  #(work) #Pass the mf for the full molecule to dfmp2
    # mp2solver = dfmp2.MP2(mf)  #(home)
    mp2solver.verbose = 5
    mp2solver.kernel(mo_energy=mo_energy, mo_coeff=mo_coeff, nocc=nocc)
    mp2solver.mo_occ = mo_occ.copy()  # this is DIRTY

    # make rdms
    def make_rdm1(mp2solver, t2, mo_coeff, mo_energy, nocc):
        '''rdm1 in the MO basis'''
        from pyscf.cc import ccsd_rdm
        doo, dvv = _gamma1_intermediates(mp2solver,
                                         mo_coeff,
                                         mo_energy,
                                         nocc,
                                         t2=None)
        nocc = doo.shape[0]
        nvir = dvv.shape[0]
        dov = np.zeros((nocc, nvir), dtype=doo.dtype)
        dvo = dov.T
        return ccsd_rdm._make_rdm1(mp, (doo, dov, dvo, dvv), with_frozen=False)

    def _gamma1_intermediates(mp, mo_coeff, mo_energy, nocc, t2=None):
        nmo = mo_coeff.shape[1]
        nvir = nmo - nocc
        eia = mo_energy[:nocc, None] - mo_energy[None, nocc:]

        if (t2 is None):
            t2 = []
            for istep, qov in enumerate(mp.loop_ao2mo(mo_coeff, nocc)):
                if (istep == 0):
                    dtype = qov.dtype
                    dm1occ = np.zeros((nocc, nocc), dtype=dtype)
                    dm1vir = np.zeros((nvir, nvir), dtype=dtype)
                for i in range(nocc):
                    buf = np.dot(qov[:, i * nvir:(i + 1) * nvir].T,
                                 qov).reshape(nvir, nocc, nvir)
                    gi = np.array(buf, copy=False)
                    gi = gi.reshape(nvir, nocc, nvir).transpose(1, 0, 2)
                    t2i = gi.conj() / lib.direct_sum('jb+a->jba', eia, eia[i])
                    t2.append(t2i)
                    l2i = t2i.conj()
                    dm1vir += np.einsum('jca,jcb->ba', l2i, t2i) * 2 \
                           - np.einsum('jca,jbc->ba', l2i, t2i)
                    dm1occ += np.einsum('iab,jab->ij', l2i, t2i) * 2 \
                           - np.einsum('iab,jba->ij', l2i, t2i)
        else:
            dtype = t2[0].dtype
            dm1occ = np.zeros((nocc, nocc), dtype=dtype)
            dm1vir = np.zeros((nvir, nvir), dtype=dtype)
            for i in range(nocc):
                t2i = t2[i]
                l2i = t2i.conj()
                dm1vir += np.einsum('jca,jcb->ba', l2i, t2i) * 2 \
                      - np.einsum('jca,jbc->ba', l2i, t2i)
                dm1occ += np.einsum('iab,jab->ij', l2i, t2i) * 2 \
                      - np.einsum('iab,jba->ij', l2i, t2i)
        return -dm1occ, dm1vir

    def make_rdm2(mp2solver, t2, mo_coeff, mo_energy, nocc):
        nmo = nmo0 = mo_coeff.shape[1]
        nocc0 = nocc
        nvir = nmo - nocc
        eia = mo_energy[:nocc, None] - mo_energy[None, nocc:]
        moidx = oidx = vidx = None
        dm1 = make_rdm1(mp2solver, t2, mo_coeff, mo_energy, nocc)
        dm1[np.diag_indices(nocc0)] -= 2
        dm2 = np.zeros((nmo0, nmo0, nmo0, nmo0), dtype=dm1.dtype)

        if (t2 is None):
            for istep, qov in enumerate(mp2solver.loop_ao2mo(mo_coeff, nocc)):
                for i in range(nocc):
                    buf = np.dot(qov[:, i * nvir:(i + 1) * nvir].T,
                                 qov).reshape(nvir, nocc, nvir)
                    gi = np.array(buf, copy=False)
                    gi = gi.reshape(nvir, nocc, nvir).transpose(1, 0, 2)
                    t2i = gi.conj() / lib.direct_sum('jb+a->jba', eia, eia[i])
                    dovov = t2i.transpose(1, 0, 2) * 2 - t2i.transpose(2, 0, 1)
                    dovov *= 2
                    if moidx is None:
                        dm2[i, nocc:, :nocc, nocc:] = dovov
                        dm2[nocc:, i,
                            nocc:, :nocc] = dovov.conj().transpose(0, 2, 1)
                    else:
                        dm2[oidx[i], vidx[:, None, None], oidx[:, None],
                            vidx] = dovov
                        dm2[vidx[:, None, None], oidx[i], vidx[:, None],
                            oidx] = dovov.conj().transpose(0, 2, 1)
        else:
            for i in range(nocc):
                t2i = t2[i]
                dovov = t2i.transpose(1, 0, 2) * 2 - t2i.transpose(2, 0, 1)
                dovov *= 2
                if moidx is None:
                    dm2[i, nocc:, :nocc, nocc:] = dovov
                    dm2[nocc:, i,
                        nocc:, :nocc] = dovov.conj().transpose(0, 2, 1)
                else:
                    dm2[oidx[i], vidx[:, None, None], oidx[:, None],
                        vidx] = dovov
                    dm2[vidx[:, None, None], oidx[i], vidx[:, None],
                        oidx] = dovov.conj().transpose(0, 2, 1)
        for i in range(nocc0):
            dm2[i, i, :, :] += dm1.T * 2
            dm2[:, :, i, i] += dm1.T * 2
            dm2[:, i, i, :] -= dm1.T
            dm2[i, :, :, i] -= dm1
        for i in range(nocc0):
            for j in range(nocc0):
                dm2[i, i, j, j] += 4
                dm2[i, j, j, i] -= 2
        return dm2

    t2 = None
    rdm1 = make_rdm1(mp2solver, t2, mo_coeff, mo_energy, nocc)
    rdm2 = make_rdm2(mp2solver, t2, mo_coeff, mo_energy, nocc)

    # transform rdm's to original basis
    tei = ao2mo.restore(1, intsp_df, cfx.shape[1])
    rdm1 = np.dot(cf, np.dot(rdm1, cf.T))
    rdm2 = np.einsum('ai,ijkl->ajkl', cf, rdm2)
    rdm2 = np.einsum('bj,ajkl->abkl', cf, rdm2)
    rdm2 = np.einsum('ck,abkl->abcl', cf, rdm2)
    rdm2 = np.einsum('dl,abcl->abcd', cf, rdm2)

    ImpEnergy = +0.25 *np.einsum('ij,jk,ki->', 2*Hp+jkp, rdm1, Xp) \
                +0.25 *np.einsum('ij,jk,ki->', 2*Hp+jkp, Xp, rdm1) \
                +0.125*np.einsum('ijkl,ijkm,ml->', tei, rdm2, Xp) \
                +0.125*np.einsum('ijkl,ijml,mk->', tei, rdm2, Xp) \
                +0.125*np.einsum('ijkl,imkl,mj->', tei, rdm2, Xp) \
                +0.125*np.einsum('ijkl,mjkl,mi->', tei, rdm2, Xp)
    print("imp energy = ", ImpEnergy)

    Nel = np.trace(np.dot(np.dot(rdm1, Sp), Xp))

    return Nel, ImpEnergy