Example #1
0
 def __init__(self,
              comm,
              system,
              beta,
              dt,
              options={},
              H1=None,
              verbose=False):
     OneBody.__init__(self,
                      comm,
                      system,
                      beta,
                      dt,
                      options,
                      H1=H1,
                      verbose=verbose)
     self.alpha = options.get('alpha', 0.75)
     self.max_scf_it = options.get('max_scf_it', self.max_it)
     self.max_macro_it = options.get('max_macro_it', self.max_it)
     self.find_mu = options.get('find_mu', True)
     if comm.rank == 0:
         P, HMF, mu = self.thermal_hartree_fock(system, beta)
         muN = mu * numpy.eye(system.nbasis, dtype=self.G.dtype)
         dmat = numpy.array([
             scipy.linalg.expm(-dt * (HMF[0] - muN)),
             scipy.linalg.expm(-dt * (HMF[1] - muN))
         ])
         dmat_inv = numpy.array([
             scipy.linalg.inv(self.dmat[0], check_finite=False),
             scipy.linalg.inv(self.dmat[1], check_finite=False)
         ])
         G = numpy.array(
             [greens_function(self.dmat[0]),
              greens_function(self.dmat[1])])
         data = {
             'P': P,
             'mu': mu,
             'dmat': dmat,
             'dmat_inv': dmat_inv,
             'G': G
         }
     else:
         data = None
     data = comm.bcast(data, root=0)
     self.P = data['P']
     self.nav = particle_number(self.P).real
     self.dmat = data['dmat']
     self.dmat_inv = data['dmat_inv']
     self.G = data['G']
     self.mu = data['mu']
Example #2
0
 def scf(self, system, beta, mu, P):
     # 1. Compute HMF
     HMF = fock_matrix(system, P)
     dt = self.dtau
     muN = mu * numpy.eye(system.nbasis, dtype=self.G.dtype)
     rho = numpy.array([
         scipy.linalg.expm(-dt * (HMF[0] - muN)),
         scipy.linalg.expm(-dt * (HMF[1] - muN))
     ])
     Pold = one_rdm_stable(rho, self.num_bins)
     if self.verbose:
         print(" # Running Thermal SCF.")
     for it in range(self.max_scf_it):
         HMF = fock_matrix(system, Pold)
         rho = numpy.array([
             scipy.linalg.expm(-dt * (HMF[0] - muN)),
             scipy.linalg.expm(-dt * (HMF[1] - muN))
         ])
         Pnew = (1 - self.alpha) * one_rdm_stable(
             rho, self.num_bins) + self.alpha * Pold
         change = numpy.linalg.norm(Pnew - Pold)
         if change < self.deps:
             break
         if self.verbose:
             N = particle_number(P).real
             E = local_energy(system, P, opt=False)[0].real
             S = entropy(beta, mu, HMF)
             omega = E - mu * N - 1.0 / beta * S
             print(
                 " # Iteration: {:4d} dP: {:13.8e} Omega: {:13.8e}".format(
                     it, change, omega.real))
         Pold = Pnew.copy()
     if self.verbose:
         N = particle_number(P).real
         print(" # Average particle number: {:13.8e}".format(N))
     return HMF
Example #3
0
    def __init__(self,
                 comm,
                 system,
                 beta,
                 dt,
                 options={},
                 nav=None,
                 H1=None,
                 verbose=False):
        self.name = 'thermal'
        self.verbose = verbose
        if H1 is None:
            try:
                self.H1 = system.H1
            except AttributeError:
                self.H1 = system.h1e
        else:
            self.H1 = H1

        if verbose:
            print("# beta in OneBody: {}".format(beta))
            print("# dt in OneBody: {}".format(dt))

        dmat_up = scipy.linalg.expm(-dt * (self.H1[0]))
        dmat_down = scipy.linalg.expm(-dt * (self.H1[1]))
        self.dmat = numpy.array([dmat_up, dmat_down])
        cond = numpy.linalg.cond(self.dmat[0])
        if verbose:
            print("# condition number of BT: {: 10e}".format(cond))

        if nav is not None:
            self.nav = nav
        else:
            self.nav = options.get("nav", None)
            if self.nav is None:
                self.nav = system.nup + system.ndown
        if verbose:
            print("# Target average electron number: {}".format(self.nav))

        self.max_it = options.get('max_it', 1000)
        self.deps = options.get('threshold', 1e-6)
        self.mu = options.get('mu', None)

        self.num_slices = int(beta / dt)
        self.stack_size = options.get("stack_size", None)

        if (self.stack_size == None):
            if verbose:
                print("# Estimating stack size from BT.")
            eigs, ev = scipy.linalg.eigh(self.dmat[0])
            emax = numpy.max(eigs)
            emin = numpy.min(eigs)
            self.cond = numpy.linalg.cond(self.dmat[0])
            # We will end up multiplying many BTs together. Can roughly determine
            # safe stack size from condition number of BT as the condition number of
            # the product will scale roughly as cond(BT)^(number of products).
            # We can determine a conservative stack size by requiring that the
            # condition number of the product does not exceed 1e3.
            self.stack_size = min(self.num_slices,
                                  int(3.0 / numpy.log10(self.cond)))
            if verbose:
                print("# Initial stack size, # of slices: {}, {}".format(
                    self.stack_size, self.num_slices))

        # adjust stack size
        self.stack_size = update_stack(self.stack_size,
                                       self.num_slices,
                                       verbose=verbose)
        self.num_bins = int(beta / (self.stack_size * dt))

        if verbose:
            print("# Number of stacks: {}".format(self.num_bins))

        sign = 1
        if system._alt_convention:
            if verbose:
                print(
                    "# Using alternate sign convention for chemical potential."
                )
            sign = -1
        dtau = self.stack_size * dt
        self.dtau = dtau
        if self.mu is None:
            self.rho = numpy.array([
                scipy.linalg.expm(-dtau * (self.H1[0])),
                scipy.linalg.expm(-dtau * (self.H1[1]))
            ])
            if comm.rank == 0:
                mu = find_chemical_potential(system,
                                             self.rho,
                                             dtau,
                                             self.num_bins,
                                             self.nav,
                                             deps=self.deps,
                                             max_it=self.max_it,
                                             verbose=verbose)
            else:
                mu = None
            self.mu = comm.bcast(mu, root=0)
        else:
            self.rho = numpy.array([
                scipy.linalg.expm(-dtau * (self.H1[0])),
                scipy.linalg.expm(-dtau * (self.H1[1]))
            ])

        if verbose:
            print("# Chemical potential in trial density matrix: {: .10e}".
                  format(self.mu))

        if system.mu is None:
            system.mu = self.mu

        self.P = one_rdm_stable(
            compute_rho(self.rho, self.mu, dtau, sign=sign), self.num_bins)
        self.nav = particle_number(self.P).real
        if verbose:
            print("# Average particle number in trial density matrix: "
                  "{}".format(self.nav))
        self.dmat = compute_rho(self.dmat, self.mu, dt, sign=sign)
        self.dmat_inv = numpy.array([
            scipy.linalg.inv(self.dmat[0], check_finite=False),
            scipy.linalg.inv(self.dmat[1], check_finite=False)
        ])

        self.G = numpy.array(
            [greens_function(self.dmat[0]),
             greens_function(self.dmat[1])])
        self.error = False
Example #4
0
    def update(self, system, qmc, trial, psi, step, free_projection=False):
        """Update mixed estimates for walkers.

        Parameters
        ----------
        system : system object.
            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.
        """
        if free_projection:
            for i, w in enumerate(psi.walkers):
                # For T > 0 w.ot = 1 always.
                wfac = w.weight * w.ot * w.phase
                if step % self.energy_eval_freq == 0:
                    w.greens_function(trial)
                    if self.eval_energy:
                        E, T, V = w.local_energy(system)
                    else:
                        E, T, V = 0, 0, 0
                    self.estimates[self.names.enumer] += wfac * E
                    self.estimates[self.names.e1b:self.names.e2b +
                                   1] += (wfac * numpy.array([T, V]))
                    self.estimates[self.names.edenom] += wfac
                if self.thermal:
                    nav = particle_number(one_rdm_from_G(w.G))
                    self.estimates[self.names.nav] += wfac * nav
                self.estimates[self.names.uweight] += w.unscaled_weight
                self.estimates[self.names.uweight] += w.weight
                self.estimates[self.names.ehyb] += wfac * w.hybrid_energy
                self.estimates[self.names.ovlp] += wfac * abs(w.ot)
        else:
            # When using importance sampling we only need to know the current
            # walkers weight as well as the local energy, the walker's overlap
            # with the trial wavefunction is not needed.
            for i, w in enumerate(psi.walkers):
                if self.thermal:
                    if self.average_gf:
                        E_sum = 0
                        T_sum = 0
                        V_sum = 0
                        nav = 0
                        for ts in range(w.stack_length):
                            w.greens_function(trial,
                                              slice_ix=ts * w.stack_size)
                            E, T, V = w.local_energy(system,
                                                     two_rdm=self.two_rdm)
                            E_sum += E
                            T_sum += T
                            V_sum += V
                            nav += particle_number(one_rdm_from_G(w.G))
                        self.estimates[
                            self.names.nav] += w.weight * nav / w.stack_length
                        self.estimates[
                            self.names.
                            enumer] += w.weight * E_sum.real / w.stack_length
                        self.estimates[self.names.e1b:self.names.e2b + 1] += (
                            w.weight * numpy.array([T_sum, V_sum]).real /
                            w.stack_length)
                    else:
                        w.greens_function(trial)
                        E, T, V = w.local_energy(system, two_rdm=self.two_rdm)
                        nav = particle_number(one_rdm_from_G(w.G))
                        self.estimates[self.names.nav] += w.weight * nav
                        self.estimates[self.names.enumer] += w.weight * E.real
                        self.estimates[self.names.e1b:self.names.e2b +
                                       1] += (w.weight *
                                              numpy.array([T, V]).real)
                        self.estimates[self.names.edenom] += w.weight
                else:
                    if step % self.energy_eval_freq == 0:
                        w.greens_function(trial)
                        if self.eval_energy:
                            E, T, V = w.local_energy(system)
                        else:
                            E, T, V = 0, 0, 0
                        self.estimates[self.names.enumer] += w.weight * E.real
                        self.estimates[self.names.e1b:self.names.e2b +
                                       1] += (w.weight *
                                              numpy.array([T, V]).real)
                        self.estimates[self.names.edenom] += w.weight
                self.estimates[self.names.uweight] += w.unscaled_weight
                self.estimates[self.names.weight] += w.weight
                self.estimates[self.names.ovlp] += w.weight * abs(w.ot)
                self.estimates[self.names.ehyb] += w.weight * w.hybrid_energy
                if self.calc_one_rdm:
                    start = self.names.time + 1
                    end = self.names.time + 1 + w.G.size
                    self.estimates[start:end] += w.weight * w.G.flatten().real
                if self.calc_two_rdm is not None:
                    start = end
                    end = end + self.two_rdm.size
                    self.estimates[
                        start:end] += w.weight * self.two_rdm.flatten().real
Example #5
0
    def __init__(self, walker_opts, system, trial, verbose=False):
        self.weight = walker_opts.get('weight', 1.0)
        self.unscaled_weight = self.weight
        self.phase = 1.0 + 0.0j
        self.alive = True
        self.num_slices = trial.num_slices
        dtype = numpy.complex128
        self.G = numpy.zeros(trial.dmat.shape, dtype=dtype)
        self.nbasis = trial.dmat[0].shape[0]
        self.total_weight = 0
        self.stack_size = walker_opts.get('stack_size', None)
        max_diff_diag = numpy.linalg.norm(
            (numpy.diag(trial.dmat[0].diagonal()) - trial.dmat[0]))
        if max_diff_diag < 1e-10:
            self.diagonal_trial = True
            if verbose:
                print("# Trial density matrix is diagonal.")
        else:
            self.diagonal_trial = False
            if verbose:
                print("# Trial density matrix is not diagonal.")

        if self.stack_size == None:
            self.stack_size = trial.stack_size
        if (self.num_slices //
                self.stack_size) * self.stack_size != self.num_slices:
            if verbose:
                print("# Input stack size does not divide number of slices.")
            self.stack_size = update_stack(self.stack_size, self.num_slices,
                                           verbose)
        if self.stack_size > trial.stack_size:
            if verbose:
                print("# Walker stack size differs from that estimated from "
                      "trial density matrix.")
                print("# Be careful. cond(BT)**stack_size: %10.3e." %
                      (trial.cond**self.stack_size))
        self.stack_length = self.num_slices // self.stack_size
        if verbose:
            print("# Walker stack size: {}".format(self.stack_size))

        self.lowrank = walker_opts.get('low_rank', False)
        self.lowrank_thresh = walker_opts.get('low_rank_thresh', 1e-6)
        if verbose:
            print("# Using low rank trick: {}".format(self.lowrank))
        self.stack = PropagatorStack(self.stack_size,
                                     trial.num_slices,
                                     trial.dmat.shape[-1],
                                     dtype,
                                     trial.dmat,
                                     trial.dmat_inv,
                                     diagonal=self.diagonal_trial,
                                     lowrank=self.lowrank,
                                     thresh=self.lowrank_thresh)

        # Initialise all propagators to the trial density matrix.
        self.stack.set_all(trial.dmat)
        self.greens_function_qr_strat(trial)
        self.stack.G = self.G
        self.M0 = numpy.array([
            scipy.linalg.det(self.G[0], check_finite=False),
            scipy.linalg.det(self.G[1], check_finite=False)
        ])
        self.stack.ovlp = numpy.array([1.0 / self.M0[0], 1.0 / self.M0[1]])
        self.ot = 1.0

        # # temporary storage for stacks...
        I = numpy.identity(system.nbasis, dtype=dtype)
        One = numpy.ones(system.nbasis, dtype=dtype)
        self.Tl = numpy.array([I, I])
        self.Ql = numpy.array([I, I])
        self.Dl = numpy.array([One, One])
        self.Tr = numpy.array([I, I])
        self.Qr = numpy.array([I, I])
        self.Dr = numpy.array([One, One])

        self.hybrid_energy = 0.0
        if verbose:
            eloc = self.local_energy(system)
            P = one_rdm_from_G(self.G)
            nav = particle_number(P)
            print("# Initial walker energy: {} {} {}".format(*eloc))
            print("# Initial walker electron number: {}".format(nav))
        # self.buff_names = ['weight', 'G', 'unscaled_weight', 'phase', 'Tl',
        # 'Ql', 'Dl', 'Tr', 'Qr', 'Dr', 'M0']
        self.buff_names, self.buff_size = get_numeric_names(self.__dict__)
Example #6
0
    "sparse": False,
    "integrals": "hamil.h5"
}

system = Generic(inputs=sys_opts)

# trial = OneBody(comm, system, 1.0, 0.05, verbose=True)
mus = numpy.arange(-1, 1)
data = []
dt = 0.05
fci = pd.read_csv('be_fixed_n.out', sep=r'\s+')
for b, n in zip(fci.beta, fci.N):
    trial = OneBody(comm, system, b, dt, options={"nav": n}, verbose=True)
    data.append([
        local_energy(system, trial.P, opt=False)[0].real,
        particle_number(trial.P).real
    ])
pl.plot(fci.beta, zip(*data)[0], label='Match N')
match = zip(*data)[0]
data = []
for b, n in zip(fci.beta, fci.N):
    trial = MeanField(comm, system, b, dt, options={"nav": n}, verbose=True)
    data.append([
        local_energy(system, trial.P, opt=False)[0].real,
        particle_number(trial.P).real
    ])
pl.plot(fci.beta, fci.E, label='FCI')
pl.plot(fci.beta, zip(*data)[0], label='THF', linestyle=':')
data = pd.DataFrame({
    'beta': fci.beta,
    'FCI': fci.E,
Example #7
0
def delta_nav(dm, nav):
    return particle_number(dm) - nav
Example #8
0
def find_chemical_potential(system,
                            rho,
                            beta,
                            num_bins,
                            target,
                            deps=1e-6,
                            max_it=1000,
                            verbose=False):
    # Todo: some sort of generic starting point independent of
    # system/temperature
    dmu1 = dmu2 = 1
    mu1 = -1
    mu2 = 1
    sign = -1 if system._alt_convention else 1
    if verbose:
        print("# Finding chemical potential to match <N> = {:13.8e}".format(
            target))
    while numpy.sign(dmu1) * numpy.sign(dmu2) > 0:
        rho1 = compute_rho(rho, mu1, beta, sign=sign)
        dmat = one_rdm_stable(rho1, num_bins)
        dmu1 = delta_nav(dmat, target)
        rho2 = compute_rho(rho, mu2, beta, sign=sign)
        dmat = one_rdm_stable(rho2, num_bins)
        dmu2 = delta_nav(dmat, target)
        if numpy.sign(dmu1) * numpy.sign(dmu2) < 0:
            if verbose:
                print("# Chemical potential lies within range of [%f,%f]" %
                      (mu1, mu2))
                print("# delta_mu1 = %f, delta_mu2 = %f" %
                      (dmu1.real, dmu2.real))
            break
        else:
            mu1 -= 2
            mu2 += 2
            if verbose:
                print("# Increasing chemical potential search to [%f,%f]" %
                      (mu1, mu2))
    found_mu = False
    if verbose:
        print("# " +
              format_fixed_width_strings(['iteration', 'mu', 'Dmu', '<N>']))
    for i in range(0, max_it):
        mu = 0.5 * (mu1 + mu2)
        rho_mu = compute_rho(rho, mu, beta, sign=sign)
        dmat = one_rdm_stable(rho_mu, num_bins)
        dmu = delta_nav(dmat, target).real
        if verbose:
            out = [i, mu, dmu, particle_number(dmat).real]
            print("# " + format_fixed_width_floats(out))
        if abs(dmu) < deps:
            found_mu = True
            break
        else:
            if dmu * dmu1 > 0:
                mu1 = mu
            elif dmu * dmu2 > 0:
                mu2 = mu
    if found_mu:
        return mu
    else:
        print("# Error chemical potential not found")
        return None