Esempio n. 1
0
def energy_mp2_aux(mo, se, both_sides=False):
    ''' Calculates the two-body contribution to the electronic energy
        using the MOs and the auxiliary representation of the
        self-energy according the the MP2 form of the Galitskii-Migdal
        formula.

    Parameters
    ----------
    mo : (n) ndarray
        MO energies
    se : Aux
        auxiliary representation of self-energy
    both_sides : bool, optional
        if True, calculate both halves of the functional and return
        the mean, default False

    Returns
    -------
    e2b : float
        two-body contribution to electronic energy
    '''

    if isinstance(se, (tuple, list)):
        n = len(se)
        if util.iter_depth(mo) == 2:
            return sum([
                energy_mp2_aux(mo[i], se[i], both_sides=both_sides)
                for i in range(n)
            ]) / n
        else:
            return sum([
                energy_mp2_aux(mo, se[i], both_sides=both_sides)
                for i in range(n)
            ]) / n

    nphys = se.nphys

    occ = mo < se.chempot
    vir = mo >= se.chempot

    vxk = se.v_vir[occ]
    dxk = 1.0 / util.outer_sum([mo[occ], -se.e_vir])

    e2b = util.einsum('xk,xk,xk->', vxk, vxk.conj(), dxk)

    if both_sides:
        vxk = se.v_occ[vir]
        dxk = -1.0 / util.outer_sum([mo[vir], -se.e_occ])

        e2b += util.einsum('xk,xk,xk->', vxk, vxk.conj(), dxk)
        e2b *= 0.5

    return np.ravel(e2b.real)[0]
Esempio n. 2
0
 def test_2d_uu(self):
     m = np.random.random((2, 5, 5))
     c1 = np.random.random((2, 5, 10))
     c2 = np.random.random((2, 5, 10))
     t1 = util.ao2mo(m, c1, c2)
     t2 = util.einsum('spq,spi,sqj->sij', m, c1, c2)
     self.assertAlmostEqual(np.max(np.absolute(t1 - t2)), 0, 8)
Esempio n. 3
0
 def test_2d_rr(self):
     m = np.random.random((5, 5))
     c1 = np.random.random((5, 10))
     c2 = np.random.random((5, 10))
     t1 = util.ao2mo(m, c1, c2)
     t2 = util.einsum('pq,pi,qj->ij', m, c1, c2)
     self.assertAlmostEqual(np.max(np.absolute(t1 - t2)), 0, 8)
Esempio n. 4
0
    def build_se(self):
        if self.rpa is None:
            self.solve_casida()

        e_rpa, v_rpa, xpy = self.rpa
        naux_gf = self.gf.naux
        chempot = self.chempot

        c = self.gf.v[:self.nphys]
        co = c[:, self.gf.e < chempot]
        cv = c[:, self.gf.e >= chempot]
        xyia = util.mo2qo(self.eri, c, co, cv).reshape(self.nphys, naux_gf, -1)

        omega = util.einsum('xyk,ks->xys', xyia, xpy)
        e_gf = self.gf.e

        e_rpa_s = np.outer(np.sign(e_gf - chempot), e_rpa)
        e = util.dirsum('i,ij->ij', e_gf, e_rpa_s).flatten()
        v = omega.reshape((self.nphys, -1))

        self.se = aux.Aux(e, v, chempot=self.chempot)

        log.write('naux (se,build) = %d\n' % self.se.naux, self.verbose)

        return self.se
Esempio n. 5
0
 def test_mo2qo(self):
     m = np.random.random((5, 5, 5, 5))
     c1 = np.random.random((5, 10))
     c2 = np.random.random((5, 10))
     c3 = np.random.random((5, 10))
     t1 = util.mo2qo(m, c1, c2, c3)
     t2 = util.einsum('pqrs,qi,rj,sk->pijk', m, c1, c2, c3)
     self.assertAlmostEqual(np.max(np.absolute(t1 - t2)), 0, 8)
Esempio n. 6
0
 def test_4d_rr(self):
     m = np.random.random((5, 5, 5, 5))
     c1 = np.random.random((5, 10))
     c2 = np.random.random((5, 10))
     c3 = np.random.random((5, 10))
     c4 = np.random.random((5, 10))
     t1 = util.ao2mo(m, c1, c2, c3, c4)
     t2 = util.einsum('pqrs,pi,qj,rk,sl->ijkl', m, c1, c2, c3, c4)
     self.assertAlmostEqual(np.max(np.absolute(t1 - t2)), 0, 8)
Esempio n. 7
0
 def test_4d_uu(self):
     m = np.random.random((2, 2, 5, 5, 5, 5))
     c1 = np.random.random((2, 5, 10))
     c2 = np.random.random((2, 5, 10))
     c3 = np.random.random((2, 5, 10))
     c4 = np.random.random((2, 5, 10))
     t1 = util.ao2mo(m, c1, c2, c3, c4)
     t2 = util.einsum('abpqrs,api,aqj,brk,bsl->abijkl', m, c1, c2, c3, c4)
     self.assertAlmostEqual(np.max(np.absolute(t1 - t2)), 0, 8)
Esempio n. 8
0
def block_lanczos_1block(se, h_phys, **kwargs):
    ''' The above function simplifies significantly in the case of nmom=1.
    '''
    qr = _get_qr_function(method=kwargs.get('qr', 'cholesky'))
    v, b = qr(se.v.T)
    m = util.einsum('ip,i,iq->pq', v, se.e, v)
    return [h_phys, m], [
        b,
    ]
Esempio n. 9
0
def function(x, fit):
    ''' Computes the target function.

    Parameters
    ----------
    x : (n) ndarray
        vector of fitting variables
    fit : FitHelper
        helper class

    Returns
    -------
    f : float
        sum of f(x)
    '''

    e, v, sf, dsf = fit.generate(x)

    f = util.einsum('w,wxy->', fit.wts, dsf.real**2)
    f += util.einsum('w,wxy->', fit.wts, dsf.imag**2)

    return f
Esempio n. 10
0
 def setUpClass(self):
     import warnings
     warnings.simplefilter('ignore', FutureWarning)
     self.m = mol.Molecule(atoms='O 0 0 0; H 0 0 1',
                           basis='cc-pvdz',
                           spin=1)
     self.uhf = hf.UHF(self.m).run()
     self.uhf_df = hf.UHF(self.m, with_df=True).run()
     self.eri = self.uhf.eri_mo
     self.eri_df = self.uhf_df.eri_mo
     self.se = (aux.build_ump2(self.uhf_df.e,
                               util.einsum('qij,sqkl->sijkl',
                                           self.eri_df[0], self.eri_df),
                               chempot=self.uhf_df.chempot,
                               wtol=0),
                aux.build_ump2(self.uhf_df.e[::-1],
                               util.einsum('qij,sqkl->sijkl',
                                           self.eri_df[1],
                                           self.eri_df[::-1]),
                               chempot=self.uhf.chempot[::-1],
                               wtol=0))
     self.e_mp2 = -0.15197757655845123
     self.e_mp2_scs = -0.1502359064727459
Esempio n. 11
0
    def get_fock(self, rdm1, basis='ao'):
        ''' Builds the Fock matrix according to the UHF functional.
            Input arrays may be spin-free or indexed for alpha and
            beta spins.

        Parameters
        ----------
        rdm1 : (n,n) or (2,n,n) array
            one-body reduced density matrix

        Returns
        -------
        fock : (2,n,n) array
            Fock matrix
        '''

        c = self.c if basis == 'mo' else np.eye(self.nao)

        dm = util.einsum('...ij,...pi,...qj->...pq', rdm1, c, c)
        fock = self._pyscf.get_fock(dm=dm)
        fock = util.einsum('...pq,...pi,...qj->...ij', fock, c, c)

        return fock
Esempio n. 12
0
    def get_fock(self, rdm1, basis='ao'):
        ''' Builds the Fock matrix according to the RHF functional.

        Parameters
        ----------
        rdm1 : (n,n) ndarray
            one-body reduced density matrix
        basis : str, optional
            input basis of `rdm1`, and output basis of `fock`, 
            default 'ao'

        Returns
        -------
        fock : (n,n) array
            Fock matrix
        '''

        c = self.c if basis == 'mo' else np.eye(self.nao)

        dm = util.einsum('ij,pi,qj->pq', rdm1, c, c)
        fock = self._pyscf.get_fock(dm=dm)
        fock = util.einsum('pq,pi,qj->ij', fock, c, c)

        return fock
Esempio n. 13
0
 def setUpClass(self):
     import warnings
     warnings.simplefilter('ignore', FutureWarning)
     self.m = mol.Molecule(atoms='O 0 0 0; H 0 0 1; H 0 1 0',
                           basis='cc-pvdz')
     self.rhf = hf.RHF(self.m).run()
     self.rhf_df = hf.RHF(self.m, with_df=True).run()
     self.eri = self.rhf.eri_mo
     self.eri_df = self.rhf_df.eri_mo
     self.se = aux.build_rmp2(self.rhf_df.e,
                              util.einsum('qij,qkl->ijkl', self.eri_df,
                                          self.eri_df),
                              chempot=self.rhf_df.chempot,
                              wtol=0)
     self.e_mp2 = -0.20905684700662164
     self.e_mp2_scs = -0.20503556854447708
Esempio n. 14
0
def ao2mo_2d(array, c_a, c_b):
    ''' Transforms the basis of a 2d array.

    Parameters
    ----------
    array : (p,q) array
        array to be transformed
    c_a : (p,i) array
        vectors to transform first dimension of `array`
    c_b : (q,j) array
        vectors to transform second dimension of `array`

    Returns
    -------
    trans : (i,j) ndarray
        transformed array
    '''

    trans = einsum('pq,pi,qj->ij', array, c_a, c_b)

    return trans
Esempio n. 15
0
def objective(x, fit):
    ''' Computes the objective function and gradient.

    Parameters
    ----------
    x : (n) ndarray
        vector of fitting variables
    fit : FitHelper
        helper class

    Returns
    -------
    f : float
        sum of f(x)
    dx : (n) ndarray
        vector of the derivative of f(x)
    '''

    e, v, sf, dsf = fit.generate(x)

    r = fit.build_denominator(e, v)

    gv = util.einsum('xk,wk->wxk', v, r)
    ge = util.einsum('wxk,wyk->wxyk', gv, gv)

    f = util.einsum('w,wxy->', fit.wts, dsf.real**2)
    f += util.einsum('w,wxy->', fit.wts, dsf.imag**2)

    de = util.einsum('w,wxy,wxyk->k', fit.wts, dsf.real, ge.real)
    de += util.einsum('w,wxy,wxyk->k', fit.wts, dsf.imag, ge.imag)
    de *= 2

    dv = util.einsum('w,wzx,wxk->zk', fit.wts, dsf.real, gv.real)
    dv += util.einsum('w,wzx,wxk->zk', fit.wts, dsf.imag, ge.imag)
    dv *= 4

    return f, fit.pack(de, dv)
Esempio n. 16
0
    def solve_casida(self):
        #TODO: this step is n^6 and inefficient in memory, rethink

        e_ia = util.outer_sum([-self.gf.e_occ, self.gf.e_vir])

        co = self.gf.v[:self.nphys, self.gf.e < self.chempot]
        cv = self.gf.v[:self.nphys, self.gf.e >= self.chempot]
        iajb = util.ao2mo(self.eri, co, cv, co, cv).reshape((e_ia.size, ) * 2)

        apb = np.diag(e_ia.flatten()) + 4.0 * iajb
        amb = np.diag(np.sqrt(e_ia.flatten()))

        h_rpa = util.dots((amb, apb, amb))
        e_rpa, v_rpa = util.eigh(h_rpa)
        e_rpa = np.sqrt(e_rpa)

        xpy = util.einsum('ij,jk,k->ik', amb, v_rpa, 1.0 / np.sqrt(e_rpa))
        xpy *= np.sqrt(2.0)

        self.rpa = (e_rpa, v_rpa, xpy)

        return self.rpa
Esempio n. 17
0
 def get_emp2(self, e, v, mask, spin):
     fac = 0.5 if np.all(
         self.uhf.e[spin][mask] < self.uhf.chempot[spin]) else -0.5
     return util.einsum(
         'xk,xk->', v[mask]**2,
         fac / (self.uhf.e[spin][mask, None] - e[None, :])).ravel()[0]
Esempio n. 18
0
def build_ump2_part_se_direct(eo,
                              ev,
                              xija,
                              grid,
                              chempot=0.0,
                              ordering='feynman'):
    ''' Builds a set of auxiliaries representing all (i,j,a) or (a,b,i)
        diagrams for an unrestricted reference. Poles are summed straight
        into the self-energy and returns an `ndarray` instead of `Aux`.

    Parameters
    ----------
    eo : (o) ndarray
        occupied (virtual) energies
    ev : (v) ndarray
        virtual (occupied) energies
    xija : (n,o,o,v)
        two-electron integrals indexed as physical, occupied, occupied,
        virtual (physical, virtual, virtual, occupied)
    grid : (k) ImFqGrid, ImFqQuad or ReFqGrid
        grid
    chempot : tuple of float, optional
        chemical potential for alpha, beta (beta, alpha) spin
    ordering : str
        ordering of the poles {'feynman', 'advanced', 'retarded'}
        (default 'feynman')

    Returns
    -------
    se : (k,n,n) ndarray
        frequency-dependent self-energy
    '''

    if not _is_tuple(chempot):
        chempot = (chempot, chempot)

    #TODO write in C

    if grid.axis == 'imag':
        if ordering == 'feynman':
            get_s = lambda x: np.sign(x)
        elif ordering == 'advanced':
            get_s = lambda x: np.ones(x.shape, dtype=types.int64)
        elif ordering == 'retarded':
            get_s = lambda x: -np.ones(x.shape, dtype=types.int64)
    else:
        get_s = lambda x: 0.0

    w = grid.prefac * grid.values

    nphys, nocca, _, nvira = xija[0].shape
    se = np.zeros((grid.shape[0], nphys, nphys), dtype=types.complex128)

    eova = util.outer_sum([eo[0], -ev[0]]).flatten() - chempot[0]
    eovb = util.outer_sum([eo[1], -ev[1]]).flatten() - chempot[0]

    for i in range(nocca):
        ei_a = eo[0][i] + eova
        ei_b = eo[0][i] + eovb

        vi_a = xija[0][:, i].reshape((nphys, -1))
        vip_a = xija[0][:, :, i].reshape((nphys, -1))
        vi_b = xija[1][:, i].reshape((nphys, -1))

        di_a = 1.0 / util.outer_sum([w, -ei_a + get_s(ei_a) * grid.eta * 1.0j])
        di_b = 1.0 / util.outer_sum([w, -ei_b + get_s(ei_b) * grid.eta * 1.0j])

        se += util.einsum('wk,xk,yk->wxy', di_a, vi_a, (vi_a - vip_a).conj())
        se += util.einsum('wk,xk,yk->wxy', di_b, vi_b, (vi_b).conj())

    return se
Esempio n. 19
0
def hessian(x, fit):
    ''' Computes the Hessian of the function.

    Parameters
    ----------
    x : (n) ndarray
        vector of fitting variables
    fit : FitHelper
        helper class

    Returns
    -------
    hx : (n,n) ndarray
        matrix of the Hessian of f(x)
    '''

    e, v, sf, dsf = fit.generate(x)

    r = fit.build_denominator(e, v)

    gv = util.einsum('xk,wk->wxk', v, r)
    ge = util.einsum('wxk,wyk->wxyk', gv, gv)

    gee = util.einsum('wk,wxyk->wxyk', r, ge) * 2
    gev = util.einsum('wk,wxk->wxk', r, gv)
    gvv = r

    hee = util.einsum('w,wxyk,wxyl->kl', fit.wts, ge.real, ge.real)
    hee += util.einsum('w,wxyk,wxyl->kl', fit.wts, ge.imag, ge.imag)
    hee *= 2

    dee = util.einsum('w,wxy,wxyk->k', fit.wts, dsf.real, gee.real)
    dee += util.einsum('w,wxy,wxyk->k', fit.wts, dsf.imag, gee.imag)
    dee *= 2

    diag = util.diagonal(hee)
    diag += dee

    hev = util.einsum('w,wxzk,wxl->kzl', fit.wts, ge.real, gv.real)
    hev += util.einsum('w,wxzk,wxl->kzl', fit.wts, ge.imag, gv.imag)
    hev *= 4

    dev = util.einsum('w,wxz,wxl->zl', fit.wts, dsf.real, gev.real)
    dev += util.einsum('w,wxz,wxl->zl', fit.wts, dsf.imag, gev.imag)
    dev *= 4

    diag = util.diagonal(hev, axis1=0, axis2=2)
    diag += dev

    hev = hev.reshape((fit.naux, fit.ncoup))

    hvv = util.einsum('w,wyk,wxl->xkyl', fit.wts, gv.real, gv.real)
    hvv += util.einsum('w,wyk,wxl->xkyl', fit.wts, gv.imag, gv.imag)
    hvv *= 4

    dvv = util.einsum('w,wxk,wxl->kl', fit.wts, gv.real, gv.real)
    dvv += util.einsum('w,wxk,wxl->kl', fit.wts, gv.imag, gv.imag)
    dvv *= 4

    diag = util.diagonal(hvv, axis1=0, axis2=2)
    diag += dvv[:, :, None]

    dvv = util.einsum('w,wxy,wl->xyl', fit.wts, dsf.real, gvv.real)
    dvv += util.einsum('w,wxy,wl->xyl', fit.wts, dsf.imag, gvv.imag)
    dvv *= 4

    diag = util.diagonal(hvv, axis1=1, axis2=3)
    diag += dvv

    hvv = hvv.reshape((fit.ncoup, fit.ncoup))

    h = np.block([[hee, hev], [hev.T, hvv]])

    return h
Esempio n. 20
0
 def test_as_spectrum(self):
     se = self.se
     f1 = util.einsum('xk,yk,wk->wxy', se.v, se.v, se.build_denominator(self.imfq, se.e, se.v, chempot=se.chempot))
     f2 = se.as_spectrum(self.imfq)
     self.assertAlmostEqual(np.max(np.absolute(f1 - f2)), 0, 8)
Esempio n. 21
0
    def get_1p_or_1h(self):
        occa, occb, vira, virb = self._get_slices()

        self.e_mp2 = 0
        hs = []

        for a, b in [(0, 1), (1, 0)]:
            if a == 0:
                occa, occb, vira, virb = self._get_slices()
            else:
                occb, occa, virb, vira = self._get_slices()

            eri_aa_ovov = self.eri[a, a][occa, vira, occa, vira]
            eri_ab_ovov = self.eri[a, b][occa, vira, occb, virb]

            eo_a = self.hf.e[a][occa]
            eo_b = self.hf.e[b][occb]
            ev_a = self.hf.e[a][vira]
            ev_b = self.hf.e[b][virb]

            t2_aa = eri_aa_ovov.copy()
            t2_aa /= util.dirsum('i,a,j,b->iajb', eo_a, -ev_a, eo_a, -ev_a)
            t2a_aa = t2_aa - t2_aa.swapaxes(0, 2).copy()

            t2_ab = eri_ab_ovov.copy()
            t2_ab /= util.dirsum('i,a,j,b->iajb', eo_a, -ev_a, eo_b, -ev_b)

            self.e_mp2 += util.einsum('iajb,iajb->', t2a_aa, eri_aa_ovov) * 0.5
            self.e_mp2 += util.einsum('iajb,iajb->', t2_ab, eri_ab_ovov) * 0.5

            h = np.diag(eo_a)

            h += util.einsum('a,iakb,jakb->ij', ev_a, t2a_aa, t2a_aa)
            h += util.einsum('a,iakb,jakb->ij', ev_a, t2_ab, t2_ab)
            h += util.einsum('a,ibka,jbka->ij', ev_b, t2_ab, t2_ab)
            h -= util.einsum('k,iakb,jakb->ij', eo_a, t2a_aa, t2a_aa) * 0.5
            h -= util.einsum('k,iakb,jakb->ij', eo_b, t2_ab, t2_ab) * 0.5
            h -= util.einsum('k,iakb,jakb->ij', eo_b, t2_ab, t2_ab) * 0.5
            h -= util.einsum('i,iakb,jakb->ij', eo_a, t2a_aa, t2a_aa) * 0.25
            h -= util.einsum('i,iakb,jakb->ij', eo_a, t2_ab, t2_ab) * 0.25
            h -= util.einsum('i,iakb,jakb->ij', eo_a, t2_ab, t2_ab) * 0.25
            h -= util.einsum('j,iakb,jakb->ij', eo_a, t2a_aa, t2a_aa) * 0.25
            h -= util.einsum('j,iakb,jakb->ij', eo_a, t2_ab, t2_ab) * 0.25
            h -= util.einsum('j,iakb,jakb->ij', eo_a, t2_ab, t2_ab) * 0.25
            h += util.einsum('iakb,jakb->ij', t2a_aa, eri_aa_ovov) * 0.5
            h -= util.einsum('iakb,jbka->ij', t2a_aa, eri_aa_ovov) * 0.5
            h += util.einsum('iakb,jakb->ij', t2_ab, eri_ab_ovov)
            h += util.einsum('jakb,iakb->ij', t2a_aa, eri_aa_ovov) * 0.5
            h -= util.einsum('jakb,kaib->ij', t2a_aa, eri_aa_ovov) * 0.5
            h += util.einsum('jakb,iakb->ij', t2_ab, eri_ab_ovov)

            hs.append(h)

        self.h_1p_or_1h = tuple(hs)
Esempio n. 22
0
 def test_build_derivative(self):
     se = self.se
     df1 = -util.einsum('xk,yk,wk->wxy', se.v, se.v, se.build_denominator(self.imfq, se.e, se.v, chempot=se.chempot)**2)
     df2 = se.build_derivative(self.imfq, se.e, se.v, chempot=se.chempot)
     self.assertAlmostEqual(np.max(np.absolute(df1 - df2)), 0, 8)
Esempio n. 23
0
    def run(self):
        t_amp = np.zeros((self.nvir, self.nvir, self.nocc, self.nocc), dtype=types.float64)

        o = slice(None, self.nocc)
        v = slice(self.nocc, None)

        opdm_corr = np.zeros((self.nso,)*2, dtype=types.float64)
        opdm_ref  = opdm_corr.copy()
        opdm_ref[o,o] = np.eye(self.nocc)
        tpdm_corr = np.zeros((self.nso,)*4, dtype=types.float64)

        x = opdm_corr.copy()

        eija = util.outer_sum([-self.e[v], -self.e[v], self.e[o], self.e[o]])
        eija = 1.0 / eija

        if self.diis:
            diis = util.DIIS(self.diis_space)

        for niter in range(1, self.maxiter+1):
            f = self.h1e_mo + util.einsum('piqi->pq', self.eri_mo[:,o,:,o])
            fp = f.copy()
            np.fill_diagonal(fp, 0.0)
            e = f.diagonal()

            t1 = self.eri_mo[v,v,o,o]
            t2 = util.einsum('ac,cbij->abij', fp[v,v], t_amp)
            t3 = util.einsum('ki,abkj->abij', fp[o,o], t_amp)

            t_amp = t1.copy()
            t_amp += t2 - t2.transpose(1,0,2,3)
            t_amp -= t3 - t3.transpose(0,1,3,2)
            t_amp *= eija

            if niter > 1:
                if self.diis:
                    t_amp = diis.update(t_amp)

                if self.damping > 0.0:
                    damping = self.damping
                    t_amp = (1.0 - damping) * t_amp + damping * self._t_prev

            if self.damping > 0.0:
                self._t_prev = t_amp.copy()

            opdm_corr[v,v] = util.einsum('ijac,bcij->ba', t_amp.T, t_amp) * 0.5
            opdm_corr[o,o] = util.einsum('jkab,abik->ji', t_amp.T, t_amp) * -0.5
            opdm = opdm_corr + opdm_ref

            tpdm_corr[v,v,o,o] = t_amp
            tpdm_corr[o,o,v,v] = t_amp.T
            tpdm2 = util.einsum('rp,sq->rspq', opdm_corr, opdm_ref)
            tpdm3 = util.einsum('rp,sq->rspq', opdm_ref, opdm_ref)
            tpdm = tpdm_corr.copy()
            tpdm += tpdm2 - tpdm2.transpose(1,0,2,3)
            tpdm -= tpdm2.transpose(0,1,3,2) - tpdm2.transpose(1,0,3,2)
            tpdm += tpdm3 - tpdm3.transpose(1,0,2,3)

            fnr  = util.einsum('pr,rq->pq', self.h1e_mo, opdm)
            fnr += util.einsum('prst,stqr->pq', self.eri_mo, tpdm) * 0.5
            x[v,o] = ((fnr - fnr.T)[v,o]) / util.outer_sum([-self.e[v], self.e[o]])

            u = expm(x - x.T)
            c = np.dot(self.c, u)
            self.c = c

            self.h1e_mo = util.ao2mo(self.h1e_ao, c, c)
            self.eri_mo = util.ao2mo(self.eri_ao, c, c, c, c)

            e_prev = self.e_tot
            self.e_1body = util.einsum('pq,qp->', self.h1e_mo, opdm)
            self.e_1body += self.hf.e_nuc
            self.e_2body = 0.25 * util.einsum('pqrs,rspq->', self.eri_mo, tpdm)

            if abs(self.e_tot - e_prev) < self.etol:
                break

        return self
Esempio n. 24
0
def build_rmp2_part_se_direct(eo,
                              ev,
                              xija,
                              grid,
                              chempot=0.0,
                              ordering='feynman'):
    ''' Builds a set of auxiliaries representing all (i,j,a) or (a,b,i)
        diagrams for a restricted reference. Poles are summed straight
        into the self-energy and returns an `ndarray` instead of `Aux`.

    Parameters
    ----------
    eo : (o) ndarray
        occupied (virtual) energies
    ev : (v) ndarray
        virtual (occupied) energies
    xija : (n,o,o,v)
        two-electron integrals indexed as physical, occupied, occupied,
        virtual (physical, virtual, virtual, occupied)
    grid : (k) ImFqGrid, ImFqQuad or ReFqGrid
        grid
    chempot : float, optional
        chemical potential
    ordering : str
        ordering of the poles {'feynman', 'advanced', 'retarded'}
        (default 'feynman')

    Returns
    -------
    se : (k,n,n) ndarray
        frequency-dependent self-energy
    '''

    #TODO write in C

    if grid.axis == 'imag':
        if ordering == 'feynman':
            get_s = lambda x: np.sign(x)
        elif ordering == 'advanced':
            get_s = lambda x: np.ones(x.shape, dtype=types.int64)
        elif ordering == 'retarded':
            get_s = lambda x: -np.ones(x.shape, dtype=types.int64)
    else:
        get_s = lambda x: 0.0

    w = grid.prefac * grid.values

    nphys, nocc, _, nvir = xija.shape
    se = np.zeros((grid.shape[0], nphys, nphys), dtype=types.complex128)

    eov = util.outer_sum([eo, -ev]).flatten()

    for i in range(nocc):
        ei = eo[i] + eov - chempot

        vi = xija[:, i].reshape((nphys, -1))
        vip = xija[:, :, i].reshape((nphys, -1))

        di = 1.0 / util.outer_sum([w, -ei + get_s(ei) * grid.eta * 1.0j])

        se += util.einsum('wk,xk,yk->wxy', di, vi, (2 * vi - vip).conj())

    return se
Esempio n. 25
0
 def test_moment(self):
     se = self.se
     m1 = util.einsum('xk,nk,yk->nxy', se.v, se.e[None,:] ** np.arange(4)[:,None], se.v)
     m2 = se.moment(range(4))
     self.assertAlmostEqual(np.max(np.absolute(m1 - m2)), 0, 8)
Esempio n. 26
0
def build_dfrmp2_part_se_direct(eo,
                                ev,
                                ixq,
                                qja,
                                grid,
                                chempot=0.0,
                                ordering='feynman'):
    ''' Builds a set of auxiliaries representing all (i,j,a) or (a,b,i)
        diagrams for a restricted reference. Poles are summed straight
        into the self-energy and returns an `ndarray` instead of `Aux`.

    Parameters
    ----------
    eo : (o) ndarray
        occupied (virtual) energies
    ev : (v) ndarray
        virtual (occupied) energies
    ixq : (o,n,q) ndarray
        density-fitted two-electron integrals indexed as occupied, 
        physical, auxiliary (physical, virtual, auxiliary)
    qja : (q,o,v) ndarray
        density-fitted two-electron integrals indexed as auxiliary,
        occupied, virtual (auxiliary, virtual, occupied)
    grid : (k) ImFqGrid, ImFqQuad or ReFqGrid
        grid
    chempot : float, optional
        chemical potential
    ordering : str
        ordering of the poles {'feynman', 'advanced', 'retarded'}
        (default 'feynman')

    Returns
    -------
    se : (k,n,n) ndarray
        frequency-dependent self-energy
    '''

    if grid.axis == 'imag':
        if ordering == 'feynman':
            get_s = lambda x: np.sign(x)
        elif ordering == 'advanced':
            get_s = lambda x: np.ones(x.shape, dtype=types.int64)
        elif ordering == 'retarded':
            get_s = lambda x: -np.ones(x.shape, dtype=types.int64)
    else:
        get_s = lambda x: 0.0

    w = grid.prefac * grid.values

    nphys = ixq.shape[1]
    ndf, nocc, nvir = qja.shape
    npoles = nocc * nocc * nvir

    se = np.zeros((grid.shape[0], nphys, nphys), dtype=types.complex128)

    ixq = ixq.reshape((nocc * nphys, ndf))
    qja = qja.reshape((ndf, nocc * nvir))

    eov = util.outer_sum([eo, -ev]).flatten()

    for i in range(nocc):
        ei = eo[i] + eov - chempot

        vi = np.dot(ixq[i * nphys:(i + 1) * nphys].conj(), qja).reshape(
            (nphys, -1))
        vip = np.dot(ixq.conj(), qja[:, i * nvir:(i + 1) * nvir])
        vip = util.reshape_internal(vip, (nocc, nphys, -1), (0, 1),
                                    (nphys, -1))

        di = 1.0 / util.outer_sum([w, -ei + get_s(ei) * grid.eta * 1.0j])

        se += util.einsum('wk,xk,yk->wxy', di, vi, (2 * vi - vip).conj())

    return se
Esempio n. 27
0
    def get_1p_or_1h(self):
        occ, vir = self._get_slices()

        eri_ovov = self.eri[occ, vir, occ, vir]
        eo = self.hf.e[occ]
        ev = self.hf.e[vir]

        t2 = eri_ovov.copy()
        t2 /= util.dirsum('i,a,j,b->iajb', eo, -ev, eo, -ev)
        t2a = t2 - t2.swapaxes(0, 2).copy()

        os = self.options['os_factor']
        ss = self.options['ss_factor']
        self.e_mp2 = util.einsum('iajb,iajb->', t2, eri_ovov) * (os + ss)
        self.e_mp2 -= util.einsum('iajb,ibja->', t2, eri_ovov) * ss

        h = np.diag(eo)

        h += util.einsum('a,iakb,jakb->ij', ev, t2a, t2a)
        h += util.einsum('a,iakb,jakb->ij', ev, t2, t2)
        h += util.einsum('a,ibka,jbka->ij', ev, t2, t2)
        h -= util.einsum('k,iakb,jakb->ij', eo, t2a, t2a) * 0.5
        h -= util.einsum('k,iakb,jakb->ij', eo, t2, t2) * 0.5
        h -= util.einsum('k,iakb,jakb->ij', eo, t2, t2) * 0.5
        h -= util.einsum('i,iakb,jakb->ij', eo, t2a, t2a) * 0.25
        h -= util.einsum('i,iakb,jakb->ij', eo, t2, t2) * 0.25
        h -= util.einsum('i,iakb,jakb->ij', eo, t2, t2) * 0.25
        h -= util.einsum('j,iakb,jakb->ij', eo, t2a, t2a) * 0.25
        h -= util.einsum('j,iakb,jakb->ij', eo, t2, t2) * 0.25
        h -= util.einsum('j,iakb,jakb->ij', eo, t2, t2) * 0.25
        h += util.einsum('iakb,jakb->ij', t2a, eri_ovov) * 0.5
        h -= util.einsum('iakb,jbka->ij', t2a, eri_ovov) * 0.5
        h += util.einsum('iakb,jakb->ij', t2, eri_ovov)
        h += util.einsum('jakb,iakb->ij', t2a, eri_ovov) * 0.5
        h -= util.einsum('jakb,kaib->ij', t2a, eri_ovov) * 0.5
        h += util.einsum('jakb,iakb->ij', t2, eri_ovov)

        self.h_1p_or_1h = h
Esempio n. 28
0
def build_dfump2_part_se_direct(eo, ev, ixq, qja, grid, chempot=0.0, ordering='feynman'):
    ''' Builds a set of auxiliaries representing all (i,j,a) or (a,b,i)
        diagrams for an unrestricted reference. Poles are summed straight
        into the self-energy and returns an `ndarray` instead of `Aux`.

    Parameters
    ----------
    eo : (o) ndarray
        occupied (virtual) energies
    ev : (v) ndarray
        virtual (occupied) energies
    ixq : 1-tuple or 2-tuple of (n,o,o,v)
        density-fitted two-electron integrals index as occupied,
        physical, auxiliary (virtual, physical, auxiliary) for alpha,
        beta (beta, alpha) spin. Only alpha (beta) is required.
    qja : 2-tuple of (n,o,o,v)
        density-fitted two-electron integrals index as auxiliary,
        occupied, virtual (auxiliary, virtual, occupied) for alpha,
        beta (beta, alpha) spin.
    grid : (k) ImFqGrid, ImFqQuad or ReFqGrid
        grid
    chempot : tuple of float, optional
        chemical potential for alpha, beta (beta, alpha) spin
    ordering : str
        ordering of the poles {'feynman', 'advanced', 'retarded'}
        (default 'feynman')

    Returns
    -------
    se : (k,n,n) ndarray
        frequency-dependent self-energy
    '''

    if not _is_tuple(chempot):
        chempot = (chempot, chempot)

    #TODO write in C

    if grid.axis == 'imag':
        if ordering == 'feynman':
            get_s = lambda x : np.sign(x)
        elif ordering == 'advanced':
            get_s = lambda x : np.ones(x.shape, dtype=types.int64)
        elif ordering == 'retarded':
            get_s = lambda x : -np.ones(x.shape, dtype=types.int64)
    else:
        get_s = lambda x : 0.0

    w = grid.prefac * grid.values

    nphys = ixq[0].shape[1]
    ndf, nocca, nvira = qja[0].shape
    _, noccb, nvirb = qja[1].shape

    se = np.zeros((grid.shape[0], nphys, nphys), dtype=types.complex128)

    ixq = (ixq[0].reshape((nocca*nphys, ndf)),)
    qja = (qja[0].reshape((ndf, nocca*nvira)), 
           qja[1].reshape((ndf, noccb*nvirb)))

    eova = util.outer_sum([eo[0], -ev[0]]).flatten() - chempot[0]
    eovb = util.outer_sum([eo[1], -ev[1]]).flatten() - chempot[0]

    for i in range(nocca):
        ei_a = eo[0][i] + eova
        ei_b = eo[0][i] + eovb

        xq_a = ixq[0][i*nphys:(i+1)*nphys]

        vi_a = np.dot(xq_a.conj(), qja[0]).reshape((nphys, -1))
        vi_b = np.dot(xq_a.conj(), qja[1]).reshape((nphys, -1))
        vip_a = np.dot(ixq[0].conj(), qja[0][:,i*nvira:(i+1)*nvira])
        vip_a = util.reshape_internal(vip_a, (nocca, nphys, nvira), (0,1), (nphys, nocca*nvira))

        di_a = 1.0 / util.outer_sum([w, -ei_a + get_s(ei_a) * grid.eta * 1.0j])
        di_b = 1.0 / util.outer_sum([w, -ei_b + get_s(ei_b) * grid.eta * 1.0j])

        se += util.einsum('wk,xk,yk->wxy', di_a, vi_a, (vi_a - vip_a).conj())
        se += util.einsum('wk,xk,yk->wxy', di_b, vi_b, vi_b.conj())

    return se
Esempio n. 29
0
def energy_2body_aux(gf, se, both_sides=False):
    ''' Calculates the two-body contribution to the electronic energy
        using the auxiliary representation of the Green's function and
        self-energy, according to the Galitskii-Migdal formula.

    Parameters
    ----------
    gf : Aux
        auxiliary representation of Green's function
    se : Aux
        auxiliary representation of self-energy
    both_sides : bool, optional
        if True, calculate both halves of the functional and return
        the mean, default False

    Returns
    -------
    e2b : float
        two-body contribution to electronic energy
    '''

    #TODO in C

    if isinstance(se, (tuple, list)):
        n = len(se)
        if isinstance(gf, (tuple, list)):
            return sum([
                energy_2body_aux(gf[i], se[i], both_sides=both_sides)
                for i in range(n)
            ]) / n
        else:
            return sum([
                energy_2body_aux(gf, se[i], both_sides=both_sides)
                for i in range(n)
            ]) / n

    nphys = se.nphys

    e2b = 0.0

    for l in range(gf.nocc):
        vxl = gf.v[:nphys, l]
        vxk = se.v[:, se.nocc:]

        dlk = 1.0 / (gf.e[l] - se.e[se.nocc:])

        e2b += util.einsum('xk,yk,x,y,k->', vxk, vxk.conj(), vxl, vxl.conj(),
                           dlk)

    if both_sides:
        for l in range(gf.nocc, gf.naux):
            vxl = gf.v[:nphys, l]
            vxk = se.v[:, :se.nocc]

            dlk = -1.0 / (gf.e[l] - se.e[:se.nocc])

            e2b += util.einsum('xk,yk,x,y,k->', vxk, vxk.conj(), vxl,
                               vxl.conj(), dlk)
    else:
        e2b *= 2.0

    return np.ravel(e2b.real)[0]
Esempio n. 30
0
 def get_emp2(self, e, v, mask):
     fac = 1 if np.all(self.rhf.e[mask] < self.rhf.chempot) else -1
     return util.einsum('xk,xk->', v[mask]**2, fac /
                        (self.rhf.e[mask, None] - e[None, :])).ravel()[0]