Exemple #1
0
def dpH2(x, pgrad, node_coords, gradient, wf):
    """Variance dpH^2 across a node"""
    coords = OpenConfigs(gradient * x + node_coords)
    val = wf.recompute(coords)
    d = pgrad(coords, wf)
    dpH2 = np.array(d['dpH'])[:, 0, 0]**2 * np.exp(2 * val[1])
    return dpH2
Exemple #2
0
def test():
    # Default multi-Slater wave function
    mol = gto.M(atom="Li 0. 0. 0.; H 0. 0. 1.5",
                basis="cc-pvtz",
                unit="bohr",
                spin=0)
    mf = scf.RHF(mol).run()
    mc = mcscf.CASCI(mf, ncas=2, nelecas=(1, 1))
    mc.kernel()

    wf, to_opt = default_msj(mol, mf, mc)
    old_parms = wf.parameters
    lt = LinearTransform(wf.parameters, to_opt)

    # Test serialize parameters
    x0 = lt.serialize_parameters(wf.parameters)
    x0 += np.random.normal(size=x0.shape)
    wf.parameters = lt.deserialize(x0)
    assert wf.parameters["wf1det_coeff"][0] == old_parms["wf1det_coeff"][0]
    assert np.sum(wf.parameters["wf2bcoeff"][0] -
                  old_parms["wf2bcoeff"][0]) == 0

    # Test serialize gradients
    configs = OpenConfigs(np.random.randn(10, 4, 3))
    wf.recompute(configs)
    pgrad = wf.pgradient()
    pgrad_serial = lt.serialize_gradients(pgrad)
    assert np.sum(pgrad_serial[:, :3] - pgrad["wf1det_coeff"][:, 1:4]) == 0
Exemple #3
0
def locatenode(df, scale):
  """
  Pinpoint a node, scale variable scales wf value
  so that minimization algorithm can converge
  """

  from scipy.optimize import minimize_scalar
  mol, wf, to_opt, freeze = wavefunction() 
  
  ind = np.argsort(-df['dpH'].values)
  node_coords_0 = np.array(df.iloc[ind[0]]['configs']) #Pretty close!

  #Get the gradient
  def wfgrad(coords, wf, mol):
    nelec = mol.nelec[0] + mol.nelec[1]
    val = wf.recompute(coords)
    grad = []
    for e in range(nelec):
      node_grad = wf.gradient(e, coords.electron(e)) * np.exp(val[1]) * val[0]
      grad.append(node_grad)
    grad = np.array(grad)
    grad /= np.linalg.norm(grad.ravel())
    return np.rollaxis(grad, -1) 

  #Value function along that gradient
  def wvfal(x, wf, gradient):
      node_coords = OpenConfigs(node_coords_0 + gradient * x)
      val = wf.recompute(node_coords)
      return np.exp(2 * val[1])/scale #Scaling for minimization 

  #Minimize function 
  node_coords = node_coords_0

  for i in range(1):
    val = wf.recompute(OpenConfigs(node_coords))
    grad = wfgrad(OpenConfigs(node_coords), wf, mol)
    print("Wfval: ", np.exp(val[1])*val[0])

    res = minimize_scalar(lambda x: wvfal(x, wf, grad), bracket = [-0.1, 0.1], tol = 1e-16)
    print("x: ",res.x)

    #Upgrade gradient
    node_coords += grad * res.x[0]
    val = wf.recompute(OpenConfigs(node_coords))
    print("Wfval post: ", np.exp(val[1])*val[0])

  return node_coords, grad
Exemple #4
0
def test():
    """ Ensure that DMC obtains the exact result for a hydrogen atom """
    from pyscf import lib, gto, scf
    from pyqmc.slater import PySCFSlater
    from pyqmc.jastrowspin import JastrowSpin
    from pyqmc.dmc import limdrift, rundmc
    from pyqmc.mc import vmc
    from pyqmc.accumulators import EnergyAccumulator
    from pyqmc.func3d import CutoffCuspFunction
    from pyqmc.multiplywf import MultiplyWF
    from pyqmc.coord import OpenConfigs
    import pandas as pd

    mol = gto.M(atom="H 0. 0. 0.", basis="sto-3g", unit="bohr", spin=1)
    mf = scf.UHF(mol).run()
    nconf = 1000
    configs = OpenConfigs(np.random.randn(nconf, 1, 3))
    wf1 = PySCFSlater(mol, mf)
    wf = wf1
    wf2 = JastrowSpin(mol, a_basis=[CutoffCuspFunction(5, 0.2)], b_basis=[])
    wf2.parameters["acoeff"] = np.asarray([[[1.0, 0]]])
    wf = MultiplyWF(wf1, wf2)

    dfvmc, configs_ = vmc(
        wf, configs, nsteps=50, accumulators={"energy": EnergyAccumulator(mol)}
    )
    dfvmc = pd.DataFrame(dfvmc)
    print(
        "vmc energy",
        np.mean(dfvmc["energytotal"]),
        np.std(dfvmc["energytotal"]) / np.sqrt(len(dfvmc)),
    )

    warmup = 200
    branchtime = 5
    dfdmc, configs_, weights_ = rundmc(
        wf,
        configs,
        nsteps=4000 + warmup * branchtime,
        branchtime=branchtime,
        accumulators={"energy": EnergyAccumulator(mol)},
        ekey=("energy", "total"),
        tstep=0.01,
        drift_limiter=limdrift,
        verbose=True,
    )

    dfdmc = pd.DataFrame(dfdmc)
    dfdmc.sort_values("step", inplace=True)

    dfprod = dfdmc[dfdmc.step >= warmup]

    rb_summary = reblock.reblock_summary(dfprod[["energytotal", "energyei"]], 20)
    print(rb_summary)
    energy, err = [rb_summary[v]["energytotal"] for v in ("mean", "standard error")]
    assert (
        np.abs(energy + 0.5) < 5 * err
    ), "energy not within {0} of -0.5: energy {1}".format(5 * err, np.mean(energy))
Exemple #5
0
def initial_guess(mol, nconfig, r=1.0):
    """ Generate an initial guess by distributing electrons near atoms
    proportional to their charge.

    Args: 

     mol: A PySCF-like molecule object. Should have atom_charges(), atom_coords(), and nelec

     nconfig: How many configurations to generate.

     r: How far from the atoms to distribute the electrons

    Returns: 

     A numpy array with shape (nconfig,nelectrons,3) with the electrons randomly distributed near 
     the atoms.
    
    """
    from pyqmc.coord import OpenConfigs, PeriodicConfigs

    nelec = np.sum(mol.nelec)
    epos = np.zeros((nconfig, nelec, 3))
    wts = mol.atom_charges()
    wts = wts / np.sum(wts)

    # assign electrons to atoms based on atom charges
    # assign the minimum number first, and assign the leftover ones randomly
    # this algorithm chooses atoms *with replacement* to assign leftover electrons

    for s in [0, 1]:
        neach = np.array(np.floor(mol.nelec[s] * wts),
                         dtype=int)  # integer number of elec on each atom
        nleft = (mol.nelec[s] * wts - neach
                 )  # fraction of electron unassigned on each atom
        nassigned = np.sum(neach)  # number of electrons assigned
        totleft = int(mol.nelec[s] -
                      nassigned)  # number of electrons not yet assigned
        if totleft > 0:
            bins = np.cumsum(nleft) / totleft
            inds = np.argpartition(np.random.random((nconfig, len(wts))),
                                   totleft,
                                   axis=1)[:, :totleft]
            ind0 = s * mol.nelec[0]
            epos[:, ind0:ind0 + nassigned, :] = np.repeat(
                mol.atom_coords(), neach,
                axis=0)[np.newaxis]  # assign core electrons
            epos[:,
                 ind0 + nassigned:ind0 + mol.nelec[s], :] = mol.atom_coords()[
                     inds]  # assign remaining electrons

    epos += r * np.random.randn(
        *epos.shape)  # random shifts from atom positions
    if hasattr(mol, "a"):
        epos = PeriodicConfigs(epos, mol.a)
    else:
        epos = OpenConfigs(epos)
    return epos
Exemple #6
0
def dpH(x, pgrad, pgrad_bare, node_coords, gradient, wf):
    """Bias of dpH across a node"""
    coords = OpenConfigs(gradient * x + node_coords)
    val = wf.recompute(coords)
    d = pgrad(coords, wf)
    dpH = np.array(d['dpH'])[:, 0, 0]

    d_bare = pgrad_bare(coords, wf)
    dpH_bare = np.array(d_bare['dpH'])[:, 0]

    return (dpH - dpH_bare) * np.exp(2 * val[1])
Exemple #7
0
def viznode(node_coords, node_grad, cutoffs, vizfile='viznode.pdf'):
    from wavefunction import wavefunction
    mol, wf, to_opt, freeze = wavefunction()
    eacc = EnergyAccumulator(mol)
    transform = LinearTransform(wf.parameters, to_opt, freeze)

    #Generate the distances we want
    x = np.arange(np.sqrt(1 / 0.01), 1001)
    x = 1. / x**2
    x = np.append(x, np.linspace(0.01, 0.12, 100))
    x = np.append(x, np.array([0, 1e-15, 1e-12, 1e-8] + [-y for y in x]))
    x = np.sort(x)

    coord_path = np.einsum('ij,l->lij', node_grad[0], x) + node_coords[0]
    coord_path = OpenConfigs(coord_path)

    #Move across the node in this path
    val = wf.recompute(coord_path)
    fig, ax = plt.subplots(nrows=2, ncols=1, figsize=(3, 6), sharex=True)
    for k, cutoff in enumerate([1e-8] + cutoffs):
        pgrad = PGradTransform_new(eacc,
                                   transform,
                                   nodal_cutoff=np.array([cutoff]))
        d = pgrad(coord_path, wf)

        total = d['total']
        dpH = np.array(d['dpH'])[:, 0, 0]

        if (cutoff == 1e-8):
            ax[0].plot(x,
                       dpH * (val[0] * np.exp(val[1]))**2,
                       'k-',
                       label=r'$10^{' + str(int(np.log10(cutoff))) + '}$')
            ax[1].plot(x, np.log10(dpH**2 * (val[0] * np.exp(val[1]))**2),
                       'k-')
        else:
            ax[0].plot(x,
                       dpH * (val[0] * np.exp(val[1]))**2,
                       '-',
                       label=r'$10^{' + str(int(np.log10(cutoff))) + '}$')
            ax[1].plot(x, np.log10(dpH**2 * (val[0] * np.exp(val[1]))**2), '-')

    ax[0].set_ylabel(r'$E_L\frac{\partial_p \Psi}{\Psi} f_\epsilon |\Psi|^2$')
    ax[1].set_ylabel(
        r'log$_{10}((E_L\frac{\partial_p \Psi}{\Psi})^2 f_\epsilon^2|\Psi|^2)$'
    )
    ax[1].set_xlabel(r'$l$ (Bohr)')
    ax[0].set_xlim((-max(x) - 0.02, max(x) + 0.02))
    ax[1].set_xlim((-max(x) - 0.02, max(x) + 0.02))
    ax[0].legend(loc='best', title=r'$\epsilon$ (Bohr)')
    plt.savefig(vizfile, bbox_inches='tight')
    plt.close()
Exemple #8
0
def collectconfigs(n, dump_file):
    """
  Collect all the configurations from genconfig
  into a single place
  """
    dpH_total = []
    weight_total = []
    logweight_total = []
    distance_squared = []

    mol, wf, to_opt, freeze = wavefunction()

    eacc = EnergyAccumulator(mol)
    transform = LinearTransform(wf.parameters, to_opt, freeze)
    pgrad_bare = PGradTransform_new(eacc, transform, 1e-20)

    for i in range(1, n + 1):
        print(i)
        coords = OpenConfigs(pd.read_pickle('vmc/coords' + str(i) + '.pickle'))
        df = pd.read_json('vmc/evals' + str(i) + '.json')

        wf.recompute(coords)
        print("Recomputed")
        node_cut, r2 = pgrad_bare._node_cut(coords, wf)
        print("nodes cut")

        dpH = df['dpH'].values
        wfval = df['wfval'].values
        wfpval = df['wfpval'].values

        logweight = 2 * (wfval - wfpval)
        weight = np.exp(logweight)
        print(i, weight[weight == 0])

        dpH_total += list(dpH)
        weight_total += list(weight)
        logweight_total += list(logweight)
        distance_squared += list(r2)
        print(i, np.array(weight_total)[np.array(weight_total) == 0])

        df = pd.DataFrame({
            'dpH': dpH_total,
            'weight_total': weight_total,
            'logweight_total': logweight_total,
            'distance_squared': distance_squared
        })
        df.to_pickle(dump_file)
    return df
Exemple #9
0
def sweepelectron():
  """
  Sweep an electron across the molecule
  to find a guess for the nodal position
  """
  import copy 
  from pyqmc.accumulators import EnergyAccumulator, LinearTransform, PGradTransform
  
  #Generate wave function and bare parameter gradient objects
  mol, wf, to_opt, freeze = wavefunction() 
  eacc = EnergyAccumulator(mol)
  transform = LinearTransform(wf.parameters, to_opt, freeze)
  pgrad = PGradTransform(eacc, transform, 1e-20)

  #Initial coords
  configs = pyqmc.initial_guess(mol, 1).configs[:,:,:]

  #Sweep electron 0
  full_df = None
  e = 3 #electron
  dim = 1 #Coordinate to vary
  
  for i in np.linspace(0, 20, 200):
    new_configs = copy.deepcopy(configs)
    new_configs[:,e,dim] += i
    shifted_configs = OpenConfigs(new_configs)
    wfval = wf.recompute(shifted_configs)
    d = pgrad(shifted_configs, wf)
    small_df = pd.DataFrame({
      'ke':[d['ke'][0]],
      'total':[d['total'][0]],
      'dppsi':[d['dppsi'][0][0]],
      'dpH'  :[d['dpH'][0][0]],
      'wfval':[wfval[0][0]*np.exp(wfval[1][0])],
      'ycoord': i,
      'configs':[copy.deepcopy(new_configs)],
    })
    if(full_df is None): full_df = small_df
    else: full_df = pd.concat((full_df, small_df), axis=0)
  
  return full_df.reset_index()
Exemple #10
0
def psi2(x, node_coords, gradient, wf):
    """Wavefunction squared across the node"""
    coords = OpenConfigs(gradient * x + node_coords)
    val = wf.recompute(coords)
    return np.exp(val[1] * 2)
Exemple #11
0
 def wvfal(x, wf, gradient):
     node_coords = OpenConfigs(node_coords_0 + gradient * x)
     val = wf.recompute(node_coords)
     return np.exp(2 * val[1])/scale #Scaling for minimization 
Exemple #12
0
    import pyqmc
    from pyqmc.slateruhf import PySCFSlaterUHF

    # from pyqmc.jastrow import Jastrow2B
    from pyqmc.coord import OpenConfigs
    import time
    import pandas as pd

    mol = gto.M(atom="Li 0. 0. 0.; Li 0. 0. 1.5", basis="cc-pvtz", unit="bohr")
    mf = scf.UHF(mol).run()
    wf = PySCFSlaterUHF(mol, mf)

    # wf=Jastrow2B(10,mol)
    df = []
    for i in range(5):
        configs = OpenConfigs(np.random.randn(18000, np.sum(mol.nelec), 3))
        res = test_wf_gradient_laplacian(wf, configs)
        for d in res:
            d.update({"step": i})
        df.extend(res)
    print("testing gradient: errors\n", pd.DataFrame(df))
    quit()
    for i in range(5):
        configs = OpenConfigs(np.random.randn(10, np.sum(mol.nelec), 3))
        print("testing gradient: errors",
              test_wf_gradient(wf, configs, delta=1e-5))
    for i in range(5):
        configs = OpenConfigs(np.random.randn(10, np.sum(mol.nelec), 3))
        print("testing laplacian: errors",
              test_wf_laplacian(wf, configs, delta=1e-5))
Exemple #13
0
import numpy as np
from pyscf import lib, gto, scf
import pyqmc
from pyqmc.slateruhf import PySCFSlaterUHF
from pyqmc.jastrowspin import JastrowSpin
# from pyqmc.jastrow import Jastrow2B
from pyqmc.coord import OpenConfigs
import time
from pyqmc.manybody_jastrow import J3
import pyqmc.testwf as test
from pyqmc.wf import WaveFunction
from pyqmc.multiplywf import MultiplyWF
# import pandas as pd

mol = gto.M(atom="Li 0. 0. 0.; Li 0. 0. 1.5", basis="sto-3g", unit="bohr")
mf = scf.UHF(mol).run()
wf1 = PySCFSlaterUHF(mol, mf)
wf2 = JastrowSpin(mol)
# wf3 = J3(mol)
wf = WaveFunction([wf1, wf2])
wfmultiply = MultiplyWF(wf1, wf2)
configs = OpenConfigs(np.random.randn(10, np.sum(mol.nelec), 3))
wf.recompute(configs)
# res = test.test_wf_gradient(wf, configs)
e = 2
epos = configs.electron(e)
test.test_mask(wf, 3, epos)