HOWTOs¶
Periodic systems¶
def run_si_scf(chkfile="si_scf.chk", a=5.43):
cell = gto.Cell(
atom="Si 0. 0. 0.; Si {0} {0} {0}".format(a / 4),
unit="angstrom",
basis="ccecp-ccpvtz",
ecp="ccecp",
a=(np.ones((3, 3)) - np.eye(3)) * a / 2,
)
cell.exp_to_discard = 0.1
cell.build()
kpts = cell.make_kpts([8, 8, 8])
mf = scf.KRKS(cell, kpts=kpts)
mf.chkfile = chkfile
mf.run()
Run QMC on n_conventional conventional unit cells of silicon.
import pyqmc.recipes
import numpy as np
def run_si_qmc(chkfile="si_scf.chk", n_conventional=2):
# Define periodic supercell in PyQMC
conventional_S = np.ones((3, 3)) - 2 * np.eye(3)
S = n_conventional * conventional_S
pyqmc.recipes.OPTIMIZE(chkfile, "si_opt.chk", S=S)
pyqmc.recipes.DMC(chkfile, "si_dmc.chk", load_parameters="si_opt.chk", S=S)
Orbital optimization¶
pyqmc.recipes.OPTIMIZE(chkfile, "opt.chk",slater_kws={'optimize_orbitals':True,'optimize_zeros':False})
Selected CI wave function¶
Most of the effort is in setting up and saving the CI coefficients correctly, which is done in run_hci() here.
You can copy run_hci() and use it on any system.
import pyqmc
import pyscf
import pyscf.hci
import pyqmc.recipes
import numpy as np
from pyscf import gto, scf
def run_mf(chkfile):
mol = gto.M(
atom="""
O 0.0000000, 0.000000, 0.00000000
H 0.761561 , 0.478993, 0.00000000
H -0.761561, 0.478993, 0.00000000""",
basis="ccecp-ccpvdz",
ecp={"O": "ccecp"},
)
mf = scf.RHF(mol)
mf.chkfile = chkfile
mf.run()
def run_hci(hf_chkfile, chkfile, select_cutoff=0.1, nroots=4):
mol, mf = pyqmc.recover_pyscf(hf_chkfile, cancel_outputs=False)
cisolver = pyscf.hci.SCI(mol)
cisolver.select_cutoff=select_cutoff
cisolver.nroots=nroots
nmo = mf.mo_coeff.shape[1]
nelec = mol.nelec
h1 = mf.mo_coeff.T.dot(mf.get_hcore()).dot(mf.mo_coeff)
h2 = pyscf.ao2mo.full(mol, mf.mo_coeff)
e, civec = cisolver.kernel(h1, h2, nmo, nelec)
pyscf.lib.chkfile.save(chkfile,'ci',
{'ci':np.array(civec),
'nmo':nmo,
'nelec':nelec,
'_strs':cisolver._strs,
'select_cutoff':select_cutoff,
'energy':e+mol.energy_nuc(),
})
if __name__=="__main__":
run_mf("mf.chk")
run_hci("mf.chk","hci.chk")
pyqmc.recipes.OPTIMIZE("mf.chk", "opt.chk", ci_checkfile="hci.chk", nconfig=1000)
MPI parallelization¶
You must put the execution in an if __name__=="__main__" block; otherwise mpi4py will not work.
from mpi4py.futures import MPIPoolExecutor
import mpi4py.MPI
import pyqmc.recipes
if __name__=="__main__":
comm = mpi4py.MPI.COMM_WORLD
npartitions= comm.Get_size()-1
with MPIPoolExecutor(max_workers=npartitions) as client:
pyqmc.recipes.OPTIMIZE("h2o.hdf5", "h2o_opt_mpi.hdf5", client=client, npartitions=npartitions)
One of the MPI ranks gets used as the main thread. So if you want to run it on 2 processors, you can do:
mpiexec -n 3 python -m mpi4py.futures test_mpi.py
Single node parallelization (without MPI)¶
from concurrent.futures import ProcessPoolExecutor
if __name__=="__main__":
npartitions = 2
with ProcessPoolExecutor(max_workers=npartitions) as client:
pyqmc.recipes.OPTIMIZE("h2o.hdf5", "h2o_opt_mpi.hdf5", client=client, npartitions=npartitions)
Define a new accumulator¶
This simple accumulator computes the average x,y, and z position of electrons.
This is done in the __call__ function; configs.configs is a numpy array of [walker, electron, xyz].
Note that if you run in parallel, you must define the class at the global scope.
import numpy as np
class DipoleAccumulator:
def __init__(self):
pass
def __call__(self, configs, wf):
return {'electric_dipole':np.sum(configs.configs,axis=1) }
def shapes(self):
return {"electric_dipole": (3,)}
def avg(self, configs, wf):
d = {}
for k, it in self(configs, wf).items():
d[k] = np.mean(it, axis=0)
return d
def keys(self):
return self.shapes().keys()
import pyqmc.recipes
pyqmc.recipes.VMC("h2o.hdf5", "dipole.hdf5",
start_from="h2o_sj_800.hdf5",
accumulators={'extra_accumulators':{'dipole':DipoleAccumulator()}})
Read in the 1-RDM¶
You should have computed the 1-RDM by setting accumulators={'rdm1':True} in pyqmc.recipes.VMC or DMC.
import pyqmc.obdm
def avg(vec):
nblock = vec.shape[0]
avg = np.mean(vec,axis=0)
std = np.std(vec,axis=0)
return avg, std/np.sqrt(nblock)
with h5py.File("h2o_sj_vmc.hdf5") as f:
warmup=2
en, en_err = avg(f['energytotal'][warmup:,...])
rdm1, rdm1_err=avg(f['rdm1value'][warmup:,...])
rdm1norm, rdm1norm_err = avg(f['rdm1norm'][warmup:,...])
rdm1=pyqmc.obdm.normalize_obdm(rdm1,rdm1norm)
rdm1_err=pyqmc.obdm.normalize_obdm(rdm1_err,rdm1norm)
Compute the density from the 1-RDM¶
mol, mf = pyqmc.recover_pyscf("h2o.hdf5")
import pyscf.tools
ao_rdm1 = np.einsum('pi,ij,qj->pq', mf.mo_coeff, rdm1, mf.mo_coeff.conj())
resolution=0.05
dens=pyscf.tools.cubegen.density(mol, "h2o_sj_density.cube",ao_rdm1,resolution=resolution)
Plot the density from a cube file¶
import ase.io
data = ase.io.cube.read_cube(open("h2o_sj_density.cube"))
print(data.keys())
print(data['data'].shape)
yzplane = data['data'][int(data['data'].shape[0]/2),:,:]
fig = plt.figure(figsize=(8,8))
vmax=np.max(yzplane)
plt.contourf(yzplane,levels=[vmax*x for x in np.logspace(-6,-1,80)], cmap='magma')
plt.xticks([])
plt.yticks([])