Пример #1
0
 def test_madelung(self):
     cell = pbcgto.Cell()
     cell.atom = 'He 0 0 0'
     cell.a = '''0.      1.7834  1.7834
                 1.7834  0.      1.7834
                 1.7834  1.7834  0.    '''
     cell.build()
     scell = tools.super_cell(cell, [2,3,5])
     mad0 = tools.madelung(scell, [0,0,0])
     kpts = cell.make_kpts([2,3,5])
     mad1 = tools.madelung(cell, kpts)
     self.assertAlmostEqual(mad0-mad1, 0, 9)
Пример #2
0
    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
Пример #3
0
    def ao2mo(self, mo_coeff=None):
        from pyscf.pbc import tools
        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

        # _scf.exxdiv affects eris.fock. HF exchange correction should be
        # excluded from the Fock matrix.
        with lib.temporary_env(self._scf, exxdiv=None):
            eris = 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
Пример #4
0
    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
Пример #5
0
    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
Пример #6
0
    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
Пример #7
0
    def ao2mo(self, mo_coeff=None):
        from pyscf.pbc import tools
        ao2mofn = mp.mp2._gen_ao2mofn(self._scf)
        # _scf.exxdiv affects eris.fock. HF exchange correction should be
        # excluded from the Fock matrix.
        with lib.temporary_env(self._scf, exxdiv=None):
            eris = 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
Пример #8
0
    def ao2mo(self, mo_coeff=None):
        from pyscf.pbc import tools
        ao2mofn = mp.mp2._gen_ao2mofn(self._scf)
        # _scf.exxdiv affects eris.fock. HF exchange correction should be
        # excluded from the Fock matrix.
        with lib.temporary_env(self._scf, exxdiv=None):
            eris = 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
Пример #9
0
    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
Пример #10
0
    def ao2mo(self, mo_coeff=None):
        from pyscf.pbc import tools
        ao2mofn = mp.mp2._gen_ao2mofn(self._scf)
        # _scf.exxdiv affects eris.fock. HF exchange correction should be
        # excluded from the Fock matrix.
        with lib.temporary_env(self._scf, exxdiv=None):
            eris = rccsd._make_eris_incore(self, mo_coeff, ao2mofn=ao2mofn)

        # eris.mo_energy so far is just the diagonal part of the Fock matrix
        # without the exxdiv treatment. Here to add the exchange correction to
        # get better orbital energies. It is important for the low-dimension
        # systems since their occupied and the virtual orbital energies may
        # overlap which may lead to numerical issue in the CCSD iterations.
        if mo_coeff is self._scf.mo_coeff:
            eris.mo_energy = self._scf.mo_energy[self.get_frozen_mask()]
        else:
            # Add the HFX correction of Ewald probe charge method.
            # 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(self._scf.cell, self._scf.kpt)
            eris.mo_energy = _adjust_occ(eris.mo_energy, eris.nocc, -madelung)
        return eris
Пример #11
0
    def ao2mo(self, mo_coeff=None):
        from pyscf.pbc import tools
        ao2mofn = mp.mp2._gen_ao2mofn(self._scf)
        # _scf.exxdiv affects eris.fock. HF exchange correction should be
        # excluded from the Fock matrix.
        with lib.temporary_env(self._scf, exxdiv=None):
            eris = rccsd._make_eris_incore(self, mo_coeff, ao2mofn=ao2mofn)

        # eris.mo_energy so far is just the diagonal part of the Fock matrix
        # without the exxdiv treatment. Here to add the exchange correction to
        # get better orbital energies. It is important for the low-dimension
        # systems since their occupied and the virtual orbital energies may
        # overlap which may lead to numerical issue in the CCSD iterations.
        #if mo_coeff is self._scf.mo_coeff:
        #    eris.mo_energy = self._scf.mo_energy[self.get_frozen_mask()]
        #else:
        #    # Add the HFX correction of Ewald probe charge method.
        #    # 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(self._scf.cell, self._scf.kpt)
        eris.mo_energy = _adjust_occ(eris.mo_energy, eris.nocc, -madelung)
        return eris
Пример #12
0
    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)
Пример #13
0
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
Пример #14
0
    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)
Пример #15
0
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
Пример #16
0
    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)