def initial_greens_function_uhf(self, A, B, trial, nup, weights): r"""Compute initial green's function at timestep n for UHF wavefunction. Here we actually compute the equal-time green's function: .. math:: G_{ij} = \langle c_i c_j^{\dagger} \rangle Parameters ---------- A : :class:`numpy.ndarray` Left hand wavefunction for green's function. B : :class:`numpy.ndarray` Left hand wavefunction for green's function. trial : :class:`pauxy.trial_wavefunction.X' object Trial wavefunction class. nup : int Number of up electrons. weight : :class:`numpy.ndarray` Any GS orthogonalisation factors which need to be included. Returns ------- G_nn : :class:`numpy.ndarray` Green's function. """ Ggr_up = self.I - gab(A[:, :nup], B[:, :nup]) Ggr_down = self.I - gab(A[:, nup:], B[:, nup:]) Gls_up = self.I - Ggr_up Gls_down = self.I - Ggr_down return (numpy.array([Ggr_up, Ggr_down]), numpy.array([Gls_up, Gls_down]))
def freeze_core(h1e, chol, ecore, nc, ncas, verbose=True): # 1. Construct one-body hamiltonian print(ecore, type(h1e), type(chol)) nbasis = h1e.shape[-1] chol = chol.reshape((-1, nbasis, nbasis)) system = dotdict({ 'H1': numpy.array([h1e, h1e]), 'chol_vecs': chol, 'ecore': ecore, 'nbasis': nbasis }) psi = numpy.identity(nbasis)[:, :nc] Gcore = gab(psi, psi) ecore = local_energy_generic_cholesky(system, [Gcore, Gcore])[0] (hc_a, hc_b) = core_contribution_cholesky(system.chol_vecs, [Gcore, Gcore]) h1e = numpy.array([h1e, h1e]) h1e[0] = h1e[0] + 2 * hc_a h1e[1] = h1e[1] + 2 * hc_b h1e = h1e[:, nc:nc + ncas, nc:nc + ncas] nchol = chol.shape[0] chol = chol[:, nc:nc + ncas, nc:nc + ncas].reshape((nchol, -1)) # 4. Subtract one-body term from writing H2 as sum of squares. if verbose: print(" # Number of active orbitals: %d" % ncas) print(" # Freezing %d core electrons and %d virtuals." % (2 * nc, nbasis - nc - ncas)) print(" # Frozen core energy : %13.8e" % ecore.real) return h1e, chol, ecore
def unit_test(): from pauxy.systems.ueg import UEG import numpy as np inputs = {'nup': 7, 'ndown': 7, 'rs': 1.0, 'ecut': 2.0} system = UEG(inputs, True) nbsf = system.nbasis Pa = np.zeros([nbsf, nbsf], dtype=np.complex128) Pb = np.zeros([nbsf, nbsf], dtype=np.complex128) na = system.nup nb = system.ndown for i in range(na): Pa[i, i] = 1.0 for i in range(nb): Pb[i, i] = 1.0 P = np.array([Pa, Pb]) etot, ekin, epot = local_energy_ueg(system, G=P) print("ERHF = {}, {}, {}".format(etot, ekin, epot)) from pauxy.utils.linalg import exponentiate_matrix, reortho from pauxy.estimators.greens_function import gab # numpy.random.seed() rCa = numpy.random.randn(nbsf, na) zCa = numpy.random.randn(nbsf, na) rCb = numpy.random.randn(nbsf, nb) zCb = numpy.random.randn(nbsf, nb) Ca = rCa + 1j * zCa Cb = rCb + 1j * zCb Ca, detR = reortho(Ca) Cb, detR = reortho(Cb) # S = print(Ca.dot(Cb.T)) # print(S) # exit() Ca = numpy.array(Ca, dtype=numpy.complex128) Cb = numpy.array(Cb, dtype=numpy.complex128) P = [gab(Ca, Ca), gab(Cb, Cb)]
def __init__(self, system, cplx, trial, parallel=False, verbose=0): if verbose: print("# Constructing UHF trial wavefunction") self.verbose = verbose init_time = time.time() self.name = "UHF" self.type = "UHF" self.initial_wavefunction = trial.get('initial_wavefunction', 'trial') if cplx: self.trial_type = complex else: self.trial_type = float # Unpack input options. self.ninitial = trial.get('ninitial', 10) self.nconv = trial.get('nconv', 5000) self.ueff = trial.get('ueff', 0.4) self.deps = trial.get('deps', 1e-8) self.alpha = trial.get('alpha', 0.5) # For interface compatability self.coeffs = 1.0 self.type = 'UHF' self.ndets = 1 (self.psi, self.eigs, self.emin, self.error, self.nav) = (self.find_uhf_wfn(system, cplx, self.ueff, self.ninitial, self.nconv, self.alpha, self.deps, verbose)) if self.error and not parallel: warnings.warn('Error in constructing trial wavefunction. Exiting') sys.exit() Gup = gab(self.psi[:, :system.nup], self.psi[:, :system.nup]).T Gdown = gab(self.psi[:, system.nup:], self.psi[:, system.nup:]).T self.G = numpy.array([Gup, Gdown]) self.etrial = local_energy(system, self.G)[0].real self.bp_wfn = trial.get('bp_wfn', None) self.initialisation_time = time.time() - init_time self.init = self.psi
def find_uhf_wfn(self, system, cplx, ueff, ninit, nit_max, alpha, deps=1e-8, verbose=0): emin = 0 uold = system.U system.U = ueff minima = [] # Local minima nup = system.nup # Search over different random starting points. for attempt in range(0, ninit): # Set up initial (random) guess for the density. (self.trial, eold) = self.initialise(system.nbasis, system.nup, system.ndown, cplx) niup = self.density(self.trial[:, :nup]) nidown = self.density(self.trial[:, nup:]) niup_old = self.density(self.trial[:, :nup]) nidown_old = self.density(self.trial[:, nup:]) for it in range(0, nit_max): (niup, nidown, e_up, e_down) = (self.diagonalise_mean_field( system, ueff, niup, nidown)) # Construct Green's function to compute the energy. Gup = gab(self.trial[:, :nup], self.trial[:, :nup]).T Gdown = gab(self.trial[:, nup:], self.trial[:, nup:]).T enew = local_energy(system, numpy.array([Gup, Gdown]))[0].real if verbose > 1: print("# %d %f %f" % (it, enew, eold)) sc = self.self_consistant(enew, eold, niup, niup_old, nidown, nidown_old, it, deps, verbose) if sc: # Global minimum search. if attempt == 0: minima.append(enew) psi_accept = copy.deepcopy(self.trial) e_accept = numpy.append(e_up, e_down) elif all(numpy.array(minima) - enew > deps): minima.append(enew) psi_accept = copy.deepcopy(self.trial) e_accept = numpy.append(e_up, e_down) break else: mixup = self.mix_density(niup, niup_old, alpha) mixdown = self.mix_density(nidown, nidown_old, alpha) niup_old = niup nidown_old = nidown niup = mixup nidown = mixdown eold = enew if verbose > 1: print("# SCF cycle: {:3d}. After {:4d} steps the minimum UHF" " energy found is: {: 8f}".format(attempt, it, eold)) system.U = uold print("# Minimum energy found: {: 8f}".format(min(minima))) try: return (psi_accept, e_accept, min(minima), False, [niup, nidown]) except UnboundLocalError: warnings.warn("Warning: No UHF wavefunction found." "Delta E: %f" % (enew - emin)) return (trial, numpy.append(e_up, e_down), None, True, None)
def __init__(self, system, cplx, trial, parallel=False, verbose=False): self.verbose = verbose if verbose: print("# Parsing multi-determinant trial wavefunction input" " options.") init_time = time.time() self.name = "multi_determinant" self.expansion = "multi_determinant" self.type = "Not GHF" self.eigs = numpy.array([0.0]) if cplx: self.trial_type = numpy.complex128 else: self.trial_type = numpy.float64 # For debugging purposes. self.error = False self.orbital_file = trial.get('orbitals', None) self.coeffs_file = trial.get('coefficients', None) self.write = trial.get('write', False) if self.orbital_file is not None: self.ndets = trial.get('ndets', None) self.psi = numpy.zeros((ndets, nbasis, system.ne), dtype=self.trial_type) self.from_ascii(system) elif system.orbs is not None: orbs = system.orbs.copy() self.ndets = orbs.shape[0] if system.frozen_core: nc = system.ncore nfv = system.nfv nb = system.nbasis orbs_core = orbs[0, :, :nc] orbs = orbs[:, nc:nb - nfv, :] Gcore, half = gab_mod(orbs_core, orbs_core) self.Gcore = numpy.array([Gcore, Gcore]) self.psi = numpy.zeros(shape=(self.ndets, system.nactive, system.ne), dtype=self.trial_type) self.psi[:, :, :system.nup] = orbs[:, :, nc:nc + system.nup].copy() self.psi[:, :, system.nup:] = orbs[:, :, 2 * nc + system.nup:2 * nc + system.ne].copy() self.coeffs = system.coeffs self.nup = system.nup else: print("Could not construct trial wavefunction.") self.error = True nbasis = system.nbasis self.GAB = numpy.zeros(shape=(2, self.ndets, self.ndets, system.nactive, system.nactive), dtype=self.trial_type) self.weights = numpy.zeros(shape=(2, self.ndets, self.ndets), dtype=self.trial_type) # Store the complex conjugate of the multi-determinant trial # wavefunction expansion coefficients for ease later. Gup = gab(self.psi[0, :, :system.nup], self.psi[0, :, :system.nup]) Gdn = gab(self.psi[0, :, system.nup:], self.psi[0, :, system.nup:]) self.G = numpy.array([Gup, Gdn]) self.initialisation_time = time.time() - init_time if self.write: self.to_qmcpack_ascii() if verbose: print("# Number of determinants in expansion: %d" % self.ndets) print("# Finished setting up trial wavefunction.")
def update_uhf(self, system, qmc, trial, psi, step, free_projection=False): """Calculate back-propagated estimates for RHF/UHF walkers. Parameters ---------- system : system object in general. Container for model input options. qmc : :class:`pauxy.state.QMCOpts` object. Container for qmc input options. trial : :class:`pauxy.trial_wavefunction.X' object Trial wavefunction class. psi : :class:`pauxy.walkers.Walkers` object CPMC wavefunction. step : int Current simulation step free_projection : bool True if doing free projection. """ buff_ix = psi.walkers[0].field_configs.step if buff_ix not in self.splits: return nup = system.nup for i, wnm in enumerate(psi.walkers): if self.init_walker: phi_bp = trial.init.copy() else: phi_bp = trial.psi.copy() # TODO: Fix for ITCF. self.back_propagate(phi_bp, wnm.field_configs, system, self.nstblz, self.BT2, self.dt) self.G[0] = gab(phi_bp[:, :nup], wnm.phi_old[:, :nup]).T self.G[1] = gab(phi_bp[:, nup:], wnm.phi_old[:, nup:]).T if self.eval_energy: eloc = local_energy(system, self.G, opt=False, two_rdm=self.two_rdm) energies = numpy.array(list(eloc)) else: energies = numpy.zeros(3) if self.calc_two_rdm is not None and self.calc_two_rdm is not "structure_factor": # <p^+ q^+ s r> = G(p, r, q, s) also spin-summed self.two_rdm = numpy.einsum("pr,qs->prqs",self.G[0], self.G[0], optimize=True)\ - numpy.einsum("ps,qr->prqs",self.G[0], self.G[0], optimize=True) self.two_rdm += numpy.einsum("pr,qs->prqs",self.G[1], self.G[1], optimize=True)\ - numpy.einsum("ps,qr->prqs",self.G[1], self.G[1], optimize=True) self.two_rdm += numpy.einsum("pr,qs->prqs",self.G[0], self.G[1], optimize=True)\ + numpy.einsum("pr,qs->prqs",self.G[1], self.G[0], optimize=True) if self.eval_ekt: if (system.name == 'UEG'): # there needs to be a factor of 2.0 here to account for the convention of cholesky vectors in the system class chol_vecs = 2.0 * system.chol_vecs.toarray().T.reshape( (system.nchol, system.nbasis, system.nbasis)) self.ekt_fock_1p = ekt_1p_fock_opt(system.H1[0], chol_vecs, self.G[0], self.G[1]) self.ekt_fock_1h = ekt_1h_fock_opt(system.H1[0], chol_vecs, self.G[0], self.G[1]) else: self.ekt_fock_1p = ekt_1p_fock_opt(system.H1[0], system.chol_vecs, self.G[0], self.G[1]) self.ekt_fock_1h = ekt_1h_fock_opt(system.H1[0], system.chol_vecs, self.G[0], self.G[1]) if self.restore_weights is not None: cosine_fac, ph_fac = wnm.field_configs.get_wfac() if self.restore_weights == "full": # BP-Pres wfac = ph_fac / cosine_fac else: # BP-PRes (partial) wfac = ph_fac weight = wnm.weight * wfac else: # BP-PhL weight = wnm.weight self.estimates[:self.nreg] += weight * energies self.estimates[self.nreg] += weight start = self.nreg + 1 end = start + self.G.size self.estimates[start:end] += weight * self.G.flatten() if self.calc_two_rdm is not None: start = end end = end + self.two_rdm.size self.estimates[start:end] += weight * self.two_rdm.flatten() if self.eval_ekt: start = end end = end + self.ekt_fock_1p.size self.estimates[start:end] += weight * self.ekt_fock_1p.flatten( ) start = end end = end + self.ekt_fock_1h.size self.estimates[start:end] += weight * self.ekt_fock_1h.flatten( ) if buff_ix == self.splits[-1]: wnm.field_configs.reset() if buff_ix == self.splits[-1]: psi.copy_historic_wfn() self.accumulated = True self.buff_ix = buff_ix