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