Exemple #1
0
def make_coups_inner(v, wtol=1e-12):
    ''' Builds a set of couplings using the eigenvectors of the inner
        product of the space spanned by a set of vectors.

    Parameters
    ----------
    v : (n,m) ndarray
        input vectors
    wtol : float, optional
        threshold for an eigenvalue to be considered zero

    Returns
    -------
    coup : (n,k) ndarray
        coupling vectors
    '''

    if v.ndim == 1:
        v = v[:, None]

    s = np.dot(v.conj().T, v)

    #TODO: lib.dsyevd_2x2

    w, coup = util.eigh(s)

    mask = w >= wtol

    coup = np.dot(v, coup[:, mask])
    coup /= np.sqrt(util.complex_sum(coup * coup, axis=0))
    coup *= np.sqrt(w[mask])

    return coup
Exemple #2
0
def build_auxiliaries(h, nphys):
    ''' Builds a set of auxiliary energies and couplings from the
        block tridiagonal Hamiltonian.

    Parameters
    ----------
    h : (n,n) ndarray
        block tridiagonal Hamiltonian
    nphys : int
        number of physical degrees of freedom

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

    w, v = util.eigh(h[nphys:, nphys:])

    e = w

    v = np.dot(h[:nphys, nphys:2 * nphys], v[:nphys])

    return e, v
Exemple #3
0
def diag_fock_ext(se, fock, nelec, chempot=0.0, occupancy=2.0, buf=None):
    ''' Diagonalises the extended Fock matrix and returns finds a
        chemical potential via Aufbau.

    Parameters
    ----------
    se : Aux
        auxiliaries
    fock : ndarray
        physical space Fock matrix
    nelec : int
        target number of electrons
    chempot : float, optional
        chemical potential on the auxiliary space (NOT the same as
        that on the physical space!), default 0.0
    occupancy : float, optional
        orbital occupancy, i.e. 2 for RHF and 1 for UHF, default 2
    buf : ndarray, optional
        array to store the extended Fock matrix
    
    Returns
    -------
    w : ndarray
        eigenvalues
    v : ndarray
        eigenvectors
    chempot : float
        chemical potential on the physical space which best satisfies
        the number of electrons
    error : float
        error in the number of electrons in the physical space
    '''

    f_ext = se.as_hamiltonian(fock, chempot=chempot, out=buf)
    w, v = util.eigh(f_ext)

    chempot_phys, error = util.chempot.find_chempot(se.nphys,
                                                    nelec,
                                                    h=(w, v),
                                                    occupancy=occupancy)

    return w, v, chempot_phys, error
Exemple #4
0
def make_coups_outer(v, s=None, wtol=1e-12):
    ''' Builds a set of couplings using the eigenvectors of the outer
        product of the space spanned by a set of vectors, scaled by
        their signs.

    Parameters
    ----------
    v : (n,m) ndarray
        input vectors
    s : (m) ndarray, optional
        signs (+1 causal, -1 causal) of vectors
    wtol : float, optional
        threshold for an eigenvalue to be considered zero

    Returns
    -------
    coup : (n,k) ndarray
        coupling vectors
    sign : (k) ndarray, optional
        signs, if `s` is not `None`
    '''

    if v.ndim == 1:
        v = v[:, None]

    if s is None:
        m = np.dot(v, v.conj().T)
    else:
        m = np.dot(s * v, v.conj().T)

    w, coup = util.eigh(m)

    mask = np.absolute(w) >= wtol

    coup = coup[:, mask]
    coup *= np.sqrt(np.absolute(w[mask]))

    if s is None:
        return coup
    else:
        sign = np.sign(w[mask])
        return coup, sign
Exemple #5
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
Exemple #6
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
Exemple #7
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