def greens_e_vector_ea_rhf(cc, p, kp=None): nkpts, nocc, nvir = cc.t1.shape ds_type = cc.t1.dtype vector1 = np.zeros((nvir), dtype=ds_type) vector2 = np.zeros((nkpts, nkpts, nocc, nvir, nvir), dtype=ds_type) if hasattr(cc, 'l1') and cc.l1 is not None: l1 = cc.l1 l2 = cc.l2 else: l1 = np.conj(cc.t1) l2 = np.conj(cc.t2) if p < nocc: # Changed both to plus vector1 += l1[kp, p, :] for ki in range(nkpts): for kj in range(nkpts): vector2[ki, kj] += 2*l2[ki,kj,kp,p,:,:,:] - \ l2[kj,ki,kp,:,p,:,:] else: vector1[p - nocc] = -1.0 vector1 += np.einsum('ia,i->a', l1[kp], cc.t1[kp, :, p - nocc]) for kk in range(nkpts): for kl in range(nkpts): kconserv = kpts_helper.get_kconserv(cc._scf.cell, cc.kpts) ka = kconserv[kl, kp, kk] vector1 += 2 * np.einsum('klca,klc->a', l2[ka,kk,kl], \ cc.t2[ka,kk,kl,:,:,:,p-nocc]) vector1 -= np.einsum('klca,lkc->a', l2[ka,kk,kl], \ cc.t2[kk,ka,kl,:,:,:,p-nocc]) for kb in range(nkpts): vector2[kb, kp, :, p - nocc, :] += -2. * l1[kb] for ka in range(nkpts): # kj == ka # kb == kc == kp vector2[ka, ka, :, :, p - nocc] += l1[ka] for kj in range(nkpts): for kb in range(nkpts): kconserv = kpts_helper.get_kconserv(cc._scf.cell, cc.kpts) ka = kconserv[kp, kj, kb] vector2[kj,ka] += 2*np.einsum('k,jkba->jab', \ cc.t1[kp,:,p-nocc], l2[kj,kp,kb,:,:,:,:]) vector2[kj,ka] -= np.einsum('k,jkab->jab', \ cc.t1[kp,:,p-nocc], l2[kj,kp,ka,:,:,:,:]) return eom_rccsd.amplitudes_to_vector_ea(vector1, vector2)
def greens_e_vector_ip_krhf(cc, p, kp): assert_non_padded(cc, p, kp) kconserv = kpts_helper.get_kconserv(cc._scf.cell, cc.kpts) return nested_to_vector(( greens_e_singles_ip_krhf(cc.t1, cc.t2, cc.l1, cc.l2, p, kp, kconserv), greens_e_doubles_ip_krhf(cc.t1, cc.l1, cc.l2, p, kp, kconserv), ))[0]
def cc_Wovvo(cc,t1,t2,eris): nkpts, nocc, nvir = t1.shape 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) for km in range(nkpts): for kb in range(nkpts): for ke in range(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) Wmbej = eris_ovvo.copy() for km in range(nkpts): for kb in range(nkpts): for ke in range(nkpts): kj = kconserv[km,ke,kb] Wmbej[km,kb,ke] += einsum('jf,mbef->mbej',t1[kj,:,:],eris.ovvv[km,kb,ke]) Wmbej[km,kb,ke] += -einsum('nb,mnej->mbej',t1[kb,:,:],eris_oovo[km,kb,ke]) 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]) if kn == kb and kf == kj: Wmbej[km,kb,ke] += -einsum('jf,nb,mnef->mbej',t1[kj],t1[kn], eris.oovv[km,kn,ke]) return Wmbej
def greens_e_vector_ip_rhf(cc, p, kp=None): nkpts, nocc, nvir = cc.t1.shape vector1 = np.zeros((nocc), dtype=complex) vector2 = np.zeros((nkpts, nkpts, nocc, nocc, nvir), dtype=complex) if hasattr(cc, 'l1') and cc.l1 is not None: l1 = cc.l1 l2 = cc.l2 else: l1 = np.conj(cc.t1) l2 = np.conj(cc.t2) #print '################################' #print 'max t1 kpt',np.max(np.abs(cc.t1)) if p < nocc: vector1[p] = -1.0 #vector1 += 0.5 * np.einsum('ia,i->a', l1[0], cc.t1[0,p,:]) #vector1 += 0.5 * np.einsum('ia,i->a', l1[1], cc.t1[1,p,:]) vector1 += np.einsum('ia,a->i', l1[kp], cc.t1[kp, p, :]) for kc in range(nkpts): for kl in range(nkpts): #kconserv = cc.khelper.kconserv kconserv = kpts_helper.get_kconserv(cc._scf.cell, cc.kpts) kd = kconserv[kp, kl, kc] print '#########################################' print 'kp, ', cc.kpts[kp] print 'kc, ', cc.kpts[kc] print 'kl, ', cc.kpts[kl] print 'kd, ' print 'plc, ', cc.kpts[kconserv[kp, kl, kc]] print 'conv calc, ', cc.kpts[kp] - cc.kpts[kl] + cc.kpts[kc] #vector1 += 2 * np.einsum('ilcd,lcd->i', \ vector1 += (2)*np.einsum('ilcd,lcd->i', \ l2[kp,kl,kc], cc.t2[kp,kl,kc,p,:,:,:]) #l2[kp,kl,kc], cc.t2[kl,kc,kd,p,:,:,:]) vector1 -= (1)*np.einsum('ilcd,lcd->i', \ #vector1 -= np.einsum('ilcd,ldc->i', \ l2[kp,kl,kc], cc.t2[kp,kl,kd,p,:,:,:]) #l2[kp,kl,kc], cc.t2[kp,kl,kc,p,:,:,:]) for kj in range(nkpts): vector2[kp, kj, p, :, :] += -2 * l1[kj] for ki in range(nkpts): # kj == kk == kp, ki == kb vector2[ki, kp, :, p, :] += l1[ki] for kj in range(nkpts): # kc == kk == kp vector2[ki,kj] += 2*np.einsum('c,ijcb->ijb', \ cc.t1[kp,p,:], l2[ki,kj,kp,:,:,:,:]) vector2[ki,kj] -= np.einsum('c,jicb->ijb', \ cc.t1[kp,p,:], l2[kj,ki,kp,:,:,:,:]) else: vector1 += -l1[kp, :, p - nocc] for ki in range(nkpts): for kj in range(nkpts): vector2[ki, kj] += -2*l2[ki,kj,kp,:,:,p-nocc,:] + \ l2[kj,ki,kp,:,:,p-nocc,:] return cc.amplitudes_to_vector_ip(vector1, vector2)
def rand_t1_t2(mycc): nkpts = mycc.nkpts nocca, noccb = mycc.nocc nmoa, nmob = mycc.nmo nvira, nvirb = nmoa - nocca, nmob - noccb np.random.seed(1) t1a = (np.random.random((nkpts,nocca,nvira)) + np.random.random((nkpts,nocca,nvira))*1j - .5-.5j) t1b = (np.random.random((nkpts,noccb,nvirb)) + np.random.random((nkpts,noccb,nvirb))*1j - .5-.5j) t2aa = (np.random.random((nkpts,nkpts,nkpts,nocca,nocca,nvira,nvira)) + np.random.random((nkpts,nkpts,nkpts,nocca,nocca,nvira,nvira))*1j - .5-.5j) kconserv = kpts_helper.get_kconserv(kmf.cell, kmf.kpts) t2aa = t2aa - t2aa.transpose(1,0,2,4,3,5,6) tmp = t2aa.copy() for ki, kj, kk in kpts_helper.loop_kkk(nkpts): kl = kconserv[ki, kk, kj] t2aa[ki,kj,kk] = t2aa[ki,kj,kk] - tmp[ki,kj,kl].transpose(0,1,3,2) t2ab = (np.random.random((nkpts,nkpts,nkpts,nocca,noccb,nvira,nvirb)) + np.random.random((nkpts,nkpts,nkpts,nocca,noccb,nvira,nvirb))*1j - .5-.5j) t2bb = (np.random.random((nkpts,nkpts,nkpts,noccb,noccb,nvirb,nvirb)) + np.random.random((nkpts,nkpts,nkpts,noccb,noccb,nvirb,nvirb))*1j - .5-.5j) t2bb = t2bb - t2bb.transpose(1,0,2,4,3,5,6) tmp = t2bb.copy() for ki, kj, kk in kpts_helper.loop_kkk(nkpts): kl = kconserv[ki, kk, kj] t2bb[ki,kj,kk] = t2bb[ki,kj,kk] - tmp[ki,kj,kl].transpose(0,1,3,2) t1 = (t1a, t1b) t2 = (t2aa, t2ab, t2bb) return t1, t2
def test_rand_ccsd_frozen3(self): '''Single (eom-)ccsd iteration with random t1/t2 and single frozen virtual orbital.''' kconserv = kpts_helper.get_kconserv(rand_kmf.cell, rand_kmf.kpts) kmf = pbcscf.addons.convert_to_ghf(rand_kmf) # Round to make this insensitive to small changes between PySCF versions mat_veff = kmf.get_veff().round(4) mat_hcore = kmf.get_hcore().round(4) kmf.get_veff = lambda *x: mat_veff kmf.get_hcore = lambda *x: mat_hcore frozen = [[],[],[5]] # freezing one virtual rand_cc = pbcc.KGCCSD(kmf, frozen=frozen) eris = rand_cc.ao2mo(rand_cc.mo_coeff) eris.mo_energy = [eris.fock[k].diagonal() for k in range(rand_cc.nkpts)] t1, t2 = rand_t1_t2(kmf, rand_cc) # Manually zero'ing out the frozen elements of the t1/t2 t1[2, :, 0] = 0.0 for ki in range(rand_cc.nkpts): for kj in range(rand_cc.nkpts): for ka in range(rand_cc.nkpts): kb = kconserv[ki, ka, kj] if ka == 2: t2[ki, kj, ka, :, :, 0] = 0.0 if kb == 2: t2[ki, kj, ka, :, :, :, 0] = 0.0 Ht1, Ht2 = rand_cc.update_amps(t1, t2, eris) self.assertAlmostEqual(finger(Ht1), (-19.6637196882-16.2773841431j), 6) self.assertAlmostEqual(finger(Ht2), (881.655146297+1283.71020059j), 6)
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 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 = mdf.MDF(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 test_rand_ccsd_frozen3(self): '''Single (eom-)ccsd iteration with random t1/t2 and single frozen virtual orbital.''' kmf = copy.copy(rand_kmf) mat_veff = kmf.get_veff().round(4) mat_hcore = kmf.get_hcore().round(4) kmf.get_veff = lambda *x: mat_veff kmf.get_hcore = lambda *x: mat_hcore kconserv = kpts_helper.get_kconserv(kmf.cell, kmf.kpts) frozen = [[],[],[3]] # freezing one virtual rand_cc = pbcc.KRCCSD(kmf, frozen=frozen) eris = rand_cc.ao2mo(kmf.mo_coeff) eris.mo_energy = [eris.fock[k].diagonal() for k in range(rand_cc.nkpts)] t1, t2 = rand_t1_t2(kmf, rand_cc) # Manually zero'ing out the frozen elements of the t1/t2 t1[2, :, 0] = 0.0 for ki in range(rand_cc.nkpts): for kj in range(rand_cc.nkpts): for ka in range(rand_cc.nkpts): kb = kconserv[ki, ka, kj] if ka == 2: t2[ki, kj, ka, :, :, 0] = 0.0 if kb == 2: t2[ki, kj, ka, :, :, :, 0] = 0.0 Ht1, Ht2 = rand_cc.update_amps(t1, t2, eris) self.assertAlmostEqual(lib.fp(Ht1), (5.3320153970710118-7.9402122992688602j), 6) self.assertAlmostEqual(lib.fp(Ht2), (-236.46389414847206-360.1605297160217j), 6) # Excited state results rand_cc.t1, rand_cc.t2, rand_cc.eris = t1, t2, eris kshift = 2 r1, r2 = rand_r1_r2_ip(kmf, rand_cc) r1[0] = 0.0 for ki in range(rand_cc.nkpts): for kj in range(rand_cc.nkpts): ka = kconserv[ki, kshift, kj] if ka == 2: r2[ki, kj, :, :, 0] = 0.0 Hr1, Hr2 = _run_ip_matvec(rand_cc, r1, r2, kshift) self.assertAlmostEqual(lib.fp(Hr1), (0.4067595510145880 + 0.0770280877446436j), 6) self.assertAlmostEqual(lib.fp(Hr2), (0.0926714318228812 + -1.0702702421619084j), 6) r1, r2 = rand_r1_r2_ea(kmf, rand_cc) r1[0] = 0.0 for kj in range(rand_cc.nkpts): for ka in range(rand_cc.nkpts): kb = kconserv[kshift, ka, kj] if ka == 2: r2[kj, ka, :, 0, :] = 0.0 if kb == 2: r2[kj, ka, :, :, 0] = 0.0 Hr1, Hr2 = _run_ea_matvec(rand_cc, r1, r2, kshift) self.assertAlmostEqual(lib.fp(Hr1), (0.0070404498167285 + -0.1646809321907418j), 6) self.assertAlmostEqual(lib.fp(Hr2), (0.4518315588945250 + -0.5508323185152750j), 6)
def rand_t1_t2(cell, kpts, nocc, nvir): nkpts = len(kpts) nocca, noccb = nocc nvira, nvirb = nvir t1a = (numpy.random.random((nkpts,nocca,nvira)) + numpy.random.random((nkpts,nocca,nvira))*1j - .5-.5j) t1b = (numpy.random.random((nkpts,noccb,nvirb)) + numpy.random.random((nkpts,noccb,nvirb))*1j - .5-.5j) t2aa = (numpy.random.random((nkpts,nkpts,nkpts,nocca,nocca,nvira,nvira)) + numpy.random.random((nkpts,nkpts,nkpts,nocca,nocca,nvira,nvira))*1j - .5-.5j) kconserv = kpts_helper.get_kconserv(cell, kpts) t2aa = t2aa - t2aa.transpose(1,0,2,4,3,5,6) tmp = t2aa.copy() for ki, kj, kk in kpts_helper.loop_kkk(nkpts): kl = kconserv[ki, kk, kj] t2aa[ki,kj,kk] = t2aa[ki,kj,kk] - tmp[ki,kj,kl].transpose(0,1,3,2) t2ab = (numpy.random.random((nkpts,nkpts,nkpts,nocca,noccb,nvira,nvirb)) + numpy.random.random((nkpts,nkpts,nkpts,nocca,noccb,nvira,nvirb))*1j - .5-.5j) t2bb = (numpy.random.random((nkpts,nkpts,nkpts,noccb,noccb,nvirb,nvirb)) + numpy.random.random((nkpts,nkpts,nkpts,noccb,noccb,nvirb,nvirb))*1j - .5-.5j) t2bb = t2bb - t2bb.transpose(1,0,2,4,3,5,6) tmp = t2bb.copy() for ki, kj, kk in kpts_helper.loop_kkk(nkpts): kl = kconserv[ki, kk, kj] t2bb[ki,kj,kk] = t2bb[ki,kj,kk] - tmp[ki,kj,kl].transpose(0,1,3,2) t1 = (t1a, t1b) t2 = (t2aa, t2ab, t2bb) return t1, t2
def test_spatial2spin_ea(self): numpy.random.seed(1) kpts = cell.make_kpts([1,2,3]) nkpts = len(kpts) nmo = (8, 8) nocc = (3, 2) nvir = (nmo[0]-nocc[0], nmo[1]-nocc[1]) orbspin = numpy.zeros((len(kpts),nmo[0]+nmo[1]), dtype=int) orbspin[:,1::2] = 1 kconserv = kpts_helper.get_kconserv(cell, kpts) kshift = 0 spin_r1_ea = (numpy.random.rand(nvir[0]+nvir[1])*1j + numpy.random.rand(nvir[0]+nvir[1]) - 0.5 - 0.5*1j) spin_r2_ea = (numpy.random.rand(nkpts**2 * (nocc[0]+nocc[1])* (nvir[0]+nvir[1])**2) + numpy.random.rand(nkpts**2 * (nocc[0]+nocc[1])* (nvir[0]+nvir[1])**2)*1j - 0.5 - 0.5*1j) spin_r2_ea = spin_r2_ea.reshape(nkpts, nkpts, (nocc[0]+nocc[1]), (nvir[0]+nvir[1]), (nvir[0]+nvir[1])) spin_r2_ea = eom_kccsd_ghf.enforce_2p_spin_ea_doublet(spin_r2_ea, kconserv, kshift, orbspin) [r1a, r1b], [r2aaa, r2baa, r2abb, r2bbb] = \ eom_kccsd_ghf.spin2spatial_ea_doublet(spin_r1_ea, spin_r2_ea, kconserv, kshift, orbspin) r1, r2 = eom_kccsd_ghf.spatial2spin_ea_doublet([r1a, r1b], [r2aaa, r2baa, r2abb, r2bbb], kconserv, kshift, orbspin=orbspin) self.assertAlmostEqual(abs(r1-spin_r1_ea).max(), 0, 12) self.assertAlmostEqual(abs(r2-spin_r2_ea).max(), 0, 12)
def test_rand_ccsd_frozen3(self): '''Single (eom-)ccsd iteration with random t1/t2 and single frozen virtual orbital.''' kconserv = kpts_helper.get_kconserv(rand_kmf.cell, rand_kmf.kpts) kmf = pbcscf.addons.convert_to_ghf(rand_kmf) # Round to make this insensitive to small changes between PySCF versions mat_veff = kmf.get_veff().round(4) mat_hcore = kmf.get_hcore().round(4) kmf.get_veff = lambda *x: mat_veff kmf.get_hcore = lambda *x: mat_hcore frozen = [[], [], [5]] # freezing one virtual rand_cc = pbcc.KGCCSD(kmf, frozen=frozen) eris = rand_cc.ao2mo(rand_cc.mo_coeff) eris.mo_energy = [ eris.fock[k].diagonal() for k in range(rand_cc.nkpts) ] t1, t2 = rand_t1_t2(kmf, rand_cc) # Manually zero'ing out the frozen elements of the t1/t2 t1[2, :, 0] = 0.0 for ki in range(rand_cc.nkpts): for kj in range(rand_cc.nkpts): for ka in range(rand_cc.nkpts): kb = kconserv[ki, ka, kj] if ka == 2: t2[ki, kj, ka, :, :, 0] = 0.0 if kb == 2: t2[ki, kj, ka, :, :, :, 0] = 0.0 Ht1, Ht2 = rand_cc.update_amps(t1, t2, eris) self.assertAlmostEqual(finger(Ht1), (-19.6637196882 - 16.2773841431j), 6) self.assertAlmostEqual(finger(Ht2), (881.655146297 + 1283.71020059j), 6)
def test_rand_ccsd_frozen3(self): '''Single (eom-)ccsd iteration with random t1/t2 and single frozen virtual orbital.''' kconserv = kpts_helper.get_kconserv(rand_kmf.cell, rand_kmf.kpts) frozen = [[],[],[3]] # freezing one virtual rand_cc = pbcc.KRCCSD(rand_kmf, frozen=frozen) eris = rand_cc.ao2mo(rand_kmf.mo_coeff) eris.mo_energy = [eris.fock[k].diagonal() for k in range(rand_cc.nkpts)] t1, t2 = rand_t1_t2(rand_kmf, rand_cc) # Manually zero'ing out the frozen elements of the t1/t2 t1[2, :, 0] = 0.0 for ki in range(rand_cc.nkpts): for kj in range(rand_cc.nkpts): for ka in range(rand_cc.nkpts): kb = kconserv[ki, ka, kj] if ka == 2: t2[ki, kj, ka, :, :, 0] = 0.0 if kb == 2: t2[ki, kj, ka, :, :, :, 0] = 0.0 Ht1, Ht2 = rand_cc.update_amps(t1, t2, eris) self.assertAlmostEqual(finger(Ht1), (5.3320153970710118-7.9402122992688602j), 6) self.assertAlmostEqual(finger(Ht2), (-236.46389414847206-360.1605297160217j), 6) # Excited state results rand_cc.t1, rand_cc.t2, rand_cc.eris = t1, t2, eris kshift = 2 r1, r2 = rand_r1_r2_ip(rand_kmf, rand_cc) r1[0] = 0.0 for ki in range(rand_cc.nkpts): for kj in range(rand_cc.nkpts): ka = kconserv[ki, kshift, kj] if ka == 2: r2[ki, kj, :, :, 0] = 0.0 Hr1, Hr2 = _run_ip_matvec(rand_cc, r1, r2, kshift) self.assertAlmostEqual(finger(Hr1), (0.4067595510145880 + 0.0770280877446436j), 6) self.assertAlmostEqual(finger(Hr2), (0.0926714318228812 + -1.0702702421619084j), 6) r1, r2 = rand_r1_r2_ea(rand_kmf, rand_cc) r1[0] = 0.0 for kj in range(rand_cc.nkpts): for ka in range(rand_cc.nkpts): kb = kconserv[kshift, ka, kj] if ka == 2: r2[kj, ka, :, 0, :] = 0.0 if kb == 2: r2[kj, ka, :, :, 0] = 0.0 Hr1, Hr2 = _run_ea_matvec(rand_cc, r1, r2, kshift) self.assertAlmostEqual(finger(Hr1), (0.0070404498167285 + -0.1646809321907418j), 6) self.assertAlmostEqual(finger(Hr2), (0.4518315588945250 + -0.5508323185152750j), 6)
def spin2spatial(self, tx, orbspin=None, kconserv=None): if orbspin is None: if getattr(self.mo_coeff[0], 'orbspin', None) is not None: orbspin = [self.mo_coeff[k].orbspin[idx] for k, idx in enumerate(self.get_frozen_mask())] else: orbspin = numpy.zeros((self.nkpts,self.nmo), dtype=int) orbspin[:,1::2] = 1 if kconserv is None: kconserv = kpts_helper.get_kconserv(self._scf.cell, self.kpts) return spin2spatial(tx, orbspin, kconserv)
def spin2spatial(self, tx, orbspin=None, kconserv=None): if orbspin is None: if getattr(self.mo_coeff[0], 'orbspin', None) is not None: orbspin = [self.mo_coeff[k].orbspin[idx] for k, idx in enumerate(self.get_frozen_mask())] else: orbspin = numpy.zeros((self.nkpts,self.nmo), dtype=int) orbspin[:,1::2] = 1 if kconserv is None: kconserv = kpts_helper.get_kconserv(self._scf.cell, self.kpts) return spin2spatial(tx, orbspin, kconserv)
def rand_t1_t2(mycc): nkpts = mycc.nkpts nocc = mycc.nocc nmo = mycc.nmo nvir = nmo - nocc np.random.seed(1) t1 = (np.random.random((nkpts, nocc, nvir)) + np.random.random((nkpts, nocc, nvir)) * 1j - .5 - .5j) t2 = (np.random.random((nkpts, nkpts, nkpts, nocc, nocc, nvir, nvir)) + np.random.random((nkpts, nkpts, nkpts, nocc, nocc, nvir, nvir)) * 1j - .5 - .5j) kconserv = kpts_helper.get_kconserv(kmf.cell, kmf.kpts) Ps = kconserve_pmatrix(nkpts, kconserv) t2 = t2 + np.einsum('xyzijab,xyzw->yxwjiba', t2, Ps) return t1, t2
def rand_t1_t2(kmf, mycc): nkpts = mycc.nkpts nocc = mycc.nocc nmo = mycc.nmo nvir = nmo - nocc np.random.seed(1) t1 = (np.random.random((nkpts, nocc, nvir)) + np.random.random((nkpts, nocc, nvir)) * 1j - .5 - .5j) t2 = (np.random.random((nkpts, nkpts, nkpts, nocc, nocc, nvir, nvir)) + np.random.random((nkpts, nkpts, nkpts, nocc, nocc, nvir, nvir)) * 1j - .5 - .5j) kconserv = kpts_helper.get_kconserv(kmf.cell, kmf.kpts) Ps = kconserve_pmatrix(nkpts, kconserv) t2 = t2 + np.einsum('xyzijab,xyzw->yxwjiba', t2, Ps) return t1, t2
def rand_r1_r2_ip(kmf, mycc, kshift): '''Antisymmetrized 1p/2p1h operators for spin-orbitals.''' nkpts = mycc.nkpts nocc = mycc.nocc nmo = mycc.nmo nvir = nmo - nocc np.random.seed(1) r1 = (np.random.random((nocc,)) + np.random.random((nocc,)) * 1j - .5 - .5j) r2 = (np.random.random((nkpts, nkpts, nocc, nocc, nvir)) + np.random.random((nkpts, nkpts, nocc, nocc, nvir)) * 1j - .5 - .5j) kconserv = kpts_helper.get_kconserv(kmf.cell, kmf.kpts) Ps = kconserve_pmatrix(nkpts, kconserv) r2 = r2 - np.einsum('xyija,xyz->yxjia', r2, Ps[:, :, kshift, :]) return r1, r2
def rand_r1_r2_ip(kmf, mycc, kshift): '''Antisymmetrized 1p/2p1h operators for spin-orbitals.''' nkpts = mycc.nkpts nocc = mycc.nocc nmo = mycc.nmo nvir = nmo - nocc np.random.seed(1) r1 = (np.random.random((nocc,)) + np.random.random((nocc,)) * 1j - .5 - .5j) r2 = (np.random.random((nkpts, nkpts, nocc, nocc, nvir)) + np.random.random((nkpts, nkpts, nocc, nocc, nvir)) * 1j - .5 - .5j) kconserv = kpts_helper.get_kconserv(kmf.cell, kmf.kpts) Ps = kconserve_pmatrix(nkpts, kconserv) r2 = r2 - np.einsum('xyija,xyz->yxjia', r2, Ps[:, :, kshift, :]) return r1, r2
def rand_t1_t2(kmf, mycc): '''Antisymmetrized t1/t2 for spin-orbitals.''' nkpts = mycc.nkpts nocc = mycc.nocc nmo = mycc.nmo nvir = nmo - nocc np.random.seed(1) t1 = (np.random.random((nkpts, nocc, nvir)) + np.random.random((nkpts, nocc, nvir)) * 1j - .5 - .5j) t2 = (np.random.random((nkpts, nkpts, nkpts, nocc, nocc, nvir, nvir)) + np.random.random((nkpts, nkpts, nkpts, nocc, nocc, nvir, nvir)) * 1j - .5 - .5j) kconserv = kpts_helper.get_kconserv(kmf.cell, kmf.kpts) Ps = kconserve_pmatrix(nkpts, kconserv) t2 = t2 - np.einsum('xyzijab,xyzw->yxzjiab', t2, Ps) t2 = t2 + np.einsum('xyzijab,xyzw->yxwjiba', t2, Ps) return t1, t2
def rand_t1_t2(kmf, mycc): '''Antisymmetrized t1/t2 for spin-orbitals.''' nkpts = mycc.nkpts nocc = mycc.nocc nmo = mycc.nmo nvir = nmo - nocc np.random.seed(1) t1 = (np.random.random((nkpts, nocc, nvir)) + np.random.random((nkpts, nocc, nvir)) * 1j - .5 - .5j) t2 = (np.random.random((nkpts, nkpts, nkpts, nocc, nocc, nvir, nvir)) + np.random.random((nkpts, nkpts, nkpts, nocc, nocc, nvir, nvir)) * 1j - .5 - .5j) kconserv = kpts_helper.get_kconserv(kmf.cell, kmf.kpts) Ps = kconserve_pmatrix(nkpts, kconserv) t2 = t2 - np.einsum('xyzijab,xyzw->yxzjiab', t2, Ps) t2 = t2 + np.einsum('xyzijab,xyzw->yxwjiba', t2, Ps) return t1, t2
def greens_e_vector_ip_rhf(cc, p, kp=None): nkpts, nocc, nvir = cc.t1.shape vector1 = np.zeros((nocc), dtype=complex) vector2 = np.zeros((nkpts, nkpts, nocc, nocc, nvir), dtype=complex) if hasattr(cc, 'l1') and cc.l1 is not None: l1 = cc.l1 l2 = cc.l2 else: l1 = np.conj(cc.t1) l2 = np.conj(cc.t2) if p < nocc: vector1[p] = -1.0 vector1 += np.einsum('ia,a->i', l1[kp], cc.t1[kp, p, :]) for kl in range(nkpts): for kc in range(nkpts): kconserv = kpts_helper.get_kconserv(cc._scf.cell, cc.kpts) kd = kconserv[kp, kl, kc] vector1 += 2 * np.einsum('ilcd,lcd->i', \ l2[kp,kl,kc], cc.t2[kp,kl,kc,p,:,:,:]) vector1 -= np.einsum('ilcd,ldc->i', \ l2[kp,kl,kc], cc.t2[kp,kl,kd,p,:,:,:]) for kj in range(nkpts): vector2[kp, kj, p, :, :] += -2 * l1[kj] for ki in range(nkpts): # kj == kk == kp, ki == kb vector2[ki, kp, :, p, :] += l1[ki] for kj in range(nkpts): # kc == kk == kp vector2[ki,kj] += 2*np.einsum('c,ijcb->ijb', \ cc.t1[kp,p,:], l2[ki,kj,kp,:,:,:,:]) vector2[ki,kj] -= np.einsum('c,jicb->ijb', \ cc.t1[kp,p,:], l2[kj,ki,kp,:,:,:,:]) else: vector1 += -l1[kp, :, p - nocc] for ki in range(nkpts): for kj in range(nkpts): vector2[ki, kj] += -2*l2[ki,kj,kp,:,:,p-nocc,:] + \ l2[ki,kj,kp,:,:,:,p-nocc] return eom_rccsd.amplitudes_to_vector_ip(vector1, vector2)
def __init__(self, cc, eris=None, t1=None, t2=None): self._cc = cc self.verbose = cc.verbose self.kconserv = kpts_helper.get_kconserv(cc._scf.cell, cc.kpts) self.stdout = cc.stdout if t1 is None: t1 = cc.t1 self.t1 = t1 if t2 is None: t2 = cc.t2 self.t2 = t2 if eris is None: eris = cc.ao2mo() self.eris = eris self._made_shared = False self.made_ip_imds = False self.made_ea_imds = False self.made_ee_imds = False
def __init__(self, cc, eris=None, t1=None, t2=None): self._cc = cc self.verbose = cc.verbose self.kconserv = kpts_helper.get_kconserv(cc._scf.cell, cc.kpts) self.stdout = cc.stdout if t1 is None: t1 = cc.t1 self.t1 = t1 if t2 is None: t2 = cc.t2 self.t2 = t2 if eris is None: eris = cc.ao2mo() self.eris = eris self._made_shared = False self.made_ip_imds = False self.made_ea_imds = False self.made_ee_imds = False
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 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 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_34(cc, kpts, integrals): kconserv = kpts_helper.get_kconserv(cc._scf.cell, cc.kpts) nkpts = len(kpts) diff = 0.0 for kp in range(nkpts): for kq in range(nkpts): for kr in range(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 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)
def make_tau(cc, t2, t1a, t1b, fac=1., out=None): nkpts, nocc, nvir = t1a.shape tau1 = t2.copy() kconserv = kpts_helper.get_kconserv(cc._scf.cell, cc.kpts) for ki in range(nkpts): for ka in range(nkpts): for kj in range(nkpts): kb = kconserv[ki,ka,kj] tmp = numpy.zeros((nocc,nocc,nvir,nvir),dtype=t2.dtype) if ki == ka and kj == kb: tmp += einsum('ia,jb->ijab',t1a[ki],t1b[kj]) if ki == kb and kj == ka: tmp -= einsum('ib,ja->ijab',t1a[ki],t1b[kj]) if kj == ka and ki == kb: tmp -= einsum('ja,ib->ijab',t1a[kj],t1b[ki]) if kj == kb and ki == ka: tmp += einsum('jb,ia->ijab',t1a[kj],t1b[ki]) tau1[ki,kj,ka] += fac*0.5*tmp return tau1
def cc_Woooo(cc,t1,t2,eris): nkpts, nocc, nvir = t1.shape tau = make_tau(cc,t2,t1,t1) Wmnij = eris.oooo.copy() kconserv = kpts_helper.get_kconserv(cc._scf.cell, cc.kpts) for km in range(nkpts): for kn in range(nkpts): # Since it's not enough just to switch i and j and need to create the k_i and k_j # so that P(ij) switches both i,j and k_i,k_j # t1[ k_j, j, e ] * v[ k_m, k_n, k_i, m, n, i, e ] -> tmp[ k_i, k_j, m, n, i, j ] # Here, x = k_j and y = k_i tmp = einsum('xje,ymnie->yxmnij',t1,eris.ooov[km,kn]) tmp = tmp - tmp.transpose(1,0,2,3,5,4) for ki in range(nkpts): kj = kconserv[km,ki,kn] Wmnij[km,kn,ki] += tmp[ki,kj] # Here, x = k_e Wmnij[km,kn,ki] += 0.25*einsum('xijef,xmnef->mnij', tau[ki,kj],eris.oovv[km,kn]) return Wmnij
def cc_Wvvvv(cc,t1,t2,eris): nkpts, nocc, nvir = t1.shape eris_vovv = - eris.ovvv.transpose(1,0,2,4,3,5,6) tau = make_tau(cc,t2,t1,t1) Wabef = eris.vvvv.copy() kconserv = kpts_helper.get_kconserv(cc._scf.cell, cc.kpts) for ka in range(nkpts): for kb in range(nkpts): for ke in range(nkpts): km = kb tmp = einsum('mb,amef->abef',t1[kb],eris_vovv[ka,km,ke]) km = ka tmp -= einsum('ma,bmef->abef',t1[ka],eris_vovv[kb,km,ke]) Wabef[ka,kb,ke] += -tmp # km + kn - ka = kb # => kn = ka - km + 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 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 init_amps(self, eris): time0 = time.clock(), time.time() nocc = self.get_nocc() nvir = self.get_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() 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 in range(nkpts): for kj in range(nkpts): for ka in range(nkpts): kb = kconserv[ki, ka, kj] for i in range(nocc): for a in range(nvir): eia[i, a] = foo[ki, i, i] - fvv[ka, a, a] for j in range(nocc): for b in range(nvir): eijab[i, j, a, b] = (foo[ki, i, i] + foo[kj, j, j] - fvv[ka, a, a] - fvv[kb, b, b]) t2[ki, kj, ka, i, j, a, b] = eris_oovv[ki, kj, ka, i, j, a, b] / eijab[i, j, a, b] 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) #print("MP2 energy =", self.emp2) return self.emp2, t1, t2
def test_spatial2spin(self): numpy.random.seed(1) kpts = cell.make_kpts([1, 2, 3]) nmo = (8, 8) nocc = (3, 2) nvir = (nmo[0] - nocc[0], nmo[1] - nocc[1]) t1, t2 = rand_t1_t2(cell, kpts, nocc, nvir) orbspin = numpy.zeros((len(kpts), nmo[0] + nmo[1]), dtype=int) orbspin[:, 1::2] = 1 kconserv = kpts_helper.get_kconserv(cell, kpts) r1 = kccsd.spatial2spin(t1, orbspin, kconserv) r1 = kccsd.spin2spatial(r1, orbspin, kconserv) self.assertAlmostEqual(abs(r1[0] - t1[0]).max(), 0, 12) self.assertAlmostEqual(abs(r1[1] - t1[1]).max(), 0, 12) r2 = kccsd.spatial2spin(t2, orbspin, kconserv) r2 = kccsd.spin2spatial(r2, orbspin, kconserv) self.assertAlmostEqual(abs(r2[0] - t2[0]).max(), 0, 12) self.assertAlmostEqual(abs(r2[1] - t2[1]).max(), 0, 12) self.assertAlmostEqual(abs(r2[2] - t2[2]).max(), 0, 12)
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 kernel(mycc, eris, t1=None, t2=None, max_memory=2000, verbose=logger.INFO): '''Returns the CCSD(T) for restricted closed-shell systems with k-points. Note: Returns real part of the CCSD(T) energy, raises warning if there is a complex part. Args: mycc (:class:`RCCSD`): Coupled-cluster object storing results of a coupled-cluster calculation. eris (:class:`_ERIS`): Integral object holding the relevant electron- repulsion integrals and Fock matrix elements t1 (:obj:`ndarray`): t1 coupled-cluster amplitudes t2 (:obj:`ndarray`): t2 coupled-cluster amplitudes max_memory (float): Maximum memory used in calculation (NOT USED) verbose (int, :class:`Logger`): verbosity of calculation Returns: energy_t (float): The real-part of the k-point CCSD(T) energy. ''' assert isinstance(mycc, pyscf.pbc.cc.kccsd_rhf.RCCSD) cpu1 = cpu0 = (time.clock(), time.time()) if isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(mycc.stdout, verbose) if t1 is None: t1 = mycc.t1 if t2 is None: t2 = mycc.t2 if eris is None: raise TypeError( 'Electron repulsion integrals, `eris`, must be passed in ' 'to the CCSD(T) kernel or created in the cc object for ' 'the k-point CCSD(T) to run!') if t1 is None or t2 is None: raise TypeError( 'Must pass in t1/t2 amplitudes to k-point CCSD(T)! (Maybe ' 'need to run `.ccsd()` on the ccsd object?)') cell = mycc._scf.cell kpts = mycc.kpts # The dtype of any local arrays that will be created dtype = t1.dtype nkpts, nocc, nvir = t1.shape mo_energy_occ = [eris.mo_energy[ki][:nocc] for ki in range(nkpts)] mo_energy_vir = [eris.mo_energy[ki][nocc:] for ki in range(nkpts)] mo_energy = np.asarray([eris.mo_energy[ki] for ki in range(nkpts)], dtype=np.float, order='C') fov = eris.fock[:, :nocc, nocc:] mo_e = mo_energy mo_e_o = mo_energy_occ mo_e_v = mo_energy_vir # Set up class for k-point conservation kconserv = kpts_helper.get_kconserv(cell, kpts) # Create necessary temporary eris for fast read feri_tmp, t2T, eris_vvop, eris_vooo_C = create_t3_eris( mycc, kconserv, [eris.vovv, eris.oovv, eris.ooov, t2]) t1T = np.array([x.T for x in t1], dtype=np.complex, order='C') fvo = np.array([x.T for x in fov], dtype=np.complex, order='C') cpu1 = log.timer_debug1('CCSD(T) tmp eri creation', *cpu1) #def get_w_old(ki, kj, kk, ka, kb, kc, a0, a1, b0, b1, c0, c1, out=None): # '''Wijkabc intermediate as described in Scuseria paper before Pijkabc acts''' # km = kconserv[kc, kk, kb] # kf = kconserv[kk, kc, kj] # ret = einsum('kjcf,fiba->abcijk', t2[kk,kj,kc,:,:,c0:c1,:], eris.vovv[kf,ki,kb,:,:,b0:b1,a0:a1].conj()) # ret = ret - einsum('mkbc,jima->abcijk', t2[km,kk,kb,:,:,b0:b1,c0:c1], eris.ooov[kj,ki,km,:,:,:,a0:a1].conj()) # return ret def get_w(ki, kj, kk, ka, kb, kc, a0, a1, b0, b1, c0, c1): '''Wijkabc intermediate as described in Scuseria paper before Pijkabc acts Uses tranposed eris for fast data access.''' km = kconserv[kc, kk, kb] kf = kconserv[kk, kc, kj] out = einsum('cfjk,abif->abcijk', t2T[kc, kf, kj, c0:c1, :, :, :], eris_vvop[ka, kb, ki, a0:a1, b0:b1, :, nocc:]) out = out - einsum('cbmk,aijm->abcijk', t2T[kc, kb, km, c0:c1, b0:b1, :, :], eris_vooo_C[ka, ki, kj, a0:a1, :, :, :]) return out def get_permuted_w(ki, kj, kk, ka, kb, kc, orb_indices): '''Pijkabc operating on Wijkabc intermediate as described in Scuseria paper''' a0, a1, b0, b1, c0, c1 = orb_indices out = get_w(ki, kj, kk, ka, kb, kc, a0, a1, b0, b1, c0, c1) out = out + get_w(kj, kk, ki, kb, kc, ka, b0, b1, c0, c1, a0, a1).transpose(2, 0, 1, 5, 3, 4) out = out + get_w(kk, ki, kj, kc, ka, kb, c0, c1, a0, a1, b0, b1).transpose(1, 2, 0, 4, 5, 3) out = out + get_w(ki, kk, kj, ka, kc, kb, a0, a1, c0, c1, b0, b1).transpose(0, 2, 1, 3, 5, 4) out = out + get_w(kk, kj, ki, kc, kb, ka, c0, c1, b0, b1, a0, a1).transpose(2, 1, 0, 5, 4, 3) out = out + get_w(kj, ki, kk, kb, ka, kc, b0, b1, a0, a1, c0, c1).transpose(1, 0, 2, 4, 3, 5) return out def get_rw(ki, kj, kk, ka, kb, kc, orb_indices): '''R operating on Wijkabc intermediate as described in Scuseria paper''' a0, a1, b0, b1, c0, c1 = orb_indices ret = (4. * get_permuted_w(ki, kj, kk, ka, kb, kc, orb_indices) + 1. * get_permuted_w(kj, kk, ki, ka, kb, kc, orb_indices).transpose(0, 1, 2, 5, 3, 4) + 1. * get_permuted_w(kk, ki, kj, ka, kb, kc, orb_indices).transpose(0, 1, 2, 4, 5, 3) - 2. * get_permuted_w(ki, kk, kj, ka, kb, kc, orb_indices).transpose(0, 1, 2, 3, 5, 4) - 2. * get_permuted_w(kk, kj, ki, ka, kb, kc, orb_indices).transpose(0, 1, 2, 5, 4, 3) - 2. * get_permuted_w(kj, ki, kk, ka, kb, kc, orb_indices).transpose(0, 1, 2, 4, 3, 5)) return ret #def get_v_old(ki, kj, kk, ka, kb, kc, a0, a1, b0, b1, c0, c1): # '''Vijkabc intermediate as described in Scuseria paper''' # km = kconserv[ki,ka,kj] # kf = kconserv[ki,ka,kj] # out = np.zeros((a1-a0,b1-b0,c1-c0) + (nocc,)*3, dtype=dtype) # if kk == kc: # out = out + einsum('kc,ijab->abcijk', 0.5*t1[kk,:,c0:c1], eris.oovv[ki,kj,ka,:,:,a0:a1,b0:b1].conj()) # out = out + einsum('kc,ijab->abcijk', 0.5*fov[kk,:,c0:c1], t2[ki,kj,ka,:,:,a0:a1,b0:b1]) # return out def get_v(ki, kj, kk, ka, kb, kc, a0, a1, b0, b1, c0, c1): '''Vijkabc intermediate as described in Scuseria paper''' km = kconserv[ki, ka, kj] kf = kconserv[ki, ka, kj] out = np.zeros((a1 - a0, b1 - b0, c1 - c0) + (nocc, ) * 3, dtype=dtype) if kk == kc: out = out + einsum('ck,baji->abcijk', 0.5 * t1T[kk, c0:c1, :], eris_vvop[kb, ka, kj, b0:b1, a0:a1, :, :nocc]) # We see this is the same t2T term needed for the `w` contraction: # einsum('cbmk,aijm->abcijk', t2T[kc,kb,km,c0:c1,b0:b1], eris_vooo_C[ka,ki,kj,a0:a1]) # # For the kpoint indices [kk,ki,kj,kc,ka,kb] we have that we need # t2T[kb,ka,km], where km = kconserv[kb,kj,ka] # The remaining k-point not used in t2T, i.e. kc, has the condition kc == kk in the case of # get_v. So, we have from 3-particle conservation # (kk-kc) + ki + kj - ka - kb = 0, # i.e. ki = km. out = out + einsum('ck,baij->abcijk', 0.5 * fvo[kk, c0:c1, :], t2T[kb, ka, ki, b0:b1, a0:a1, :, :]) return out def get_permuted_v(ki, kj, kk, ka, kb, kc, orb_indices): '''Pijkabc operating on Vijkabc intermediate as described in Scuseria paper''' a0, a1, b0, b1, c0, c1 = orb_indices tmp = np.zeros((a1 - a0, b1 - b0, c1 - c0) + (nocc, ) * 3, dtype=dtype) ret = get_v(ki, kj, kk, ka, kb, kc, a0, a1, b0, b1, c0, c1) ret = ret + get_v(kj, kk, ki, kb, kc, ka, b0, b1, c0, c1, a0, a1).transpose(2, 0, 1, 5, 3, 4) ret = ret + get_v(kk, ki, kj, kc, ka, kb, c0, c1, a0, a1, b0, b1).transpose(1, 2, 0, 4, 5, 3) ret = ret + get_v(ki, kk, kj, ka, kc, kb, a0, a1, c0, c1, b0, b1).transpose(0, 2, 1, 3, 5, 4) ret = ret + get_v(kk, kj, ki, kc, kb, ka, c0, c1, b0, b1, a0, a1).transpose(2, 1, 0, 5, 4, 3) ret = ret + get_v(kj, ki, kk, kb, ka, kc, b0, b1, a0, a1, c0, c1).transpose(1, 0, 2, 4, 3, 5) return ret def contract_t3Tv(kpt_indices, orb_indices, data): '''Calculate t3T(ransposed) array using C driver.''' ki, kj, kk, ka, kb, kc = kpt_indices a0, a1, b0, b1, c0, c1 = orb_indices slices = np.array([a0, a1, b0, b1, c0, c1], dtype=np.int32) mo_offset = np.array([ki, kj, kk, ka, kb, kc], dtype=np.int32) vvop_ab = np.asarray(data[0][0], dtype=np.complex, order='C') vvop_ac = np.asarray(data[0][1], dtype=np.complex, order='C') vvop_ba = np.asarray(data[0][2], dtype=np.complex, order='C') vvop_bc = np.asarray(data[0][3], dtype=np.complex, order='C') vvop_ca = np.asarray(data[0][4], dtype=np.complex, order='C') vvop_cb = np.asarray(data[0][5], dtype=np.complex, order='C') vooo_aj = np.asarray(data[1][0], dtype=np.complex, order='C') vooo_ak = np.asarray(data[1][1], dtype=np.complex, order='C') vooo_bi = np.asarray(data[1][2], dtype=np.complex, order='C') vooo_bk = np.asarray(data[1][3], dtype=np.complex, order='C') vooo_ci = np.asarray(data[1][4], dtype=np.complex, order='C') vooo_cj = np.asarray(data[1][5], dtype=np.complex, order='C') t2T_cj = np.asarray(data[2][0], dtype=np.complex, order='C') t2T_bk = np.asarray(data[2][1], dtype=np.complex, order='C') t2T_ci = np.asarray(data[2][2], dtype=np.complex, order='C') t2T_ak = np.asarray(data[2][3], dtype=np.complex, order='C') t2T_bi = np.asarray(data[2][4], dtype=np.complex, order='C') t2T_aj = np.asarray(data[2][5], dtype=np.complex, order='C') t2T_cb = np.asarray(data[3][0], dtype=np.complex, order='C') t2T_bc = np.asarray(data[3][1], dtype=np.complex, order='C') t2T_ca = np.asarray(data[3][2], dtype=np.complex, order='C') t2T_ac = np.asarray(data[3][3], dtype=np.complex, order='C') t2T_ba = np.asarray(data[3][4], dtype=np.complex, order='C') t2T_ab = np.asarray(data[3][5], dtype=np.complex, order='C') data = [ vvop_ab, vvop_ac, vvop_ba, vvop_bc, vvop_ca, vvop_cb, vooo_aj, vooo_ak, vooo_bi, vooo_bk, vooo_ci, vooo_cj, t2T_cj, t2T_cb, t2T_bk, t2T_bc, t2T_ci, t2T_ca, t2T_ak, t2T_ac, t2T_bi, t2T_ba, t2T_aj, t2T_ab ] data_ptrs = [x.ctypes.data_as(ctypes.c_void_p) for x in data] data_ptrs = (ctypes.c_void_p * 24)(*data_ptrs) a0, a1, b0, b1, c0, c1 = task t3Tw = np.empty((a1 - a0, b1 - b0, c1 - c0) + (nocc, ) * 3, dtype=np.complex, order='C') t3Tv = np.empty((a1 - a0, b1 - b0, c1 - c0) + (nocc, ) * 3, dtype=np.complex, order='C') drv = _ccsd.libcc.CCsd_zcontract_t3T drv(t3Tw.ctypes.data_as(ctypes.c_void_p), t3Tv.ctypes.data_as(ctypes.c_void_p), mo_e.ctypes.data_as(ctypes.c_void_p), t1T.ctypes.data_as(ctypes.c_void_p), fvo.ctypes.data_as(ctypes.c_void_p), ctypes.c_int(nocc), ctypes.c_int(nvir), ctypes.c_int(nkpts), mo_offset.ctypes.data_as(ctypes.c_void_p), slices.ctypes.data_as(ctypes.c_void_p), data_ptrs) return t3Tw, t3Tv def get_data(kpt_indices): idx_args = get_data_slices(kpt_indices, task, kconserv) vvop_indices, vooo_indices, t2T_vvop_indices, t2T_vooo_indices = idx_args vvop_data = [eris_vvop[tuple(x)] for x in vvop_indices] vooo_data = [eris_vooo_C[tuple(x)] for x in vooo_indices] t2T_vvop_data = [t2T[tuple(x)] for x in t2T_vvop_indices] t2T_vooo_data = [t2T[tuple(x)] for x in t2T_vooo_indices] data = [vvop_data, vooo_data, t2T_vvop_data, t2T_vooo_data] return data energy_t = 0.0 # Get location of padded elements in occupied and virtual space nonzero_opadding, nonzero_vpadding = padding_k_idx(mycc, kind="split") mem_now = lib.current_memory()[0] max_memory = max(0, mycc.max_memory - mem_now) blkmin = 4 # temporary t3 array is size: 2 * nkpts**3 * blksize**3 * nocc**3 * 16 vir_blksize = min( nvir, max(blkmin, int((max_memory * .9e6 / 16 / nocc**3 / nkpts**3 / 2)**(1. / 3)))) tasks = [] log.debug('max_memory %d MB (%d MB in use)', max_memory, mem_now) log.debug('virtual blksize = %d (nvir = %d)', nvir, vir_blksize) for a0, a1 in lib.prange(0, nvir, vir_blksize): for b0, b1 in lib.prange(0, nvir, vir_blksize): for c0, c1 in lib.prange(0, nvir, vir_blksize): tasks.append((a0, a1, b0, b1, c0, c1)) for ka in range(nkpts): for kb in range(ka + 1): for task_id, task in enumerate(tasks): a0, a1, b0, b1, c0, c1 = task my_permuted_w = np.zeros( (nkpts, ) * 3 + (a1 - a0, b1 - b0, c1 - c0) + (nocc, ) * 3, dtype=dtype) my_permuted_v = np.zeros( (nkpts, ) * 3 + (a1 - a0, b1 - b0, c1 - c0) + (nocc, ) * 3, dtype=dtype) for ki, kj, kk in product(range(nkpts), repeat=3): # Find momentum conservation condition for triples # amplitude t3ijkabc kc = kpts_helper.get_kconserv3(cell, kpts, [ki, kj, kk, ka, kb]) if not (ka >= kb and kb >= kc): continue kpt_indices = [ki, kj, kk, ka, kb, kc] data = get_data(kpt_indices) t3Tw, t3Tv = contract_t3Tv(kpt_indices, task, data) my_permuted_w[ki, kj, kk] = t3Tw my_permuted_v[ki, kj, kk] = t3Tv #my_permuted_w[ki,kj,kk] = get_permuted_w(ki,kj,kk,ka,kb,kc,task) #my_permuted_v[ki,kj,kk] = get_permuted_v(ki,kj,kk,ka,kb,kc,task) for ki, kj, kk in product(range(nkpts), repeat=3): # eigenvalue denominator: e(i) + e(j) + e(k) eijk = _get_epqr([0, nocc, ki, mo_e_o, nonzero_opadding], [0, nocc, kj, mo_e_o, nonzero_opadding], [0, nocc, kk, mo_e_o, nonzero_opadding]) # Find momentum conservation condition for triples # amplitude t3ijkabc kc = kpts_helper.get_kconserv3(cell, kpts, [ki, kj, kk, ka, kb]) if not (ka >= kb and kb >= kc): continue if ka == kb and kb == kc: symm_kpt = 1. elif ka == kb or kb == kc: symm_kpt = 3. else: symm_kpt = 6. eabc = _get_epqr([a0, a1, ka, mo_e_v, nonzero_vpadding], [b0, b1, kb, mo_e_v, nonzero_vpadding], [c0, c1, kc, mo_e_v, nonzero_vpadding], fac=[-1., -1., -1.]) eijkabc = (eijk[None, None, None, :, :, :] + eabc[:, :, :, None, None, None]) pwijk = my_permuted_w[ki, kj, kk] + my_permuted_v[ki, kj, kk] rwijk = ( 4. * my_permuted_w[ki, kj, kk] + 1. * my_permuted_w[kj, kk, ki].transpose(0, 1, 2, 5, 3, 4) + 1. * my_permuted_w[kk, ki, kj].transpose(0, 1, 2, 4, 5, 3) - 2. * my_permuted_w[ki, kk, kj].transpose(0, 1, 2, 3, 5, 4) - 2. * my_permuted_w[kk, kj, ki].transpose(0, 1, 2, 5, 4, 3) - 2. * my_permuted_w[kj, ki, kk].transpose(0, 1, 2, 4, 3, 5)) rwijk = rwijk / eijkabc energy_t += symm_kpt * einsum('abcijk,abcijk', rwijk, pwijk.conj()) energy_t *= (1. / 3) energy_t /= nkpts if abs(energy_t.imag) > 1e-4: log.warn('Non-zero imaginary part of CCSD(T) energy was found %s', energy_t.imag) log.timer('CCSD(T)', *cpu0) log.note('CCSD(T) correction per cell = %.15g', energy_t.real) log.note('CCSD(T) correction per cell (imag) = %.15g', energy_t.imag) return energy_t.real
def kernel(mycc, eris, t1=None, t2=None, max_memory=2000, verbose=logger.INFO): '''Returns the CCSD(T) for restricted closed-shell systems with k-points. Note: Returns real part of the CCSD(T) energy, raises warning if there is a complex part. Args: mycc (:class:`RCCSD`): Coupled-cluster object storing results of a coupled-cluster calculation. eris (:class:`_ERIS`): Integral object holding the relevant electron- repulsion integrals and Fock matrix elements t1 (:obj:`ndarray`): t1 coupled-cluster amplitudes t2 (:obj:`ndarray`): t2 coupled-cluster amplitudes max_memory (float): Maximum memory used in calculation (NOT USED) verbose (int, :class:`Logger`): verbosity of calculation Returns: energy_t (float): The real-part of the k-point CCSD(T) energy. ''' assert isinstance(mycc, pyscf.pbc.cc.kccsd_rhf.RCCSD) if isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(mycc.stdout, verbose) if t1 is None: t1 = mycc.t1 if t2 is None: t2 = mycc.t2 if eris is None: raise TypeError('Electron repulsion integrals, `eris`, must be passed in ' 'to the CCSD(T) kernel or created in the cc object for ' 'the k-point CCSD(T) to run!') if t1 is None or t2 is None: raise TypeError('Must pass in t1/t2 amplitudes to k-point CCSD(T)! (Maybe ' 'need to run `.ccsd()` on the ccsd object?)') cell = mycc._scf.cell kpts = mycc.kpts # The dtype of any local arrays that will be created dtype = t1.dtype nkpts, nocc, nvir = t1.shape mo_energy_occ = [eris.mo_energy[ki][:nocc] for ki in range(nkpts)] mo_energy_vir = [eris.mo_energy[ki][nocc:] for ki in range(nkpts)] fov = eris.fock[:, :nocc, nocc:] # Set up class for k-point conservation kconserv = kpts_helper.get_kconserv(cell, kpts) def get_w(ki, kj, kk, ka, kb, kc, a, b, c): '''Wijkabc intermediate as described in Scuseria paper before Pijkabc acts''' km = kconserv[ki, ka, kj] kf = kconserv[kk, kc, kj] ret = einsum('kjf,fi->ijk', t2[kk, kj, kc, :, :, c, :], eris.vovv[kf, ki, kb, :, :, b, a].conj()) ret = ret - einsum('mk,jim->ijk', t2[km, kk, kb, :, :, b, c], eris.ooov[kj, ki, km, :, :, :, a].conj()) return ret def get_permuted_w(ki, kj, kk, ka, kb, kc, a, b, c): '''Pijkabc operating on Wijkabc intermediate as described in Scuseria paper''' ret = get_w(ki, kj, kk, ka, kb, kc, a, b, c) ret = ret + get_w(kj, kk, ki, kb, kc, ka, b, c, a).transpose(2, 0, 1) ret = ret + get_w(kk, ki, kj, kc, ka, kb, c, a, b).transpose(1, 2, 0) ret = ret + get_w(ki, kk, kj, ka, kc, kb, a, c, b).transpose(0, 2, 1) ret = ret + get_w(kk, kj, ki, kc, kb, ka, c, b, a).transpose(2, 1, 0) ret = ret + get_w(kj, ki, kk, kb, ka, kc, b, a, c).transpose(1, 0, 2) return ret def get_rw(ki, kj, kk, ka, kb, kc, a, b, c): '''R operating on Wijkabc intermediate as described in Scuseria paper''' ret = (4. * get_permuted_w(ki, kj, kk, ka, kb, kc, a, b, c) + 1. * get_permuted_w(kk, ki, kj, ka, kb, kc, a, b, c).transpose(1, 2, 0) + 1. * get_permuted_w(kj, kk, ki, ka, kb, kc, a, b, c).transpose(2, 0, 1) - 2. * get_permuted_w(kk, kj, ki, ka, kb, kc, a, b, c).transpose(2, 1, 0) - 2. * get_permuted_w(ki, kk, kj, ka, kb, kc, a, b, c).transpose(0, 2, 1) - 2. * get_permuted_w(kj, ki, kk, ka, kb, kc, a, b, c).transpose(1, 0, 2)) return ret def get_v(ki, kj, kk, ka, kb, kc, a, b, c): '''Vijkabc intermediate as described in Scuseria paper''' km = kconserv[ki, ka, kj] kf = kconserv[ki, ka, kj] ret = np.zeros((nocc, nocc, nocc), dtype=dtype) if kk == kc: ret = ret + einsum('k,ij->ijk', t1[kk, :, c], eris.oovv[ki, kj, ka, :, :, a, b].conj()) ret = ret + einsum('k,ij->ijk', fov[kk, :, c], t2[ki, kj, ka, :, :, a, b]) return ret def get_permuted_v(ki, kj, kk, ka, kb, kc, a, b, c): '''Pijkabc operating on Vijkabc intermediate as described in Scuseria paper''' ret = get_v(ki, kj, kk, ka, kb, kc, a, b, c) ret = ret + get_v(kj, kk, ki, kb, kc, ka, b, c, a).transpose(2, 0, 1) ret = ret + get_v(kk, ki, kj, kc, ka, kb, c, a, b).transpose(1, 2, 0) ret = ret + get_v(ki, kk, kj, ka, kc, kb, a, c, b).transpose(0, 2, 1) ret = ret + get_v(kk, kj, ki, kc, kb, ka, c, b, a).transpose(2, 1, 0) ret = ret + get_v(kj, ki, kk, kb, ka, kc, b, a, c).transpose(1, 0, 2) return ret energy_t = 0.0 # Get location of padded elements in occupied and virtual space nonzero_opadding, nonzero_vpadding = padding_k_idx(mycc, kind="split") for ki in range(nkpts): for kj in range(ki + 1): for kk in range(kj + 1): # eigenvalue denominator: e(i) + e(j) + e(k) eijk = LARGE_DENOM * np.ones((nocc,)*3, dtype=mo_energy_occ[0].dtype) n0_ovp_ijk = np.ix_(nonzero_opadding[ki], nonzero_opadding[kj], nonzero_opadding[kk]) eijk[n0_ovp_ijk] = lib.direct_sum('i,j,k->ijk', mo_energy_occ[ki], mo_energy_occ[kj], mo_energy_occ[kk])[n0_ovp_ijk] for ka in range(nkpts): for kb in range(nkpts): # Find momentum conservation condition for triples # amplitude t3ijkabc kc = kpts_helper.get_kconserv3(cell, kpts, [ki, kj, kk, ka, kb]) ia_index = ki * nkpts + ka jb_index = kj * nkpts + kb kc_index = kk * nkpts + kc if not (ia_index >= jb_index and jb_index >= kc_index): continue # Factors to include for permutational symmetry among k-points if (ia_index == jb_index and jb_index == kc_index): symm_kpt = 1. # only one unique [ia, jb, kc] index elif (ia_index == jb_index or jb_index == kc_index): symm_kpt = 3. # three unique permutations of [ia, jb, kc] else: symm_kpt = 6. # six unique permutations of [ia, jb, kc] # Determine the a, b, c indices we will loop over as # determined by the k-point symmetry. abc_indices = cartesian_prod([range(nvir)] * 3) symm_3d = symm_2d_ab = symm_2d_bc = False if ia_index == jb_index == kc_index: # ka == kb == kc symm_3d = True abc_indices = tril_product(range(nvir), repeat=3, tril_idx=[0, 1, 2]) # loop a >= b >= c symm_3d = True elif ia_index == jb_index: # ka == kb abc_indices = tril_product(range(nvir), repeat=3, tril_idx=[0, 1]) # loop a >= b symm_2d_ab = True elif jb_index == kc_index: abc_indices = tril_product(range(nvir), repeat=3, tril_idx=[1, 2]) # loop b >= c symm_2d_bc = True for a, b, c in abc_indices: # Form energy denominator # Make sure we only loop over non-frozen and/or padded elements if( not ((a in nonzero_vpadding[ka]) and (b in nonzero_vpadding[kb]) and (c in nonzero_vpadding[kc]))): continue eijkabc = (eijk - mo_energy_vir[ka][a] - mo_energy_vir[kb][b] - mo_energy_vir[kc][c]) # See symm_3d and abc_indices above for description of factors symm_abc = 1. if symm_3d: if a == b == c: symm_abc = 1. elif a == b or b == c: symm_abc = 3. else: symm_abc = 6. elif symm_2d_ab: if a == b: symm_abc = 1. else: symm_abc = 2. elif symm_2d_bc: if b == c: symm_abc = 1. else: symm_abc = 2. # The simplest written algorithm can be accomplished with the following four lines #pwijk = ( get_permuted_w(ki, kj, kk, ka, kb, kc, a, b, c) + # 0.5 * get_permuted_v(ki, kj, kk, ka, kb, kc, a, b, c) ) #rwijk = get_rw(ki, kj, kk, ka, kb, kc, a, b, c) / eijkabc #energy_t += symm_fac * einsum('ijk,ijk', pwijk, rwijk.conj()) # Creating permuted W_ijkabc intermediate w_int0 = get_w(ki, kj, kk, ka, kb, kc, a, b, c) w_int1 = get_w(kj, kk, ki, kb, kc, ka, b, c, a).transpose(2, 0, 1) w_int2 = get_w(kk, ki, kj, kc, ka, kb, c, a, b).transpose(1, 2, 0) w_int3 = get_w(ki, kk, kj, ka, kc, kb, a, c, b).transpose(0, 2, 1) w_int4 = get_w(kk, kj, ki, kc, kb, ka, c, b, a).transpose(2, 1, 0) w_int5 = get_w(kj, ki, kk, kb, ka, kc, b, a, c).transpose(1, 0, 2) # Creating permuted V_ijkabc intermediate v_int0 = get_v(ki, kj, kk, ka, kb, kc, a, b, c) v_int1 = get_v(kj, kk, ki, kb, kc, ka, b, c, a).transpose(2, 0, 1) v_int2 = get_v(kk, ki, kj, kc, ka, kb, c, a, b).transpose(1, 2, 0) v_int3 = get_v(ki, kk, kj, ka, kc, kb, a, c, b).transpose(0, 2, 1) v_int4 = get_v(kk, kj, ki, kc, kb, ka, c, b, a).transpose(2, 1, 0) v_int5 = get_v(kj, ki, kk, kb, ka, kc, b, a, c).transpose(1, 0, 2) # Creating permuted W_ijkabc + 0.5 * V_ijkabc intermediate pwijk = w_int0 + 0.5 * v_int0 pwijk += w_int1 + 0.5 * v_int1 pwijk += w_int2 + 0.5 * v_int2 pwijk += w_int3 + 0.5 * v_int3 pwijk += w_int4 + 0.5 * v_int4 pwijk += w_int5 + 0.5 * v_int5 # Creating R[W] intermediate rwijk = np.zeros((nocc, nocc, nocc), dtype=dtype) # Adding in contribution 4. * P[(i, j, k) -> (i, j, k)] rwijk += 4. * w_int0 rwijk += 4. * w_int1 rwijk += 4. * w_int2 rwijk += 4. * w_int3 rwijk += 4. * w_int4 rwijk += 4. * w_int5 # Adding in contribution 1. * P[(i, j, k) -> (k, i, j)] rwijk += 1. * get_w(kk, ki, kj, ka, kb, kc, a, b, c).transpose(1, 2, 0) rwijk += 1. * get_w(ki, kj, kk, kb, kc, ka, b, c, a).transpose(2, 0, 1).transpose(1, 2, 0) rwijk += 1. * get_w(kj, kk, ki, kc, ka, kb, c, a, b).transpose(1, 2, 0).transpose(1, 2, 0) rwijk += 1. * get_w(kk, kj, ki, ka, kc, kb, a, c, b).transpose(0, 2, 1).transpose(1, 2, 0) rwijk += 1. * get_w(kj, ki, kk, kc, kb, ka, c, b, a).transpose(2, 1, 0).transpose(1, 2, 0) rwijk += 1. * get_w(ki, kk, kj, kb, ka, kc, b, a, c).transpose(1, 0, 2).transpose(1, 2, 0) # Adding in contribution 1. * P[(i, j, k) -> (j, k, i)] rwijk += 1. * get_w(kj, kk, ki, ka, kb, kc, a, b, c).transpose(2, 0, 1) rwijk += 1. * get_w(kk, ki, kj, kb, kc, ka, b, c, a).transpose(2, 0, 1).transpose(2, 0, 1) rwijk += 1. * get_w(ki, kj, kk, kc, ka, kb, c, a, b).transpose(1, 2, 0).transpose(2, 0, 1) rwijk += 1. * get_w(kj, ki, kk, ka, kc, kb, a, c, b).transpose(0, 2, 1).transpose(2, 0, 1) rwijk += 1. * get_w(ki, kk, kj, kc, kb, ka, c, b, a).transpose(2, 1, 0).transpose(2, 0, 1) rwijk += 1. * get_w(kk, kj, ki, kb, ka, kc, b, a, c).transpose(1, 0, 2).transpose(2, 0, 1) # Adding in contribution -2. * P[(i, j, k) -> (k, j, i)] rwijk += -2. * get_w(kk, kj, ki, ka, kb, kc, a, b, c).transpose(2, 1, 0) rwijk += -2. * get_w(kj, ki, kk, kb, kc, ka, b, c, a).transpose(2, 0, 1).transpose(2, 1, 0) rwijk += -2. * get_w(ki, kk, kj, kc, ka, kb, c, a, b).transpose(1, 2, 0).transpose(2, 1, 0) rwijk += -2. * get_w(kk, ki, kj, ka, kc, kb, a, c, b).transpose(0, 2, 1).transpose(2, 1, 0) rwijk += -2. * get_w(ki, kj, kk, kc, kb, ka, c, b, a).transpose(2, 1, 0).transpose(2, 1, 0) rwijk += -2. * get_w(kj, kk, ki, kb, ka, kc, b, a, c).transpose(1, 0, 2).transpose(2, 1, 0) # Adding in contribution -2. * P[(i, j, k) -> (i, k, j)] rwijk += -2. * get_w(ki, kk, kj, ka, kb, kc, a, b, c).transpose(0, 2, 1) rwijk += -2. * get_w(kk, kj, ki, kb, kc, ka, b, c, a).transpose(2, 0, 1).transpose(0, 2, 1) rwijk += -2. * get_w(kj, ki, kk, kc, ka, kb, c, a, b).transpose(1, 2, 0).transpose(0, 2, 1) rwijk += -2. * get_w(ki, kj, kk, ka, kc, kb, a, c, b).transpose(0, 2, 1).transpose(0, 2, 1) rwijk += -2. * get_w(kj, kk, ki, kc, kb, ka, c, b, a).transpose(2, 1, 0).transpose(0, 2, 1) rwijk += -2. * get_w(kk, ki, kj, kb, ka, kc, b, a, c).transpose(1, 0, 2).transpose(0, 2, 1) # Adding in contribution -2. * P[(i, j, k) -> (j, i, k)] rwijk += -2. * get_w(kj, ki, kk, ka, kb, kc, a, b, c).transpose(1, 0, 2) rwijk += -2. * get_w(ki, kk, kj, kb, kc, ka, b, c, a).transpose(2, 0, 1).transpose(1, 0, 2) rwijk += -2. * get_w(kk, kj, ki, kc, ka, kb, c, a, b).transpose(1, 2, 0).transpose(1, 0, 2) rwijk += -2. * get_w(kj, kk, ki, ka, kc, kb, a, c, b).transpose(0, 2, 1).transpose(1, 0, 2) rwijk += -2. * get_w(kk, ki, kj, kc, kb, ka, c, b, a).transpose(2, 1, 0).transpose(1, 0, 2) rwijk += -2. * get_w(ki, kj, kk, kb, ka, kc, b, a, c).transpose(1, 0, 2).transpose(1, 0, 2) rwijk /= eijkabc energy_t += symm_abc * symm_kpt * einsum('ijk,ijk', pwijk, rwijk.conj()) energy_t *= (1. / 3) energy_t /= nkpts if abs(energy_t.imag) > 1e-4: log.warn('Non-zero imaginary part of CCSD(T) energy was found %s', energy_t.imag) log.note('CCSD(T) correction per cell = %.15g', energy_t.real) log.note('CCSD(T) correction per cell (imag) = %.15g', energy_t.imag) return energy_t.real
def get_ea_identity(kshift,nocc_a,nocc_b,nvir_a,nvir_b,nkpts,I,cc): count = 0 indices = [] nocc = nocc_a + nocc_b nvir = nvir_a + nvir_b kconserv = kpts_helper.get_kconserv(cc._scf.cell, cc.kpts) # a for i in range(nvir_a): indices.append(i) # b offset = nvir_a for i in range(nvir_b): indices.append(i + offset) offset = nvir for kj in range(nkpts): for ka in range(nkpts): # aaa for j in range(nocc_a): for a in range(nvir_a): for b in range(nvir_a): r1a = np.zeros(nvir_a,dtype=complex) r1b = np.zeros(nvir_b,dtype=complex) r2aaa = np.zeros((nkpts,nkpts,nocc_a,nvir_a,nvir_a),dtype=complex) r2aba = np.zeros((nkpts,nkpts,nocc_a,nvir_b,nvir_a),dtype=complex) r2bab = np.zeros((nkpts,nkpts,nocc_b,nvir_a,nvir_b),dtype=complex) r2bbb = np.zeros((nkpts,nkpts,nocc_b,nvir_b,nvir_b),dtype=complex) if b >= a: pass else: kb = kconserv[kshift,ka,kj] r2aaa[kj,ka,j,a,b] = 1.0 r2aaa[kj,kb,j,b,a] = -1.0 I[:,nvir + count] = kccsd_uhf.amplitudes_to_vector_ea( (r1a,r1b),(r2aaa,r2aba,r2bab,r2bbb)) indices.append(offset + count) count = count + 1 for kj in range(nkpts): for ka in range(nkpts): # aba for j in range(nocc_a): for a in range(nvir_b): for b in range(nvir_a): r1a = np.zeros(nvir_a,dtype=complex) r1b = np.zeros(nvir_b,dtype=complex) r2aaa = np.zeros((nkpts,nkpts,nocc_a,nvir_a,nvir_a),dtype=complex) r2aba = np.zeros((nkpts,nkpts,nocc_a,nvir_b,nvir_a),dtype=complex) r2bab = np.zeros((nkpts,nkpts,nocc_b,nvir_a,nvir_b),dtype=complex) r2bbb = np.zeros((nkpts,nkpts,nocc_b,nvir_a,nvir_b),dtype=complex) r2aba[kj,ka,j,a,b] = 1.0 I[:,nvir + count] = kccsd_uhf.amplitudes_to_vector_ea( (r1a,r1b),(r2aaa,r2aba,r2bab,r2bbb)) indices.append(offset + count) count = count + 1 for kj in range(nkpts): for ka in range(nkpts): # bab for j in range(nocc_b): for a in range(nvir_a): for b in range(nvir_b): r1a = np.zeros(nvir_a,dtype=complex) r1b = np.zeros(nvir_b,dtype=complex) r2aaa = np.zeros((nkpts,nkpts,nocc_a,nvir_a,nvir_a),dtype=complex) r2aba = np.zeros((nkpts,nkpts,nocc_a,nvir_b,nvir_a),dtype=complex) r2bab = np.zeros((nkpts,nkpts,nocc_b,nvir_a,nvir_b),dtype=complex) r2bbb = np.zeros((nkpts,nkpts,nocc_b,nvir_a,nvir_b),dtype=complex) r2bab[kj,ka,j,a,b] = 1.0 I[:,nvir + count] = kccsd_uhf.amplitudes_to_vector_ea( (r1a,r1b),(r2aaa,r2aba,r2bab,r2bbb)) indices.append(offset + count) count = count + 1 for kj in range(nkpts): for ka in range(nkpts): # bbb for j in range(nocc_b): for a in range(nvir_b): for b in range(nvir_b): r1a = np.zeros(nvir_a,dtype=complex) r1b = np.zeros(nvir_b,dtype=complex) r2aaa = np.zeros((nkpts,nkpts,nocc_a,nvir_a,nvir_a),dtype=complex) r2aba = np.zeros((nkpts,nkpts,nocc_a,nvir_b,nvir_a),dtype=complex) r2bab = np.zeros((nkpts,nkpts,nocc_b,nvir_a,nvir_b),dtype=complex) r2bbb = np.zeros((nkpts,nkpts,nocc_b,nvir_b,nvir_b),dtype=complex) if b >= a: pass else: kb = kconserv[kshift,ka,kj] r2bbb[kj,ka,j,a,b] = 1.0 r2bbb[kj,kb,j,b,a] = -1.0 I[:,nvir + count] = kccsd_uhf.amplitudes_to_vector_ea( (r1a,r1b),(r2aaa,r2aba,r2bab,r2bbb)) indices.append(offset + count) count = count + 1 return indices
def ao2mo_7d(mydf, mo_coeff_kpts, kpts=None, factor=1, out=None): cell = mydf.cell if kpts is None: kpts = mydf.kpts nkpts = len(kpts) if isinstance(mo_coeff_kpts, numpy.ndarray) and mo_coeff_kpts.ndim == 3: mo_coeff_kpts = [mo_coeff_kpts] * 4 else: mo_coeff_kpts = list(mo_coeff_kpts) # Shape of the orbitals can be different on different k-points. The # orbital coefficients must be formatted (padded by zeros) so that the # shape of the orbital coefficients are the same on all k-points. This can # be achieved by calling pbc.mp.kmp2.padded_mo_coeff function nmoi, nmoj, nmok, nmol = [x.shape[2] for x in mo_coeff_kpts] eri_shape = (nkpts, nkpts, nkpts, nmoi, nmoj, nmok, nmol) if gamma_point(kpts): dtype = numpy.result_type(*mo_coeff_kpts) else: dtype = numpy.complex128 if out is None: out = numpy.empty(eri_shape, dtype=dtype) else: assert(out.shape == eri_shape) kptij_lst = numpy.array([(ki, kj) for ki in kpts for kj in kpts]) kptis_lst = kptij_lst[:,0] kptjs_lst = kptij_lst[:,1] kpt_ji = kptjs_lst - kptis_lst uniq_kpts, uniq_index, uniq_inverse = unique(kpt_ji) nao = cell.nao_nr() max_memory = max(2000, mydf.max_memory-lib.current_memory()[0]-nao**4*16/1e6) * .5 tao = [] ao_loc = None kconserv = kpts_helper.get_kconserv(cell, kpts) for uniq_id, kpt in enumerate(uniq_kpts): adapted_ji_idx = numpy.where(uniq_inverse == uniq_id)[0] for ji, ji_idx in enumerate(adapted_ji_idx): ki = ji_idx // nkpts kj = ji_idx % nkpts moij, ijslice = _conc_mos(mo_coeff_kpts[0][ki], mo_coeff_kpts[1][kj])[2:] zij = [] for LpqR, LpqI, sign in mydf.sr_loop(kpts[[ki,kj]], max_memory, False, mydf.blockdim): zij.append(_ao2mo.r_e2(LpqR+LpqI*1j, moij, ijslice, tao, ao_loc)) for kk in range(nkpts): kl = kconserv[ki, kj, kk] mokl, klslice = _conc_mos(mo_coeff_kpts[2][kk], mo_coeff_kpts[3][kl])[2:] eri_mo = numpy.zeros((nmoi*nmoj,nmok*nmol), dtype=numpy.complex128) for i, (LrsR, LrsI, sign) in \ enumerate(mydf.sr_loop(kpts[[kk,kl]], max_memory, False, mydf.blockdim)): zkl = _ao2mo.r_e2(LrsR+LrsI*1j, mokl, klslice, tao, ao_loc) lib.dot(zij[i].T, zkl, sign*factor, eri_mo, 1) if dtype == numpy.double: eri_mo = eri_mo.real out[ki,kj,kk] = eri_mo.reshape(eri_shape[3:]) return out
def ao2mo_7d(mydf, mo_coeff_kpts, kpts=None, factor=1, out=None): cell = mydf.cell if kpts is None: kpts = mydf.kpts nkpts = len(kpts) if isinstance(mo_coeff_kpts, numpy.ndarray) and mo_coeff_kpts.ndim == 3: mo_coeff_kpts = [mo_coeff_kpts] * 4 else: mo_coeff_kpts = list(mo_coeff_kpts) # Shape of the orbitals can be different on different k-points. The # orbital coefficients must be formatted (padded by zeros) so that the # shape of the orbital coefficients are the same on all k-points. This can # be achieved by calling pbc.mp.kmp2.padded_mo_coeff function nmoi, nmoj, nmok, nmol = [x.shape[2] for x in mo_coeff_kpts] eri_shape = (nkpts, nkpts, nkpts, nmoi, nmoj, nmok, nmol) if gamma_point(kpts): dtype = numpy.result_type(*mo_coeff_kpts) else: dtype = numpy.complex128 if out is None: out = numpy.empty(eri_shape, dtype=dtype) else: assert(out.shape == eri_shape) kptij_lst = numpy.array([(ki, kj) for ki in kpts for kj in kpts]) kptis_lst = kptij_lst[:,0] kptjs_lst = kptij_lst[:,1] kpt_ji = kptjs_lst - kptis_lst uniq_kpts, uniq_index, uniq_inverse = unique(kpt_ji) ngrids = numpy.prod(mydf.mesh) nao = cell.nao_nr() max_memory = max(2000, mydf.max_memory-lib.current_memory()[0]-nao**4*16/1e6) * .5 fswap = lib.H5TmpFile() tao = [] ao_loc = None kconserv = kpts_helper.get_kconserv(cell, kpts) for uniq_id, kpt in enumerate(uniq_kpts): q = uniq_kpts[uniq_id] adapted_ji_idx = numpy.where(uniq_inverse == uniq_id)[0] kptjs = kptjs_lst[adapted_ji_idx] coulG = mydf.weighted_coulG(q, False, mydf.mesh) coulG *= factor moij_list = [] ijslice_list = [] for ji, ji_idx in enumerate(adapted_ji_idx): ki = ji_idx // nkpts kj = ji_idx % nkpts moij, ijslice = _conc_mos(mo_coeff_kpts[0][ki], mo_coeff_kpts[1][kj])[2:] moij_list.append(moij) ijslice_list.append(ijslice) fswap.create_dataset('zij/'+str(ji), (ngrids,nmoi*nmoj), 'D') for aoaoks, p0, p1 in mydf.ft_loop(mydf.mesh, q, kptjs): for ji, aoao in enumerate(aoaoks): ki = adapted_ji_idx[ji] // nkpts kj = adapted_ji_idx[ji] % nkpts buf = aoao.transpose(1,2,0).reshape(nao**2,ngrids) zij = _ao2mo.r_e2(lib.transpose(buf), moij_list[ji], ijslice_list[ji], tao, ao_loc) zij *= coulG[p0:p1,None] fswap['zij/'+str(ji)][p0:p1] = zij mokl_list = [] klslice_list = [] for kk in range(nkpts): kl = kconserv[ki, kj, kk] mokl, klslice = _conc_mos(mo_coeff_kpts[2][kk], mo_coeff_kpts[3][kl])[2:] mokl_list.append(mokl) klslice_list.append(klslice) fswap.create_dataset('zkl/'+str(kk), (ngrids,nmok*nmol), 'D') ki = adapted_ji_idx[0] // nkpts kj = adapted_ji_idx[0] % nkpts kptls = kpts[kconserv[ki, kj, :]] for aoaoks, p0, p1 in mydf.ft_loop(mydf.mesh, q, -kptls): for kk, aoao in enumerate(aoaoks): buf = aoao.conj().transpose(1,2,0).reshape(nao**2,ngrids) zkl = _ao2mo.r_e2(lib.transpose(buf), mokl_list[kk], klslice_list[kk], tao, ao_loc) fswap['zkl/'+str(kk)][p0:p1] = zkl for ji, ji_idx in enumerate(adapted_ji_idx): ki = ji_idx // nkpts kj = ji_idx % nkpts moij, ijslice = _conc_mos(mo_coeff_kpts[0][ki], mo_coeff_kpts[1][kj])[2:] zij = [] for LpqR, LpqI, sign in mydf.sr_loop(kpts[[ki,kj]], max_memory, False, mydf.blockdim): zij.append(_ao2mo.r_e2(LpqR+LpqI*1j, moij, ijslice, tao, ao_loc)) for kk in range(nkpts): kl = kconserv[ki, kj, kk] eri_mo = lib.dot(numpy.asarray(fswap['zij/'+str(ji)]).T, numpy.asarray(fswap['zkl/'+str(kk)])) for i, (LrsR, LrsI, sign) in \ enumerate(mydf.sr_loop(kpts[[kk,kl]], max_memory, False, mydf.blockdim)): zkl = _ao2mo.r_e2(LrsR+LrsI*1j, mokl_list[kk], klslice_list[kk], tao, ao_loc) lib.dot(zij[i].T, zkl, sign*factor, eri_mo, 1) if dtype == numpy.double: eri_mo = eri_mo.real out[ki,kj,kk] = eri_mo.reshape(eri_shape[3:]) del(fswap['zij']) del(fswap['zkl']) return out
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 ao2mo_7d(mydf, mo_coeff_kpts, kpts=None, factor=1, out=None): cell = mydf.cell if kpts is None: kpts = mydf.kpts nkpts = len(kpts) if isinstance(mo_coeff_kpts, numpy.ndarray) and mo_coeff_kpts.ndim == 3: mo_coeff_kpts = [mo_coeff_kpts] * 4 else: mo_coeff_kpts = list(mo_coeff_kpts) mo_ids = [id(x) for x in mo_coeff_kpts] moTs = [] coords = cell.gen_uniform_grids(mydf.mesh) aos = mydf._numint.eval_ao(cell, coords, kpts) for n, mo_id in enumerate(mo_ids): if mo_id in mo_ids[:n]: moTs.append(moTs[mo_ids[:n].index(mo_id)]) else: moTs.append([lib.dot(mo.T, aos[k].T) for k,mo in enumerate(mo_coeff_kpts[n])]) # Shape of the orbitals can be different on different k-points. The # orbital coefficients must be formatted (padded by zeros) so that the # shape of the orbital coefficients are the same on all k-points. This can # be achieved by calling pbc.mp.kmp2.padded_mo_coeff function nmoi, nmoj, nmok, nmol = [x.shape[2] for x in mo_coeff_kpts] eri_shape = (nkpts, nkpts, nkpts, nmoi, nmoj, nmok, nmol) if gamma_point(kpts): dtype = numpy.result_type(*mo_coeff_kpts) else: dtype = numpy.complex128 if out is None: out = numpy.empty(eri_shape, dtype=dtype) else: assert(out.shape == eri_shape) kptij_lst = numpy.array([(ki, kj) for ki in kpts for kj in kpts]) kptis_lst = kptij_lst[:,0] kptjs_lst = kptij_lst[:,1] kpt_ji = kptjs_lst - kptis_lst uniq_kpts, uniq_index, uniq_inverse = unique(kpt_ji) ngrids = numpy.prod(mydf.mesh) # To hold intermediates fswap = lib.H5TmpFile() kconserv = kpts_helper.get_kconserv(cell, kpts) for uniq_id, kpt in enumerate(uniq_kpts): q = uniq_kpts[uniq_id] adapted_ji_idx = numpy.where(uniq_inverse == uniq_id)[0] ki = adapted_ji_idx[0] // nkpts kj = adapted_ji_idx[0] % nkpts coulG = tools.get_coulG(cell, q, mesh=mydf.mesh) coulG *= (cell.vol/ngrids) * factor phase = numpy.exp(-1j * numpy.dot(coords, q)) for kk in range(nkpts): kl = kconserv[ki, kj, kk] mokT = moTs[2][kk] molT = moTs[3][kl] mo_pairs = numpy.einsum('ig,g,jg->ijg', mokT.conj(), phase.conj(), molT) v = tools.ifft(mo_pairs.reshape(-1,ngrids), mydf.mesh) v *= coulG v = tools.fft(v.reshape(-1,ngrids), mydf.mesh) v *= phase fswap['zkl/'+str(kk)] = v for ji_idx in adapted_ji_idx: ki = ji_idx // nkpts kj = ji_idx % nkpts for kk in range(nkpts): moiT = moTs[0][ki] mojT = moTs[1][kj] mo_pairs = numpy.einsum('ig,jg->ijg', moiT.conj(), mojT) tmp = lib.dot(mo_pairs.reshape(-1,ngrids), numpy.asarray(fswap['zkl/'+str(kk)]).T) if dtype == numpy.double: tmp = tmp.real out[ki,kj,kk] = tmp.reshape(eri_shape[3:]) del(fswap['zkl']) return out
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 _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 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 ao2mo_7d(mydf, mo_coeff_kpts, kpts=None, factor=1, out=None): cell = mydf.cell if kpts is None: kpts = mydf.kpts nkpts = len(kpts) if isinstance(mo_coeff_kpts, numpy.ndarray) and mo_coeff_kpts.ndim == 3: mo_coeff_kpts = [mo_coeff_kpts] * 4 else: mo_coeff_kpts = list(mo_coeff_kpts) # Shape of the orbitals can be different on different k-points. The # orbital coefficients must be formatted (padded by zeros) so that the # shape of the orbital coefficients are the same on all k-points. This can # be achieved by calling pbc.mp.kmp2.padded_mo_coeff function nmoi, nmoj, nmok, nmol = [x.shape[2] for x in mo_coeff_kpts] eri_shape = (nkpts, nkpts, nkpts, nmoi, nmoj, nmok, nmol) if gamma_point(kpts): dtype = numpy.result_type(*mo_coeff_kpts) else: dtype = numpy.complex128 if out is None: out = numpy.empty(eri_shape, dtype=dtype) else: assert(out.shape == eri_shape) kptij_lst = numpy.array([(ki, kj) for ki in kpts for kj in kpts]) kptis_lst = kptij_lst[:,0] kptjs_lst = kptij_lst[:,1] kpt_ji = kptjs_lst - kptis_lst uniq_kpts, uniq_index, uniq_inverse = unique(kpt_ji) ngrids = numpy.prod(mydf.mesh) nao = cell.nao_nr() max_memory = max(2000, mydf.max_memory-lib.current_memory()[0]-nao**4*16/1e6) * .5 tao = [] ao_loc = None kconserv = kpts_helper.get_kconserv(cell, kpts) for uniq_id, kpt in enumerate(uniq_kpts): q = uniq_kpts[uniq_id] adapted_ji_idx = numpy.where(uniq_inverse == uniq_id)[0] for ji, ji_idx in enumerate(adapted_ji_idx): ki = ji_idx // nkpts kj = ji_idx % nkpts moij, ijslice = _conc_mos(mo_coeff_kpts[0][ki], mo_coeff_kpts[1][kj])[2:] zij = [] for LpqR, LpqI, sign in mydf.sr_loop(kpts[[ki,kj]], max_memory, False, mydf.blockdim): zij.append(_ao2mo.r_e2(LpqR+LpqI*1j, moij, ijslice, tao, ao_loc)) for kk in range(nkpts): kl = kconserv[ki, kj, kk] mokl, klslice = _conc_mos(mo_coeff_kpts[2][kk], mo_coeff_kpts[3][kl])[2:] eri_mo = numpy.zeros((nmoi*nmoj,nmok*nmol), dtype=numpy.complex128) for i, (LrsR, LrsI, sign) in \ enumerate(mydf.sr_loop(kpts[[kk,kl]], max_memory, False, mydf.blockdim)): zkl = _ao2mo.r_e2(LrsR+LrsI*1j, mokl, klslice, tao, ao_loc) lib.dot(zij[i].T, zkl, sign*factor, eri_mo, 1) if dtype == numpy.double: eri_mo = eri_mo.real out[ki,kj,kk] = eri_mo.reshape(eri_shape[3:]) return out
def kernel(mycc, eris, t1=None, t2=None, max_memory=2000, verbose=logger.INFO): '''Returns the CCSD(T) for general spin-orbital integrals with k-points. Note: Returns real part of the CCSD(T) energy, raises warning if there is a complex part. Args: mycc (:class:`GCCSD`): Coupled-cluster object storing results of a coupled-cluster calculation. eris (:class:`_ERIS`): Integral object holding the relevant electron- repulsion integrals and Fock matrix elements t1 (:obj:`ndarray`): t1 coupled-cluster amplitudes t2 (:obj:`ndarray`): t2 coupled-cluster amplitudes max_memory (float): Maximum memory used in calculation (NOT USED) verbose (int, :class:`Logger`): verbosity of calculation Returns: energy_t (float): The real-part of the k-point CCSD(T) energy. ''' assert isinstance(mycc, pyscf.pbc.cc.kccsd.GCCSD) if isinstance(verbose, logger.Logger): log = verbose else: log = logger.Logger(mycc.stdout, verbose) if t1 is None: t1 = mycc.t1 if t2 is None: t2 = mycc.t2 if t1 is None or t2 is None: raise TypeError('Must pass in t1/t2 amplitudes to k-point CCSD(T)! (Maybe ' 'need to run `.ccsd()` on the ccsd object?)') cell = mycc._scf.cell kpts = mycc.kpts # The dtype of any local arrays that will be created dtype = t1.dtype nkpts, nocc, nvir = t1.shape mo_energy_occ = [eris.mo_energy[ki][:nocc] for ki in range(nkpts)] mo_energy_vir = [eris.mo_energy[ki][nocc:] for ki in range(nkpts)] fov = eris.fock[:, :nocc, nocc:] # Set up class for k-point conservation kconserv = kpts_helper.get_kconserv(cell, kpts) energy_t = 0.0 for ki in range(nkpts): for kj in range(ki + 1): for kk in range(kj + 1): # eigenvalue denominator: e(i) + e(j) + e(k) eijk = lib.direct_sum('i,j,k->ijk', mo_energy_occ[ki], mo_energy_occ[kj], mo_energy_occ[kk]) # Factors to include for permutational symmetry among k-points for occupied space if ki == kj and kj == kk: symm_ijk_kpt = 1. # only one degeneracy elif ki == kj or kj == kk: symm_ijk_kpt = 3. # 3 degeneracies when only one k-point is unique else: symm_ijk_kpt = 6. # 3! combinations of arranging 3 distinct k-points for ka in range(nkpts): for kb in range(ka + 1): # Find momentum conservation condition for triples # amplitude t3ijkabc kc = kpts_helper.get_kconserv3(cell, kpts, [ki, kj, kk, ka, kb]) if kc not in range(kb + 1): continue # Factors to include for permutational symmetry among k-points for virtual space if ka == kb and kb == kc: symm_abc_kpt = 1. # one unique combination of (ka, kb, kc) elif ka == kb or kb == kc: symm_abc_kpt = 3. # 3 unique combinations of (ka, kb, kc) else: symm_abc_kpt = 6. # 6 unique combinations of (ka, kb, kc) # Determine the a, b, c indices we will loop over as # determined by the k-point symmetry. abc_indices = cartesian_prod([range(nvir)] * 3) symm_3d = symm_2d_ab = symm_2d_bc = False if ka == kc: # == kb from lower triangular summation abc_indices = tril_product(range(nvir), repeat=3, tril_idx=[0, 1, 2]) # loop a >= b >= c symm_3d = True elif ka == kb: abc_indices = tril_product(range(nvir), repeat=3, tril_idx=[0, 1]) # loop a >= b symm_2d_ab = True elif kb == kc: abc_indices = tril_product(range(nvir), repeat=3, tril_idx=[1, 2]) # loop b >= c symm_2d_bc = True for a, b, c in abc_indices: # See symm_3d and abc_indices above for description of factors symm_abc = 1. if symm_3d: if a == b == c: symm_abc = 1. elif a == b or b == c: symm_abc = 3. else: symm_abc = 6. elif symm_2d_ab: if a == b: symm_abc = 1. else: symm_abc = 2. elif symm_2d_bc: if b == c: symm_abc = 1. else: symm_abc = 2. # Form energy denominator eijkabc = (eijk - mo_energy_vir[ka][a] - mo_energy_vir[kb][b] - mo_energy_vir[kc][c]) # When padding for non-equal nocc per k-point, some fock elements will be zero idx = np.where(abs(eijkabc) < LOOSE_ZERO_TOL)[0] eijkabc[idx] = LARGE_DENOM # Form connected triple excitation amplitude t3c = np.zeros((nocc, nocc, nocc), dtype=dtype) # First term: 1 - p(ij) - p(ik) ke = kconserv[kj, ka, kk] t3c = t3c + einsum('jke,ie->ijk', t2[kj, kk, ka, :, :, a, :], -eris.ovvv[ki, ke, kc, :, :, c, b].conj()) ke = kconserv[ki, ka, kk] t3c = t3c - einsum('ike,je->ijk', t2[ki, kk, ka, :, :, a, :], -eris.ovvv[kj, ke, kc, :, :, c, b].conj()) ke = kconserv[kj, ka, ki] t3c = t3c - einsum('jie,ke->ijk', t2[kj, ki, ka, :, :, a, :], -eris.ovvv[kk, ke, kc, :, :, c, b].conj()) km = kconserv[kb, ki, kc] t3c = t3c - einsum('mi,jkm->ijk', t2[km, ki, kb, :, :, b, c], eris.ooov[kj, kk, km, :, :, :, a].conj()) km = kconserv[kb, kj, kc] t3c = t3c + einsum('mj,ikm->ijk', t2[km, kj, kb, :, :, b, c], eris.ooov[ki, kk, km, :, :, :, a].conj()) km = kconserv[kb, kk, kc] t3c = t3c + einsum('mk,jim->ijk', t2[km, kk, kb, :, :, b, c], eris.ooov[kj, ki, km, :, :, :, a].conj()) # Second term: - p(ab) + p(ab) p(ij) + p(ab) p(ik) ke = kconserv[kj, kb, kk] t3c = t3c - einsum('jke,ie->ijk', t2[kj, kk, kb, :, :, b, :], -eris.ovvv[ki, ke, kc, :, :, c, a].conj()) ke = kconserv[ki, kb, kk] t3c = t3c + einsum('ike,je->ijk', t2[ki, kk, kb, :, :, b, :], -eris.ovvv[kj, ke, kc, :, :, c, a].conj()) ke = kconserv[kj, kb, ki] t3c = t3c + einsum('jie,ke->ijk', t2[kj, ki, kb, :, :, b, :], -eris.ovvv[kk, ke, kc, :, :, c, a].conj()) km = kconserv[ka, ki, kc] t3c = t3c + einsum('mi,jkm->ijk', t2[km, ki, ka, :, :, a, c], eris.ooov[kj, kk, km, :, :, :, b].conj()) km = kconserv[ka, kj, kc] t3c = t3c - einsum('mj,ikm->ijk', t2[km, kj, ka, :, :, a, c], eris.ooov[ki, kk, km, :, :, :, b].conj()) km = kconserv[ka, kk, kc] t3c = t3c - einsum('mk,jim->ijk', t2[km, kk, ka, :, :, a, c], eris.ooov[kj, ki, km, :, :, :, b].conj()) # Third term: - p(ac) + p(ac) p(ij) + p(ac) p(ik) ke = kconserv[kj, kc, kk] t3c = t3c - einsum('jke,ie->ijk', t2[kj, kk, kc, :, :, c, :], -eris.ovvv[ki, ke, ka, :, :, a, b].conj()) ke = kconserv[ki, kc, kk] t3c = t3c + einsum('ike,je->ijk', t2[ki, kk, kc, :, :, c, :], -eris.ovvv[kj, ke, ka, :, :, a, b].conj()) ke = kconserv[kj, kc, ki] t3c = t3c + einsum('jie,ke->ijk', t2[kj, ki, kc, :, :, c, :], -eris.ovvv[kk, ke, ka, :, :, a, b].conj()) km = kconserv[kb, ki, ka] t3c = t3c + einsum('mi,jkm->ijk', t2[km, ki, kb, :, :, b, a], eris.ooov[kj, kk, km, :, :, :, c].conj()) km = kconserv[kb, kj, ka] t3c = t3c - einsum('mj,ikm->ijk', t2[km, kj, kb, :, :, b, a], eris.ooov[ki, kk, km, :, :, :, c].conj()) km = kconserv[kb, kk, ka] t3c = t3c - einsum('mk,jim->ijk', t2[km, kk, kb, :, :, b, a], eris.ooov[kj, ki, km, :, :, :, c].conj()) # Form disconnected triple excitation amplitude contribution t3d = np.zeros((nocc, nocc, nocc), dtype=dtype) # First term: 1 - p(ij) - p(ik) if ki == ka: t3d = t3d + einsum('i,jk->ijk', t1[ki, :, a], -eris.oovv[kj, kk, kb, :, :, b, c].conj()) t3d = t3d + einsum('i,jk->ijk',-fov[ki, :, a], t2[kj, kk, kb, :, :, b, c]) if kj == ka: t3d = t3d - einsum('j,ik->ijk', t1[kj, :, a], -eris.oovv[ki, kk, kb, :, :, b, c].conj()) t3d = t3d - einsum('j,ik->ijk',-fov[kj, :, a], t2[ki, kk, kb, :, :, b, c]) if kk == ka: t3d = t3d - einsum('k,ji->ijk', t1[kk, :, a], -eris.oovv[kj, ki, kb, :, :, b, c].conj()) t3d = t3d - einsum('k,ji->ijk',-fov[kk, :, a], t2[kj, ki, kb, :, :, b, c]) # Second term: - p(ab) + p(ab) p(ij) + p(ab) p(ik) if ki == kb: t3d = t3d - einsum('i,jk->ijk', t1[ki, :, b], -eris.oovv[kj, kk, ka, :, :, a, c].conj()) t3d = t3d - einsum('i,jk->ijk',-fov[ki, :, b], t2[kj, kk, ka, :, :, a, c]) if kj == kb: t3d = t3d + einsum('j,ik->ijk', t1[kj, :, b], -eris.oovv[ki, kk, ka, :, :, a, c].conj()) t3d = t3d + einsum('j,ik->ijk',-fov[kj, :, b], t2[ki, kk, ka, :, :, a, c]) if kk == kb: t3d = t3d + einsum('k,ji->ijk', t1[kk, :, b], -eris.oovv[kj, ki, ka, :, :, a, c].conj()) t3d = t3d + einsum('k,ji->ijk',-fov[kk, :, b], t2[kj, ki, ka, :, :, a, c]) # Third term: - p(ac) + p(ac) p(ij) + p(ac) p(ik) if ki == kc: t3d = t3d - einsum('i,jk->ijk', t1[ki, :, c], -eris.oovv[kj, kk, kb, :, :, b, a].conj()) t3d = t3d - einsum('i,jk->ijk',-fov[ki, :, c], t2[kj, kk, kb, :, :, b, a]) if kj == kc: t3d = t3d + einsum('j,ik->ijk', t1[kj, :, c], -eris.oovv[ki, kk, kb, :, :, b, a].conj()) t3d = t3d + einsum('j,ik->ijk',-fov[kj, :, c], t2[ki, kk, kb, :, :, b, a]) if kk == kc: t3d = t3d + einsum('k,ji->ijk', t1[kk, :, c], -eris.oovv[kj, ki, kb, :, :, b, a].conj()) t3d = t3d + einsum('k,ji->ijk',-fov[kk, :, c], t2[kj, ki, kb, :, :, b, a]) t3c_plus_d = t3c + t3d t3c_plus_d /= eijkabc energy_t += symm_abc_kpt * symm_ijk_kpt * symm_abc * einsum('ijk,ijk', t3c, t3c_plus_d.conj()) energy_t = (1. / 36) * energy_t / nkpts if abs(energy_t.imag) > 1e-4: log.warn('Non-zero imaginary part of CCSD(T) energy was found %s', energy_t.imag) log.note('CCSD(T) correction per cell = %.15g', energy_t.real) return energy_t.real
def __init__(self,cell,kpts): kconserv = kpts_helper.get_kconserv(cell,kpts) nkpts = len(kpts) temp = range(0,nkpts) klist = pyscf.lib.cartesian_prod((temp,temp,temp)) completed = numpy.zeros((nkpts,nkpts,nkpts),dtype=int) self.operations = numpy.zeros((nkpts,nkpts,nkpts),dtype=int) self.equivalentList = numpy.zeros((nkpts,nkpts,nkpts,3),dtype=int) self.nUnique = 0 self.uniqueList = numpy.array([],dtype=int) ivec = 0 not_done = True while( not_done ): current_kvec = klist[ivec] # check to see if it's been done... kp = current_kvec[0] kq = current_kvec[1] kr = current_kvec[2] #print "computing ",kp,kq,kr if completed[kp,kq,kr] == 0: self.nUnique += 1 self.uniqueList = numpy.append(self.uniqueList,current_kvec) ks = kconserv[kp,kq,kr] # Now find all equivalent kvectors by permuting it all possible ways... # and then storing how its related by symmetry completed[kp,kq,kr] = 1 self.operations[kp,kq,kr] = 0 self.equivalentList[kp,kq,kr] = current_kvec.copy() completed[kr,ks,kp] = 1 self.operations[kr,ks,kp] = 1 #.transpose(2,3,0,1) self.equivalentList[kr,ks,kp] = current_kvec.copy() completed[kq,kp,ks] = 1 self.operations[kq,kp,ks] = 2 #numpy.conj(.transpose(1,0,3,2)) self.equivalentList[kq,kp,ks] = current_kvec.copy() completed[ks,kr,kq] = 1 self.operations[ks,kr,kq] = 3 #numpy.conj(.transpose(3,2,1,0)) self.equivalentList[ks,kr,kq] = current_kvec.copy() ivec += 1 if ivec == len(klist): not_done = False self.uniqueList = self.uniqueList.reshape(self.nUnique,-1) if DEBUG == 1: print("::: kpoint helper :::") print("kvector list (in)") print(" shape = ", klist.shape) print("kvector list (out)") print(" shape = ", self.uniqueList.shape) print(" unique list =") print(self.uniqueList) print("transformation =") for i in range(klist.shape[0]): pqr = klist[i] irr_pqr = self.equivalentList[pqr[0],pqr[1],pqr[2]] print("%3d %3d %3d -> %3d %3d %3d" % (pqr[0],pqr[1],pqr[2], irr_pqr[0],irr_pqr[1],irr_pqr[2]))
from pyscf.pbc.lib.kpts_helper import get_kconserv from pyscf.pbc import tools nao = cell.nao_nr() mydf = df.FFTDF(cell, kpts=kpts) Lpq_kpts = [] for i, kpti in enumerate(kpts): Lpq_kpts.append([]) for j, kptj in enumerate(kpts): q = kptj - kpti coulG = tools.get_coulG(cell, q) ngrids = len(coulG) ao_pairs_G = mydf.get_ao_pairs_G([kpti,kptj], q, compact=False) ao_pairs_G *= numpy.sqrt(coulG*cell.vol/ngrids**2).reshape(-1,1) Lpq_kpts[i].append(ao_pairs_G.reshape(-1,nao,nao)) kconserv = get_kconserv(cell, kpts) Lrs_kpts = [] for i, kpti in enumerate(kpts): Lrs_kpts.append([]) for j, kptj in enumerate(kpts): Lrs_kpts[i].append([]) q = kptj - kpti coulG = tools.get_coulG(cell, q) ngrids = len(coulG) for k, kptk in enumerate(kpts): # Handle the wrap-around k-points l = kconserv[i,j,k] kptl = kpts[l] ao_pairs_invG = mydf.get_ao_pairs_G([-kptk,-kptl], q, compact=False).conj() ao_pairs_invG *= numpy.sqrt(coulG*cell.vol/ngrids**2).reshape(-1,1) Lrs_kpts[i][j].append(ao_pairs_invG.reshape(-1,nao,nao))