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
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
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
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
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
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
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
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
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
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