def loc_orbs(mol: gto.Mole, mo_coeff: Tuple[np.ndarray, np.ndarray], \ s: np.ndarray, ref: str, variant: str) -> np.ndarray: """ this function returns a set of localized MOs of a specific variant """ # loop over spins for i, spin_mo in enumerate((mol.alpha, mol.beta)): if variant == 'fb': # foster-boys procedure loc = lo.Boys(mol, mo_coeff[i][:, spin_mo]) loc.conv_tol = LOC_CONV # FB MOs mo_coeff[i][:, spin_mo] = loc.kernel() elif variant == 'pm': # pipek-mezey procedure loc = lo.PM(mol, mo_coeff[i][:, spin_mo]) loc.conv_tol = LOC_CONV # PM MOs mo_coeff[i][:, spin_mo] = loc.kernel() elif 'ibo' in variant: # orthogonalized IAOs iao = lo.iao.iao(mol, mo_coeff[i][:, spin_mo]) iao = lo.vec_lowdin(iao, s) # IBOs mo_coeff[i][:, spin_mo] = lo.ibo.ibo(mol, mo_coeff[i][:, spin_mo], iaos=iao, \ grad_tol = LOC_CONV, exponent=int(variant[-1]), verbose=0) # closed-shell reference if ref == 'restricted' and mol.spin == 0: mo_coeff[i + 1][:, spin_mo] = mo_coeff[i][:, spin_mo] break return mo_coeff
def make_separate_spin_iaos(cell, mf, mos, iao_basis="minao"): """ Make IAOs for up and down MOs separately for all k points. Args: cell (PySCF cell): Cell for the calculation. mf (PySCF UKS or UHF object): Contains the MOs information. mos (array): indices of the MOs to use to make the IAOs. basis (basis): IAO basis desired (in PySCF format). Returns: iaos_all (list): each list entry is np array of IAO orbitals in the basis of cell for a given k point. """ # print("Making combined spin-up and spin-dw IAOs...") ovlp = mf.get_ovlp() coefs = np.array(mf.mo_coeff)[:, :, mos] iaos_up = lo.iao.iao(cell, coefs[0], minao=iao_basis) iaos_up = lo.vec_lowdin(iaos_up, ovlp) iaos_down = lo.iao.iao(cell, coefs[1], minao=iao_basis) iaos_down = lo.vec_lowdin(iaos_down, ovlp) return np.array([iaos_up, iaos_down])
def localizeValence(mf, mo_coeff, method="iao"): if (method == "iao"): return iao.iao(mf.mol, mo_coeff) elif (method == "ibo"): a = iao.iao(mf.mol, mo_coeff) a = lo.vec_lowdin(a, mf.get_ovlp()) return ibo.ibo(mf.mol, mo_coeff, iaos=a) elif (method == "boys"): return boys.Boys(mf.mol).kernel(mo_coeff) elif (method == "er"): return edmiston.ER(mf.mol).kernel(mo_coeff)
def gen_basis(mol, mf, obdm, threshold=1e-2): """From an obdm, use IAOs to generate a minimal atomic basis for a given state """ n = obdm.shape[0] obdm *= n w, v = np.linalg.eig(obdm) keep = np.abs(w) > threshold a = lo.orth_ao(mol, 'lowdin') basis = np.dot(a, v[:, keep]).real iao = lo.iao.iao(mol, basis) iao = lo.vec_lowdin(iao, mf.get_ovlp()) return iao
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 localizeAllElectron(mf, method="lowdin"): if (method == "lowdin"): return fractional_matrix_power(mf.get_ovlp(), -0.5).T elif (method == "pm"): return pipek.PM(mf.mol).kernel(mf.mo_coeff) elif (method == "boys"): return boys.Boys(mf.mol).kernel(mf.mo_coeff) elif (method == "er"): return edmiston.ER(mf.mol).kernel(mf.mo_coeff) elif (method == "iao"): return iao.iao(mf.mol, mf.mo_coeff) elif (method == "ibo"): a = iao.iao(mf.mol, mf.mo_coeff) a = lo.vec_lowdin(a, mf.get_ovlp()) return ibo.ibo(mf.mol, mf.mo_coeff, iaos=a)
def calcIAO(cell, mf, basis, occ): ''' input: cell and scf (PBC SCF) objects from pyscf and basis to calculate IAOs on occ is MOs which IAOs should span output: Calculates 1RDM on orthog atomic orbitals, orthogonalized using Lowdin S^1/2 Returns coefficient matrix for IAOs ''' s = mf.get_ovlp()[0] mo_occ = mf.mo_coeff[0][0][:, occ[0]] mo_occ2 = mf.mo_coeff[1][0][:, occ[1]] mo_occ = np.concatenate((mo_occ, mo_occ2), axis=1) a = lo.iao.iao(cell, mo_occ, minao=basis) a = lo.vec_lowdin(a, s) return a
def make_combined_spin_iaos(cell, mf, mos, iao_basis="minao"): """ Make IAOs for up and down MOs together for all k points. Args: cell (PySCF cell): Cell for the calculation. mf (PySCF UKS or UHF object): Contains the MOs information. mos (array): indices of the MOs to use to make the IAOs. basis (basis): IAO basis desired (in PySCF format). Returns: iaos_all (list): each list entry is np array of IAO orbitals in the basis of cell for a given k point. """ # print("Making combined spin-up and spin-dw IAOs...") ovlp = mf.get_ovlp() # Concatenates the spin-up and the spin-down chosen MOs coefs = np.array(mf.mo_coeff)[ :, :, mos ] # Notice that, unlike the KUHF case, here we do not need to transpose the matrix coefs = np.concatenate([coefs[0].T, coefs[1].T]).T iaos = lo.iao.iao(cell, coefs, minao=iao_basis) iaos = lo.vec_lowdin(iaos, ovlp) return np.array([iaos, iaos])
def make_minao_lo(ks, minao_ref): """ Construct minao local orbitals. """ cell = ks.cell nao = cell.nao_nr() kpts = ks.kpts nkpts = len(kpts) ovlp = ks.get_ovlp() C_ao_minao, labels = proj_ref_ao(cell, minao=minao_ref, kpts=kpts, return_labels=True) for k in range(nkpts): C_ao_minao[k] = lo.vec_lowdin(C_ao_minao[k], ovlp[k]) labels = np.asarray(labels) C_ao_lo = np.zeros((nkpts, nao, nao), dtype=np.complex128) for idx, lab in zip(ks.U_idx, ks.U_lab): idx_minao = [i for i, l in enumerate(labels) if l in lab] assert len(idx_minao) == len(idx) C_ao_sub = C_ao_minao[:, :, idx_minao] C_ao_lo[:, :, idx] = C_ao_sub return C_ao_lo
cell.build() cell.rcut *= 2 print("running intial DFT calc to generate IAOs") mf = dft.RKS(cell) mf.chkfile = 'graphene.chk' mf.init_guess = 'chkfile' mf.xc = 'pbe,pbe' mf.kernel() #we need to makVe the IAOs out of a converged calculation print("generating IAOs") mo_occ = mf.mo_coeff[:, mf.mo_occ > 0] a = lo.iao.iao(cell, mo_occ) # Orthogonalize IAO a = lo.vec_lowdin(a, mf.get_ovlp()) #arbitrary parameters offset = 0.0001 orbital = 4 print("running constrained dft") mf = cdft(mf, mf.cell, offset, orbital, basis=a) population = fast_iao_mullikan_pop(mf, a=a) result = numpy.zeros(3) result[0] = offset result[1] = mf.e_tot result[2] = population[0][4]
scaled_kpts = cell.get_scaled_kpts(abs_kpts) kmf = pscf.KRHF(cell, abs_kpts).density_fit() gdf = df.GDF(cell, abs_kpts) kmf.with_df = gdf kmf.checkfile = './ch4.chk' kmf.verbose = 5 #kmf = pscf.KRHF(cell, abs_kpts) #kmf.__dict__.update(scf.chkfile.load('ch4.chk', 'scf')) # test ekpt = kmf.run() kmf_sc = k2gamma(kmf, abs_kpts, kmesh, realize = False, tol_deg = 5e-5, real_split = False) c_g_ao = kmf_sc.mo_coeff[0] print "Supercell gamma MO in AO basis from conversion:" print c_g_ao mo_coeff_occ = kmf_sc.mo_coeff[0][:,kmf_sc.mo_occ[0]>0] lo_iao = lo.iao.iao(kmf_sc.cell, mo_coeff_occ) # Orthogonalize IAO lo_iao = lo.vec_lowdin(lo_iao, kmf_sc.get_ovlp()[0]) # transform mo_occ to IAO representation. Note the AO dimension is reduced mo_coeff_occ = reduce(np.dot, (lo_iao.conj().T, kmf_sc.get_ovlp()[0], mo_coeff_occ)) dm = np.dot(mo_coeff_occ, mo_coeff_occ.conj().T) * 2 pmol = kmf_sc.cell.copy() pmol.build(False, False, basis='minao') kmf_sc.mulliken_pop(pmol, dm, s=np.eye(pmol.nao_nr()))
cell.build() cell.rcut*=2 print("running intial DFT calc to generate IAOs") mf = dft.RKS(cell) mf.chkfile = 'graphene.chk' mf.init_guess = 'chkfile' mf.xc = 'pbe,pbe' mf.kernel() #we need to makVe the IAOs out of a converged calculation print("generating IAOs") mo_occ = mf.mo_coeff[:,mf.mo_occ>0] a = lo.iao.iao(cell, mo_occ) # Orthogonalize IAO a = lo.vec_lowdin(a, mf.get_ovlp()) #arbitrary parameters offset = 0.0001 orbital =4 print("running constrained dft") mf = cdft(mf,mf.cell,offset,orbital,basis=a) population = fast_iao_mullikan_pop(mf,a=a) result = numpy.zeros(3) result[0] = offset result[1] = mf.e_tot result[2] = population[0][4]
def init(self,molecule,charge,spin,basis_set,orb_basis='scf',cas=False,cas_nstart=None,cas_nstop=None,cas_nel=None,loc_nstart=None,loc_nstop=None, scf_conv_tol=1e-14): # {{{ import pyscf from pyscf import gto, scf, ao2mo, molden, lo pyscf.lib.num_threads(1) #with degenerate states and multiple processors there can be issues #PYSCF inputs print(" ---------------------------------------------------------") print(" Using Pyscf:") print(" ---------------------------------------------------------") print(" ") mol = gto.Mole() mol.atom = molecule mol.max_memory = 1000 # MB mol.symmetry = True mol.charge = charge mol.spin = spin mol.basis = basis_set mol.build() print("symmertry") print(mol.topgroup) #SCF #mf = scf.RHF(mol).run(init_guess='atom') mf = scf.RHF(mol).run(conv_tol=scf_conv_tol) #C = mf.mo_coeff #MO coeffs enu = mf.energy_nuc() print(" SCF Total energy: %12.8f" %mf.e_tot) print(" SCF Elec energy: %12.8f" %(mf.e_tot-enu)) print(mf.get_fock()) print(np.linalg.eig(mf.get_fock())[0]) if mol.symmetry == True: from pyscf import symm mo = symm.symmetrize_orb(mol, mf.mo_coeff) osym = symm.label_orb_symm(mol, mol.irrep_name, mol.symm_orb, mo) #symm.addons.symmetrize_space(mol, mo, s=None, check=True, tol=1e-07) for i in range(len(osym)): print("%4d %8s %16.8f"%(i+1,osym[i],mf.mo_energy[i])) #orbitals and lectrons n_orb = mol.nao_nr() n_b , n_a = mol.nelec nel = n_a + n_b self.n_orb = mol.nao_nr() if cas == True: cas_norb = cas_nstop - cas_nstart from pyscf import mcscf assert(cas_nstart != None) assert(cas_nstop != None) assert(cas_nel != None) else: cas_nstart = 0 cas_nstop = n_orb cas_nel = nel ##AO 2 MO Transformation: orb_basis or scf if orb_basis == 'scf': print("\nUsing Canonical Hartree Fock orbitals...\n") C = cp.deepcopy(mf.mo_coeff) print("C shape") print(C.shape) elif orb_basis == 'lowdin': assert(cas == False) S = mol.intor('int1e_ovlp_sph') print("Using lowdin orthogonalized orbitals") C = lowdin(S) #end elif orb_basis == 'boys': pyscf.lib.num_threads(1) #with degenerate states and multiple processors there can be issues cl_c = mf.mo_coeff[:, :cas_nstart] cl_a = lo.Boys(mol, mf.mo_coeff[:, cas_nstart:cas_nstop]).kernel(verbose=4) cl_v = mf.mo_coeff[:, cas_nstop:] C = np.column_stack((cl_c, cl_a, cl_v)) elif orb_basis == 'boys2': pyscf.lib.num_threads(1) #with degenerate states and multiple processors there can be issues cl_c = mf.mo_coeff[:, :loc_nstart] cl_a = lo.Boys(mol, mf.mo_coeff[:, loc_nstart:loc_nstop]).kernel(verbose=4) cl_v = mf.mo_coeff[:, loc_nstop:] C = np.column_stack((cl_c, cl_a, cl_v)) elif orb_basis == 'PM': pyscf.lib.num_threads(1) #with degenerate states and multiple processors there can be issues cl_c = mf.mo_coeff[:, :cas_nstart] cl_a = lo.PM(mol, mf.mo_coeff[:, cas_nstart:cas_nstop]).kernel(verbose=4) cl_v = mf.mo_coeff[:, cas_nstop:] C = np.column_stack((cl_c, cl_a, cl_v)) elif orb_basis == 'PM2': pyscf.lib.num_threads(1) #with degenerate states and multiple processors there can be issues cl_c = mf.mo_coeff[:, :loc_nstart] cl_a = lo.PM(mol, mf.mo_coeff[:, loc_nstart:loc_nstop]).kernel(verbose=4) cl_v = mf.mo_coeff[:, loc_nstop:] C = np.column_stack((cl_c, cl_a, cl_v)) elif orb_basis == 'ER': pyscf.lib.num_threads(1) #with degenerate states and multiple processors there can be issues cl_c = mf.mo_coeff[:, :cas_nstart] cl_a = lo.PM(mol, mf.mo_coeff[:, cas_nstart:cas_nstop]).kernel(verbose=4) cl_v = mf.mo_coeff[:, cas_nstop:] C = np.column_stack((cl_c, cl_a, cl_v)) elif orb_basis == 'ER2': pyscf.lib.num_threads(1) #with degenerate states and multiple processors there can be issues cl_c = mf.mo_coeff[:, :loc_nstart] cl_a = lo.ER(mol, mf.mo_coeff[:, loc_nstart:loc_nstop]).kernel(verbose=4) cl_v = mf.mo_coeff[:, loc_nstop:] C = np.column_stack((cl_c, cl_a, cl_v)) elif orb_basis == 'ibmo': loc_vstop = loc_nstop - n_a print(loc_vstop) mo_occ = mf.mo_coeff[:,mf.mo_occ>0] mo_vir = mf.mo_coeff[:,mf.mo_occ==0] c_core = mo_occ[:,:loc_nstart] iao_occ = lo.iao.iao(mol, mo_occ[:,loc_nstart:]) iao_vir = lo.iao.iao(mol, mo_vir[:,:loc_vstop]) c_out = mo_vir[:,loc_vstop:] # Orthogonalize IAO iao_occ = lo.vec_lowdin(iao_occ, mf.get_ovlp()) iao_vir = lo.vec_lowdin(iao_vir, mf.get_ovlp()) # # Method 1, using Knizia's alogrithm to localize IAO orbitals # ''' Generate IBOS from orthogonal IAOs ''' ibo_occ = lo.ibo.ibo(mol, mo_occ[:,loc_nstart:], iaos = iao_occ) ibo_vir = lo.ibo.ibo(mol, mo_vir[:,:loc_vstop], iaos = iao_vir) C = np.column_stack((c_core,ibo_occ,ibo_vir,c_out)) else: print("Error:NO orbital basis defined") molden.from_mo(mol, 'orbitals.molden', C) if cas == True: print(C.shape) print(cas_norb) print(cas_nel) mycas = mcscf.CASSCF(mf, cas_norb, cas_nel) h1e_cas, ecore = mycas.get_h1eff(mo_coeff = C) #core core orbs to form ecore and eff h2e_cas = ao2mo.kernel(mol, C[:,cas_nstart:cas_nstop], aosym='s4',compact=False).reshape(4 * ((cas_norb), )) print(h1e_cas) print(h1e_cas.shape) #return h1e_cas,h2e_cas,ecore,C,mol,mf self.h = h1e_cas self.g = h2e_cas self.ecore = ecore self.mf = mf self.mol = mol self.C = cp.deepcopy(C[:,cas_nstart:cas_nstop]) J,K = mf.get_jk() self.J = self.C.T @ J @ self.C self.K = self.C.T @ J @ self.C #HF density if orb_basis == 'scf': #C = C[:,cas_nstart:cas_nstop] D = mf.make_rdm1(mo_coeff=C) S = mf.get_ovlp() sal, svec = np.linalg.eigh(S) idx = sal.argsort()[::-1] sal = sal[idx] svec = svec[:, idx] sal = sal**-0.5 sal = np.diagflat(sal) X = svec @ sal @ svec.T C_ao2mo = np.linalg.inv(X) @ C Cocc = C_ao2mo[:, :n_a] D = Cocc @ Cocc.T DMO = C_ao2mo.T @ D @ C_ao2mo #only for cas space DMO = DMO[cas_nstart:cas_nstop,cas_nstart:cas_nstop] self.dm_aa = DMO self.dm_bb = DMO print("DENSITY") print(self.dm_aa.shape) if 0: h = C.T.dot(mf.get_hcore()).dot(C) g = ao2mo.kernel(mol,C,aosym='s4',compact=False).reshape(4*((n_orb),)) const,heff = get_eff_for_casci(cas_nstart,cas_nstop,h,g) print(heff) print("const",const) print("ecore",ecore) idx = range(cas_nstart,cas_nstop) h = h[:,idx] h = h[idx,:] g = g[:,:,:,idx] g = g[:,:,idx,:] g = g[:,idx,:,:] g = g[idx,:,:,:] self.ecore = const self.h = h + heff self.g = g elif cas==False: h = C.T.dot(mf.get_hcore()).dot(C) g = ao2mo.kernel(mol,C,aosym='s4',compact=False).reshape(4*((n_orb),)) print(h) #return h, g, enu, C,mol,mf self.h = h self.g = g self.ecore = enu self.mf = mf self.mol = mol self.C = C J,K = mf.get_jk() self.J = self.C.T @ J @ self.C self.K = self.C.T @ J @ self.C #HF density if orb_basis == 'scf': D = mf.make_rdm1(mo_coeff=None) S = mf.get_ovlp() sal, svec = np.linalg.eigh(S) idx = sal.argsort()[::-1] sal = sal[idx] svec = svec[:, idx] sal = sal**-0.5 sal = np.diagflat(sal) X = svec @ sal @ svec.T C_ao2mo = np.linalg.inv(X) @ C Cocc = C_ao2mo[:, :n_a] D = Cocc @ Cocc.T DMO = C_ao2mo.T @ D @ C_ao2mo self.dm_aa = DMO self.dm_bb = DMO print("DENSITY") print(self.dm_aa)
def assign_rdm1s(mol: gto.Mole, s: np.ndarray, mo_coeff: Tuple[np.ndarray, np.ndarray], \ mo_occ: np.ndarray, ref: str, pop: str, part: str, multiproc: bool, verbose: int, \ **kwargs: float) -> Tuple[Union[List[np.ndarray], List[List[np.ndarray]]], Union[None, np.ndarray]]: """ this function returns a list of population weights of each spin-orbital on the individual atoms """ # declare nested kernel function in global scope global get_weights # max number of occupied spin-orbs n_spin = max(mol.alpha.size, mol.beta.size) # mol object projected into minao basis if pop == 'iao': pmol = lo.iao.reference_mol(mol) else: pmol = mol # number of atoms natm = pmol.natm # AO labels ao_labels = pmol.ao_labels(fmt=None) # overlap matrix if pop == 'mulliken': ovlp = s else: ovlp = np.eye(pmol.nao_nr()) def get_weights(orb_idx: int): """ this function computes the full set of population weights """ # get orbital orb = mo[:, orb_idx].reshape(mo.shape[0], 1) # orbital-specific rdm1 rdm1_orb = make_rdm1(orb, mocc[orb_idx]) # population weights of rdm1_orb return _population(natm, ao_labels, ovlp, rdm1_orb) # init population weights array weights = [ np.zeros([n_spin, pmol.natm], dtype=np.float64), np.zeros([n_spin, pmol.natm], dtype=np.float64) ] # loop over spin for i, spin_mo in enumerate((mol.alpha, mol.beta)): # get mo coefficients and occupation if pop == 'mulliken': mo = mo_coeff[i][:, spin_mo] elif pop == 'iao': iao = lo.iao.iao(mol, mo_coeff[i][:, spin_mo]) iao = lo.vec_lowdin(iao, s) mo = contract('ki,kl,lj->ij', iao, s, mo_coeff[i][:, spin_mo]) mocc = mo_occ[i][spin_mo] # domain domain = np.arange(spin_mo.size) # execute kernel if multiproc: n_threads = min(domain.size, lib.num_threads()) with mp.Pool(processes=n_threads) as pool: weights[i] = pool.map(get_weights, domain) # type:ignore else: weights[i] = list(map(get_weights, domain)) # type:ignore # closed-shell reference if ref == 'restricted' and mol.spin == 0: weights[i + 1] = weights[i] break # verbose print if 0 < verbose: symbols = [pmol.atom_pure_symbol(i) for i in range(pmol.natm)] print('\n *** partial population weights: ***') print(' spin ' + 'MO ' + ' '.join(['{:}'.format(i) for i in symbols])) for i, spin_mo in enumerate((mol.alpha, mol.beta)): for j in domain: with np.printoptions(suppress=True, linewidth=200, formatter={'float': '{:6.3f}'.format}): print(' {:s} {:>2d} {:}'.format( 'a' if i == 0 else 'b', spin_mo[j], weights[i][j])) # bond-wise partitioning if part == 'bonds': # init population centres array and get threshold centres = [ np.zeros([mol.alpha.size, 2], dtype=np.int), np.zeros([mol.beta.size, 2], dtype=np.int) ] thres = kwargs['thres'] # loop over spin for i, spin_mo in enumerate((mol.alpha, mol.beta)): # loop over orbitals for j in domain: # get sorted indices max_idx = np.argsort(weights[i][j])[::-1] # compute population centres if np.abs(weights[i][j][max_idx[0]]) > thres: # core orbital or lone pair centres[i][j] = np.array([max_idx[0], max_idx[0]], dtype=np.int) else: # valence orbitals centres[i][j] = np.sort( np.array([max_idx[0], max_idx[1]], dtype=np.int)) # closed-shell reference if ref == 'restricted' and mol.spin == 0: centres[i + 1] = centres[i] break # unique and repetitive centres centres_unique = np.array( [np.unique(centres[i], axis=0) for i in range(2)]) rep_idx = [[ np.where((centres[i] == j).all(axis=1))[0] for j in centres_unique[i] ] for i in range(2)] if part in ['atoms', 'eda']: return weights, None else: return rep_idx, centres_unique
def get_localized_orbitals(mf, lo_method, mo=None): if mo is None: mo = mf.mo_coeff if not isinstance(mf, khf.KSCF): mol = mf.mol s1e = mf.get_ovlp() if lo_method.lower() == 'lowdin' or lo_method.lower() == 'meta_lowdin': C = lo.orth_ao(mf, 'meta_lowdin', s=s1e) C_inv = np.dot(C.conj().T, s1e) if isinstance(mf, scf.hf.RHF): C_inv_spin = C_inv else: C_inv_spin = np.array([C_inv] * 2) elif lo_method == 'iao': s1e = mf.get_ovlp() pmol = mf.mol.copy() pmol.build(False, False, basis='minao') if isinstance(mf, scf.hf.RHF): mo_coeff_occ = mf.mo_coeff[:, mf.mo_occ > 0] C = lo.iao.iao(mf.mol, mo_coeff_occ) # Orthogonalize IAO C = lo.vec_lowdin(C, s1e) C_inv = np.dot(C.conj().T, s1e) C_inv_spin = C_inv else: mo_coeff_occ_a = mf.mo_coeff[0][:, mf.mo_occ[0] > 0] mo_coeff_occ_b = mf.mo_coeff[1][:, mf.mo_occ[1] > 0] C_a = lo.iao.iao(mf.mol, mo_coeff_occ_a) C_b = lo.iao.iao(mf.mol, mo_coeff_occ_b) C_a = lo.vec_lowdin(C_a, s1e) C_b = lo.vec_lowdin(C_b, s1e) C_inv_a = np.dot(C_a.T, s1e) C_inv_b = np.dot(C_b.T, s1e) C_inv_spin = np.array([C_inv_a, C_inv_b]) elif lo_method == 'nao': C = lo.orth_ao(mf, 'nao') C_inv = np.dot(C.conj().T, s1e) if isinstance(mf, scf.hf.RHF): C_inv_spin = C_inv else: C_inv_spin = np.array([C_inv] * 2) else: raise NotImplementedError("UNDEFINED LOCAL ORBITAL TYPE, EXIT...") mo_lo = np.einsum('...jk,...kl->...jl', C_inv_spin, mo) return C_inv_spin, mo_lo else: cell = mf.cell s1e = mf.get_ovlp() if lo_method.lower() == 'lowdin' or lo_method.lower() == 'meta_lowdin': nkpt = len(mf.kpts) C_arr = [] C_inv_arr = [] for i in range(nkpt): C_curr = lo.orth_ao(mf, 'meta_lowdin', s=s1e[i]) C_inv_arr.append(np.dot(C_curr.conj().T, s1e[i])) C_inv_arr = np.array(C_inv_arr) if isinstance(mf, scf.hf.RHF): C_inv_spin = C_inv_arr else: C_inv_spin = np.array([C_inv_arr] * 2) else: raise NotImplementedError("CONSTRUCTING...EXIT") mo_lo = np.einsum('...jk,...kl->...jl', C_inv_spin, mo) return C_inv_spin, mo_lo
def setuph2(r, obdm_steps=5): from pyscf import gto, scf, lo from pyqmc.accumulators import LinearTransform, EnergyAccumulator from pyqmc.obdm import OBDMAccumulator from pyqmc.cvmc import DescriptorFromOBDM, PGradDescriptor import itertools # ccECP from A. Annaberdiyev et al. Journal of Chemical Physics 149, 134108 (2018) basis = { "H": gto.basis.parse(""" H S 23.843185 0.00411490 10.212443 0.01046440 4.374164 0.02801110 1.873529 0.07588620 0.802465 0.18210620 0.343709 0.34852140 0.147217 0.37823130 0.063055 0.11642410 """) } """ H S 0.040680 1.00000000 H S 0.139013 1.00000000 H P 0.166430 1.00000000 H P 0.740212 1.00000000 """ ecp = { "H": gto.basis.parse_ecp(""" H nelec 0 H ul 1 21.24359508259891 1.00000000000000 3 21.24359508259891 21.24359508259891 2 21.77696655044365 -10.85192405303825 """) } mol = gto.M(atom=f"H 0. 0. 0.; H 0. 0. {r}", unit="bohr", basis=basis, ecp=ecp, verbose=5) mf = scf.RHF(mol).run() mo_occ = mf.mo_coeff[:, mf.mo_occ > 0] a = lo.iao.iao(mol, mo_occ) a = lo.vec_lowdin(a, mf.get_ovlp()) obdm_up = OBDMAccumulator(mol=mol, orb_coeff=a, nstep=obdm_steps, spin=0) obdm_down = OBDMAccumulator(mol=mol, orb_coeff=a, nstep=obdm_steps, spin=1) wf = pyqmc.slater_jastrow(mol, mf) freeze = {} for k in wf.parameters: freeze[k] = np.zeros(wf.parameters[k].shape, dtype='bool') print(freeze.keys()) print(wf.parameters['wf1mo_coeff_alpha']) #this freezing allows us to easily go between bonding and # AFM configurations. freeze['wf1mo_coeff_alpha'][0, 0] = True freeze['wf1mo_coeff_beta'][1, 0] = True descriptors = { "t": [[(1.0, (0, 1)), (1.0, (1, 0))], [(1.0, (0, 1)), (1.0, (1, 0))]], "trace": [[(1.0, (0, 0)), (1.0, (1, 1))], [(1.0, (0, 0)), (1.0, (1, 1))]], } for i in [0, 1]: descriptors[f"nup{i}"] = [[(1.0, (i, i))], []] descriptors[f"ndown{i}"] = [[], [(1.0, (i, i))]] acc = PGradDescriptor( EnergyAccumulator(mol), LinearTransform(wf.parameters, freeze=freeze), [obdm_up, obdm_down], DescriptorFromOBDM(descriptors, norm=2.0), ) return { "wf": wf, "acc": acc, "mol": mol, "mf": mf, "descriptors": descriptors }
m.__dict__.update(lib.chkfile.load('rohf/Cuvtz_r1.725_s1_ROHF_0.chk', 'scf')) for i in (mol.basis["Cu"]): if (len(cu_basis) < 2): if (i[0] == 0): cu_basis.append(i) elif (len(cu_basis) == 2): if (i[0] == 1): cu_basis.append(i) elif (len(cu_basis) == 3): if (i[0] == 2): cu_basis.append(i) else: pass o_basis = [] for i in (mol.basis["O"]): if (len(o_basis) == 0): if (i[0] == 0): o_basis.append(i) elif (len(o_basis) == 1): if (i[0] == 1): o_basis.append(i) else: pass minbasis = {'Cu': cu_basis, 'O': o_basis} #Build IAOs s = m.get_ovlp() a = lo.iao.iao(mol, mo_coeff, minao=minbasis) a = lo.vec_lowdin(a, s) a.dump('b3lyp_iao_b.pickle') #Plot IAOs m.mo_coeff[:, :a.shape[1]] = a print_qwalk_mol(mol, m, method='scf', basename='qwalk/b3lyp_iao_b')
def test_pbc(): from pyscf.pbc import gto, scf from pyqmc import PySCFSlaterUHF, PySCFSlaterPBC from pyqmc import slaterpbc import scipy lvecs = (np.ones((3, 3)) - 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)) - 2 * np.eye(3) mol = slaterpbc.get_supercell(mol, S) kpts = slaterpbc.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 = PySCFSlaterPBC(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, ) df = DataFrame(df) obdm_est = {} for k in ["obdm", "obdm_up", "obdm_down"]: avg_norm = np.array(df.loc[warmup:, k + "norm"].values.tolist()).mean(axis=0) avg_obdm = np.array(df.loc[warmup:, k + "value"].values.tolist()).mean(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 )