def ao2mo(self, mo_coeff=None): from pyscf.pbc import tools from pyscf.pbc.cc.ccsd import _adjust_occ with_df = self._scf.with_df kpt = self._scf.kpt def ao2mofn(mo_coeff): nao, nmo = mo_coeff.shape mo_a = mo_coeff[:nao//2] mo_b = mo_coeff[nao//2:] orbspin = getattr(mo_coeff, 'orbspin', None) if orbspin is None: eri = with_df.ao2mo(mo_a, kpt, compact=False) eri += with_df.ao2mo(mo_b, kpt, compact=False) eri1 = with_df.ao2mo((mo_a,mo_a,mo_b,mo_b), kpt, compact=False) eri += eri1 eri += eri1.T eri = eri.reshape([nmo]*4) else: mo = mo_a + mo_b eri = with_df.ao2mo(mo, kpt, compact=False).reshape([nmo]*4) sym_forbid = (orbspin[:,None] != orbspin) eri[sym_forbid,:,:] = 0 eri[:,:,sym_forbid] = 0 return eri with lib.temporary_env(self._scf, exxdiv=None): eris = gcisd.gccsd._make_eris_incore(self, mo_coeff, ao2mofn=ao2mofn) if mo_coeff is self._scf.mo_coeff: eris.mo_energy = self._scf.mo_energy[self.get_frozen_mask()] else: madelung = tools.madelung(self._scf.cell, self._scf.kpt) eris.mo_energy = _adjust_occ(eris.mo_energy, eris.nocc, -madelung) return eris
def ao2mo(self, mo_coeff=None): from pyscf.pbc import tools from pyscf.pbc.cc.ccsd import _adjust_occ ao2mofn = mp.mp2._gen_ao2mofn(self._scf) with lib.temporary_env(self._scf, exxdiv=None): eris = ucisd.uccsd._make_eris_incore(self, mo_coeff, ao2mofn=ao2mofn) if mo_coeff is self._scf.mo_coeff: idxa, idxb = self.get_frozen_mask() mo_e_a, mo_e_b = self._scf.mo_energy eris.mo_energy = (mo_e_a[idxa], mo_e_b[idxb]) else: nocca, noccb = eris.nocc madelung = tools.madelung(self._scf.cell, self._scf.kpt) eris.mo_energy = (_adjust_occ(eris.mo_energy[0], nocca, -madelung), _adjust_occ(eris.mo_energy[1], noccb, -madelung)) return eris
def ao2mo(self, mo_coeff=None): from pyscf.cc import rccsd from pyscf.pbc import tools from pyscf.pbc.cc.ccsd import _adjust_occ ao2mofn = mp.mp2._gen_ao2mofn(self._scf) with lib.temporary_env(self._scf, exxdiv=None): eris = rccsd._make_eris_incore(self, mo_coeff, ao2mofn=ao2mofn) if mo_coeff is self._scf.mo_coeff: eris.mo_energy = self._scf.mo_energy[self.get_frozen_mask()] else: madelung = tools.madelung(self._scf.cell, self._scf.kpt) eris.mo_energy = _adjust_occ(eris.mo_energy, eris.nocc, -madelung) return eris
def ao2mo(self, mo_coeff=None): from pyscf.pbc import tools from pyscf.pbc.cc.ccsd import _adjust_occ with_df = self._scf.with_df kpt = self._scf.kpt def ao2mofn(mo_coeff): nao, nmo = mo_coeff.shape mo_a = mo_coeff[:nao // 2] mo_b = mo_coeff[nao // 2:] orbspin = getattr(mo_coeff, 'orbspin', None) if orbspin is None: eri = with_df.ao2mo(mo_a, kpt, compact=False) eri += with_df.ao2mo(mo_b, kpt, compact=False) eri1 = with_df.ao2mo((mo_a, mo_a, mo_b, mo_b), kpt, compact=False) eri += eri1 eri += eri1.T eri = eri.reshape([nmo] * 4) else: mo = mo_a + mo_b eri = with_df.ao2mo(mo, kpt, compact=False).reshape([nmo] * 4) sym_forbid = (orbspin[:, None] != orbspin) eri[sym_forbid, :, :] = 0 eri[:, :, sym_forbid] = 0 return eri with lib.temporary_env(self._scf, exxdiv=None): eris = gcisd.gccsd._make_eris_incore(self, mo_coeff, ao2mofn=ao2mofn) if mo_coeff is self._scf.mo_coeff: eris.mo_energy = self._scf.mo_energy[self.get_frozen_mask()] else: madelung = tools.madelung(self._scf.cell, self._scf.kpt) eris.mo_energy = _adjust_occ(eris.mo_energy, eris.nocc, -madelung) return eris
def __init__(self, cis, mo_coeff=None, method="incore"): log = logger.Logger(cis.stdout, cis.verbose) cput0 = (time.clock(), time.time()) moidx = get_frozen_mask(cis) cell = cis._scf.cell nocc = cis.nocc nmo = cis.nmo nvir = nmo - nocc nkpts = cis.nkpts kpts = cis.kpts if mo_coeff is None: mo_coeff = cis.mo_coeff dtype = mo_coeff[0].dtype mo_coeff = self.mo_coeff = padded_mo_coeff(cis, mo_coeff) # Re-make our fock MO matrix elements from density and fock AO dm = cis._scf.make_rdm1(cis.mo_coeff, cis.mo_occ) exxdiv = cis._scf.exxdiv if cis.keep_exxdiv else None with lib.temporary_env(cis._scf, exxdiv=exxdiv): # _scf.exxdiv affects eris.fock. HF exchange correction should be # excluded from the Fock matrix. fockao = cis._scf.get_hcore() + cis._scf.get_veff(cell, dm) self.fock = np.asarray([ reduce(np.dot, (mo.T.conj(), fockao[k], mo)) for k, mo in enumerate(mo_coeff) ]) self.mo_energy = [self.fock[k].diagonal().real for k in range(nkpts)] if not cis.keep_exxdiv: # Add HFX correction in the self.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) self.mo_energy = [ _adjust_occ(mo_e, nocc, -madelung) for k, mo_e in enumerate(self.mo_energy) ] # Get location of padded elements in occupied and virtual space. nocc_per_kpt = get_nocc(cis, per_kpoint=True) nonzero_padding = padding_k_idx(cis, kind="joint") # Check direct and indirect gaps for possible issues with CCSD convergence. mo_e = [self.mo_energy[kp][nonzero_padding[kp]] for kp in range(nkpts)] mo_e = np.sort([y for x in mo_e for y in x]) # Sort de-nested array gap = mo_e[np.sum(nocc_per_kpt)] - mo_e[np.sum(nocc_per_kpt) - 1] if gap < 1e-5: logger.warn( cis, "H**O-LUMO gap %s too small for KCCSD. " "May cause issues in convergence.", gap, ) memory_needed = (nkpts**3 * nocc**2 * nvir**2) * 16 / 1e6 # CIS only needs two terms: <aj|ib> and <aj|bi>; another factor of two for safety memory_needed *= 4 memory_now = lib.current_memory()[0] fao2mo = cis._scf.with_df.ao2mo kconserv = cis.khelper.kconserv khelper = cis.khelper if cis.direct and type(cis._scf.with_df) is not df.GDF: raise ValueError("CIS direct method must be used with GDF") if (cis.direct and type(cis._scf.with_df) is df.GDF and cell.dimension != 2): # cis._scf.with_df needs to be df.GDF only (not MDF) _init_cis_df_eris(cis, self) else: if (method == "incore" and (memory_needed + memory_now < cis.max_memory) or cell.incore_anyway): log.info("using incore ERI storage") self.ovov = np.empty( (nkpts, nkpts, nkpts, nocc, nvir, nocc, nvir), dtype=dtype) self.voov = np.empty( (nkpts, nkpts, nkpts, nvir, nocc, nocc, nvir), dtype=dtype) for (ikp, ikq, ikr) in khelper.symm_map.keys(): 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) for (kp, kq, kr) in khelper.symm_map[(ikp, ikq, ikr)]: eri_kpt_symm = khelper.transform_symm( eri_kpt, kp, kq, kr).transpose(0, 2, 1, 3) self.ovov[kp, kr, kq] = ( eri_kpt_symm[:nocc, nocc:, :nocc, nocc:] / nkpts) self.voov[kp, kr, kq] = ( eri_kpt_symm[nocc:, :nocc, :nocc, nocc:] / nkpts) self.dtype = dtype else: log.info("using HDF5 ERI storage") self.feri1 = lib.H5TmpFile() self.ovov = self.feri1.create_dataset( "ovov", (nkpts, nkpts, nkpts, nocc, nvir, nocc, nvir), dtype.char) self.voov = self.feri1.create_dataset( "voov", (nkpts, nkpts, nkpts, nvir, nocc, nocc, nvir), dtype.char) # <ia|pq> = (ip|aq) cput1 = time.clock(), time.time() for kp in range(nkpts): for kq in range(nkpts): for kr in range(nkpts): ks = kconserv[kp, kq, kr] orbo_p = mo_coeff[kp][:, :nocc] orbv_r = mo_coeff[kr][:, nocc:] buf_kpt = fao2mo( (orbo_p, mo_coeff[kq], orbv_r, mo_coeff[ks]), (kpts[kp], kpts[kq], kpts[kr], kpts[ks]), compact=False, ) if mo_coeff[0].dtype == np.float: buf_kpt = buf_kpt.real buf_kpt = buf_kpt.reshape(nocc, nmo, nvir, nmo).transpose( 0, 2, 1, 3) self.dtype = buf_kpt.dtype self.ovov[kp, kr, kq, :, :, :, :] = ( buf_kpt[:, :, :nocc, nocc:] / nkpts) self.voov[kr, kp, ks, :, :, :, :] = ( buf_kpt[:, :, nocc:, :nocc].transpose( 1, 0, 3, 2) / nkpts) cput1 = log.timer_debug1("transforming ovpq", *cput1) log.timer("CIS integral transformation", *cput0)
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 __init__(self, cc, mo_coeff=None, method='incore'): from pyscf.pbc import df 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()) moidx = get_frozen_mask(cc) cell = cc._scf.cell kpts = cc.kpts nkpts = cc.nkpts nocc = cc.nocc nmo = cc.nmo nvir = nmo - nocc # if any(nocc != np.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 dtype = mo_coeff[0].dtype mo_coeff = self.mo_coeff = padded_mo_coeff(cc, mo_coeff) # 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) self.fock = np.asarray([reduce(np.dot, (mo.T.conj(), fockao[k], mo)) for k, mo in enumerate(mo_coeff)]) self.mo_energy = [self.fock[k].diagonal().real for k in range(nkpts)] # Add HFX correction in the self.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) self.mo_energy = [_adjust_occ(mo_e, nocc, -madelung) for k, mo_e in enumerate(self.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 = [self.mo_energy[kp][nonzero_padding[kp]] for kp in range(nkpts)] mo_e = np.sort([y for x in mo_e for y in x]) # Sort de-nested array gap = mo_e[np.sum(nocc_per_kpt)] - mo_e[np.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) mem_incore, mem_outcore, mem_basic = _mem_usage(nkpts, nocc, nvir) mem_now = lib.current_memory()[0] fao2mo = cc._scf.with_df.ao2mo kconserv = cc.khelper.kconserv khelper = cc.khelper orbo = np.asarray(mo_coeff[:,:,:nocc], order='C') orbv = np.asarray(mo_coeff[:,:,nocc:], order='C') if (method == 'incore' and (mem_incore + mem_now < cc.max_memory) or cell.incore_anyway): log.info('using incore ERI storage') self.oooo = np.empty((nkpts,nkpts,nkpts,nocc,nocc,nocc,nocc), dtype=dtype) self.ooov = np.empty((nkpts,nkpts,nkpts,nocc,nocc,nocc,nvir), dtype=dtype) self.oovv = np.empty((nkpts,nkpts,nkpts,nocc,nocc,nvir,nvir), dtype=dtype) self.ovov = np.empty((nkpts,nkpts,nkpts,nocc,nvir,nocc,nvir), dtype=dtype) self.voov = np.empty((nkpts,nkpts,nkpts,nvir,nocc,nocc,nvir), dtype=dtype) self.vovv = np.empty((nkpts,nkpts,nkpts,nvir,nocc,nvir,nvir), dtype=dtype) #self.vvvv = np.empty((nkpts,nkpts,nkpts,nvir,nvir,nvir,nvir), dtype=dtype) self.vvvv = cc._scf.with_df.ao2mo_7d(orbv, factor=1./nkpts).transpose(0,2,1,3,5,4,6) for (ikp,ikq,ikr) in khelper.symm_map.keys(): 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) for (kp, kq, kr) in khelper.symm_map[(ikp, ikq, ikr)]: eri_kpt_symm = khelper.transform_symm(eri_kpt, kp, kq, kr).transpose(0, 2, 1, 3) self.oooo[kp, kr, kq] = eri_kpt_symm[:nocc, :nocc, :nocc, :nocc] / nkpts self.ooov[kp, kr, kq] = eri_kpt_symm[:nocc, :nocc, :nocc, nocc:] / nkpts self.oovv[kp, kr, kq] = eri_kpt_symm[:nocc, :nocc, nocc:, nocc:] / nkpts self.ovov[kp, kr, kq] = eri_kpt_symm[:nocc, nocc:, :nocc, nocc:] / nkpts self.voov[kp, kr, kq] = eri_kpt_symm[nocc:, :nocc, :nocc, nocc:] / nkpts self.vovv[kp, kr, kq] = eri_kpt_symm[nocc:, :nocc, nocc:, nocc:] / nkpts #self.vvvv[kp, kr, kq] = eri_kpt_symm[nocc:, nocc:, nocc:, nocc:] / nkpts self.dtype = dtype else: log.info('using HDF5 ERI storage') self.feri1 = lib.H5TmpFile() self.oooo = self.feri1.create_dataset('oooo', (nkpts, nkpts, nkpts, nocc, nocc, nocc, nocc), dtype.char) self.ooov = self.feri1.create_dataset('ooov', (nkpts, nkpts, nkpts, nocc, nocc, nocc, nvir), dtype.char) self.oovv = self.feri1.create_dataset('oovv', (nkpts, nkpts, nkpts, nocc, nocc, nvir, nvir), dtype.char) self.ovov = self.feri1.create_dataset('ovov', (nkpts, nkpts, nkpts, nocc, nvir, nocc, nvir), dtype.char) self.voov = self.feri1.create_dataset('voov', (nkpts, nkpts, nkpts, nvir, nocc, nocc, nvir), dtype.char) self.vovv = self.feri1.create_dataset('vovv', (nkpts, nkpts, nkpts, nvir, nocc, nvir, nvir), dtype.char) vvvv_required = ((not cc.direct) # cc._scf.with_df needs to be df.GDF only (not MDF) or type(cc._scf.with_df) is not df.GDF # direct-vvvv for pbc-2D is not supported so far or cell.dimension == 2) if vvvv_required: self.vvvv = self.feri1.create_dataset('vvvv', (nkpts,nkpts,nkpts,nvir,nvir,nvir,nvir), dtype.char) # <ij|pq> = (ip|jq) cput1 = time.clock(), time.time() for kp in range(nkpts): for kq in range(nkpts): for kr in range(nkpts): ks = kconserv[kp, kq, kr] orbo_p = mo_coeff[kp][:, :nocc] orbo_r = mo_coeff[kr][:, :nocc] buf_kpt = fao2mo((orbo_p, mo_coeff[kq], orbo_r, mo_coeff[ks]), (kpts[kp], kpts[kq], kpts[kr], kpts[ks]), compact=False) if mo_coeff[0].dtype == np.float: buf_kpt = buf_kpt.real buf_kpt = buf_kpt.reshape(nocc, nmo, nocc, nmo).transpose(0, 2, 1, 3) self.dtype = buf_kpt.dtype self.oooo[kp, kr, kq, :, :, :, :] = buf_kpt[:, :, :nocc, :nocc] / nkpts self.ooov[kp, kr, kq, :, :, :, :] = buf_kpt[:, :, :nocc, nocc:] / nkpts self.oovv[kp, kr, kq, :, :, :, :] = buf_kpt[:, :, nocc:, nocc:] / nkpts cput1 = log.timer_debug1('transforming oopq', *cput1) # <ia|pq> = (ip|aq) cput1 = time.clock(), time.time() for kp in range(nkpts): for kq in range(nkpts): for kr in range(nkpts): ks = kconserv[kp, kq, kr] orbo_p = mo_coeff[kp][:, :nocc] orbv_r = mo_coeff[kr][:, nocc:] buf_kpt = fao2mo((orbo_p, mo_coeff[kq], orbv_r, mo_coeff[ks]), (kpts[kp], kpts[kq], kpts[kr], kpts[ks]), compact=False) if mo_coeff[0].dtype == np.float: buf_kpt = buf_kpt.real buf_kpt = buf_kpt.reshape(nocc, nmo, nvir, nmo).transpose(0, 2, 1, 3) self.ovov[kp, kr, kq, :, :, :, :] = buf_kpt[:, :, :nocc, nocc:] / nkpts # TODO: compute vovv on the fly self.vovv[kr, kp, ks, :, :, :, :] = buf_kpt[:, :, nocc:, nocc:].transpose(1, 0, 3, 2) / nkpts self.voov[kr, kp, ks, :, :, :, :] = buf_kpt[:, :, nocc:, :nocc].transpose(1, 0, 3, 2) / nkpts cput1 = log.timer_debug1('transforming ovpq', *cput1) ## Without k-point symmetry # cput1 = time.clock(), time.time() # for kp in range(nkpts): # for kq in range(nkpts): # for kr in range(nkpts): # ks = kconserv[kp,kq,kr] # orbv_p = mo_coeff[kp][:,nocc:] # orbv_q = mo_coeff[kq][:,nocc:] # orbv_r = mo_coeff[kr][:,nocc:] # orbv_s = mo_coeff[ks][:,nocc:] # for a in range(nvir): # orbva_p = orbv_p[:,a].reshape(-1,1) # buf_kpt = fao2mo((orbva_p,orbv_q,orbv_r,orbv_s), # (kpts[kp],kpts[kq],kpts[kr],kpts[ks]), compact=False) # if mo_coeff[0].dtype == np.float: buf_kpt = buf_kpt.real # buf_kpt = buf_kpt.reshape((1,nvir,nvir,nvir)).transpose(0,2,1,3) # self.vvvv[kp,kr,kq,a,:,:,:] = buf_kpt[:] / nkpts # cput1 = log.timer_debug1('transforming vvvv', *cput1) cput1 = time.clock(), time.time() mem_now = lib.current_memory()[0] if not vvvv_required: _init_df_eris(cc, self) elif nvir ** 4 * 16 / 1e6 + mem_now < cc.max_memory: for (ikp, ikq, ikr) in khelper.symm_map.keys(): iks = kconserv[ikp, ikq, ikr] orbv_p = mo_coeff[ikp][:, nocc:] orbv_q = mo_coeff[ikq][:, nocc:] orbv_r = mo_coeff[ikr][:, nocc:] orbv_s = mo_coeff[iks][:, nocc:] # unit cell is small enough to handle vvvv in-core buf_kpt = fao2mo((orbv_p,orbv_q,orbv_r,orbv_s), kpts[[ikp,ikq,ikr,iks]], compact=False) if dtype == np.float: buf_kpt = buf_kpt.real buf_kpt = buf_kpt.reshape((nvir, nvir, nvir, nvir)) for (kp, kq, kr) in khelper.symm_map[(ikp, ikq, ikr)]: buf_kpt_symm = khelper.transform_symm(buf_kpt, kp, kq, kr).transpose(0, 2, 1, 3) self.vvvv[kp, kr, kq] = buf_kpt_symm / nkpts else: raise MemoryError('Minimal memory requirements %s MB' % (mem_now + nvir ** 4 / 1e6 * 16 * 2)) for (ikp, ikq, ikr) in khelper.symm_map.keys(): for a in range(nvir): orbva_p = orbv_p[:, a].reshape(-1, 1) buf_kpt = fao2mo((orbva_p, orbv_q, orbv_r, orbv_s), (kpts[ikp], kpts[ikq], kpts[ikr], kpts[iks]), compact=False) if mo_coeff[0].dtype == np.float: buf_kpt = buf_kpt.real buf_kpt = buf_kpt.reshape((1, nvir, nvir, nvir)).transpose(0, 2, 1, 3) self.vvvv[ikp, ikr, ikq, a, :, :, :] = buf_kpt[0, :, :, :] / nkpts # Store symmetric permutations self.vvvv[ikr, ikp, iks, :, a, :, :] = buf_kpt.transpose(1, 0, 3, 2)[:, 0, :, :] / nkpts self.vvvv[ikq, iks, ikp, :, :, a, :] = buf_kpt.transpose(2, 3, 0, 1).conj()[:, :, 0, :] / nkpts self.vvvv[iks, ikq, ikr, :, :, :, a] = buf_kpt.transpose(3, 2, 1, 0).conj()[:, :, :, 0] / nkpts cput1 = log.timer_debug1('transforming vvvv', *cput1) log.timer('CCSD integral transformation', *cput0)
def __init__(self, cc, mo_coeff=None, method='incore'): if method != 'incore': raise NotImplementedError from pyscf.pbc import df 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()) cell = cc._scf.cell kpts = cc.kpts nkpts = cc.nkpts nocc = cc.nocc nmo = cc.nmo nvir = nmo - nocc if mo_coeff is None: mo_coeff = np.asarray(cc.mo_coeff) dtype = mo_coeff[0].dtype self.mo_coeff = mo_coeff dm = cc._scf.make_rdm1(cc.mo_coeff, cc.mo_occ) with lib.temporary_env(cc._scf, exxdiv=None): fockao = cc._scf.get_hcore() + cc._scf.get_veff(cell, dm) self.fock = np.asarray([ reduce(np.dot, (mo.T.conj(), fockao[k], mo)) for k, mo in enumerate(mo_coeff) ]) self.mo_energy = [self.fock[k].diagonal().real for k in range(nkpts)] madelung = tools.madelung(cell, kpts) self.mo_energy = np.asarray([ _adjust_occ(mo_e, nocc, -madelung) for k, mo_e in enumerate(self.mo_energy) ]) fao2mo = cc._scf.with_df.ao2mo kconserv = cc.khelper.kconserv khelper = cc.khelper orbv = np.asarray(mo_coeff[:, :, nocc:], order='C') log.info('using incore ERI storage') oooo = np.empty((nkpts, nkpts, nkpts, nocc, nocc, nocc, nocc), dtype=dtype) ooov = np.empty((nkpts, nkpts, nkpts, nocc, nocc, nocc, nvir), dtype=dtype) oovv = np.empty((nkpts, nkpts, nkpts, nocc, nocc, nvir, nvir), dtype=dtype) ovov = np.empty((nkpts, nkpts, nkpts, nocc, nvir, nocc, nvir), dtype=dtype) voov = np.empty((nkpts, nkpts, nkpts, nvir, nocc, nocc, nvir), dtype=dtype) vovv = np.empty((nkpts, nkpts, nkpts, nvir, nocc, nvir, nvir), dtype=dtype) vvvv = cc._scf.with_df.ao2mo_7d(orbv, factor=1. / nkpts).transpose( 0, 2, 1, 3, 5, 4, 6) for (ikp, ikq, ikr) in khelper.symm_map.keys(): 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) for (kp, kq, kr) in khelper.symm_map[(ikp, ikq, ikr)]: eri_kpt_symm = khelper.transform_symm(eri_kpt, kp, kq, kr).transpose( 0, 2, 1, 3) oooo[kp, kr, kq] = eri_kpt_symm[:nocc, :nocc, :nocc, :nocc] / nkpts ooov[kp, kr, kq] = eri_kpt_symm[:nocc, :nocc, :nocc, nocc:] / nkpts oovv[kp, kr, kq] = eri_kpt_symm[:nocc, :nocc, nocc:, nocc:] / nkpts ovov[kp, kr, kq] = eri_kpt_symm[:nocc, nocc:, :nocc, nocc:] / nkpts voov[kp, kr, kq] = eri_kpt_symm[nocc:, :nocc, :nocc, nocc:] / nkpts vovv[kp, kr, kq] = eri_kpt_symm[nocc:, :nocc, nocc:, nocc:] / nkpts self.dtype = dtype log.timer('CCSD integral transformation', *cput0) foo = self.fock[:, :nocc, :nocc] fov = self.fock[:, :nocc, nocc:] fvv = self.fock[:, nocc:, nocc:] dijab = np.zeros([nkpts, nkpts, nkpts, nocc, nocc, nvir, nvir]) eia = self.mo_energy[:, :nocc].reshape( nkpts, 1, nocc, 1) - self.mo_energy[:, nocc:].reshape( 1, nkpts, 1, nvir) dia = 1.0 / eia[np.diag_indices(nkpts)] for ki, kj, ka in itertools.product(range(nkpts), repeat=3): kb = kconserv[ki, ka, kj] dijab[ki, kj, ka] = 1.0 / (eia[ki, ka].reshape(nocc, 1, nvir, 1) + eia[kj, kb].reshape(1, nocc, 1, nvir)) self.kconserv = kconserv self.nkpts, self.nocc, self.nvir = nkpts, nocc, nvir self.fock = trans_21(self.fock) self.foo = trans_21(foo) self.fov = trans_21(fov) self.fvv = trans_21(fvv) self.mo_e_o = self.mo_energy[:, :nocc].reshape(-1) self.mo_e_v = self.mo_energy[:, nocc:].reshape(-1) self.oooo = trans_41_eri(oooo, kconserv) self.ooov = trans_41_eri(ooov, kconserv) self.ovov = trans_41_eri(oovv, kconserv) self.oovv = trans_41_eri(ovov, kconserv) self.voov = trans_41_eri(voov, kconserv) self.vvov = trans_41_eri(vovv, kconserv) self.vvvv = trans_41_eri(vvvv, kconserv) self.eia = trans_21(dia) self.eijab = trans_41_amp(dijab, kconserv)
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 __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 __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)