def __init__(self, cc, mo_coeff=None): from pyscf.pbc.cc.ccsd import _adjust_occ import pyscf.pbc.tools.pbc as tools if mo_coeff is None: mo_coeff = cc.mo_coeff cput0 = (time.clock(), time.time()) symlib = cc.symlib log = Logger(cc.stdout, cc.verbose) self.lib = lib nocc, nmo, nkpts = cc.nocc, cc.nmo, cc.nkpts nvir = nmo - nocc cell, kpts = cc._scf.cell, cc.kpts gvec = cell.reciprocal_vectors() sym1 = ['+-', [kpts,]*2, None, gvec] sym2 = ['+-+-', [kpts,]*4, None, gvec] mo_coeff = self.mo_coeff = padded_mo_coeff(cc, mo_coeff) nonzero_opadding, nonzero_vpadding = padding_k_idx(cc, kind="split") madelung = tools.madelung(cell, kpts) fock = None if rank==0: dm = cc._scf.make_rdm1(cc.mo_coeff, cc.mo_occ) with pyscflib.temporary_env(cc._scf, exxdiv=None): fockao = cc._scf.get_hcore() + cc._scf.get_veff(cell, dm) fock = np.asarray([reduce(np.dot, (mo.T.conj(), fockao[k], mo)) for k, mo in enumerate(mo_coeff)]) fock = comm.bcast(fock, root=0) self.dtype = dtype = np.result_type(*(mo_coeff, fock)).char self.foo = zeros([nocc,nocc], dtype, sym1, symlib=symlib, verbose=cc.SYMVERBOSE) self.fov = zeros([nocc,nvir], dtype, sym1, symlib=symlib, verbose=cc.SYMVERBOSE) self.fvv = zeros([nvir,nvir], dtype, sym1, symlib=symlib, verbose=cc.SYMVERBOSE) self.eia = zeros([nocc,nvir], np.float64, sym1, symlib=symlib, verbose=cc.SYMVERBOSE) self._foo = zeros([nocc,nocc], dtype, sym1, symlib=symlib, verbose=cc.SYMVERBOSE) self._fvv = zeros([nvir,nvir], dtype, sym1, symlib=symlib, verbose=cc.SYMVERBOSE) foo = fock[:,:nocc,:nocc] fov = fock[:,:nocc,nocc:] fvv = fock[:,nocc:,nocc:] mo_energy = [fock[k].diagonal().real for k in range(nkpts)] mo_energy = [_adjust_occ(mo_e, nocc, -madelung) for k, mo_e in enumerate(mo_energy)] mo_e_o = [e[:nocc] for e in mo_energy] mo_e_v = [e[nocc:] + cc.level_shift for e in mo_energy] foo_ = np.asarray([np.diag(e) for e in mo_e_o]) fvv_ = np.asarray([np.diag(e) for e in mo_e_v]) eia = np.zeros([nkpts,nocc,nvir]) for ki in range(nkpts): eia[ki] = _get_epq([0,nocc,ki,mo_e_o,nonzero_opadding], [0,nvir,ki,mo_e_v,nonzero_vpadding], fac=[1.0,-1.0]) if rank ==0: self.foo.write(range(foo.size), foo.ravel()) self.fov.write(range(fov.size), fov.ravel()) self.fvv.write(range(fvv.size), fvv.ravel()) self.eia.write(range(eia.size), eia.ravel()) self._foo.write(range(foo_.size), foo_.ravel()) self._fvv.write(range(fvv_.size), fvv_.ravel()) else: self.foo.write([],[]) self.fov.write([],[]) self.fvv.write([],[]) self.eia.write([],[]) self._foo.write([],[]) self._fvv.write([],[]) self.eijab = zeros([nocc,nocc,nvir,nvir], np.float64, sym2, symlib=symlib, verbose=cc.SYMVERBOSE) kconserv = cc.khelper.kconserv khelper = cc.khelper idx_oovv = np.arange(nocc*nocc*nvir*nvir) jobs = list(khelper.symm_map.keys()) tasks = static_partition(jobs) ntasks = max(comm.allgather(len(tasks))) nwrite = 0 for itask in tasks: ikp, ikq, ikr = itask pqr = np.asarray(khelper.symm_map[(ikp,ikq,ikr)]) nwrite += len(np.unique(pqr, axis=0)) nwrite_max = max(comm.allgather(nwrite)) write_count = 0 for itask in range(ntasks): if itask >= len(tasks): continue ikp, ikq, ikr = tasks[itask] iks = kconserv[ikp,ikq,ikr] done = np.zeros([nkpts,nkpts,nkpts]) for (kp, kq, kr) in khelper.symm_map[(ikp, ikq, ikr)]: if done[kp,kq,kr]: continue ks = kconserv[kp,kq,kr] eia = _get_epq([0,nocc,kp,mo_e_o,nonzero_opadding], [0,nvir,kq,mo_e_v,nonzero_vpadding], fac=[1.0,-1.0]) ejb = _get_epq([0,nocc,kr,mo_e_o,nonzero_opadding], [0,nvir,ks,mo_e_v,nonzero_vpadding], fac=[1.0,-1.0]) eijab = eia[:,None,:,None] + ejb[None,:,None,:] off = kp * nkpts**2 + kr * nkpts + kq self.eijab.write(off*idx_oovv.size+idx_oovv, eijab.ravel()) done[kp,kq,kr] = 1 write_count += 1 for i in range(nwrite_max-write_count): self.eijab.write([], []) if type(cc._scf.with_df) is df.FFTDF: _make_fftdf_eris(cc, self) else: from cc_sym import mpigdf if type(cc._scf.with_df) is mpigdf.GDF: _make_df_eris(cc, self) elif type(cc._scf.with_df) is df.GDF: log.warn("GDF converted to an MPIGDF object") cc._scf.with_df = mpigdf.from_serial(cc._scf.with_df) _make_df_eris(cc, self) else: raise NotImplementedError("DF object not recognized") log.timer("ao2mo transformation", *cput0)
def get_t3p2_imds_slow(cc, t1, t2, eris=None, t3p2_ip_out=None, t3p2_ea_out=None): """Calculates T1, T2 amplitudes corrected by second-order T3 contribution and intermediates used in IP/EA-CCSD(T)a Args: cc (:obj:`KGCCSD`): Object containing coupled-cluster results. t1 (:obj:`ndarray`): T1 amplitudes. t2 (:obj:`ndarray`): T2 amplitudes from which the T3[2] amplitudes are formed. eris (:obj:`_PhysicistsERIs`): Antisymmetrized electron-repulsion integrals in physicist's notation. t3p2_ip_out (:obj:`ndarray`): Store results of the intermediate used in IP-EOM-CCSD(T)a. t3p2_ea_out (:obj:`ndarray`): Store results of the intermediate used in EA-EOM-CCSD(T)a. Returns: delta_ccsd (float): Difference of perturbed and unperturbed CCSD ground-state energy, energy(T1 + T1[2], T2 + T2[2]) - energy(T1, T2) pt1 (:obj:`ndarray`): Perturbatively corrected T1 amplitudes. pt2 (:obj:`ndarray`): Perturbatively corrected T2 amplitudes. Reference: D. A. Matthews, J. F. Stanton "A new approach to approximate..." JCP 145, 124102 (2016); DOI:10.1063/1.4962910, Equation 14 Shavitt and Bartlett "Many-body Methods in Physics and Chemistry" 2009, Equation 10.33 """ if eris is None: eris = cc.ao2mo() fock = eris.fock nkpts, nocc, nvir = t1.shape kconserv = cc.khelper.kconserv fov = [fock[ikpt, :nocc, nocc:] for ikpt in range(nkpts)] #foo = [fock[ikpt, :nocc, :nocc].diagonal() for ikpt in range(nkpts)] #fvv = [fock[ikpt, nocc:, nocc:].diagonal() for ikpt in range(nkpts)] mo_energy_occ = numpy.array( [eris.mo_energy[ki][:nocc] for ki in range(nkpts)]) mo_energy_vir = numpy.array( [eris.mo_energy[ki][nocc:] for ki in range(nkpts)]) # Get location of padded elements in occupied and virtual space nonzero_opadding, nonzero_vpadding = padding_k_idx(cc, kind="split") mo_e_o = mo_energy_occ mo_e_v = mo_energy_vir ccsd_energy = cc.energy(t1, t2, eris) dtype = numpy.result_type(t1, t2) if t3p2_ip_out is None: t3p2_ip_out = numpy.zeros( (nkpts, nkpts, nkpts, nocc, nvir, nocc, nocc), dtype=dtype) Wmcik = t3p2_ip_out if t3p2_ea_out is None: t3p2_ea_out = numpy.zeros( (nkpts, nkpts, nkpts, nvir, nvir, nvir, nocc), dtype=dtype) Wacek = t3p2_ea_out t3 = get_full_t3p2(cc, t1, t2, eris) pt1 = numpy.zeros((nkpts, nocc, nvir), dtype=dtype) for ki in range(nkpts): ka = ki for km, kn, ke in product(range(nkpts), repeat=3): pt1[ki] += 0.25 * lib.einsum( 'mnef,imnaef->ia', eris.oovv[km, kn, ke], t3[ki, km, kn, ka, ke]) eia = _get_epq([0, nocc, ki, mo_e_o, nonzero_opadding], [0, nvir, ka, mo_e_v, nonzero_vpadding], fac=[1.0, -1.0]) pt1[ki] /= eia pt2 = numpy.zeros((nkpts, nkpts, nkpts, nocc, nocc, nvir, nvir), dtype=dtype) for ki, kj, ka in product(range(nkpts), repeat=3): kb = kconserv[ki, ka, kj] for km in range(nkpts): pt2[ki, kj, ka] += lib.einsum('ijmabe,me->ijab', t3[ki, kj, km, ka, kb], fov[km]) for ke in range(nkpts): kf = kconserv[km, ke, kb] pt2[ki, kj, ka] += 0.5 * lib.einsum( 'ijmaef,mbfe->ijab', t3[ki, kj, km, ka, ke], eris.ovvv[km, kb, kf]) kf = kconserv[km, ke, ka] pt2[ki, kj, ka] -= 0.5 * lib.einsum( 'ijmbef,mafe->ijab', t3[ki, kj, km, kb, ke], eris.ovvv[km, ka, kf]) for kn in range(nkpts): pt2[ki, kj, ka] -= 0.5 * lib.einsum( 'inmabe,nmje->ijab', t3[ki, kn, km, ka, kb], eris.ooov[kn, km, kj]) pt2[ki, kj, ka] += 0.5 * lib.einsum( 'jnmabe,nmie->ijab', t3[kj, kn, km, ka, kb], eris.ooov[kn, km, ki]) eia = _get_epq([0, nocc, ki, mo_e_o, nonzero_opadding], [0, nvir, ka, mo_e_v, nonzero_vpadding], fac=[1.0, -1.0]) ejb = _get_epq([0, nocc, kj, mo_e_o, nonzero_opadding], [0, nvir, kb, mo_e_v, nonzero_vpadding], fac=[1.0, -1.0]) eijab = eia[:, None, :, None] + ejb[:, None, :] pt2[ki, kj, ka] /= eijab pt1 += t1 pt2 += t2 for ki, kj, kk, ka, kb in product(range(nkpts), repeat=5): kc = kpts_helper.get_kconserv3(cc._scf.cell, cc.kpts, [ki, kj, kk, ka, kb]) tmp = t3[ki, kj, kk, ka, kb] km = kconserv[ki, kc, kk] ke = kconserv[ka, kk, kc] Wmcik[km, kc, ki] += 0.5 * lib.einsum('ijkabc,mjab->mcik', tmp, eris.oovv[km, kj, ka]) Wacek[ka, kc, ke] += -0.5 * lib.einsum('ijkabc,ijeb->acek', tmp, eris.oovv[ki, kj, ke]) delta_ccsd_energy = cc.energy(pt1, pt2, eris) - ccsd_energy logger.info(cc, 'CCSD energy T3[2] correction : %14.8e', delta_ccsd_energy) return delta_ccsd_energy, pt1, pt2, Wmcik, Wacek
def __init__(self, cc, mo_coeff=None): from pyscf.pbc.cc.ccsd import _adjust_occ import pyscf.pbc.tools.pbc as tools if mo_coeff is None: mo_coeff = cc.mo_coeff cput0 = (time.clock(), time.time()) log = Logger(cc.stdout, cc.verbose) self.lib = lib nocc, nmo, nkpts = cc.nocc, cc.nmo, cc.nkpts nvir = nmo - nocc cell, kpts = cc._scf.cell, cc.kpts gvec = cell.reciprocal_vectors() sym1 = ['+-', [ kpts, ] * 2, None, gvec] sym2 = ['+-+-', [ kpts, ] * 4, None, gvec] mo_coeff = self.mo_coeff = padded_mo_coeff(cc, mo_coeff) nonzero_opadding, nonzero_vpadding = padding_k_idx(cc, kind="split") madelung = tools.madelung(cell, kpts) dm = cc._scf.make_rdm1(cc.mo_coeff, cc.mo_occ) with pyscflib.temporary_env(cc._scf, exxdiv=None): fockao = cc._scf.get_hcore() + cc._scf.get_veff(cell, dm) fock = np.asarray([ reduce(np.dot, (mo.T.conj(), fockao[k], mo)) for k, mo in enumerate(mo_coeff) ]) self.dtype = dtype = np.result_type(*fock).char self.foo = tensor(fock[:, :nocc, :nocc], sym1) self.fov = tensor(fock[:, :nocc, nocc:], sym1) self.fvv = tensor(fock[:, nocc:, nocc:], sym1) mo_energy = [fock[k].diagonal().real for k in range(nkpts)] mo_energy = [ _adjust_occ(mo_e, nocc, -madelung) for k, mo_e in enumerate(mo_energy) ] mo_e_o = [e[:nocc] for e in mo_energy] mo_e_v = [e[nocc:] + cc.level_shift for e in mo_energy] foo_ = np.asarray([np.diag(e) for e in mo_e_o]) fvv_ = np.asarray([np.diag(e) for e in mo_e_v]) self._foo = tensor(foo_, sym1) self._fvv = tensor(fvv_, sym1) eia = np.zeros([nkpts, nocc, nvir]) for ki in range(nkpts): eia[ki] = _get_epq([0, nocc, ki, mo_e_o, nonzero_opadding], [0, nvir, ki, mo_e_v, nonzero_vpadding], fac=[1.0, -1.0]) self.eia = tensor(eia, sym1) self.oooo = zeros([nocc, nocc, nocc, nocc], dtype, sym2) self.ooov = zeros([nocc, nocc, nocc, nvir], dtype, sym2) self.ovov = zeros([nocc, nvir, nocc, nvir], dtype, sym2) self.oovv = zeros([nocc, nocc, nvir, nvir], dtype, sym2) self.ovvo = zeros([nocc, nvir, nvir, nocc], dtype, sym2) self.ovvv = zeros([nocc, nvir, nvir, nvir], dtype, sym2) self.vvvv = zeros([nvir, nvir, nvir, nvir], dtype, sym2) self.eijab = zeros([nocc, nocc, nvir, nvir], np.float64, sym2) with_df = cc._scf.with_df fao2mo = cc._scf.with_df.ao2mo kconserv = cc.khelper.kconserv khelper = cc.khelper jobs = list(khelper.symm_map.keys()) for itask in jobs: ikp, ikq, ikr = itask iks = kconserv[ikp, ikq, ikr] eri_kpt = fao2mo( (mo_coeff[ikp], mo_coeff[ikq], mo_coeff[ikr], mo_coeff[iks]), (kpts[ikp], kpts[ikq], kpts[ikr], kpts[iks]), compact=False) if dtype == np.float: eri_kpt = eri_kpt.real eri_kpt = eri_kpt.reshape(nmo, nmo, nmo, nmo) / nkpts done = np.zeros([nkpts, nkpts, nkpts]) for (kp, kq, kr) in khelper.symm_map[(ikp, ikq, ikr)]: if done[kp, kq, kr]: continue eri_kpt_symm = khelper.transform_symm(eri_kpt, kp, kq, kr) oooo = eri_kpt_symm[:nocc, :nocc, :nocc, :nocc] ooov = eri_kpt_symm[:nocc, :nocc, :nocc, nocc:] ovov = eri_kpt_symm[:nocc, nocc:, :nocc, nocc:] oovv = eri_kpt_symm[:nocc, :nocc, nocc:, nocc:] ovvo = eri_kpt_symm[:nocc, nocc:, nocc:, :nocc] ovvv = eri_kpt_symm[:nocc, nocc:, nocc:, nocc:] vvvv = eri_kpt_symm[nocc:, nocc:, nocc:, nocc:] ks = kconserv[kp, kq, kr] eia = _get_epq([0, nocc, kp, mo_e_o, nonzero_opadding], [0, nvir, kq, mo_e_v, nonzero_vpadding], fac=[1.0, -1.0]) ejb = _get_epq([0, nocc, kr, mo_e_o, nonzero_opadding], [0, nvir, ks, mo_e_v, nonzero_vpadding], fac=[1.0, -1.0]) eijab = eia[:, None, :, None] + ejb[None, :, None, :] self.oooo.array[kp, kq, kr] = oooo self.ooov.array[kp, kq, kr] = ooov self.ovov.array[kp, kq, kr] = ovov self.oovv.array[kp, kq, kr] = oovv self.ovvo.array[kp, kq, kr] = ovvo self.ovvv.array[kp, kq, kr] = ovvv self.vvvv.array[kp, kq, kr] = vvvv self.eijab.array[kp, kr, kq] = eijab done[kp, kq, kr] = 1 log.timer("ao2mo transformation", *cput0)