def _init_pbc(self, cell, mf, twist): from pyscf.pbc import scf from pyqmc.supercell import get_supercell_kpts # Make sure supercell has attributes S and original_cell for attribute in ["original_cell", "S", "scale"]: if not hasattr(cell, attribute): print('Warning: supercell is missing attribute "%s"' % attribute) print("setting original_cell=supercell and S=np.eye(3)") cell.original_cell = cell cell.S = np.eye(3) cell.scale = 1 self.supercell = cell self._cell = cell.original_cell # Define kpts if twist is None: twist = np.zeros(3) else: twist = np.dot(np.linalg.inv(cell.a), np.mod(twist, 1.0)) * 2 * np.pi self.kinds = get_kinds(self._cell, mf, get_supercell_kpts(cell) + twist) self._kpts = mf.kpts[self.kinds] assert len(self.kinds) == len(self._kpts), (self._kpts, mf.kpts) self.nk = len(self._kpts) # Define parameters self.param_split = {} for s, lookup in enumerate(self._coefflookup): mclist = [] for kind in self.kinds: if len(mf.mo_coeff[0][0].shape) == 2: mca = mf.mo_coeff[s][kind][:, np.asarray(mf.mo_occ[s][kind] > 0.9)] else: minocc = (0.9, 1.1)[s] mca = mf.mo_coeff[kind][:, np.asarray(mf.mo_occ[kind] > minocc)] mca = np.real_if_close(mca, tol=self.real_tol) mclist.append(mca / np.sqrt(self.nk)) self.param_split[lookup] = np.cumsum([m.shape[1] for m in mclist]) self.parameters[lookup] = np.concatenate(mclist, axis=-1) self.iscomplex = bool(sum(map(np.iscomplexobj, self.parameters.values()))) self.iscomplex = self.iscomplex or np.linalg.norm(self._kpts) > 1e-12 # Define nelec if len(mf.mo_coeff[0][0].shape) == 2: # Then indices are (spin, kpt, basis, mo) self._nelec = [int(np.sum([o[k] for k in self.kinds])) for o in mf.mo_occ] elif len(mf.mo_coeff[0][0].shape) == 1: # Then indices are (kpt, basis, mo) self._nelec = [ int(np.sum([mf.mo_occ[k] > t for k in self.kinds])) for t in (0.9, 1.1) ] else: print("Warning: PySCFSlater not expecting scf object of type", type(mf)) scale = self.supercell.scale self._nelec = [int(np.round(n * scale)) for n in self._cell.nelec] self._nelec = tuple(self._nelec) self.evaluate_orbitals = self._evaluate_orbitals_pbc self.evaluate_mos = self._evaluate_mos_pbc
def from_mean_field(self, cell, mf, twist=None): """ mf is expected to be a KUHF, KRHF, or equivalent DFT objects. Selects occupied orbitals from a given twist If cell is a supercell, will automatically choose the folded k-points that correspond to that twist. """ cell = (cell if hasattr(cell, "original_cell") else get_supercell( cell, np.asarray([[1, 0, 0], [0, 1, 0], [0, 0, 1]]))) if twist is None: twist = np.zeros(3) else: twist = np.dot(np.linalg.inv(cell.a), np.mod(twist, 1.0)) * 2 * np.pi kinds = list( set(get_k_indices(cell, mf, get_supercell_kpts(cell) + twist))) if len(kinds) != cell.scale: raise ValueError( "Did not find the right number of k-points for this supercell") detcoeff = np.array([1.0]) det_map = np.array([[0], [0]]) if len(mf.mo_coeff[0][0].shape) == 2: occup_k = [[[list(np.argwhere(mf.mo_occ[spin][k] > 0.5)[:, 0])] for k in kinds] for spin in [0, 1]] elif len(mf.mo_coeff[0][0].shape) == 1: occup_k = [[[list(np.argwhere(mf.mo_occ[k] > 1.5 - spin)[:, 0])] for k in kinds] for spin in [0, 1]] occup = [[], []] for spin in [0, 1]: count = 0 for occ_k in occup_k[spin]: occup[spin] += [o + count for o in occ_k[0]] count += len(occ_k[0]) kpts = mf.kpts[kinds] if len(mf.mo_coeff[0][0].shape) == 2: mo_coeff = [[ mf.mo_coeff[spin][k][:, occup_k[spin][kinds.index(k)][0]] for k in kinds ] for spin in [0, 1]] elif len(mf.mo_coeff[0][0].shape) == 1: mo_coeff = [[ mf.mo_coeff[k][:, occup_k[spin][kinds.index(k)][0]] for k in kinds ] for spin in [0, 1]] else: raise ValueError("Did not expect an scf object of type", type(mf)) for s in [0, 1]: occup[s] = [occup[s]] return ( detcoeff, occup, det_map, PBCOrbitalEvaluatorKpoints(cell, mo_coeff, kpts), )
def from_mean_field(self, cell, mf, twist=None, determinants=None, tol=None): """ mf is expected to be a KUHF, KRHF, or equivalent DFT objects. Selects occupied orbitals from a given twist If cell is a supercell, will automatically choose the folded k-points that correspond to that twist. """ cell = (cell if hasattr(cell, "original_cell") else supercell.get_supercell( cell, np.asarray([[1, 0, 0], [0, 1, 0], [0, 0, 1]]))) if twist is None: twist = np.zeros(3) else: twist = np.dot(np.linalg.inv(cell.a), np.mod(twist, 1.0)) * 2 * np.pi kinds = list( set( get_k_indices(cell, mf, supercell.get_supercell_kpts(cell) + twist))) if len(kinds) != cell.scale: raise ValueError( f"Found {len(kinds)} k-points but should have found {cell.scale}." ) kpts = mf.kpts[kinds] if determinants is None: determinants = [ (1.0, pyqmc.determinant_tools.create_pbc_determinant(cell, mf, [])) ] mo_coeff, determinants_flat = select_orbitals_kpoints( determinants, mf, kinds) detcoeff, occup, det_map = pyqmc.determinant_tools.create_packed_objects( determinants_flat, format="list", tol=tol) # Check for s, (occ_s, nelec_s) in enumerate(zip(occup, cell.nelec)): for determinant in occ_s: if len(determinant) != nelec_s: raise RuntimeError( f"The number of electrons of spin {s} should be {nelec_s}, but found {len(determinant)} orbital[s]. You may have used a large smearing value.. Please pass your own determinants list. " ) return ( detcoeff, occup, det_map, PBCOrbitalEvaluatorKpoints(cell, mo_coeff, kpts), )
def test_pbc(li_cubic_ccecp): from pyqmc import supercell import scipy mol, mf = li_cubic_ccecp # S = np.ones((3, 3)) - np.eye(3) S = np.identity(3) mol = supercell.get_supercell(mol, S) kpts = supercell.get_supercell_kpts(mol)[:2] kdiffs = mf.kpts[np.newaxis] - kpts[:, np.newaxis] kinds = np.nonzero(np.linalg.norm(kdiffs, axis=-1) < 1e-12)[1] # Lowdin orthogonalized AO basis. # lowdin = lo.orth_ao(mol, "lowdin") loiao = lo.iao.iao(mol.original_cell, mf.mo_coeff, kpts=kpts) occs = [mf.mo_occ[k] for k in kinds] coefs = [mf.mo_coeff[k] for k in kinds] ovlp = mf.get_ovlp()[kinds] lowdin = [lo.vec_lowdin(l, o) for l, o in zip(loiao, ovlp)] lreps = [np.linalg.multi_dot([l.T, o, c]) for l, o, c in zip(lowdin, ovlp, coefs)] # make AO to localized orbital coefficients. mfobdm = [np.einsum("ij,j,kj->ik", l.conj(), o, l) for l, o in zip(lreps, occs)] ### Test OBDM calculation. nconf = 500 nsteps = 100 warmup = 6 wf = Slater(mol, mf) configs = initial_guess(mol, nconf) obdm_dict = dict(mol=mol, orb_coeff=lowdin, kpts=kpts, nsweeps=4, warmup=10) obdm = OBDMAccumulator(**obdm_dict) df, coords = vmc( wf, configs, nsteps=nsteps, accumulators={"obdm": obdm}, # , "obdm_up": obdm_up, "obdm_down": obdm_down}, verbose=True, ) obdm_est = {} for k in ["obdm"]: # , "obdm_up", "obdm_down"]: avg_norm = np.mean(df[k + "norm"][warmup:], axis=0) avg_obdm = np.mean(df[k + "value"][warmup:], axis=0) obdm_est[k] = normalize_obdm(avg_obdm, avg_norm) mfobdm = scipy.linalg.block_diag(*mfobdm) mae = np.mean(np.abs(obdm_est["obdm"] - mfobdm)) assert mae < 0.05, f"mae {mae}"
def from_mean_field(self, cell, mf, twist=None, determinants=None): """ mf is expected to be a KUHF, KRHF, or equivalent DFT objects. Selects occupied orbitals from a given twist If cell is a supercell, will automatically choose the folded k-points that correspond to that twist. """ cell = ( cell if hasattr(cell, "original_cell") else supercell.get_supercell( cell, np.asarray([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) ) ) if twist is None: twist = np.zeros(3) else: twist = np.dot(np.linalg.inv(cell.a), np.mod(twist, 1.0)) * 2 * np.pi kinds = list( set(get_k_indices(cell, mf, supercell.get_supercell_kpts(cell) + twist)) ) if len(kinds) != cell.scale: raise ValueError( f"Found {len(kinds)} k-points but should have found {cell.scale}." ) kpts = mf.kpts[kinds] if determinants is None: determinants = [ (1.0, pyqmc.determinant_tools.create_pbc_determinant(cell, mf, [])) ] mo_coeff, determinants_flat = select_orbitals_kpoints(determinants, mf, kinds) detcoeff, occup, det_map = pyqmc.determinant_tools.create_packed_objects( determinants_flat, format="list" ) return ( detcoeff, occup, det_map, PBCOrbitalEvaluatorKpoints(cell, mo_coeff, kpts), )
def test_pbc(): from pyscf.pbc import gto, scf from pyqmc import supercell import scipy lvecs = (np.ones((3, 3)) - 2 * np.eye(3)) * 2.0 mol = gto.M( atom="H 0. 0. -{0}; H 0. 0. {0}".format(0.7), basis="sto-3g", unit="bohr", verbose=0, a=lvecs, ) mf = scf.KRHF(mol, kpts=mol.make_kpts((2, 2, 2))) mf = mf.run() S = np.ones((3, 3)) - np.eye(3) mol = supercell.get_supercell(mol, S) kpts = supercell.get_supercell_kpts(mol)[:2] kdiffs = mf.kpts[np.newaxis] - kpts[:, np.newaxis] kinds = np.nonzero(np.linalg.norm(kdiffs, axis=-1) < 1e-12)[1] # Lowdin orthogonalized AO basis. # lowdin = lo.orth_ao(mol, "lowdin") loiao = lo.iao.iao(mol.original_cell, mf.mo_coeff, kpts=kpts) occs = [mf.mo_occ[k] for k in kinds] coefs = [mf.mo_coeff[k] for k in kinds] ovlp = mf.get_ovlp()[kinds] lowdin = [lo.vec_lowdin(l, o) for l, o in zip(loiao, ovlp)] lreps = [ np.linalg.multi_dot([l.T, o, c]) for l, o, c in zip(lowdin, ovlp, coefs) ] # make AO to localized orbital coefficients. mfobdm = [ np.einsum("ij,j,kj->ik", l.conj(), o, l) for l, o in zip(lreps, occs) ] ### Test OBDM calculation. nconf = 800 nsteps = 50 warmup = 6 wf = PySCFSlater(mol, mf) configs = initial_guess(mol, nconf) obdm_dict = dict(mol=mol, orb_coeff=lowdin, kpts=kpts, nsweeps=4, warmup=10) obdm = OBDMAccumulator(**obdm_dict) obdm_up = OBDMAccumulator(**obdm_dict, spin=0) obdm_down = OBDMAccumulator(**obdm_dict, spin=1) df, coords = vmc( wf, configs, nsteps=nsteps, accumulators={ "obdm": obdm, "obdm_up": obdm_up, "obdm_down": obdm_down }, verbose=True, ) obdm_est = {} for k in ["obdm", "obdm_up", "obdm_down"]: avg_norm = np.mean(df[k + "norm"][warmup:], axis=0) avg_obdm = np.mean(df[k + "value"][warmup:], axis=0) obdm_est[k] = normalize_obdm(avg_obdm, avg_norm) print("Average OBDM(orb,orb)", obdm_est["obdm"].round(3)) mfobdm = scipy.linalg.block_diag(*mfobdm) print("mf obdm", mfobdm.round(3)) max_abs_err = np.max(np.abs(obdm_est["obdm"] - mfobdm)) assert max_abs_err < 0.05, "max abs err {0}".format(max_abs_err) print(obdm_est["obdm_up"].diagonal().round(3)) print(obdm_est["obdm_down"].diagonal().round(3)) mae = np.mean(np.abs(obdm_est["obdm_up"] + obdm_est["obdm_down"] - mfobdm)) maup = np.mean(np.abs(obdm_est["obdm_up"])) madn = np.mean(np.abs(obdm_est["obdm_down"])) mamf = np.mean(np.abs(mfobdm)) assert mae < 0.05, "mae {0}\n maup {1}\n madn {2}\n mamf {3}".format( mae, maup, madn, mamf)
def __init__(self, supercell, mf, tol=-1, detwt=(1, ), occup=None, map_dets=None, twist=None): """ detwt: list of determinant weights occup: list (spin, det, dict{kind: occupation list}) map_dets: list (spin, ndet) to identify which determinant of each spin to use (e.g. may use the same up-determinant in multiple products) """ for attribute in ["original_cell", "S"]: if not hasattr(supercell, attribute): print('Warning: supercell is missing attribute "%s"' % attribute) print("setting original_cell=supercell and S=np.eye(3)") supercell.original_cell = supercell supercell.S = np.eye(3) assert occup is not None assert len(map_dets[0]) == len(detwt) and len( map_dets[1]) == len(detwt) self.parameters = {"det_coeff": np.array(detwt)} self.tol = tol self.real_tol = 1e4 self._mol = supercell.original_cell self._nelec = tuple( int(sum(len(v) for v in o[0].values())) for o in occup) self.supercell = supercell if twist is None: twist = np.zeros(3) else: twist = np.dot(np.linalg.inv(supercell.a), np.mod(twist, 1.0)) * 2 * np.pi self.kinds = get_kinds(self._mol, mf, get_supercell_kpts(supercell) + twist) self._kpts = mf.kpts[self.kinds] assert len(self.kinds) == len(self._kpts), (self._kpts, mf.kpts) self.nk = len(self._kpts) print("nk", self.nk, self.kinds) maxorb = [{ k: np.amax([np.amax(list(d[k]) + [-1]) for d in o]) + 1 for k in self.kinds } for o in occup] self.param_split = {} self._coefflookup = ("mo_coeff_alpha", "mo_coeff_beta") for s, lookup in enumerate(self._coefflookup): mclist = [] for kind in self.kinds: if len(mf.mo_coeff[0][0].shape) == 2: mca = mf.mo_coeff[s][kind][:, :maxorb[s][kind]] else: mca = mf.mo_coeff[kind][:, :maxorb[s][kind]] mca = np.real_if_close(mca, tol=self.real_tol) mclist.append(mca / np.sqrt(self.nk)) self.param_split[lookup] = np.cumsum([m.shape[1] for m in mclist]) self.parameters[lookup] = np.concatenate(mclist, axis=-1) # _det_occup: Spin, [(Ndet_up_unique, nup), (Ndet_dn_unique, ndn)] self._det_occup = [ np.zeros((len(o), n), dtype=int) for o, n in zip(occup, self._nelec) ] for s, o in enumerate(occup): orb_inds = np.cumsum([0] + [maxorb[s][k] for k in self.kinds[:-1]]) for d, det in enumerate(o): self._det_occup[s][d] = np.concatenate([ np.array(det[k]) + ind for k, ind in zip(self.kinds, orb_inds) ]) self._det_map = np.asarray(map_dets) # Spin, N_det print("det_coeff", self.parameters["det_coeff"]) print("_det_occup\n", self._det_occup) print("_det_map\n", self._det_map) self.iscomplex = bool( sum(map(np.iscomplexobj, self.parameters.values()))) self.iscomplex = self.iscomplex or np.linalg.norm(self._kpts) > 1e-12 self.dtype = complex if self.iscomplex else float if self.iscomplex: self.get_phase = slater.get_complex_phase self.get_wrapphase = slater.get_wrapphase_complex else: self.get_phase = np.sign self.get_wrapphase = slater.get_wrapphase_real