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([]) ```