def Wovoo(cc,t1,t2,eris,kconserv): nkpts, nocc, nvir = t1.shape Wmbij = eris.ovoo.copy() for km, kb, ki in kpts_helper.loop_kkk(nkpts): kj = kconserv[km, ki, kb] for kn in range(nkpts): Wmbij[km, kb, ki] += einsum('mnie,jnbe->mbij', eris.ooov[km, kn, ki], t2[kj, kn, kb]) Wmbij[km, kb, ki] += einsum('ie,mbej->mbij', t1[ki], -eris.ovov[km, kb, kj].transpose(0, 1, 3, 2)) for kf in range(nkpts): kn = kconserv[kb, kj, kf] Wmbij[km, kb, ki] -= einsum('ie,njbf,mnef->mbij', t1[ki], t2[kn, kj, kb], eris.oovv[km, kn, ki]) # P(ij) for kn in range(nkpts): Wmbij[km, kb, ki] -= einsum('mnje,inbe->mbij', eris.ooov[km, kn, kj], t2[ki, kn, kb]) Wmbij[km, kb, ki] -= einsum('je,mbei->mbij', t1[kj], -eris.ovov[km, kb, ki].transpose(0, 1, 3, 2)) for kf in range(nkpts): kn = kconserv[kb, ki, kf] Wmbij[km, kb, ki] += einsum('je,nibf,mnef->mbij', t1[kj], t2[kn, ki, kb], eris.oovv[km, kn, kj]) FFov = Fov(cc,t1,t2,eris,kconserv) WWoooo = Woooo(cc,t1,t2,eris,kconserv) tau = make_tau(cc,t2,t1,t1,kconserv) for km, kb, ki in kpts_helper.loop_kkk(nkpts): kj = kconserv[km, ki, kb] Wmbij[km, kb, ki] -= einsum('me,ijbe->mbij', FFov[km], t2[ki, kj, kb]) Wmbij[km, kb, ki] -= einsum('nb,mnij->mbij', t1[kb], WWoooo[km, kb, ki]) for km, kb, ki in kpts_helper.loop_kkk(nkpts): kj = kconserv[km, ki, kb] Wmbij[km, kb, ki] += 0.5 * einsum('xmbef,xijef->mbij', eris.ovvv[km, kb, :], tau[ki, kj, :]) return Wmbij
def test_ao2mo_7d(self): L = 3. n = 6 cell = pgto.Cell() cell.a = numpy.diag([L,L,L]) cell.mesh = [n,n,n] cell.atom = '''He 2. 2.2 2. He 1.2 1. 1.''' cell.basis = {'He': [[0, (1.2, 1)], [1, (0.6, 1)]]} cell.verbose = 0 cell.build(0,0) kpts = cell.make_kpts([1,3,1]) nkpts = len(kpts) nao = cell.nao_nr() numpy.random.seed(1) mo =(numpy.random.random((nkpts,nao,nao)) + numpy.random.random((nkpts,nao,nao))*1j) with_df = df.GDF(cell, kpts) out = with_df.ao2mo_7d(mo, kpts) ref = numpy.empty_like(out) kconserv = kpts_helper.get_kconserv(cell, kpts) for ki, kj, kk in kpts_helper.loop_kkk(nkpts): kl = kconserv[ki, kj, kk] tmp = with_df.ao2mo((mo[ki], mo[kj], mo[kk], mo[kl]), kpts[[ki,kj,kk,kl]]) ref[ki,kj,kk] = tmp.reshape([nao]*4) self.assertAlmostEqual(abs(out-ref).max(), 0, 12)
def Wooov(cc,t1,t2,eris,kconserv): nkpts, nocc, nvir = t1.shape Wmnie = eris.ooov.copy() for km, kn, ki in kpts_helper.loop_kkk(nkpts): kf = ki Wmnie[km, kn, ki] += einsum('if,mnfe->mnie',t1[ki], eris.oovv[km, kn, kf]) return Wmnie
def Wvovv(cc,t1,t2,eris,kconserv): nkpts, nocc, nvir = t1.shape Wamef = numpy.empty((nkpts, nkpts, nkpts, nvir, nocc, nvir, nvir), dtype=eris.ovvv.dtype) for ka, km, ke in kpts_helper.loop_kkk(nkpts): kn = ka Wamef[ka, km, ke] = -eris.ovvv[km, ka, ke].transpose(1, 0, 2, 3) Wamef[ka, km, ke] -= einsum('na,nmef->amef',t1[kn],eris.oovv[kn, km, ke]) return Wamef
def Wovvo(cc,t1,t2,eris,kconserv): nkpts, nocc, nvir = t1.shape Wmbej = cc_Wovvo(cc,t1,t2,eris,kconserv) for km, kb, ke in kpts_helper.loop_kkk(nkpts): kj = kconserv[km, ke, kb] for kn in range(nkpts): kf = kconserv[km, ke, kn] Wmbej[km, kb, ke] -= 0.5*einsum('jnfb,mnef->mbej',t2[kj, kn, kf], eris.oovv[km, kn, ke]) return Wmbej
def Wvvvv(cc,t1,t2,eris,kconserv): nkpts, nocc, nvir = t1.shape tau = make_tau(cc,t2,t1,t1,kconserv) Wabef = cc_Wvvvv(cc,t1,t2,eris,kconserv) for ka, kb, ke in kpts_helper.loop_kkk(nkpts): kf = kconserv[ka, ke, kb] for km in range(nkpts): kn = kconserv[ka, km, kb] Wabef[ka, kb, ke] += 0.25*einsum('mnab,mnef->abef',tau[km, kn, ka], eris.oovv[km, kn, ke]) return Wabef
def Wvvvo(cc,t1,t2,eris,kconserv,WWvvvv=None): nkpts, nocc, nvir = t1.shape FFov = Fov(cc,t1,t2,eris,kconserv) if WWvvvv is None: WWvvvv = Wvvvv(cc,t1,t2,eris,kconserv) eris_ovvo = numpy.zeros(shape=(nkpts,nkpts,nkpts,nocc,nvir,nvir,nocc),dtype=t2.dtype) for km in range(nkpts): for kb in range(nkpts): for ke in range(nkpts): kj = kconserv[km,ke,kb] eris_ovvo[km,kb,ke] = -eris.ovov[km,kb,kj].transpose(0,1,3,2) tmp1 = numpy.zeros((nkpts, nkpts, nkpts, nvir, nvir, nvir, nocc),dtype=t2.dtype) tmp2 = numpy.zeros((nkpts, nkpts, nkpts, nvir, nvir, nvir, nocc),dtype=t2.dtype) for ka, kb, ke in kpts_helper.loop_kkk(nkpts): ki = kconserv[ka,ke,kb] tmp2[ka,kb,ke] += einsum('ma,mbei->abei',t1[ka],eris_ovvo[ka,kb,ke]) for kn in range(nkpts): tmp2[ka,kb,ke] -= einsum('ma,nibf,mnef->abei',t1[ka],t2[kn,ki,kb],eris.oovv[ka,kn,ke]) for km in range(nkpts): tmp1[ka,kb,ke] += einsum('mbef,miaf->abei',eris.ovvv[km,kb,ke],t2[km,ki,ka]) tau = make_tau(cc,t2,t1,t1,kconserv) Wabei = -tmp1 + tmp1.transpose(1,0,2,4,3,5,6) Wabei -= tmp2 - tmp2.transpose(1,0,2,4,3,5,6) for ka, kb, ke in kpts_helper.loop_kkk(nkpts): ki = kconserv[ka, ke, kb] Wabei[ka, kb, ke] += eris.ovvv[ki, ke, kb].conj().transpose(3, 2, 1, 0) Wabei[ka, kb, ke] += einsum('if,abef->abei',t1[ki],WWvvvv[ka, kb, ke]) Wabei[ka, kb, ke] -= einsum('me,miab->abei',FFov[ke],t2[ke, ki, ka]) for km in range(nkpts): kn = kconserv[ka, km, kb] Wabei[ka, kb, ke] += 0.5 * einsum('nmie,mnab->abei', eris.ooov[kn, km, ki], tau[km, kn, ka]) return Wabei
def check_antisymm_34(cc, kpts, integrals): kconserv = kpts_helper.get_kconserv(cc._scf.cell, cc.kpts) nkpts = len(kpts) diff = 0.0 for kp, kq, kr in kpts_helper.loop_kkk(nkpts): ks = kconserv[kp, kr, kq] for p in range(integrals.shape[3]): for q in range(integrals.shape[4]): for r in range(integrals.shape[5]): for s in range(integrals.shape[6]): pqrs = integrals[kp, kq, kr, p, q, r, s] pqsr = integrals[kp, kq, ks, p, q, s, r] cdiff = numpy.linalg.norm(pqrs + pqsr).real if diff > 1e-5: print("AS diff = %.15g" % cdiff, pqrs, pqsr, kp, kq, kr, ks, p, q, r, s) diff = max(diff, cdiff) print("antisymmetrization : max diff = %.15g" % diff) if diff > 1e-5: print("Energy cutoff (or cell.mesh) is not enough to converge AO integrals.")
def spin2spatial(tx, orbspin, kconserv): if tx.ndim == 3: # t1 nocc, nvir = tx.shape[1:] else: nocc, nvir = tx.shape[4:6] nkpts = len(tx) idxoa = [numpy.where(orbspin[k][:nocc] == 0)[0] for k in range(nkpts)] idxob = [numpy.where(orbspin[k][:nocc] == 1)[0] for k in range(nkpts)] idxva = [numpy.where(orbspin[k][nocc:] == 0)[0] for k in range(nkpts)] idxvb = [numpy.where(orbspin[k][nocc:] == 1)[0] for k in range(nkpts)] nocc_a = len(idxoa[0]) nocc_b = len(idxob[0]) nvir_a = len(idxva[0]) nvir_b = len(idxvb[0]) if tx.ndim == 3: # t1 t1a = numpy.zeros((nkpts,nocc_a,nvir_a), dtype=tx.dtype) t1b = numpy.zeros((nkpts,nocc_b,nvir_b), dtype=tx.dtype) for k in range(nkpts): lib.take_2d(tx[k], idxoa[k], idxva[k], out=t1a[k]) lib.take_2d(tx[k], idxob[k], idxvb[k], out=t1b[k]) return t1a, t1b else: t2aa = numpy.zeros((nkpts,nkpts,nkpts,nocc_a,nocc_a,nvir_a,nvir_a), dtype=tx.dtype) t2ab = numpy.zeros((nkpts,nkpts,nkpts,nocc_a,nocc_b,nvir_a,nvir_b), dtype=tx.dtype) t2bb = numpy.zeros((nkpts,nkpts,nkpts,nocc_b,nocc_b,nvir_b,nvir_b), dtype=tx.dtype) t2 = tx.reshape(nkpts,nkpts,nkpts,nocc**2,nvir**2) for ki, kj, ka in kpts_helper.loop_kkk(nkpts): kb = kconserv[ki,ka,kj] idxoaa = idxoa[ki][:,None] * nocc + idxoa[kj] idxoab = idxoa[ki][:,None] * nocc + idxob[kj] idxobb = idxob[ki][:,None] * nocc + idxob[kj] idxvaa = idxva[ka][:,None] * nvir + idxva[kb] idxvab = idxva[ka][:,None] * nvir + idxvb[kb] idxvbb = idxvb[ka][:,None] * nvir + idxvb[kb] lib.take_2d(t2[ki,kj,ka], idxoaa.ravel(), idxvaa.ravel(), out=t2aa[ki,kj,ka]) lib.take_2d(t2[ki,kj,ka], idxobb.ravel(), idxvbb.ravel(), out=t2bb[ki,kj,ka]) lib.take_2d(t2[ki,kj,ka], idxoab.ravel(), idxvab.ravel(), out=t2ab[ki,kj,ka]) return t2aa, t2ab, t2bb
def init_amps(self, eris): time0 = time.clock(), time.time() nocc = self.nocc nvir = self.nmo - nocc nkpts = self.nkpts mo_e_o = [eris.mo_energy[k][:nocc] for k in range(nkpts)] mo_e_v = [eris.mo_energy[k][nocc:] for k in range(nkpts)] t1 = numpy.zeros((nkpts, nocc, nvir), dtype=numpy.complex128) t2 = numpy.zeros((nkpts, nkpts, nkpts, nocc, nocc, nvir, nvir), dtype=numpy.complex128) self.emp2 = 0 foo = eris.fock[:, :nocc, :nocc].copy() fvv = eris.fock[:, nocc:, nocc:].copy() fov = eris.fock[:, :nocc, nocc:].copy() eris_oovv = eris.oovv.copy() # Get location of padded elements in occupied and virtual space nonzero_opadding, nonzero_vpadding = padding_k_idx(self, kind="split") kconserv = kpts_helper.get_kconserv(self._scf.cell, self.kpts) for ki, kj, ka in kpts_helper.loop_kkk(nkpts): kb = kconserv[ki, ka, kj] # For LARGE_DENOM, see t1new update above eia = LARGE_DENOM * numpy.ones((nocc, nvir), dtype=eris.mo_energy[0].dtype) n0_ovp_ia = numpy.ix_(nonzero_opadding[ki], nonzero_vpadding[ka]) eia[n0_ovp_ia] = (mo_e_o[ki][:,None] - mo_e_v[ka])[n0_ovp_ia] ejb = LARGE_DENOM * numpy.ones((nocc, nvir), dtype=eris.mo_energy[0].dtype) n0_ovp_jb = numpy.ix_(nonzero_opadding[kj], nonzero_vpadding[kb]) ejb[n0_ovp_jb] = (mo_e_o[kj][:,None] - mo_e_v[kb])[n0_ovp_jb] eijab = eia[:, None, :, None] + ejb[:, None, :] t2[ki, kj, ka] = eris_oovv[ki, kj, ka] / eijab t2 = numpy.conj(t2) self.emp2 = 0.25 * numpy.einsum('pqrijab,pqrijab', t2, eris_oovv).real self.emp2 /= nkpts logger.info(self, 'Init t2, MP2 energy = %.15g', self.emp2.real) logger.timer(self, 'init mp2', *time0) return self.emp2, t1, t2
def check_antisymm_3412(cc, kpts, integrals): kconserv = kpts_helper.get_kconserv(cc._scf.cell, cc.kpts) nkpts = len(kpts) diff = 0.0 for kp, kq, kr in kpts_helper.loop_kkk(nkpts): ks = kconserv[kp, kr, kq] for p in range(integrals.shape[3]): for q in range(integrals.shape[4]): for r in range(integrals.shape[5]): for s in range(integrals.shape[6]): pqrs = integrals[kp, kq, kr, p, q, r, s] rspq = integrals[kq, kp, kr, q, p, r, s] cdiff = numpy.linalg.norm(pqrs - rspq).real if diff > 1e-5: print("AS diff = %.15g" % cdiff, pqrs, rspq, kp, kq, kr, ks, p, q, r, s) diff = max(diff, cdiff) print("antisymmetrization : max diff = %.15g" % diff) if diff > 1e-5: print( "Energy cutoff (or cell.mesh) is not enough to converge AO integrals." ) return diff
def init_amps(self, eris): time0 = logger.process_clock(), logger.perf_counter() nocc = self.nocc nvir = self.nmo - nocc nkpts = self.nkpts mo_e_o = [eris.mo_energy[k][:nocc] for k in range(nkpts)] mo_e_v = [eris.mo_energy[k][nocc:] for k in range(nkpts)] t1 = numpy.zeros((nkpts, nocc, nvir), dtype=numpy.complex128) t2 = numpy.zeros((nkpts, nkpts, nkpts, nocc, nocc, nvir, nvir), dtype=numpy.complex128) self.emp2 = 0 eris_oovv = eris.oovv.copy() # Get location of padded elements in occupied and virtual space nonzero_opadding, nonzero_vpadding = padding_k_idx(self, kind="split") kconserv = kpts_helper.get_kconserv(self._scf.cell, self.kpts) for ki, kj, ka in kpts_helper.loop_kkk(nkpts): kb = kconserv[ki, ka, kj] # For LARGE_DENOM, see t1new update above eia = LARGE_DENOM * numpy.ones((nocc, nvir), dtype=eris.mo_energy[0].dtype) n0_ovp_ia = numpy.ix_(nonzero_opadding[ki], nonzero_vpadding[ka]) eia[n0_ovp_ia] = (mo_e_o[ki][:,None] - mo_e_v[ka])[n0_ovp_ia] ejb = LARGE_DENOM * numpy.ones((nocc, nvir), dtype=eris.mo_energy[0].dtype) n0_ovp_jb = numpy.ix_(nonzero_opadding[kj], nonzero_vpadding[kb]) ejb[n0_ovp_jb] = (mo_e_o[kj][:,None] - mo_e_v[kb])[n0_ovp_jb] eijab = eia[:, None, :, None] + ejb[:, None, :] t2[ki, kj, ka] = eris_oovv[ki, kj, ka] / eijab t2 = numpy.conj(t2) self.emp2 = 0.25 * numpy.einsum('pqrijab,pqrijab', t2, eris_oovv).real self.emp2 /= nkpts logger.info(self, 'Init t2, MP2 energy = %.15g', self.emp2.real) logger.timer(self, 'init mp2', *time0) return self.emp2, t1, t2
def init_amps(self, eris): time0 = time.clock(), time.time() nocc = self.nocc nvir = self.nmo - nocc nkpts = self.nkpts t1 = numpy.zeros((nkpts, nocc, nvir), dtype=numpy.complex128) t2 = numpy.zeros((nkpts, nkpts, nkpts, nocc, nocc, nvir, nvir), dtype=numpy.complex128) self.emp2 = 0 foo = eris.fock[:, :nocc, :nocc].copy() fvv = eris.fock[:, nocc:, nocc:].copy() fov = eris.fock[:, :nocc, nocc:].copy() eris_oovv = eris.oovv.copy() eia = numpy.zeros((nocc, nvir)) eijab = numpy.zeros((nocc, nocc, nvir, nvir)) kconserv = kpts_helper.get_kconserv(self._scf.cell, self.kpts) for ki, kj, ka in kpts_helper.loop_kkk(nkpts): kb = kconserv[ki, ka, kj] eijab = (foo[ki].diagonal()[:, None, None, None] + foo[kj].diagonal()[None, :, None, None] - fvv[ka].diagonal()[None, None, :, None] - fvv[kb].diagonal()[None, None, None, :]) # Due to padding; see above discussion concerning t1new in update_amps() idx = numpy.where(abs(eijab) < LOOSE_ZERO_TOL)[0] eijab[idx] = LARGE_DENOM t2[ki, kj, ka] = eris_oovv[ki, kj, ka] / eijab t2 = numpy.conj(t2) self.emp2 = 0.25 * numpy.einsum('pqrijab,pqrijab', t2, eris_oovv).real self.emp2 /= nkpts logger.info(self, 'Init t2, MP2 energy = %.15g', self.emp2.real) logger.timer(self, 'init mp2', *time0) return self.emp2, t1, t2
def update_amps(cc, t1, t2, eris): time0 = time.clock(), time.time() log = logger.Logger(cc.stdout, cc.verbose) nkpts, nocc, nvir = t1.shape fock = eris.fock mo_e_o = [e[:nocc] for e in eris.mo_energy] mo_e_v = [e[nocc:] + cc.level_shift for e in eris.mo_energy] # Get location of padded elements in occupied and virtual space nonzero_opadding, nonzero_vpadding = padding_k_idx(cc, kind="split") fov = fock[:, :nocc, nocc:].copy() foo = fock[:, :nocc, :nocc].copy() fvv = fock[:, nocc:, nocc:].copy() # Get the momentum conservation array # Note: chemist's notation for momentum conserving t2(ki,kj,ka,kb), even though # integrals are in physics notation kconserv = kpts_helper.get_kconserv(cc._scf.cell, cc.kpts) tau = imdk.make_tau(cc, t2, t1, t1, kconserv) Fvv = imdk.cc_Fvv(cc, t1, t2, eris, kconserv) Foo = imdk.cc_Foo(cc, t1, t2, eris, kconserv) Fov = imdk.cc_Fov(cc, t1, t2, eris, kconserv) Woooo = imdk.cc_Woooo(cc, t1, t2, eris, kconserv) Wvvvv = imdk.cc_Wvvvv(cc, t1, t2, eris, kconserv) Wovvo = imdk.cc_Wovvo(cc, t1, t2, eris, kconserv) # Move energy terms to the other side for k in range(nkpts): Foo[k][numpy.diag_indices(nocc)] -= mo_e_o[k] Fvv[k][numpy.diag_indices(nvir)] -= mo_e_v[k] eris_ovvo = numpy.zeros(shape=(nkpts, nkpts, nkpts, nocc, nvir, nvir, nocc), dtype=t2.dtype) eris_oovo = numpy.zeros(shape=(nkpts, nkpts, nkpts, nocc, nocc, nvir, nocc), dtype=t2.dtype) eris_vvvo = numpy.zeros(shape=(nkpts, nkpts, nkpts, nvir, nvir, nvir, nocc), dtype=t2.dtype) for km, kb, ke in kpts_helper.loop_kkk(nkpts): kj = kconserv[km, ke, kb] # <mb||je> -> -<mb||ej> eris_ovvo[km, kb, ke] = -eris.ovov[km, kb, kj].transpose(0, 1, 3, 2) # <mn||je> -> -<mn||ej> # let kb = kn as a dummy variable eris_oovo[km, kb, ke] = -eris.ooov[km, kb, kj].transpose(0, 1, 3, 2) # <ma||be> -> - <be||am>* # let kj = ka as a dummy variable kj = kconserv[km, ke, kb] eris_vvvo[ke, kj, kb] = -eris.ovvv[km, kb, ke].transpose(2, 3, 1, 0).conj() # T1 equation t1new = numpy.zeros(shape=t1.shape, dtype=t1.dtype) for ka in range(nkpts): ki = ka t1new[ka] += numpy.array(fov[ka, :, :]).conj() t1new[ka] += einsum('ie,ae->ia', t1[ka], Fvv[ka]) t1new[ka] += -einsum('ma,mi->ia', t1[ka], Foo[ka]) for km in range(nkpts): t1new[ka] += einsum('imae,me->ia', t2[ka, km, ka], Fov[km]) t1new[ka] += -einsum('nf,naif->ia', t1[km], eris.ovov[km, ka, ki]) for kn in range(nkpts): ke = kconserv[km, ki, kn] t1new[ka] += -0.5 * einsum('imef,maef->ia', t2[ki, km, ke], eris.ovvv[km, ka, ke]) t1new[ka] += -0.5 * einsum('mnae,nmei->ia', t2[km, kn, ka], eris_oovo[kn, km, ke]) # T2 equation t2new = numpy.array(eris.oovv).conj() for ki, kj, ka in kpts_helper.loop_kkk(nkpts): # Chemist's notation for momentum conserving t2(ki,kj,ka,kb) kb = kconserv[ki, ka, kj] Ftmp = Fvv[kb] - 0.5 * einsum('mb,me->be', t1[kb], Fov[kb]) tmp = einsum('ijae,be->ijab', t2[ki, kj, ka], Ftmp) t2new[ki, kj, ka] += tmp #t2new[ki,kj,kb] -= tmp.transpose(0,1,3,2) Ftmp = Fvv[ka] - 0.5 * einsum('ma,me->ae', t1[ka], Fov[ka]) tmp = einsum('ijbe,ae->ijab', t2[ki, kj, kb], Ftmp) t2new[ki, kj, ka] -= tmp Ftmp = Foo[kj] + 0.5 * einsum('je,me->mj', t1[kj], Fov[kj]) tmp = einsum('imab,mj->ijab', t2[ki, kj, ka], Ftmp) t2new[ki, kj, ka] -= tmp #t2new[kj,ki,ka] += tmp.transpose(1,0,2,3) Ftmp = Foo[ki] + 0.5 * einsum('ie,me->mi', t1[ki], Fov[ki]) tmp = einsum('jmab,mi->ijab', t2[kj, ki, ka], Ftmp) t2new[ki, kj, ka] += tmp for km in range(nkpts): # Wminj # - km - kn + ka + kb = 0 # => kn = ka - km + kb kn = kconserv[ka, km, kb] t2new[ki, kj, ka] += 0.5 * einsum( 'mnab,mnij->ijab', tau[km, kn, ka], Woooo[km, kn, ki]) ke = km t2new[ki, kj, ka] += 0.5 * einsum( 'ijef,abef->ijab', tau[ki, kj, ke], Wvvvv[ka, kb, ke]) # Wmbej # - km - kb + ke + kj = 0 # => ke = km - kj + kb ke = kconserv[km, kj, kb] tmp = einsum('imae,mbej->ijab', t2[ki, km, ka], Wovvo[km, kb, ke]) # - km - kb + ke + kj = 0 # => ke = km - kj + kb # # t[i,e] => ki = ke # t[m,a] => km = ka if km == ka and ke == ki: tmp -= einsum('ie,ma,mbej->ijab', t1[ki], t1[km], eris_ovvo[km, kb, ke]) t2new[ki, kj, ka] += tmp t2new[ki, kj, kb] -= tmp.transpose(0, 1, 3, 2) t2new[kj, ki, ka] -= tmp.transpose(1, 0, 2, 3) t2new[kj, ki, kb] += tmp.transpose(1, 0, 3, 2) ke = ki tmp = einsum('ie,abej->ijab', t1[ki], eris_vvvo[ka, kb, ke]) t2new[ki, kj, ka] += tmp # P(ij) term ke = kj tmp = einsum('je,abei->ijab', t1[kj], eris_vvvo[ka, kb, ke]) t2new[ki, kj, ka] -= tmp km = ka tmp = einsum('ma,mbij->ijab', t1[ka], eris.ovoo[km, kb, ki]) t2new[ki, kj, ka] -= tmp # P(ab) term km = kb tmp = einsum('mb,maij->ijab', t1[kb], eris.ovoo[km, ka, ki]) t2new[ki, kj, ka] += tmp for ki in range(nkpts): ka = ki # Remove zero/padded elements from denominator eia = LARGE_DENOM * numpy.ones( (nocc, nvir), dtype=eris.mo_energy[0].dtype) n0_ovp_ia = numpy.ix_(nonzero_opadding[ki], nonzero_vpadding[ka]) eia[n0_ovp_ia] = (mo_e_o[ki][:, None] - mo_e_v[ka])[n0_ovp_ia] t1new[ki] /= eia kconserv = kpts_helper.get_kconserv(cc._scf.cell, cc.kpts) for ki, kj, ka in kpts_helper.loop_kkk(nkpts): kb = kconserv[ki, ka, kj] # For LARGE_DENOM, see t1new update above eia = LARGE_DENOM * numpy.ones( (nocc, nvir), dtype=eris.mo_energy[0].dtype) n0_ovp_ia = numpy.ix_(nonzero_opadding[ki], nonzero_vpadding[ka]) eia[n0_ovp_ia] = (mo_e_o[ki][:, None] - mo_e_v[ka])[n0_ovp_ia] ejb = LARGE_DENOM * numpy.ones( (nocc, nvir), dtype=eris.mo_energy[0].dtype) n0_ovp_jb = numpy.ix_(nonzero_opadding[kj], nonzero_vpadding[kb]) ejb[n0_ovp_jb] = (mo_e_o[kj][:, None] - mo_e_v[kb])[n0_ovp_jb] eijab = eia[:, None, :, None] + ejb[:, None, :] t2new[ki, kj, ka] /= eijab time0 = log.timer_debug1('update t1 t2', *time0) return t1new, t2new
def _make_eris_incore(cc, mo_coeff=None): from pyscf.pbc import tools from pyscf.pbc.cc.ccsd import _adjust_occ log = logger.Logger(cc.stdout, cc.verbose) cput0 = (time.clock(), time.time()) eris = gccsd._PhysicistsERIs() cell = cc._scf.cell kpts = cc.kpts nkpts = cc.nkpts nocc = cc.nocc nmo = cc.nmo nvir = nmo - nocc eris.nocc = nocc #if any(nocc != numpy.count_nonzero(cc._scf.mo_occ[k] > 0) for k in range(nkpts)): # raise NotImplementedError('Different occupancies found for different k-points') if mo_coeff is None: mo_coeff = cc.mo_coeff nao = mo_coeff[0].shape[0] dtype = mo_coeff[0].dtype moidx = get_frozen_mask(cc) nocc_per_kpt = numpy.asarray(get_nocc(cc, per_kpoint=True)) nmo_per_kpt = numpy.asarray(get_nmo(cc, per_kpoint=True)) padded_moidx = [] for k in range(nkpts): kpt_nocc = nocc_per_kpt[k] kpt_nvir = nmo_per_kpt[k] - kpt_nocc kpt_padded_moidx = numpy.concatenate( (numpy.ones(kpt_nocc, dtype=numpy.bool), numpy.zeros(nmo - kpt_nocc - kpt_nvir, dtype=numpy.bool), numpy.ones(kpt_nvir, dtype=numpy.bool))) padded_moidx.append(kpt_padded_moidx) eris.mo_coeff = [] eris.orbspin = [] # Generate the molecular orbital coefficients with the frozen orbitals masked. # Each MO is tagged with orbspin, a list of 0's and 1's that give the overall # spin of each MO. # # Here we will work with two index arrays; one is for our original (small) moidx # array while the next is for our new (large) padded array. for k in range(nkpts): kpt_moidx = moidx[k] kpt_padded_moidx = padded_moidx[k] mo = numpy.zeros((nao, nmo), dtype=dtype) mo[:, kpt_padded_moidx] = mo_coeff[k][:, kpt_moidx] if getattr(mo_coeff[k], 'orbspin', None) is not None: orbspin_dtype = mo_coeff[k].orbspin[kpt_moidx].dtype orbspin = numpy.zeros(nmo, dtype=orbspin_dtype) orbspin[kpt_padded_moidx] = mo_coeff[k].orbspin[kpt_moidx] mo = lib.tag_array(mo, orbspin=orbspin) eris.orbspin.append(orbspin) # FIXME: What if the user freezes all up spin orbitals in # an RHF calculation? The number of electrons will still be # even. else: # guess orbital spin - assumes an RHF calculation assert (numpy.count_nonzero(kpt_moidx) % 2 == 0) orbspin = numpy.zeros(mo.shape[1], dtype=int) orbspin[1::2] = 1 mo = lib.tag_array(mo, orbspin=orbspin) eris.orbspin.append(orbspin) eris.mo_coeff.append(mo) # Re-make our fock MO matrix elements from density and fock AO dm = cc._scf.make_rdm1(cc.mo_coeff, cc.mo_occ) with lib.temporary_env(cc._scf, exxdiv=None): # _scf.exxdiv affects eris.fock. HF exchange correction should be # excluded from the Fock matrix. fockao = cc._scf.get_hcore() + cc._scf.get_veff(cell, dm) eris.fock = numpy.asarray([ reduce(numpy.dot, (mo.T.conj(), fockao[k], mo)) for k, mo in enumerate(eris.mo_coeff) ]) eris.mo_energy = [eris.fock[k].diagonal().real for k in range(nkpts)] # Add HFX correction in the eris.mo_energy to improve convergence in # CCSD iteration. It is useful for the 2D systems since their occupied and # the virtual orbital energies may overlap which may lead to numerical # issue in the CCSD iterations. # FIXME: Whether to add this correction for other exxdiv treatments? # Without the correction, MP2 energy may be largely off the correct value. madelung = tools.madelung(cell, kpts) eris.mo_energy = [ _adjust_occ(mo_e, nocc, -madelung) for k, mo_e in enumerate(eris.mo_energy) ] # Get location of padded elements in occupied and virtual space. nocc_per_kpt = get_nocc(cc, per_kpoint=True) nonzero_padding = padding_k_idx(cc, kind="joint") # Check direct and indirect gaps for possible issues with CCSD convergence. mo_e = [eris.mo_energy[kp][nonzero_padding[kp]] for kp in range(nkpts)] mo_e = numpy.sort([y for x in mo_e for y in x]) # Sort de-nested array gap = mo_e[numpy.sum(nocc_per_kpt)] - mo_e[numpy.sum(nocc_per_kpt) - 1] if gap < 1e-5: logger.warn( cc, 'H**O-LUMO gap %s too small for KCCSD. ' 'May cause issues in convergence.', gap) kconserv = kpts_helper.get_kconserv(cell, kpts) if getattr(mo_coeff[0], 'orbspin', None) is None: # The bottom nao//2 coefficients are down (up) spin while the top are up (down). mo_a_coeff = [mo[:nao // 2] for mo in eris.mo_coeff] mo_b_coeff = [mo[nao // 2:] for mo in eris.mo_coeff] eri = numpy.empty((nkpts, nkpts, nkpts, nmo, nmo, nmo, nmo), dtype=numpy.complex128) fao2mo = cc._scf.with_df.ao2mo for kp, kq, kr in kpts_helper.loop_kkk(nkpts): ks = kconserv[kp, kq, kr] eri_kpt = fao2mo((mo_a_coeff[kp], mo_a_coeff[kq], mo_a_coeff[kr], mo_a_coeff[ks]), (kpts[kp], kpts[kq], kpts[kr], kpts[ks]), compact=False) eri_kpt += fao2mo((mo_b_coeff[kp], mo_b_coeff[kq], mo_b_coeff[kr], mo_b_coeff[ks]), (kpts[kp], kpts[kq], kpts[kr], kpts[ks]), compact=False) eri_kpt += fao2mo((mo_a_coeff[kp], mo_a_coeff[kq], mo_b_coeff[kr], mo_b_coeff[ks]), (kpts[kp], kpts[kq], kpts[kr], kpts[ks]), compact=False) eri_kpt += fao2mo((mo_b_coeff[kp], mo_b_coeff[kq], mo_a_coeff[kr], mo_a_coeff[ks]), (kpts[kp], kpts[kq], kpts[kr], kpts[ks]), compact=False) eri_kpt = eri_kpt.reshape(nmo, nmo, nmo, nmo) eri[kp, kq, kr] = eri_kpt else: mo_a_coeff = [mo[:nao // 2] + mo[nao // 2:] for mo in eris.mo_coeff] eri = numpy.empty((nkpts, nkpts, nkpts, nmo, nmo, nmo, nmo), dtype=numpy.complex128) fao2mo = cc._scf.with_df.ao2mo for kp, kq, kr in kpts_helper.loop_kkk(nkpts): ks = kconserv[kp, kq, kr] eri_kpt = fao2mo((mo_a_coeff[kp], mo_a_coeff[kq], mo_a_coeff[kr], mo_a_coeff[ks]), (kpts[kp], kpts[kq], kpts[kr], kpts[ks]), compact=False) eri_kpt[(eris.orbspin[kp][:, None] != eris.orbspin[kq]).ravel()] = 0 eri_kpt[:, (eris.orbspin[kr][:, None] != eris.orbspin[ks]).ravel()] = 0 eri_kpt = eri_kpt.reshape(nmo, nmo, nmo, nmo) eri[kp, kq, kr] = eri_kpt # Check some antisymmetrized properties of the integrals if DEBUG: check_antisymm_3412(cc, cc.kpts, eri) # Antisymmetrizing (pq|rs)-(ps|rq), where the latter integral is equal to # (rq|ps); done since we aren't tracking the kpoint of orbital 's' eri = eri - eri.transpose(2, 1, 0, 5, 4, 3, 6) # Chemist -> physics notation eri = eri.transpose(0, 2, 1, 3, 5, 4, 6) # Set the various integrals eris.dtype = eri.dtype eris.oooo = eri[:, :, :, :nocc, :nocc, :nocc, :nocc].copy() / nkpts eris.ooov = eri[:, :, :, :nocc, :nocc, :nocc, nocc:].copy() / nkpts eris.ovoo = eri[:, :, :, :nocc, nocc:, :nocc, :nocc].copy() / nkpts eris.oovv = eri[:, :, :, :nocc, :nocc, nocc:, nocc:].copy() / nkpts eris.ovov = eri[:, :, :, :nocc, nocc:, :nocc, nocc:].copy() / nkpts eris.ovvv = eri[:, :, :, :nocc, nocc:, nocc:, nocc:].copy() / nkpts eris.vvvv = eri[:, :, :, nocc:, nocc:, nocc:, nocc:].copy() / nkpts log.timer('CCSD integral transformation', *cput0) return eris
def spatial2spin(tx, orbspin, kconserv): '''Convert T1/T2 of spatial orbital representation to T1/T2 of spin-orbital representation ''' if isinstance(tx, numpy.ndarray) and tx.ndim == 3: # KRCCSD t1 amplitudes return spatial2spin((tx, tx), orbspin, kconserv) elif isinstance(tx, numpy.ndarray) and tx.ndim == 7: # KRCCSD t2 amplitudes t2aa = tx - tx.transpose(0, 1, 2, 4, 3, 5, 6) return spatial2spin((t2aa, tx, t2aa), orbspin, kconserv) elif len(tx) == 2: # KUCCSD t1 t1a, t1b = tx nocc_a, nvir_a = t1a.shape[1:] nocc_b, nvir_b = t1b.shape[1:] else: # KUCCSD t2 t2aa, t2ab, t2bb = tx nocc_a, nocc_b, nvir_a, nvir_b = t2ab.shape[3:] nkpts = len(orbspin) nocc = nocc_a + nocc_b nvir = nvir_a + nvir_b idxoa = [numpy.where(orbspin[k][:nocc] == 0)[0] for k in range(nkpts)] idxob = [numpy.where(orbspin[k][:nocc] == 1)[0] for k in range(nkpts)] idxva = [numpy.where(orbspin[k][nocc:] == 0)[0] for k in range(nkpts)] idxvb = [numpy.where(orbspin[k][nocc:] == 1)[0] for k in range(nkpts)] if len(tx) == 2: # t1 t1 = numpy.zeros((nkpts, nocc, nvir), dtype=t1a.dtype) for k in range(nkpts): lib.takebak_2d(t1[k], t1a[k], idxoa[k], idxva[k]) lib.takebak_2d(t1[k], t1b[k], idxob[k], idxvb[k]) t1 = lib.tag_array(t1, orbspin=orbspin) return t1 else: t2 = numpy.zeros((nkpts, nkpts, nkpts, nocc**2, nvir**2), dtype=t2aa.dtype) for ki, kj, ka in kpts_helper.loop_kkk(nkpts): kb = kconserv[ki, ka, kj] idxoaa = idxoa[ki][:, None] * nocc + idxoa[kj] idxoab = idxoa[ki][:, None] * nocc + idxob[kj] idxoba = idxob[kj][:, None] * nocc + idxoa[ki] idxobb = idxob[ki][:, None] * nocc + idxob[kj] idxvaa = idxva[ka][:, None] * nvir + idxva[kb] idxvab = idxva[ka][:, None] * nvir + idxvb[kb] idxvba = idxvb[kb][:, None] * nvir + idxva[ka] idxvbb = idxvb[ka][:, None] * nvir + idxvb[kb] tmp2aa = t2aa[ki, kj, ka].reshape(nocc_a * nocc_a, nvir_a * nvir_a) tmp2bb = t2bb[ki, kj, ka].reshape(nocc_b * nocc_b, nvir_b * nvir_b) tmp2ab = t2ab[ki, kj, ka].reshape(nocc_a * nocc_b, nvir_a * nvir_b) lib.takebak_2d(t2[ki, kj, ka], tmp2aa, idxoaa.ravel(), idxvaa.ravel()) lib.takebak_2d(t2[ki, kj, ka], tmp2bb, idxobb.ravel(), idxvbb.ravel()) lib.takebak_2d(t2[ki, kj, ka], tmp2ab, idxoab.ravel(), idxvab.ravel()) lib.takebak_2d(t2[kj, ki, kb], tmp2ab, idxoba.T.ravel(), idxvba.T.ravel()) abba = -tmp2ab lib.takebak_2d(t2[ki, kj, kb], abba, idxoab.ravel(), idxvba.T.ravel()) lib.takebak_2d(t2[kj, ki, ka], abba, idxoba.T.ravel(), idxvab.ravel()) t2 = t2.reshape(nkpts, nkpts, nkpts, nocc, nocc, nvir, nvir) t2 = lib.tag_array(t2, orbspin=orbspin) return t2
def update_amps(cc, t1, t2, eris): time0 = time1 = time.clock(), time.time() log = logger.Logger(cc.stdout, cc.verbose) nkpts, nocc, nvir = t1.shape fock = eris.fock mo_e_o = [e[:nocc] for e in eris.mo_energy] mo_e_v = [e[nocc:] + cc.level_shift for e in eris.mo_energy] # Get location of padded elements in occupied and virtual space nonzero_opadding, nonzero_vpadding = padding_k_idx(cc, kind="split") fov = fock[:, :nocc, nocc:] foo = fock[:, :nocc, :nocc] fvv = fock[:, nocc:, nocc:] kconserv = cc.khelper.kconserv Foo = imdk.cc_Foo(t1, t2, eris, kconserv) Fvv = imdk.cc_Fvv(t1, t2, eris, kconserv) Fov = imdk.cc_Fov(t1, t2, eris, kconserv) Loo = imdk.Loo(t1, t2, eris, kconserv) Lvv = imdk.Lvv(t1, t2, eris, kconserv) # Move energy terms to the other side for k in range(nkpts): Foo[k][np.diag_indices(nocc)] -= mo_e_o[k] Fvv[k][np.diag_indices(nvir)] -= mo_e_v[k] Loo[k][np.diag_indices(nocc)] -= mo_e_o[k] Lvv[k][np.diag_indices(nvir)] -= mo_e_v[k] time1 = log.timer_debug1('intermediates', *time1) # T1 equation t1new = np.array(fov).astype(t1.dtype).conj() for ka in range(nkpts): ki = ka # kc == ki; kk == ka t1new[ka] += -2. * einsum('kc,ka,ic->ia', fov[ki], t1[ka], t1[ki]) t1new[ka] += einsum('ac,ic->ia', Fvv[ka], t1[ki]) t1new[ka] += -einsum('ki,ka->ia', Foo[ki], t1[ka]) tau_term = np.empty((nkpts, nocc, nocc, nvir, nvir), dtype=t1.dtype) for kk in range(nkpts): tau_term[kk] = 2 * t2[kk, ki, kk] - t2[ki, kk, kk].transpose(1, 0, 2, 3) tau_term[ka] += einsum('ic,ka->kica', t1[ki], t1[ka]) for kk in range(nkpts): kc = kk t1new[ka] += einsum('kc,kica->ia', Fov[kc], tau_term[kk]) t1new[ka] += einsum('akic,kc->ia', 2 * eris.voov[ka, kk, ki], t1[kc]) t1new[ka] += einsum('kaic,kc->ia', -eris.ovov[kk, ka, ki], t1[kc]) for kc in range(nkpts): kd = kconserv[ka, kc, kk] Svovv = 2 * eris.vovv[ka, kk, kc] - eris.vovv[ka, kk, kd].transpose(0, 1, 3, 2) tau_term_1 = t2[ki, kk, kc].copy() if ki == kc and kk == kd: tau_term_1 += einsum('ic,kd->ikcd', t1[ki], t1[kk]) t1new[ka] += einsum('akcd,ikcd->ia', Svovv, tau_term_1) # kk - ki + kl = kc # => kl = ki - kk + kc kl = kconserv[ki, kk, kc] Sooov = 2 * eris.ooov[kk, kl, ki] - eris.ooov[kl, kk, ki].transpose(1, 0, 2, 3) tau_term_1 = t2[kk, kl, ka].copy() if kk == ka and kl == kc: tau_term_1 += einsum('ka,lc->klac', t1[ka], t1[kc]) t1new[ka] += -einsum('klic,klac->ia', Sooov, tau_term_1) time1 = log.timer_debug1('t1', *time1) # T2 equation t2new = np.empty_like(t2) for ki, kj, ka in kpts_helper.loop_kkk(nkpts): t2new[ki, kj, ka] = eris.oovv[ki, kj, ka].conj() mem_now = lib.current_memory()[0] if (nocc ** 4 * nkpts ** 3) * 16 / 1e6 + mem_now < cc.max_memory * .9: Woooo = imdk.cc_Woooo(t1, t2, eris, kconserv) else: fimd = lib.H5TmpFile() Woooo = fimd.create_dataset('oooo', (nkpts, nkpts, nkpts, nocc, nocc, nocc, nocc), t1.dtype.char) Woooo = imdk.cc_Woooo(t1, t2, eris, kconserv, Woooo) for ki, kj, ka in kpts_helper.loop_kkk(nkpts): # Chemist's notation for momentum conserving t2(ki,kj,ka,kb) kb = kconserv[ki, ka, kj] t2new_tmp = np.zeros((nocc, nocc, nvir, nvir), dtype=t2.dtype) for kl in range(nkpts): kk = kconserv[kj, kl, ki] tau_term = t2[kk, kl, ka].copy() if kl == kb and kk == ka: tau_term += einsum('ic,jd->ijcd', t1[ka], t1[kb]) t2new_tmp += 0.5 * einsum('klij,klab->ijab', Woooo[kk, kl, ki], tau_term) t2new[ki, kj, ka] += t2new_tmp t2new[kj, ki, kb] += t2new_tmp.transpose(1, 0, 3, 2) Woooo = None fimd = None time1 = log.timer_debug1('t2 oooo', *time1) # einsum('abcd,ijcd->ijab', Wvvvv, tau) add_vvvv_(cc, t2new, t1, t2, eris) time1 = log.timer_debug1('t2 vvvv', *time1) for ki, kj, ka in kpts_helper.loop_kkk(nkpts): kb = kconserv[ki, ka, kj] t2new_tmp = einsum('ac,ijcb->ijab', Lvv[ka], t2[ki, kj, ka]) t2new_tmp += einsum('ki,kjab->ijab', -Loo[ki], t2[ki, kj, ka]) kc = kconserv[ka, ki, kb] tmp2 = np.asarray(eris.vovv[kc, ki, kb]).transpose(3, 2, 1, 0).conj() \ - einsum('kbic,ka->abic', eris.ovov[ka, kb, ki], t1[ka]) t2new_tmp += einsum('abic,jc->ijab', tmp2, t1[kj]) kk = kconserv[ki, ka, kj] tmp2 = np.asarray(eris.ooov[kj, ki, kk]).transpose(3, 2, 1, 0).conj() \ + einsum('akic,jc->akij', eris.voov[ka, kk, ki], t1[kj]) t2new_tmp -= einsum('akij,kb->ijab', tmp2, t1[kb]) t2new[ki, kj, ka] += t2new_tmp t2new[kj, ki, kb] += t2new_tmp.transpose(1, 0, 3, 2) mem_now = lib.current_memory()[0] if (nocc ** 2 * nvir ** 2 * nkpts ** 3) * 16 / 1e6 * 2 + mem_now < cc.max_memory * .9: Wvoov = imdk.cc_Wvoov(t1, t2, eris, kconserv) Wvovo = imdk.cc_Wvovo(t1, t2, eris, kconserv) else: fimd = lib.H5TmpFile() Wvoov = fimd.create_dataset('voov', (nkpts, nkpts, nkpts, nvir, nocc, nocc, nvir), t1.dtype.char) Wvovo = fimd.create_dataset('vovo', (nkpts, nkpts, nkpts, nvir, nocc, nvir, nocc), t1.dtype.char) Wvoov = imdk.cc_Wvoov(t1, t2, eris, kconserv, Wvoov) Wvovo = imdk.cc_Wvovo(t1, t2, eris, kconserv, Wvovo) for ki, kj, ka in kpts_helper.loop_kkk(nkpts): kb = kconserv[ki, ka, kj] t2new_tmp = np.zeros((nocc, nocc, nvir, nvir), dtype=t2.dtype) for kk in range(nkpts): kc = kconserv[ka, ki, kk] tmp_voov = 2. * Wvoov[ka, kk, ki] - Wvovo[ka, kk, kc].transpose(0, 1, 3, 2) t2new_tmp += einsum('akic,kjcb->ijab', tmp_voov, t2[kk, kj, kc]) kc = kconserv[ka, ki, kk] t2new_tmp -= einsum('akic,kjbc->ijab', Wvoov[ka, kk, ki], t2[kk, kj, kb]) kc = kconserv[kk, ka, kj] t2new_tmp -= einsum('bkci,kjac->ijab', Wvovo[kb, kk, kc], t2[kk, kj, ka]) t2new[ki, kj, ka] += t2new_tmp t2new[kj, ki, kb] += t2new_tmp.transpose(1, 0, 3, 2) Wvoov = Wvovo = None fimd = None time1 = log.timer_debug1('t2 voov', *time1) for ki in range(nkpts): ka = ki # Remove zero/padded elements from denominator eia = LARGE_DENOM * np.ones((nocc, nvir), dtype=eris.mo_energy[0].dtype) n0_ovp_ia = np.ix_(nonzero_opadding[ki], nonzero_vpadding[ka]) eia[n0_ovp_ia] = (mo_e_o[ki][:,None] - mo_e_v[ka])[n0_ovp_ia] t1new[ki] /= eia for ki, kj, ka in kpts_helper.loop_kkk(nkpts): kb = kconserv[ki, ka, kj] # For LARGE_DENOM, see t1new update above eia = LARGE_DENOM * np.ones((nocc, nvir), dtype=eris.mo_energy[0].dtype) n0_ovp_ia = np.ix_(nonzero_opadding[ki], nonzero_vpadding[ka]) eia[n0_ovp_ia] = (mo_e_o[ki][:,None] - mo_e_v[ka])[n0_ovp_ia] ejb = LARGE_DENOM * np.ones((nocc, nvir), dtype=eris.mo_energy[0].dtype) n0_ovp_jb = np.ix_(nonzero_opadding[kj], nonzero_vpadding[kb]) ejb[n0_ovp_jb] = (mo_e_o[kj][:,None] - mo_e_v[kb])[n0_ovp_jb] eijab = eia[:, None, :, None] + ejb[:, None, :] t2new[ki, kj, ka] /= eijab time0 = log.timer_debug1('update t1 t2', *time0) return t1new, t2new
def add_vvvv_(cc, Ht2, t1, t2, eris): nocc = cc.nocc nmo = cc.nmo nvir = nmo - nocc nkpts = cc.nkpts kconserv = cc.khelper.kconserv mem_now = lib.current_memory()[0] if cc.direct and getattr(eris, 'Lpv', None) is not None: #: If memory is not enough to hold eris.Lpv #:def get_Wvvvv(ka, kb, kc): #: kd = kconserv[ka,kc,kb] #: v = cc._scf.with_df.ao2mo([eris.mo_coeff[k] for k in [ka,kc,kb,kd]], #: cc.kpts[[ka,kc,kb,kd]]).reshape([nmo]*4) #: Wvvvv = lib.einsum('kcbd,ka->abcd', v[:nocc,nocc:,nocc:,nocc:], -t1[ka]) #: Wvvvv += lib.einsum('ackd,kb->abcd', v[nocc:,nocc:,:nocc,nocc:], -t1[kb]) #: Wvvvv += v[nocc:,nocc:,nocc:,nocc:].transpose(0,2,1,3) #: Wvvvv *= (1./nkpts) #: return Wvvvv def get_Wvvvv(ka, kb, kc): Lpv = eris.Lpv kd = kconserv[ka, kc, kb] Lbd = (Lpv[kb,kd][:,nocc:] - lib.einsum('Lkd,kb->Lbd', Lpv[kb,kd][:,:nocc], t1[kb])) Wvvvv = lib.einsum('Lac,Lbd->abcd', Lpv[ka,kc][:,nocc:], Lbd) Lbd = None kcbd = lib.einsum('Lkc,Lbd->kcbd', Lpv[ka,kc][:,:nocc], Lpv[kb,kd][:,nocc:]) Wvvvv -= lib.einsum('kcbd,ka->abcd', kcbd, t1[ka]) Wvvvv *= (1. / nkpts) return Wvvvv elif (nvir ** 4 * nkpts ** 3) * 16 / 1e6 + mem_now < cc.max_memory * .9: _Wvvvv = imdk.cc_Wvvvv(t1, t2, eris, kconserv) def get_Wvvvv(ka, kb, kc): return _Wvvvv[ka, kb, kc] else: fimd = lib.H5TmpFile() _Wvvvv = fimd.create_dataset('vvvv', (nkpts, nkpts, nkpts, nvir, nvir, nvir, nvir), t1.dtype.char) _Wvvvv = imdk.cc_Wvvvv(t1, t2, eris, kconserv, _Wvvvv) def get_Wvvvv(ka, kb, kc): return _Wvvvv[ka, kb, kc] #:Ps = kconserve_pmatrix(cc.nkpts, cc.khelper.kconserv) #:Wvvvv = einsum('xyzakcd,ykb->xyzabcd', eris.vovv, -t1) #:Wvvvv = Wvvvv + einsum('xyzabcd,xyzw->yxwbadc', Wvvvv, Ps) #:Wvvvv += eris.vvvv #: #:tau = t2.copy() #:idx = np.arange(nkpts) #:tau[idx,:,idx] += einsum('xic,yjd->xyijcd', t1, t1) #:Ht2 += einsum('xyuijcd,zwuabcd,xyuv,zwuv->xyzijab', tau, Wvvvv, Ps, Ps) for ka, kb, kc in kpts_helper.loop_kkk(nkpts): kd = kconserv[ka, kc, kb] Wvvvv = get_Wvvvv(ka, kb, kc) for ki in range(nkpts): kj = kconserv[ka, ki, kb] tau = t2[ki, kj, kc].copy() if ki == kc and kj == kd: tau += np.einsum('ic,jd->ijcd', t1[ki], t1[kj]) Ht2[ki, kj, ka] += lib.einsum('abcd,ijcd->ijab', Wvvvv, tau) fimd = None return Ht2
def _make_eris_incore(cc, mo_coeff=None): log = logger.Logger(cc.stdout, cc.verbose) cput0 = (time.clock(), time.time()) eris = gccsd._PhysicistsERIs() kpts = cc.kpts nkpts = cc.nkpts nocc = cc.nocc nmo = cc.nmo nvir = nmo - nocc eris.nocc = nocc #if any(nocc != numpy.count_nonzero(cc._scf.mo_occ[k] > 0) for k in range(nkpts)): # raise NotImplementedError('Different occupancies found for different k-points') if mo_coeff is None: mo_coeff = cc.mo_coeff #else: # # If mo_coeff is not canonical orbital # # TODO does this work for k-points? changed to conjugate. # raise NotImplementedError nao = mo_coeff[0].shape[0] dtype = mo_coeff[0].dtype moidx = get_frozen_mask(cc) nocc_per_kpt = numpy.asarray(get_nocc(cc, per_kpoint=True)) nmo_per_kpt = numpy.asarray(get_nmo(cc, per_kpoint=True)) padded_moidx = [] for k in range(nkpts): kpt_nocc = nocc_per_kpt[k] kpt_nvir = nmo_per_kpt[k] - kpt_nocc kpt_padded_moidx = numpy.concatenate( (numpy.ones(kpt_nocc, dtype=numpy.bool), numpy.zeros(nmo - kpt_nocc - kpt_nvir, dtype=numpy.bool), numpy.ones(kpt_nvir, dtype=numpy.bool))) padded_moidx.append(kpt_padded_moidx) eris.mo_coeff = [] eris.orbspin = [] # Generate the molecular orbital coefficients with the frozen orbitals masked. # Each MO is tagged with orbspin, a list of 0's and 1's that give the overall # spin of each MO. # # Here we will work with two index arrays; one is for our original (small) moidx # array while the next is for our new (large) padded array. for k in range(nkpts): kpt_moidx = moidx[k] kpt_padded_moidx = padded_moidx[k] mo = numpy.zeros((nao, nmo), dtype=dtype) mo[:, kpt_padded_moidx] = mo_coeff[k][:, kpt_moidx] if hasattr(mo_coeff[k], 'orbspin'): orbspin_dtype = mo_coeff[k].orbspin[kpt_moidx].dtype orbspin = numpy.zeros(nmo, dtype=orbspin_dtype) orbspin[kpt_padded_moidx] = mo_coeff[k].orbspin[kpt_moidx] mo = lib.tag_array(mo, orbspin=orbspin) eris.orbspin.append(orbspin) # FIXME: What if the user freezes all up spin orbitals in # an RHF calculation? The number of electrons will still be # even. else: # guess orbital spin - assumes an RHF calculation assert (numpy.count_nonzero(kpt_moidx) % 2 == 0) orbspin = numpy.zeros(mo.shape[1], dtype=int) orbspin[1::2] = 1 mo = lib.tag_array(mo, orbspin=orbspin) eris.orbspin.append(orbspin) eris.mo_coeff.append(mo) # Re-make our fock MO matrix elements from density and fock AO dm = cc._scf.make_rdm1(cc.mo_coeff, cc.mo_occ) fockao = cc._scf.get_hcore() + cc._scf.get_veff(cc._scf.cell, dm) eris.fock = numpy.asarray([ reduce(numpy.dot, (mo.T.conj(), fockao[k], mo)) for k, mo in enumerate(eris.mo_coeff) ]) kconserv = kpts_helper.get_kconserv(cc._scf.cell, cc.kpts) # The bottom nao//2 coefficients are down (up) spin while the top are up (down). # These are 'spin-less' quantities; spin-conservation will be added manually. so_coeff = [mo[:nao // 2] + mo[nao // 2:] for mo in eris.mo_coeff] eri = numpy.empty((nkpts, nkpts, nkpts, nmo, nmo, nmo, nmo), dtype=numpy.complex128) fao2mo = cc._scf.with_df.ao2mo for kp, kq, kr in kpts_helper.loop_kkk(nkpts): ks = kconserv[kp, kq, kr] eri_kpt = fao2mo( (so_coeff[kp], so_coeff[kq], so_coeff[kr], so_coeff[ks]), (kpts[kp], kpts[kq], kpts[kr], kpts[ks]), compact=False) eri_kpt[(eris.orbspin[kp][:, None] != eris.orbspin[kq]).ravel()] = 0 eri_kpt[:, (eris.orbspin[kr][:, None] != eris.orbspin[ks]).ravel()] = 0 eri_kpt = eri_kpt.reshape(nmo, nmo, nmo, nmo) eri[kp, kq, kr] = eri_kpt # Check some antisymmetrized properties of the integrals if DEBUG: check_antisymm_3412(cc, cc.kpts, eri) # Antisymmetrizing (pq|rs)-(ps|rq), where the latter integral is equal to # (rq|ps); done since we aren't tracking the kpoint of orbital 's' eri = eri - eri.transpose(2, 1, 0, 5, 4, 3, 6) # Chemist -> physics notation eri = eri.transpose(0, 2, 1, 3, 5, 4, 6) # Set the various integrals eris.dtype = eri.dtype eris.oooo = eri[:, :, :, :nocc, :nocc, :nocc, :nocc].copy() / nkpts eris.ooov = eri[:, :, :, :nocc, :nocc, :nocc, nocc:].copy() / nkpts eris.ovoo = eri[:, :, :, :nocc, nocc:, :nocc, :nocc].copy() / nkpts eris.oovv = eri[:, :, :, :nocc, :nocc, nocc:, nocc:].copy() / nkpts eris.ovov = eri[:, :, :, :nocc, nocc:, :nocc, nocc:].copy() / nkpts eris.ovvv = eri[:, :, :, :nocc, nocc:, nocc:, nocc:].copy() / nkpts eris.vvvv = eri[:, :, :, nocc:, nocc:, nocc:, nocc:].copy() / nkpts log.timer('CCSD integral transformation', *cput0) return eris
def update_amps(cc, t1, t2, eris): time0 = time.clock(), time.time() log = logger.Logger(cc.stdout, cc.verbose) nkpts, nocc, nvir = t1.shape fock = eris.fock mo_e_o = [e[:nocc] for e in eris.mo_energy] mo_e_v = [e[nocc:] + cc.level_shift for e in eris.mo_energy] # Get location of padded elements in occupied and virtual space nonzero_opadding, nonzero_vpadding = padding_k_idx(cc, kind="split") fov = fock[:, :nocc, nocc:].copy() foo = fock[:, :nocc, :nocc].copy() fvv = fock[:, nocc:, nocc:].copy() # Get the momentum conservation array # Note: chemist's notation for momentum conserving t2(ki,kj,ka,kb), even though # integrals are in physics notation kconserv = kpts_helper.get_kconserv(cc._scf.cell, cc.kpts) tau = imdk.make_tau(cc, t2, t1, t1, kconserv) Fvv = imdk.cc_Fvv(cc, t1, t2, eris, kconserv) Foo = imdk.cc_Foo(cc, t1, t2, eris, kconserv) Fov = imdk.cc_Fov(cc, t1, t2, eris, kconserv) Woooo = imdk.cc_Woooo(cc, t1, t2, eris, kconserv) Wvvvv = imdk.cc_Wvvvv(cc, t1, t2, eris, kconserv) Wovvo = imdk.cc_Wovvo(cc, t1, t2, eris, kconserv) # Move energy terms to the other side for k in range(nkpts): Foo[k][numpy.diag_indices(nocc)] -= mo_e_o[k] Fvv[k][numpy.diag_indices(nvir)] -= mo_e_v[k] eris_ovvo = numpy.zeros(shape=(nkpts, nkpts, nkpts, nocc, nvir, nvir, nocc), dtype=t2.dtype) eris_oovo = numpy.zeros(shape=(nkpts, nkpts, nkpts, nocc, nocc, nvir, nocc), dtype=t2.dtype) eris_vvvo = numpy.zeros(shape=(nkpts, nkpts, nkpts, nvir, nvir, nvir, nocc), dtype=t2.dtype) for km, kb, ke in kpts_helper.loop_kkk(nkpts): kj = kconserv[km, ke, kb] # <mb||je> -> -<mb||ej> eris_ovvo[km, kb, ke] = -eris.ovov[km, kb, kj].transpose(0, 1, 3, 2) # <mn||je> -> -<mn||ej> # let kb = kn as a dummy variable eris_oovo[km, kb, ke] = -eris.ooov[km, kb, kj].transpose(0, 1, 3, 2) # <ma||be> -> - <be||am>* # let kj = ka as a dummy variable kj = kconserv[km, ke, kb] eris_vvvo[ke, kj, kb] = -eris.ovvv[km, kb, ke].transpose(2, 3, 1, 0).conj() # T1 equation t1new = numpy.zeros(shape=t1.shape, dtype=t1.dtype) for ka in range(nkpts): ki = ka t1new[ka] += numpy.array(fov[ka, :, :]).conj() t1new[ka] += einsum('ie,ae->ia', t1[ka], Fvv[ka]) t1new[ka] += -einsum('ma,mi->ia', t1[ka], Foo[ka]) for km in range(nkpts): t1new[ka] += einsum('imae,me->ia', t2[ka, km, ka], Fov[km]) t1new[ka] += -einsum('nf,naif->ia', t1[km], eris.ovov[km, ka, ki]) for kn in range(nkpts): ke = kconserv[km, ki, kn] t1new[ka] += -0.5 * einsum('imef,maef->ia', t2[ki, km, ke], eris.ovvv[km, ka, ke]) t1new[ka] += -0.5 * einsum('mnae,nmei->ia', t2[km, kn, ka], eris_oovo[kn, km, ke]) # T2 equation t2new = numpy.array(eris.oovv).conj() for ki, kj, ka in kpts_helper.loop_kkk(nkpts): # Chemist's notation for momentum conserving t2(ki,kj,ka,kb) kb = kconserv[ki, ka, kj] Ftmp = Fvv[kb] - 0.5 * einsum('mb,me->be', t1[kb], Fov[kb]) tmp = einsum('ijae,be->ijab', t2[ki, kj, ka], Ftmp) t2new[ki, kj, ka] += tmp #t2new[ki,kj,kb] -= tmp.transpose(0,1,3,2) Ftmp = Fvv[ka] - 0.5 * einsum('ma,me->ae', t1[ka], Fov[ka]) tmp = einsum('ijbe,ae->ijab', t2[ki, kj, kb], Ftmp) t2new[ki, kj, ka] -= tmp Ftmp = Foo[kj] + 0.5 * einsum('je,me->mj', t1[kj], Fov[kj]) tmp = einsum('imab,mj->ijab', t2[ki, kj, ka], Ftmp) t2new[ki, kj, ka] -= tmp #t2new[kj,ki,ka] += tmp.transpose(1,0,2,3) Ftmp = Foo[ki] + 0.5 * einsum('ie,me->mi', t1[ki], Fov[ki]) tmp = einsum('jmab,mi->ijab', t2[kj, ki, ka], Ftmp) t2new[ki, kj, ka] += tmp for km in range(nkpts): # Wminj # - km - kn + ka + kb = 0 # => kn = ka - km + kb kn = kconserv[ka, km, kb] t2new[ki, kj, ka] += 0.5 * einsum('mnab,mnij->ijab', tau[km, kn, ka], Woooo[km, kn, ki]) ke = km t2new[ki, kj, ka] += 0.5 * einsum('ijef,abef->ijab', tau[ki, kj, ke], Wvvvv[ka, kb, ke]) # Wmbej # - km - kb + ke + kj = 0 # => ke = km - kj + kb ke = kconserv[km, kj, kb] tmp = einsum('imae,mbej->ijab', t2[ki, km, ka], Wovvo[km, kb, ke]) # - km - kb + ke + kj = 0 # => ke = km - kj + kb # # t[i,e] => ki = ke # t[m,a] => km = ka if km == ka and ke == ki: tmp -= einsum('ie,ma,mbej->ijab', t1[ki], t1[km], eris_ovvo[km, kb, ke]) t2new[ki, kj, ka] += tmp t2new[ki, kj, kb] -= tmp.transpose(0, 1, 3, 2) t2new[kj, ki, ka] -= tmp.transpose(1, 0, 2, 3) t2new[kj, ki, kb] += tmp.transpose(1, 0, 3, 2) ke = ki tmp = einsum('ie,abej->ijab', t1[ki], eris_vvvo[ka, kb, ke]) t2new[ki, kj, ka] += tmp # P(ij) term ke = kj tmp = einsum('je,abei->ijab', t1[kj], eris_vvvo[ka, kb, ke]) t2new[ki, kj, ka] -= tmp km = ka tmp = einsum('ma,mbij->ijab', t1[ka], eris.ovoo[km, kb, ki]) t2new[ki, kj, ka] -= tmp # P(ab) term km = kb tmp = einsum('mb,maij->ijab', t1[kb], eris.ovoo[km, ka, ki]) t2new[ki, kj, ka] += tmp for ki in range(nkpts): ka = ki # Remove zero/padded elements from denominator eia = LARGE_DENOM * numpy.ones((nocc, nvir), dtype=eris.mo_energy[0].dtype) n0_ovp_ia = numpy.ix_(nonzero_opadding[ki], nonzero_vpadding[ka]) eia[n0_ovp_ia] = (mo_e_o[ki][:,None] - mo_e_v[ka])[n0_ovp_ia] t1new[ki] /= eia kconserv = kpts_helper.get_kconserv(cc._scf.cell, cc.kpts) for ki, kj, ka in kpts_helper.loop_kkk(nkpts): kb = kconserv[ki, ka, kj] # For LARGE_DENOM, see t1new update above eia = LARGE_DENOM * numpy.ones((nocc, nvir), dtype=eris.mo_energy[0].dtype) n0_ovp_ia = numpy.ix_(nonzero_opadding[ki], nonzero_vpadding[ka]) eia[n0_ovp_ia] = (mo_e_o[ki][:,None] - mo_e_v[ka])[n0_ovp_ia] ejb = LARGE_DENOM * numpy.ones((nocc, nvir), dtype=eris.mo_energy[0].dtype) n0_ovp_jb = numpy.ix_(nonzero_opadding[kj], nonzero_vpadding[kb]) ejb[n0_ovp_jb] = (mo_e_o[kj][:,None] - mo_e_v[kb])[n0_ovp_jb] eijab = eia[:, None, :, None] + ejb[:, None, :] t2new[ki, kj, ka] /= eijab time0 = log.timer_debug1('update t1 t2', *time0) return t1new, t2new
def _make_eris_incore(cc, mo_coeff=None): from pyscf.pbc import tools from pyscf.pbc.cc.ccsd import _adjust_occ log = logger.Logger(cc.stdout, cc.verbose) cput0 = (time.clock(), time.time()) eris = gccsd._PhysicistsERIs() cell = cc._scf.cell kpts = cc.kpts nkpts = cc.nkpts nocc = cc.nocc nmo = cc.nmo nvir = nmo - nocc eris.nocc = nocc #if any(nocc != numpy.count_nonzero(cc._scf.mo_occ[k] > 0) for k in range(nkpts)): # raise NotImplementedError('Different occupancies found for different k-points') if mo_coeff is None: mo_coeff = cc.mo_coeff nao = mo_coeff[0].shape[0] dtype = mo_coeff[0].dtype moidx = get_frozen_mask(cc) nocc_per_kpt = numpy.asarray(get_nocc(cc, per_kpoint=True)) nmo_per_kpt = numpy.asarray(get_nmo(cc, per_kpoint=True)) padded_moidx = [] for k in range(nkpts): kpt_nocc = nocc_per_kpt[k] kpt_nvir = nmo_per_kpt[k] - kpt_nocc kpt_padded_moidx = numpy.concatenate((numpy.ones(kpt_nocc, dtype=numpy.bool), numpy.zeros(nmo - kpt_nocc - kpt_nvir, dtype=numpy.bool), numpy.ones(kpt_nvir, dtype=numpy.bool))) padded_moidx.append(kpt_padded_moidx) eris.mo_coeff = [] eris.orbspin = [] # Generate the molecular orbital coefficients with the frozen orbitals masked. # Each MO is tagged with orbspin, a list of 0's and 1's that give the overall # spin of each MO. # # Here we will work with two index arrays; one is for our original (small) moidx # array while the next is for our new (large) padded array. for k in range(nkpts): kpt_moidx = moidx[k] kpt_padded_moidx = padded_moidx[k] mo = numpy.zeros((nao, nmo), dtype=dtype) mo[:, kpt_padded_moidx] = mo_coeff[k][:, kpt_moidx] if getattr(mo_coeff[k], 'orbspin', None) is not None: orbspin_dtype = mo_coeff[k].orbspin[kpt_moidx].dtype orbspin = numpy.zeros(nmo, dtype=orbspin_dtype) orbspin[kpt_padded_moidx] = mo_coeff[k].orbspin[kpt_moidx] mo = lib.tag_array(mo, orbspin=orbspin) eris.orbspin.append(orbspin) # FIXME: What if the user freezes all up spin orbitals in # an RHF calculation? The number of electrons will still be # even. else: # guess orbital spin - assumes an RHF calculation assert (numpy.count_nonzero(kpt_moidx) % 2 == 0) orbspin = numpy.zeros(mo.shape[1], dtype=int) orbspin[1::2] = 1 mo = lib.tag_array(mo, orbspin=orbspin) eris.orbspin.append(orbspin) eris.mo_coeff.append(mo) # Re-make our fock MO matrix elements from density and fock AO dm = cc._scf.make_rdm1(cc.mo_coeff, cc.mo_occ) with lib.temporary_env(cc._scf, exxdiv=None): # _scf.exxdiv affects eris.fock. HF exchange correction should be # excluded from the Fock matrix. fockao = cc._scf.get_hcore() + cc._scf.get_veff(cell, dm) eris.fock = numpy.asarray([reduce(numpy.dot, (mo.T.conj(), fockao[k], mo)) for k, mo in enumerate(eris.mo_coeff)]) eris.mo_energy = [eris.fock[k].diagonal().real for k in range(nkpts)] # Add HFX correction in the eris.mo_energy to improve convergence in # CCSD iteration. It is useful for the 2D systems since their occupied and # the virtual orbital energies may overlap which may lead to numerical # issue in the CCSD iterations. # FIXME: Whether to add this correction for other exxdiv treatments? # Without the correction, MP2 energy may be largely off the correct value. madelung = tools.madelung(cell, kpts) eris.mo_energy = [_adjust_occ(mo_e, nocc, -madelung) for k, mo_e in enumerate(eris.mo_energy)] # Get location of padded elements in occupied and virtual space. nocc_per_kpt = get_nocc(cc, per_kpoint=True) nonzero_padding = padding_k_idx(cc, kind="joint") # Check direct and indirect gaps for possible issues with CCSD convergence. mo_e = [eris.mo_energy[kp][nonzero_padding[kp]] for kp in range(nkpts)] mo_e = numpy.sort([y for x in mo_e for y in x]) # Sort de-nested array gap = mo_e[numpy.sum(nocc_per_kpt)] - mo_e[numpy.sum(nocc_per_kpt)-1] if gap < 1e-5: logger.warn(cc, 'H**O-LUMO gap %s too small for KCCSD. ' 'May cause issues in convergence.', gap) kconserv = kpts_helper.get_kconserv(cell, kpts) if getattr(mo_coeff[0], 'orbspin', None) is None: # The bottom nao//2 coefficients are down (up) spin while the top are up (down). mo_a_coeff = [mo[:nao // 2] for mo in eris.mo_coeff] mo_b_coeff = [mo[nao // 2:] for mo in eris.mo_coeff] eri = numpy.empty((nkpts, nkpts, nkpts, nmo, nmo, nmo, nmo), dtype=numpy.complex128) fao2mo = cc._scf.with_df.ao2mo for kp, kq, kr in kpts_helper.loop_kkk(nkpts): ks = kconserv[kp, kq, kr] eri_kpt = fao2mo( (mo_a_coeff[kp], mo_a_coeff[kq], mo_a_coeff[kr], mo_a_coeff[ks]), (kpts[kp], kpts[kq], kpts[kr], kpts[ks]), compact=False) eri_kpt += fao2mo( (mo_b_coeff[kp], mo_b_coeff[kq], mo_b_coeff[kr], mo_b_coeff[ks]), (kpts[kp], kpts[kq], kpts[kr], kpts[ks]), compact=False) eri_kpt += fao2mo( (mo_a_coeff[kp], mo_a_coeff[kq], mo_b_coeff[kr], mo_b_coeff[ks]), (kpts[kp], kpts[kq], kpts[kr], kpts[ks]), compact=False) eri_kpt += fao2mo( (mo_b_coeff[kp], mo_b_coeff[kq], mo_a_coeff[kr], mo_a_coeff[ks]), (kpts[kp], kpts[kq], kpts[kr], kpts[ks]), compact=False) eri_kpt = eri_kpt.reshape(nmo, nmo, nmo, nmo) eri[kp, kq, kr] = eri_kpt else: mo_a_coeff = [mo[:nao // 2] + mo[nao // 2:] for mo in eris.mo_coeff] eri = numpy.empty((nkpts, nkpts, nkpts, nmo, nmo, nmo, nmo), dtype=numpy.complex128) fao2mo = cc._scf.with_df.ao2mo for kp, kq, kr in kpts_helper.loop_kkk(nkpts): ks = kconserv[kp, kq, kr] eri_kpt = fao2mo( (mo_a_coeff[kp], mo_a_coeff[kq], mo_a_coeff[kr], mo_a_coeff[ks]), (kpts[kp], kpts[kq], kpts[kr], kpts[ks]), compact=False) eri_kpt[(eris.orbspin[kp][:, None] != eris.orbspin[kq]).ravel()] = 0 eri_kpt[:, (eris.orbspin[kr][:, None] != eris.orbspin[ks]).ravel()] = 0 eri_kpt = eri_kpt.reshape(nmo, nmo, nmo, nmo) eri[kp, kq, kr] = eri_kpt # Check some antisymmetrized properties of the integrals if DEBUG: check_antisymm_3412(cc, cc.kpts, eri) # Antisymmetrizing (pq|rs)-(ps|rq), where the latter integral is equal to # (rq|ps); done since we aren't tracking the kpoint of orbital 's' eri = eri - eri.transpose(2, 1, 0, 5, 4, 3, 6) # Chemist -> physics notation eri = eri.transpose(0, 2, 1, 3, 5, 4, 6) # Set the various integrals eris.dtype = eri.dtype eris.oooo = eri[:, :, :, :nocc, :nocc, :nocc, :nocc].copy() / nkpts eris.ooov = eri[:, :, :, :nocc, :nocc, :nocc, nocc:].copy() / nkpts eris.ovoo = eri[:, :, :, :nocc, nocc:, :nocc, :nocc].copy() / nkpts eris.oovv = eri[:, :, :, :nocc, :nocc, nocc:, nocc:].copy() / nkpts eris.ovov = eri[:, :, :, :nocc, nocc:, :nocc, nocc:].copy() / nkpts eris.ovvv = eri[:, :, :, :nocc, nocc:, nocc:, nocc:].copy() / nkpts eris.vvvv = eri[:, :, :, nocc:, nocc:, nocc:, nocc:].copy() / nkpts log.timer('CCSD integral transformation', *cput0) return eris
def spatial2spin(tx, orbspin, kconserv): '''Convert T1/T2 of spatial orbital representation to T1/T2 of spin-orbital representation ''' if isinstance(tx, numpy.ndarray) and tx.ndim == 3: # KRCCSD t1 amplitudes return spatial2spin((tx,tx), orbspin, kconserv) elif isinstance(tx, numpy.ndarray) and tx.ndim == 7: # KRCCSD t2 amplitudes t2aa = tx - tx.transpose(0,1,2,4,3,5,6) return spatial2spin((t2aa,tx,t2aa), orbspin, kconserv) elif len(tx) == 2: # KUCCSD t1 t1a, t1b = tx nocc_a, nvir_a = t1a.shape[1:] nocc_b, nvir_b = t1b.shape[1:] else: # KUCCSD t2 t2aa, t2ab, t2bb = tx nocc_a, nocc_b, nvir_a, nvir_b = t2ab.shape[3:] nkpts = len(orbspin) nocc = nocc_a + nocc_b nvir = nvir_a + nvir_b idxoa = [numpy.where(orbspin[k][:nocc] == 0)[0] for k in range(nkpts)] idxob = [numpy.where(orbspin[k][:nocc] == 1)[0] for k in range(nkpts)] idxva = [numpy.where(orbspin[k][nocc:] == 0)[0] for k in range(nkpts)] idxvb = [numpy.where(orbspin[k][nocc:] == 1)[0] for k in range(nkpts)] if len(tx) == 2: # t1 t1 = numpy.zeros((nkpts,nocc,nvir), dtype=t1a.dtype) for k in range(nkpts): lib.takebak_2d(t1[k], t1a[k], idxoa[k], idxva[k]) lib.takebak_2d(t1[k], t1b[k], idxob[k], idxvb[k]) t1 = lib.tag_array(t1, orbspin=orbspin) return t1 else: t2 = numpy.zeros((nkpts,nkpts,nkpts,nocc**2,nvir**2), dtype=t2aa.dtype) for ki, kj, ka in kpts_helper.loop_kkk(nkpts): kb = kconserv[ki,ka,kj] idxoaa = idxoa[ki][:,None] * nocc + idxoa[kj] idxoab = idxoa[ki][:,None] * nocc + idxob[kj] idxoba = idxob[kj][:,None] * nocc + idxoa[ki] idxobb = idxob[ki][:,None] * nocc + idxob[kj] idxvaa = idxva[ka][:,None] * nvir + idxva[kb] idxvab = idxva[ka][:,None] * nvir + idxvb[kb] idxvba = idxvb[kb][:,None] * nvir + idxva[ka] idxvbb = idxvb[ka][:,None] * nvir + idxvb[kb] tmp2aa = t2aa[ki,kj,ka].reshape(nocc_a*nocc_a,nvir_a*nvir_a) tmp2bb = t2bb[ki,kj,ka].reshape(nocc_b*nocc_b,nvir_b*nvir_b) tmp2ab = t2ab[ki,kj,ka].reshape(nocc_a*nocc_b,nvir_a*nvir_b) lib.takebak_2d(t2[ki,kj,ka], tmp2aa, idxoaa.ravel() , idxvaa.ravel() ) lib.takebak_2d(t2[ki,kj,ka], tmp2bb, idxobb.ravel() , idxvbb.ravel() ) lib.takebak_2d(t2[ki,kj,ka], tmp2ab, idxoab.ravel() , idxvab.ravel() ) lib.takebak_2d(t2[kj,ki,kb], tmp2ab, idxoba.T.ravel(), idxvba.T.ravel()) abba = -tmp2ab lib.takebak_2d(t2[ki,kj,kb], abba, idxoab.ravel() , idxvba.T.ravel()) lib.takebak_2d(t2[kj,ki,ka], abba, idxoba.T.ravel(), idxvab.ravel() ) t2 = t2.reshape(nkpts,nkpts,nkpts,nocc,nocc,nvir,nvir) t2 = lib.tag_array(t2, orbspin=orbspin) return t2
def update_amps(cc, t1, t2, eris, max_memory=2000): time0 = time.clock(), time.time() log = logger.Logger(cc.stdout, cc.verbose) nkpts, nocc, nvir = t1.shape fock = eris.fock fov = fock[:, :nocc, nocc:].copy() foo = fock[:, :nocc, :nocc].copy() fvv = fock[:, nocc:, nocc:].copy() tau = imdk.make_tau(cc, t2, t1, t1) Fvv = imdk.cc_Fvv(cc, t1, t2, eris) Foo = imdk.cc_Foo(cc, t1, t2, eris) Fov = imdk.cc_Fov(cc, t1, t2, eris) Woooo = imdk.cc_Woooo(cc, t1, t2, eris) Wvvvv = imdk.cc_Wvvvv(cc, t1, t2, eris) Wovvo = imdk.cc_Wovvo(cc, t1, t2, eris) # Move energy terms to the other side for k in range(nkpts): Fvv[k] -= numpy.diag(numpy.diag(fvv[k])) Foo[k] -= numpy.diag(numpy.diag(foo[k])) # Get the momentum conservation array # Note: chemist's notation for momentum conserving t2(ki,kj,ka,kb), even though # integrals are in physics notation kconserv = kpts_helper.get_kconserv(cc._scf.cell, cc.kpts) eris_ovvo = numpy.zeros(shape=(nkpts, nkpts, nkpts, nocc, nvir, nvir, nocc), dtype=t2.dtype) eris_oovo = numpy.zeros(shape=(nkpts, nkpts, nkpts, nocc, nocc, nvir, nocc), dtype=t2.dtype) eris_vvvo = numpy.zeros(shape=(nkpts, nkpts, nkpts, nvir, nvir, nvir, nocc), dtype=t2.dtype) for km, kb, ke in kpts_helper.loop_kkk(nkpts): kj = kconserv[km, ke, kb] # <mb||je> -> -<mb||ej> eris_ovvo[km, kb, ke] = -eris.ovov[km, kb, kj].transpose(0, 1, 3, 2) # <mn||je> -> -<mn||ej> # let kb = kn as a dummy variable eris_oovo[km, kb, ke] = -eris.ooov[km, kb, kj].transpose(0, 1, 3, 2) # <ma||be> -> - <be||am>* # let kj = ka as a dummy variable kj = kconserv[km, ke, kb] eris_vvvo[ke, kj, kb] = -eris.ovvv[km, kb, ke].transpose(2, 3, 1, 0).conj() # T1 equation t1new = numpy.zeros(shape=t1.shape, dtype=t1.dtype) for ka in range(nkpts): ki = ka t1new[ka] += numpy.array(fov[ka, :, :]).conj() t1new[ka] += einsum('ie,ae->ia', t1[ka], Fvv[ka]) t1new[ka] += -einsum('ma,mi->ia', t1[ka], Foo[ka]) for km in range(nkpts): t1new[ka] += einsum('imae,me->ia', t2[ka, km, ka], Fov[km]) t1new[ka] += -einsum('nf,naif->ia', t1[km], eris.ovov[km, ka, ki]) for kn in range(nkpts): ke = kconserv[km, ki, kn] t1new[ka] += -0.5 * einsum('imef,maef->ia', t2[ki, km, ke], eris.ovvv[km, ka, ke]) t1new[ka] += -0.5 * einsum('mnae,nmei->ia', t2[km, kn, ka], eris_oovo[kn, km, ke]) # T2 equation t2new = numpy.array(eris.oovv).conj() for ki, kj, ka in kpts_helper.loop_kkk(nkpts): # Chemist's notation for momentum conserving t2(ki,kj,ka,kb) kb = kconserv[ki, ka, kj] Ftmp = Fvv[kb] - 0.5 * einsum('mb,me->be', t1[kb], Fov[kb]) tmp = einsum('ijae,be->ijab', t2[ki, kj, ka], Ftmp) t2new[ki, kj, ka] += tmp #t2new[ki,kj,kb] -= tmp.transpose(0,1,3,2) Ftmp = Fvv[ka] - 0.5 * einsum('ma,me->ae', t1[ka], Fov[ka]) tmp = einsum('ijbe,ae->ijab', t2[ki, kj, kb], Ftmp) t2new[ki, kj, ka] -= tmp Ftmp = Foo[kj] + 0.5 * einsum('je,me->mj', t1[kj], Fov[kj]) tmp = einsum('imab,mj->ijab', t2[ki, kj, ka], Ftmp) t2new[ki, kj, ka] -= tmp #t2new[kj,ki,ka] += tmp.transpose(1,0,2,3) Ftmp = Foo[ki] + 0.5 * einsum('ie,me->mi', t1[ki], Fov[ki]) tmp = einsum('jmab,mi->ijab', t2[kj, ki, ka], Ftmp) t2new[ki, kj, ka] += tmp for km in range(nkpts): # Wminj # - km - kn + ka + kb = 0 # => kn = ka - km + kb kn = kconserv[ka, km, kb] t2new[ki, kj, ka] += 0.5 * einsum( 'mnab,mnij->ijab', tau[km, kn, ka], Woooo[km, kn, ki]) ke = km t2new[ki, kj, ka] += 0.5 * einsum( 'ijef,abef->ijab', tau[ki, kj, ke], Wvvvv[ka, kb, ke]) # Wmbej # - km - kb + ke + kj = 0 # => ke = km - kj + kb ke = kconserv[km, kj, kb] tmp = einsum('imae,mbej->ijab', t2[ki, km, ka], Wovvo[km, kb, ke]) # - km - kb + ke + kj = 0 # => ke = km - kj + kb # # t[i,e] => ki = ke # t[m,a] => km = ka if km == ka and ke == ki: tmp -= einsum('ie,ma,mbej->ijab', t1[ki], t1[km], eris_ovvo[km, kb, ke]) t2new[ki, kj, ka] += tmp t2new[ki, kj, kb] -= tmp.transpose(0, 1, 3, 2) t2new[kj, ki, ka] -= tmp.transpose(1, 0, 2, 3) t2new[kj, ki, kb] += tmp.transpose(1, 0, 3, 2) ke = ki tmp = einsum('ie,abej->ijab', t1[ki], eris_vvvo[ka, kb, ke]) t2new[ki, kj, ka] += tmp # P(ij) term ke = kj tmp = einsum('je,abei->ijab', t1[kj], eris_vvvo[ka, kb, ke]) t2new[ki, kj, ka] -= tmp km = ka tmp = einsum('ma,mbij->ijab', t1[ka], eris.ovoo[km, kb, ki]) t2new[ki, kj, ka] -= tmp # P(ab) term km = kb tmp = einsum('mb,maij->ijab', t1[kb], eris.ovoo[km, ka, ki]) t2new[ki, kj, ka] += tmp eia = numpy.zeros(shape=(nocc, nvir), dtype=t1new.dtype) for ki in range(nkpts): eia = foo[ki].diagonal()[:, None] - fvv[ki].diagonal()[None, :] # When padding the occupied/virtual arrays, some fock elements will be zero idx = numpy.where(abs(eia) < LOOSE_ZERO_TOL)[0] eia[idx] = LARGE_DENOM t1new[ki] /= eia eijab = numpy.zeros(shape=(nocc, nocc, nvir, nvir), dtype=t2new.dtype) kconserv = kpts_helper.get_kconserv(cc._scf.cell, cc.kpts) for ki, kj, ka in kpts_helper.loop_kkk(nkpts): kb = kconserv[ki, ka, kj] eijab = (foo[ki].diagonal()[:, None, None, None] + foo[kj].diagonal()[None, :, None, None] - fvv[ka].diagonal()[None, None, :, None] - fvv[kb].diagonal()[None, None, None, :]) # Due to padding; see above discussion concerning t1new in update_amps() idx = numpy.where(abs(eijab) < LOOSE_ZERO_TOL)[0] eijab[idx] = LARGE_DENOM t2new[ki, kj, ka] /= eijab time0 = log.timer_debug1('update t1 t2', *time0) return t1new, t2new