Ejemplo n.º 1
0
    def build_part(gf_occ, gf_vir, eri, sym_in='s2'):
        ''' Builds the truncated occupied (or virtual) self-energy.

        Parameters
        ----------
        gf_occ : Aux
            Occupied (or virtual) Green's function
        gf_vir : Aux
            Virtual (or occupied) Green's function
        eri : ndarray
            Cholesky-decomposed DF ERI tensor
        sym_in : str, optional
            Symmetry of `eri`, default 's2'

        Returns
        -------
        se : Aux
            Occupied (or virtual) truncated self-energy
        '''

        syms = dict(sym_in=sym_in, sym_out='s1')
        nphys = gf_occ.nphys
        nocc = gf_occ.naux
        nvir = gf_vir.naux

        ixq = OptRAGF2.ao2mo(eri, gf_occ.v, np.eye(nphys), **syms).T
        qja = OptRAGF2.ao2mo(eri, gf_occ.v, gf_vir.v, **syms)

        vv = np.zeros((nphys, nphys), dtype=types.float64)
        vev = np.zeros((nphys, nphys), dtype=types.float64)

        if libagf2._libagf2 is not None:
            vv, vev = libagf2.build_part_loop_rhf(ixq,
                                                  qja,
                                                  gf_occ,
                                                  gf_vir,
                                                  0,
                                                  nocc,
                                                  vv=vv,
                                                  vev=vev)

        else:
            buf1 = np.zeros((nphys, nocc * nvir), dtype=types.float64)
            buf2 = np.zeros((nocc * nphys, nvir), dtype=types.float64)

            for i in range(nocc):
                xja = np.dot(ixq[i * nphys:(i + 1) * nphys], qja, out=buf1)
                xia = np.dot(ixq, qja[:, i * nvir:(i + 1) * nvir], out=buf2)
                xia = util.reshape_internal(xia, (nocc, nphys, nvir), (0, 1),
                                            (nphys, nocc * nvir))

                eja = util.outer_sum([gf_occ.e[i] + gf_occ.e, -gf_vir.e])
                eja = eja.ravel()

                vv = util.dgemm(xja, xja.T, alpha=2, beta=1, c=vv)
                vv = util.dgemm(xja, xia.T, alpha=-1, beta=1, c=vv)

                vev = util.dgemm(xja * eja[None],
                                 xja.T,
                                 alpha=2,
                                 beta=1,
                                 c=vev)
                vev = util.dgemm(xja * eja[None],
                                 xia.T,
                                 alpha=-1,
                                 beta=1,
                                 c=vev)

        b = np.linalg.cholesky(vv).T
        b_inv = np.linalg.inv(b)

        m = np.dot(np.dot(b_inv.T, vev), b_inv)

        e, c = util.eigh(m)
        c = np.dot(b.T, c[:nphys])

        se = gf_occ.new(e, c)

        return se
Ejemplo n.º 2
0
def build_dfump2_part(eo, ev, ixq, qja, wtol=1e-12, ss_factor=1.0, os_factor=1.0):
    ''' Builds a set of auxiliaries representing all (i,j,a) or (a,b,i)
        diagrams for an unrestricted reference.

    Parameters
    ----------
    eo : 2-tuple of (o) ndarray
        occupied (virtual) energies for alpha, beta (beta, alpha) spin
    ev : 2-tuple of (v) ndarray
        virtual (occupied) energies for alpha, beta (beta, alpha) spin
    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.
    wtol : float, optional
        threshold for an eigenvalue to be considered zero
    ss_factor : float, optional
        same spin factor, default 1.0
    os_factor : float, optional
        opposite spin factor, default 1.0

    Returns
    -------
    e : (m) ndarray
        auxiliary energies
    v : (n,m) ndarray
        auxiliary couplings
    '''

    nphys = ixq[0].shape[1]
    ndf, nocca, nvira = qja[0].shape
    _, noccb, nvirb = qja[1].shape
    npoles  = nvira * nocca * (nocca-1) // 2
    npoles += nvirb * nocca * noccb

    e = np.zeros((npoles), dtype=types.float64)
    v = np.zeros((nphys, npoles), dtype=ixq[0].dtype)

    a_factor = np.sqrt(ss_factor)
    b_factor = np.sqrt(os_factor)

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

    n0 = 0
    for i in range(nocca):
        nja_a = i * nvira
        nja_b = noccb * nvirb
        jm = slice(None, i)
        am = slice(n0, n0+nja_a)
        bm = slice(n0+nja_a, n0+nja_a+nja_b)

        xq_a = ixq[0][i*nphys:(i+1)*nphys]
        qa_a = qja[0][:,i*nvira:(i+1)*nvira]

        xja_aa = np.dot(ixq[0][:i*nphys].conj(), qa_a)
        xja_aa = util.reshape_internal(xja_aa, (i, nphys, nvira), (0,1), (nphys, i*nvira))
        xia_aa = np.dot(xq_a.conj(), qja[0][:,:i*nvira]).reshape((nphys,-1))
        xja_ab = np.dot(xq_a.conj(), qja[1]).reshape((nphys,-1))

        xija_aa = np.dot(ixq[0].conj(), qja[0]).reshape((nocca, nphys, nocca, nvira)).swapaxes(0,1)
        xija_ab = np.dot(ixq[0].conj(), qja[1]).reshape((nocca, nphys, noccb, nvirb)).swapaxes(0,1)
        assert np.allclose(xia_aa, xija_aa[:,i,:i].reshape((nphys, -1)))
        assert np.allclose(xja_aa, xija_aa[:,:i,i].reshape((nphys, -1)))
        assert np.allclose(xja_ab, xija_ab[:,i].reshape((nphys, -1)))

        e[am] = eo[0][i] + np.subtract.outer(eo[0][jm], ev[0]).flatten()
        e[bm] = eo[0][i] + np.subtract.outer(eo[1], ev[1]).flatten()

        v[:,am] = a_factor * (xia_aa - xja_aa)
        v[:,bm] = b_factor * xja_ab

        n0 += nja_a + nja_b

    mask = np.absolute(util.complex_sum(v*v, axis=0)) >= wtol
    e = e[mask]
    v = v[:,mask]

    e = e[:n0]
    v = v[:,:n0]

    assert e.shape[0] == v.shape[1]

    return e, v
Ejemplo n.º 3
0
        def _build_part(s=slice(None)):
            vv = np.zeros((nphys, nphys), dtype=types.float64)
            vev = np.zeros((nphys, nphys), dtype=types.float64)

            if libagf2._libagf2 is not None:
                vv, vev = libagf2.build_part_loop_uhf(ixq[s],
                                                      qja[s],
                                                      gf_occ[s],
                                                      gf_vir[s],
                                                      0,
                                                      nocc[s][0],
                                                      vv=vv,
                                                      vev=vev)

            else:
                nocca, noccb = nocc[s]
                nvira, nvirb = nvir[s]
                ixq_a, ixq_b = ixq[s]
                qja_a, qja_b = qja[s]
                gf_occ_a, gf_occ_b = gf_occ[s]
                gf_vir_a, gf_vir_b = gf_vir[s]

                buf1 = np.zeros((nphys, nocca * nvira), dtype=types.float64)
                buf2 = np.zeros((nocca * nphys, nvira), dtype=types.float64)
                buf3 = np.zeros((nphys, noccb * nvirb), dtype=types.float64)

                for i in range(nocca):
                    xja_aa = np.dot(ixq_a[i * nphys:(i + 1) * nphys],
                                    qja_a,
                                    out=buf1)
                    xia_aa = np.dot(ixq_a,
                                    qja_a[:, i * nvira:(i + 1) * nvira],
                                    out=buf2)
                    xia_aa = util.reshape_internal(xia_aa,
                                                   (nocca, nphys, nvira),
                                                   (0, 1),
                                                   (nphys, nocca * nvira))
                    xja_ab = np.dot(ixq_a[i * nphys:(i + 1) * nphys],
                                    qja_b,
                                    out=buf3)

                    eja_aa = util.outer_sum(
                        [gf_occ_a.e[i] + gf_occ_a.e, -gf_vir_a.e]).flatten()
                    eja_ab = util.outer_sum(
                        [gf_occ_a.e[i] + gf_occ_b.e, -gf_vir_b.e]).flatten()

                    vv = util.dgemm(xja_aa, xja_aa.T, alpha=1, beta=1, c=vv)
                    vv = util.dgemm(xja_aa, xia_aa.T, alpha=-1, beta=1, c=vv)
                    vv = util.dgemm(xja_ab, xja_ab.T, alpha=1, beta=1, c=vv)

                    vev = util.dgemm(xja_aa * eja_aa[None],
                                     xja_aa.T,
                                     alpha=1,
                                     beta=1,
                                     c=vev)
                    vev = util.dgemm(xja_aa * eja_aa[None],
                                     xia_aa.T,
                                     alpha=-1,
                                     beta=1,
                                     c=vev)
                    vev = util.dgemm(xja_ab * eja_ab[None],
                                     xja_ab.T,
                                     alpha=1,
                                     beta=1,
                                     c=vev)

            b = np.linalg.cholesky(vv).T
            b_inv = np.linalg.inv(b)

            m = np.dot(np.dot(b_inv.T, vev), b_inv)

            e, c = util.eigh(m)
            c = np.dot(b.T, c[:nphys])

            se = gf_occ[s][0].new(e, c)

            return se
Ejemplo n.º 4
0
def build_dfump2_part_direct(eo, ev, ixq, qja, wtol=1e-12, ss_factor=1.0, os_factor=1.0):
    ''' Builds a set of auxiliaries representing all (i,j,a) or (a,b,i)
        diagrams for an unrestricted reference. Uses a generator which
        iterates over blocks.

    Parameters
    ----------
    eo : 2-tuple of (o) ndarray
        occupied (virtual) energies for alpha, beta (beta, alpha) spin
    ev : 2-tuple of (v) ndarray
        virtual (occupied) energies for alpha, beta (beta, alpha) spin
    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.
    wtol : float, optional
        threshold for an eigenvalue to be considered zero
    ss_factor : float, optional
        same spin factor, default 1.0
    os_factor : float, optional
        opposite spin factor, default 1.0

    Yields
    ------
    e : (m) ndarray
        auxiliary energies
    v : (n,m) ndarray
        auxiliary couplings
    '''

    nphys = ixq[0].shape[1]
    ndf, nocca, nvira = qja[0].shape
    _, noccb, nvirb = qja[1].shape
    npoles  = nvira * nocca * (nocca-1) // 2
    npoles += nvirb * nocca * noccb

    a_factor = np.sqrt(ss_factor)
    b_factor = np.sqrt(os_factor)

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

    for i in range(nocca):
        nja_a = i * nvira
        nja_b = noccb * nvirb
        jm = slice(None, i)

        xq_a = ixq[0][i*nphys:(i+1)*nphys]
        qa_a = qja[0][:,i*nvira:(i+1)*nvira]

        xja_aa = np.dot(ixq[0][:i*nphys].conj(), qa_a)
        xja_aa = util.reshape_internal(xja_aa, (i, nphys, nvira), (0,1), (nphys, i*nvira))
        xia_aa = np.dot(xq_a.conj(), qja[0][:,:i*nvira]).reshape((nphys,-1))
        xja_ab = np.dot(ixq[0][i*nphys:(i+1)*nphys].conj(), qja[1]).reshape((nphys,-1))

        ea = eo[0][i] + np.subtract.outer(eo[0][jm], ev[0]).flatten()
        eb = eo[0][i] + np.subtract.outer(eo[1], ev[1]).flatten()

        va = a_factor * (xja_aa - xia_aa)
        vb = b_factor * xja_ab

        if len(ea):
            yield ea, va
        if len(eb):
            yield eb, vb
Ejemplo n.º 5
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
Ejemplo n.º 6
0
def build_dfump2_iter(se, h_phys, eri_mo, **kwargs):
    ''' Builds a set of auxiliaries representing all (i,j,a) and (a,b,i)
        diagrams by iterating the current set of auxiliaries according
        to the eigenvalue form of the Dyson equation.

        Unlike the other routines in this module, this builds for both
        spins.

    Parameters
    ----------
    aux : tuple of Aux
        auxiliaries of previous iteration as (alpha, beta)
    h_phys : (2,n,n) ndarray
        physical space Hamiltonian for alpha and beta spin, if `ndim==2`
        then spin-symmetry in the Hamiltonian is assumed
    eri_mo : (2,q,n,n) ndarray
        density-fitted two-electron repulsion integrals in MO basis, 
        where the first index is spin
    wtol : float, optional
        threshold for an eigenvalue to be considered zero
    ss_factor : float, optional
        same spin factor, default 1.0
    os_factor : float, optional
        opposite spin factor, default 1.0

    Returns
    -------
    poles_a : Aux
        auxiliaries for alpha spin
    poles_b : Aux
        auxiliaries for beta spin
    '''

    h_phys = np.asarray(h_phys, dtype=types.float64)

    if h_phys.ndim == 2:
        h_phys = np.stack((h_phys, h_phys))

    ea, ca = se[0].eig(h_phys[0])
    eb, cb = se[1].eig(h_phys[1])

    oa = ea < se[0].chempot
    ob = eb < se[1].chempot
    va = ea >= se[0].chempot
    vb = eb >= se[1].chempot

    nphys = se[0].nphys
    nocca = np.sum(oa)
    noccb = np.sum(ob)
    nvira = np.sum(va)
    nvirb = np.sum(vb)

    eo = (ea[oa], eb[ob])
    ev = (ea[va], eb[vb])
    co = (ca[:se[0].nphys,oa], cb[:se[1].nphys,ob])
    cv = (ca[:se[0].nphys,va], cb[:se[1].nphys,vb])
    eye = np.eye(nphys)

    ixq_a = util.ao2mo_df(eri_mo[0], co[0], eye)
    ixq_a = util.reshape_internal(ixq_a, (-1, nocca*nphys), (0,1), (nocca, nphys, -1))
    qja_a = util.ao2mo_df(eri_mo[0], co[0], cv[0])
    qja_b = util.ao2mo_df(eri_mo[1], co[1], cv[1])
    eija_a, vija_a = build_dfump2_part(eo, ev, (ixq_a,), (qja_a, qja_b), **kwargs)
    del ixq_a

    ixq_b = util.ao2mo_df(eri_mo[1], co[1], eye)
    ixq_b = util.reshape_internal(ixq_b, (-1, noccb*nphys), (0,1), (noccb, nphys, -1))
    eija_b, vija_b = build_dfump2_part(eo[::-1], ev[::-1], (ixq_b,), (qja_b, qja_a), **kwargs)
    del ixq_b, qja_a, qja_b

    axq_a = util.ao2mo_df(eri_mo[0], cv[0], eye)
    axq_a = util.reshape_internal(axq_a, (-1, nvira*nphys), (0,1), (nvira, nphys, -1))
    qbi_a = util.ao2mo_df(eri_mo[0], cv[0], co[0])
    qbi_b = util.ao2mo_df(eri_mo[1], cv[1], co[1])
    eabi_a, vabi_a = build_dfump2_part(ev, eo, (axq_a,), (qbi_a, qbi_b), **kwargs)
    del axq_a

    axq_b = util.ao2mo_df(eri_mo[1], cv[1], eye)
    axq_b = util.reshape_internal(axq_b, (-1, nvirb*nphys), (0,1), (nvirb, nphys, -1))
    eabi_b, vabi_b = build_dfump2_part(ev[::-1], eo[::-1], (axq_b,), (qbi_b, qbi_a), **kwargs)
    del axq_b, qbi_a, qbi_b

    ea = np.concatenate((eija_a, eabi_a), axis=0)
    eb = np.concatenate((eija_b, eabi_b), axis=0)
    va = np.concatenate((vija_a, vabi_a), axis=1)
    vb = np.concatenate((vija_b, vabi_b), axis=1)

    poles_a = se[0].new(ea, va)
    poles_b = se[1].new(eb, vb)

    return poles_a, poles_b
Ejemplo n.º 7
0
def build_dfrmp2_part(eo,
                      ev,
                      ixq,
                      qja,
                      wtol=1e-12,
                      ss_factor=1.0,
                      os_factor=1.0):
    ''' Builds a set of auxiliaries representing all (i,j,a) or (a,b,i)
        diagrams for a restricted reference.

    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)
    wtol : float, optional
        threshold for an eigenvalue to be considered zero
    ss_factor : float, optional
        same spin factor, default 1.0
    os_factor : float, optional
        opposite spin factor, default 1.0

    Returns
    -------
    e : (m) ndarray
        auxiliary energies
    v : (n,m) ndarray
        auxiliary couplings
    '''

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

    e = np.zeros((npoles), dtype=types.float64)
    v = np.zeros((nphys, npoles), dtype=ixq.dtype)

    pos_factor = np.sqrt(0.5 * os_factor)
    neg_factor = np.sqrt(0.5 * os_factor + ss_factor)
    dia_factor = np.sqrt(os_factor)

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

    n0 = 0
    for i in range(nocc):
        nja = i * nvir
        am = slice(n0, n0 + nja)
        bm = slice(n0 + nja, n0 + nja * 2)
        cm = slice(n0 + nja * 2, n0 + nja * 2 + nvir)

        xq = ixq[i * nphys:(i + 1) * nphys]
        qa = qja[:, i * nvir:(i + 1) * nvir]

        xja = np.dot(ixq[:i * nphys].conj(), qa)
        xja = util.reshape_internal(xja, (i, nphys, nvir), (0, 1),
                                    (nphys, i * nvir))
        xia = np.dot(xq.conj(), qja[:, :i * nvir]).reshape((nphys, -1))
        xa = np.dot(xq.conj(), qa)

        e[am] = e[bm] = eo[i] + util.dirsum('i,a->ia', eo[:i], -ev).ravel()
        e[cm] = 2 * eo[i] - ev

        v[:, am] = neg_factor * (xja - xia)
        v[:, bm] = pos_factor * (xja + xia)
        v[:, cm] = dia_factor * xa

        n0 += nja * 2 + nvir

    mask = np.absolute(util.complex_sum(v * v, axis=0)) >= wtol
    e = e[mask]
    v = v[:, mask]

    assert e.shape[0] == v.shape[1]

    return e, v
Ejemplo n.º 8
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
Ejemplo n.º 9
0
def build_dfrmp2_part_direct(eo,
                             ev,
                             ixq,
                             qja,
                             wtol=1e-12,
                             ss_factor=1.0,
                             os_factor=1.0):
    ''' Builds a set of auxiliaries representing all (i,j,a) or (a,b,i)
        diagrams for a restricted reference. Uses a generator which
        iterates over blocks.

    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)
    wtol : float, optional
        threshold for an eigenvalue to be considered zero
    ss_factor : float, optional
        same spin factor, default 1.0
    os_factor : float, optional
        opposite spin factor, deafult 1.0

    Yields
    ------
    e : (m) ndarray
        auxiliary energies
    v : (n,m) ndarray
        auxiliary couplings
    '''

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

    pos_factor = np.sqrt(0.5 * os_factor)
    neg_factor = np.sqrt(0.5 * os_factor + ss_factor)
    dia_factor = np.sqrt(os_factor)

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

    for i in range(nocc):
        nja = i * nvir

        xq = ixq[i * nphys:(i + 1) * nphys]
        qa = qja[:, i * nvir:(i + 1) * nvir]

        xja = np.dot(ixq[:i * nphys].conj(), qa)
        xja = util.reshape_internal(xja, (i, nphys, nvir), (0, 1),
                                    (nphys, i * nvir))
        xia = np.dot(xq.conj(), qja[:, :i * nvir]).reshape((nphys, -1))
        xa = np.dot(xq.conj(), qa)

        ea = eb = eo[i] + util.dirsum('i,a->ia', eo[:i], -ev).ravel()
        ec = 2 * eo[i] - ev

        va = neg_factor * (xja - xia)
        vb = pos_factor * (xja + xia)
        vc = dia_factor * xa

        if len(ea):
            yield ea, va
        if len(eb):
            yield eb, vb
        if len(ec):
            yield ec, vc
Ejemplo n.º 10
0
def build_dfrmp2_iter(se, h_phys, eri_mo, **kwargs):
    ''' Builds a set of auxiliaries representing all (i,j,a) and (a,b,i)
        diagrams by iterating the current set of auxiliaries according
        to the eigenvalue form of the Dyson equation.

    Parameters
    ----------
    se : Aux
        auxiliaries of previous iteration
    h_phys : (n,n) ndarray
        physical space hamiltonian
    eri_mo : (q,n,n) ndarray
        density-fitted two-electron repulsion integrals in MO basis
    wtol : float, optional
        threshold for an eigenvalue to be considered zero
    ss_factor : float, optional
        same spin factor, default 1.0
    os_factor : float, optional
        opposite spin factor, deafult 1.0

    Returns
    -------
    poles : Aux
        auxiliaries
    '''

    e, c = se.eig(h_phys)

    o = e < se.chempot
    v = e >= se.chempot

    nphys = se.nphys
    nocc = np.sum(o)
    nvir = np.sum(v)

    eo = e[o]
    ev = e[v]
    co = c[:se.nphys, o]
    cv = c[:se.nphys, v]
    eye = np.eye(se.nphys)

    ixq = util.ao2mo_df(eri_mo, co, eye)
    ixq = util.reshape_internal(ixq, (-1, nocc * nphys), (0, 1),
                                (nocc, nphys, -1))
    qja = util.ao2mo_df(eri_mo, co, cv)
    eija, vija = build_dfrmp2_part(eo, ev, ixq, qja, **kwargs)
    del ixq, qja

    axq = util.ao2mo_df(eri_mo, cv, eye)
    axq = util.reshape_internal(axq, (-1, nvir * nphys), (0, 1),
                                (nvir, nphys, -1))
    qbi = util.ao2mo_df(eri_mo, cv, co)
    eabi, vabi = build_dfrmp2_part(ev, eo, axq, qbi, **kwargs)
    del axq, qbi

    e = np.concatenate((eija, eabi), axis=0)
    v = np.concatenate((vija, vabi), axis=1)

    poles = se.new(e, v)

    return poles