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
from pyscf import lo from pyscf.tools import molden mol = gto.M( atom = ''' C 0.000000000000 1.398696930758 0.000000000000 C 0.000000000000 -1.398696930758 0.000000000000 C 1.211265339156 0.699329968382 0.000000000000 C 1.211265339156 -0.699329968382 0.000000000000 C -1.211265339156 0.699329968382 0.000000000000 C -1.211265339156 -0.699329968382 0.000000000000 H 0.000000000000 2.491406946734 0.000000000000 H 0.000000000000 -2.491406946734 0.000000000000 H 2.157597486829 1.245660462400 0.000000000000 H 2.157597486829 -1.245660462400 0.000000000000 H -2.157597486829 1.245660462400 0.000000000000 H -2.157597486829 -1.245660462400 0.000000000000''', basis = '6-31g') mf = scf.RHF(mol).run() pz_idx = numpy.array([17,20,21,22,23,30,36,41,42,47,48,49])-1 loc_orb = lo.Boys(mol, mf.mo_coeff[:,pz_idx]).kernel() molden.from_mo(mol, 'boys.molden', loc_orb) loc_orb = lo.ER(mol, mf.mo_coeff[:,pz_idx]).kernel() molden.from_mo(mol, 'edmiston.molden', loc_orb) loc_orb = lo.PM(mol, mf.mo_coeff[:,pz_idx]).kernel() molden.from_mo(mol, 'pm.molden', loc_orb)
#!/usr/bin/env python ''' PM localization for PBC systems. It supports gamma point only. ''' import numpy as np from pyscf.pbc import gto from pyscf.pbc import scf from pyscf import lo cell = gto.Cell() cell.atom = ''' C 3.17500000 3.17500000 3.17500000 H 2.54626556 2.54626556 2.54626556 H 3.80373444 3.80373444 2.54626556 H 2.54626556 3.80373444 3.80373444 H 3.80373444 2.54626556 3.80373444 ''' cell.basis = 'sto3g' cell.a = np.eye(3) * 6.35 cell.build() mf = scf.RHF(cell).density_fit().run() lmo = lo.PM(cell, mf.mo_coeff[:, 1:5]).kernel() nk = [1, 1, 1] abs_kpts = cell.make_kpts(nk) kmf = scf.KRHF(cell, abs_kpts).density_fit().run() lmo = lo.PM(cell, kmf.mo_coeff[0][:, 1:5]).kernel()
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 localize(pyscf_mf, loc_type='pm', verbose=0): """ Localize orbitals given a PySCF mean-field object Args: pyscf_mf: PySCF mean field object loc_type (str): localization type; Pipek-Mezey ('pm') or Edmiston-Rudenberg ('er') verbose (int): print level during localization Returns: pyscf_mf: Updated PySCF mean field object with localized orbitals """ # Note: After loading with `load_casfile_to_pyscf()` you can quiet message # by resetting mf.mol, i.e., mf.mol = gto.M(...) # but this assumes you have the *exact* molecular specification on hand. # I've gotten acceptable results by restoring mf.mol this way (usually # followed by calling mf.kernel()). But consistent localization is not a # given (not unique) despite restoring data this way, hence the message. if len(pyscf_mf.mol.atom) == 0: sys.exit("`localize()` requires atom loc. and atomic basis to be" + \ " defined.\n " + \ "It also can be sensitive to the initial guess and MO" + \ " coefficients.\n " + \ "Best to try re-creating the PySCF molecule and doing the" + \ " SCF, rather than\n " + \ "try to load the mean-field object with" + \ " `load_casfile_to_pyscf()`. You can \n " + \ "try to provide the missing information, but consistency" + \ " cannot be guaranteed!") # Split-localize (localize DOCC, SOCC, and virtual separately) docc_idx = np.where(np.isclose(pyscf_mf.mo_occ, 2.))[0] socc_idx = np.where(np.isclose(pyscf_mf.mo_occ, 1.))[0] virt_idx = np.where(np.isclose(pyscf_mf.mo_occ, 0.))[0] # Pipek-Mezey if loc_type.lower() == 'pm': print("Localizing doubly occupied ... ", end="") loc_docc_mo = lo.PM( pyscf_mf.mol, pyscf_mf.mo_coeff[:, docc_idx]).kernel(verbose=verbose) print("singly occupied ... ", end="") loc_socc_mo = lo.PM( pyscf_mf.mol, pyscf_mf.mo_coeff[:, socc_idx]).kernel(verbose=verbose) print("virtual ... ", end="") loc_virt_mo = lo.PM( pyscf_mf.mol, pyscf_mf.mo_coeff[:, virt_idx]).kernel(verbose=verbose) print("DONE") # Edmiston-Rudenberg elif loc_type.lower() == 'er': print("Localizing doubly occupied ... ", end="") loc_docc_mo = lo.ER( pyscf_mf.mol, pyscf_mf.mo_coeff[:, docc_idx]).kernel(verbose=verbose) print("singly occupied ... ", end="") loc_socc_mo = lo.ER( pyscf_mf.mol, pyscf_mf.mo_coeff[:, socc_idx]).kernel(verbose=verbose) print("virtual ... ", end="") loc_virt_mo = lo.ER( pyscf_mf.mol, pyscf_mf.mo_coeff[:, virt_idx]).kernel(verbose=verbose) print("DONE") # overwrite orbitals with localized orbitals pyscf_mf.mo_coeff[:, docc_idx] = loc_docc_mo.copy() pyscf_mf.mo_coeff[:, socc_idx] = loc_socc_mo.copy() pyscf_mf.mo_coeff[:, virt_idx] = loc_virt_mo.copy() return pyscf_mf
def init_pyscf(molecule, charge, spin, basis, orbitals): # {{{ #PYSCF inputs print(" ---------------------------------------------------------") print(" ") print(" Using Pyscf:") print(" ") print(" ---------------------------------------------------------") print(" ") mol = gto.Mole() mol.atom = molecule # this is needed to prevent openblas - openmp clash for some reason # todo: take out lib.num_threads(1) mol.max_memory = 1000 # MB mol.charge = charge mol.spin = spin mol.basis = basis mol.build() #orbitals and electrons n_orb = mol.nao_nr() n_b, n_a = mol.nelec nel = n_a + n_b #SCF mf = scf.RHF(mol).run() #mf = scf.ROHF(mol).run() C = mf.mo_coeff #MO coeffs S = mf.get_ovlp() print(" Orbs1:") print(C) Cl = cp.deepcopy(C) if orbitals == "boys": print("\nUsing Boys localised orbitals:\n") cl_o = lo.Boys(mol, mf.mo_coeff[:, :n_a]).kernel(verbose=4) cl_v = lo.Boys(mol, mf.mo_coeff[:, n_a:]).kernel(verbose=4) Cl = np.column_stack((cl_o, cl_v)) elif orbitals == "pipek": print("\nUsing Pipek-Mezey localised orbitals:\n") cl_o = lo.PM(mol, mf.mo_coeff[:, :n_a]).kernel(verbose=4) cl_v = lo.PM(mol, mf.mo_coeff[:, n_a:]).kernel(verbose=4) Cl = np.column_stack((cl_o, cl_v)) elif orbitals == "edmiston": print("\nUsing Edmiston-Ruedenberg localised orbitals:\n") cl_o = lo.ER(mol, mf.mo_coeff[:, :n_a]).kernel(verbose=4) cl_v = lo.ER(mol, mf.mo_coeff[:, n_a:]).kernel(verbose=4) Cl = np.column_stack((cl_o, cl_v)) # elif orbitals == "svd": # print("\nUsing SVD localised orbitals:\n") # cl_o = cp.deepcopy(mf.mo_coeff[:,:n_a]) # cl_v = cp.deepcopy(mf.mo_coeff[:,n_a:]) # # [U,s,V] = np.linalg.svd(cl_o) # cl_o = cl_o.dot(V.T) # Cl = np.column_stack((cl_o,cl_v)) elif orbitals == "canonical": print("\nUsing Canonical orbitals:\n") pass else: print("Error: Wrong orbital specification:") exit() print(" Overlap:") print(C.T.dot(S).dot(Cl)) # sort by cluster blocks = [[0, 1, 2, 3], [4, 5, 6, 7]] O = Cl[:, :n_a] V = Cl[:, n_a:] [sorted_order, cluster_sizes] = mulliken_clustering(blocks, mol, O) O = O[:, sorted_order] [sorted_order, cluster_sizes] = mulliken_clustering(blocks, mol, V) V = V[:, sorted_order] Cl = np.column_stack((O, V)) C = cp.deepcopy(Cl) # dump orbitals for viewing molden.from_mo(mol, 'orbitals_canon.molden', C) molden.from_mo(mol, 'orbitals_local.molden', Cl) ##READING INTEGRALS FROM PYSCF E_nu = gto.Mole.energy_nuc(mol) T = mol.intor('int1e_kin_sph') V = mol.intor('int1e_nuc_sph') hcore = T + V S = mol.intor('int1e_ovlp_sph') g = mol.intor('int2e_sph') print("\nSystem and Method:") print(mol.atom) print("Basis set :%12s" % (mol.basis)) print("Number of Orbitals :%10i" % (n_orb)) print("Number of electrons :%10i" % (nel)) print("Nuclear Repulsion :%16.10f " % E_nu) print("Electronic SCF energy :%16.10f " % (mf.e_tot - E_nu)) print("SCF Energy :%16.10f" % (mf.e_tot)) print(" AO->MO") g = np.einsum("pqrs,pl->lqrs", g, C) g = np.einsum("lqrs,qm->lmrs", g, C) g = np.einsum("lmrs,rn->lmns", g, C) g = np.einsum("lmns,so->lmno", g, C) h = reduce(np.dot, (C.conj().T, hcore, C)) # #mf = mf.density_fit(auxbasis='weigend') # #mf._eri = None # mcc = cc.UCCSD(mf) # eris = mcc.ao2mo() # eris.g = g # eris.focka = h # eris.fockb = h # # emp2, t1, t2 = mcc.init_amps(eris) # exit() # print(abs(t2).sum() - 4.9318753386922278) # print(emp2 - -0.20401737899811551) # t1, t2 = update_amps(mcc, t1, t2, eris) # print(abs(t1).sum() - 0.046961325647584914) # print(abs(t2).sum() - 5.378260578551683 ) # # # exit() return (n_orb, n_a, n_b, h, g, mol, E_nu, mf.e_tot, C, S)
mol = gto.M( atom=open('Ru_ph_ph_ph.xyz').read(), unit='ang', basis='STO3G', charge=2, verbose=3, symmetry='C1', max_memory=13000, ) mf = mol.HF().run() # split localizing by Pipek-Mezey if len(sys.argv) == 2 and sys.argv[1] == 'localized': print("Using PM localized orbitals") C = np.hstack((lo.PM(mol, mf.mo_coeff[:, mf.mo_occ > 0]).kernel(), lo.PM(mol, mf.mo_coeff[:, mf.mo_occ == 0]).kernel())) else: print("Using RHF orbitals") C = mf.mo_coeff tree = t3ns.T3NS(mol, c=C, network='T3NS') tree.kernel(D=50, doci=True, max_sweeps=10, verbosity=2) tree.disentangle() tree.kernel(D=50, doci=True, max_sweeps=10, verbosity=2) E = tree.kernel(D=100, doci=True, max_sweeps=100, energy_conv=1e-5,
cell.pseudo = 'gth-pade' cell.verbose = 5 cell.build(unit='Angstrom') mf = scf.RHF(cell) mf.kernel() ''' generates IAOs ''' mo_occ = mf.mo_coeff[:, mf.mo_occ > 0] #a = lo.iao.iao(cell, mo_occ, minao='minao') #a = lo.iao.iao(cell, mo_occ, minao='gth-szv') a = iao.iao(cell, mo_occ, minao='gth-szv', scf_basis=True, ref_basis='gth-szv') # scf basis print "IAO shape: ", a.shape molden.from_mo(cell, 'diamondiao_szv.molden', a) # Orthogonalize IAO a = lo.vec_lowdin(a, mf.get_ovlp()) molden.from_mo(cell, 'diamondiao_szv_ortho.molden', a) loc_obj = lo.PM(cell, a) cost_before = loc_obj.cost_function() print "cost function before localization: ", cost_before loc_orb = loc_obj.kernel() molden.from_mo(cell, 'diamondiao_szv_PM.molden', loc_orb) #ibo must take the orthonormalized IAOs #ibo = lo.ibo.ibo(cell, mo_occ, a) #print "IBO shape: ", ibo.shape #molden.from_mo(cell, 'diamondibo_szv_ibo.molden', ibo)
mycas = mcscf.CASSCF(mf, 6, 6) # Be careful with the keyword argument "base". By default sort_mo function takes # the 1-based indices. The return indices of .argsort() method above are 0-based cas_orbs = mycas.sort_mo(cas_list, mf.mo_coeff, base=0) mycas.kernel(cas_orbs) # # Localized orbitals are often used as the initial guess of CASSCF method. # When localizing SCF orbitals, it's better to call the localization twice to # obtain the localized orbitals for occupied space and virtual space # separately. This split localization scheme can ensure that the initial core # determinant sits inside the HF occupied space. # nocc = mol.nelectron // 2 loc1 = lo.PM(mol, mf.mo_coeff[:, :nocc]).kernel() loc2 = lo.PM(mol, mf.mo_coeff[:, nocc:]).kernel() loc_orbs = numpy.hstack((loc1, loc2)) pz_pop = mo_mapping.mo_comps('C 2pz', mol, loc_orbs) cas_list = pz_pop.argsort()[-6:] print('cas_list', cas_list) print('pz population for active space orbitals', pz_pop[cas_list]) # # Symmetry was enabled in this molecule. By default, symmetry-adapted CASSCF # algorithm will be called for molecule with symmetry. However, the orbital # localization above breaks the orbital spatial symmetry. If proceeding the # symmetry-adapted CASSCF calculation, the program may complain that the # CASSCF initial guess is not symmetrized after certain attempts of orbital # symmetrization. The simplest operation for this problem is to mute the # spatial symmetry of the molecule.