def aug_etb_for_dfbasis(mol, dfbasis='weigend', beta=2.3, start_at='Rb'): '''augment weigend basis with even tempered gaussian basis exps = alpha*beta^i for i = 1..N ''' nuc_start = gto.mole._charge(start_at) uniq_atoms = set([a[0] for a in mol._atom]) newbasis = {} for symb in uniq_atoms: nuc_charge = gto.mole._charge(symb) if nuc_charge < nuc_start: newbasis[symb] = dfbasis #?elif symb in mol._ecp: else: conf = lib.parameters.ELEMENTS[nuc_charge][2] max_shells = 4 - conf.count(0) emin_by_l = [1e99] * 8 emax_by_l = [0] * 8 for b in mol._basis[symb]: l = b[0] if l >= max_shells + 1: continue if isinstance(b[1], int): e_c = numpy.array(b[2:]) else: e_c = numpy.array(b[1:]) es = e_c[:, 0] cs = e_c[:, 1:] es = es[abs(cs).max(axis=1) > 1e-3] emax_by_l[l] = max(es.max(), emax_by_l[l]) emin_by_l[l] = min(es.min(), emin_by_l[l]) l_max = 8 - emax_by_l.count(0) emin_by_l = numpy.array(emin_by_l[:l_max]) emax_by_l = numpy.array(emax_by_l[:l_max]) # Estimate the exponents ranges by geometric average emax = numpy.sqrt(numpy.einsum('i,j->ij', emax_by_l, emax_by_l)) emin = numpy.sqrt(numpy.einsum('i,j->ij', emin_by_l, emin_by_l)) liljsum = numpy.arange(l_max)[:, None] + numpy.arange(l_max) emax_by_l = [ emax[liljsum == ll].max() for ll in range(l_max * 2 - 1) ] emin_by_l = [ emin[liljsum == ll].min() for ll in range(l_max * 2 - 1) ] # Tune emin and emax emin_by_l = numpy.array( emin_by_l) * 2 # *2 for alpha+alpha on same center emax_by_l = numpy.array( emax_by_l) * 2 #/ (numpy.arange(l_max*2-1)*.5+1) ns = numpy.log( (emax_by_l + emin_by_l) / emin_by_l) / numpy.log(beta) etb = [(l, max(n, 1), emin_by_l[l], beta) for l, n in enumerate(numpy.ceil(ns).astype(int))] newbasis[symb] = gto.expand_etbs(etb) return newbasis
def aug_etb_for_dfbasis(mol, dfbasis=DFBASIS, beta=ETB_BETA, start_at=FIRST_ETB_ELEMENT): '''augment weigend basis with even-tempered gaussian basis exps = alpha*beta^i for i = 1..N ''' nuc_start = gto.charge(start_at) uniq_atoms = set([a[0] for a in mol._atom]) newbasis = {} for symb in uniq_atoms: nuc_charge = gto.charge(symb) if nuc_charge < nuc_start: newbasis[symb] = dfbasis #?elif symb in mol._ecp: else: conf = elements.CONFIGURATION[nuc_charge] max_shells = 4 - conf.count(0) emin_by_l = [1e99] * 8 emax_by_l = [0] * 8 l_max = 0 for b in mol._basis[symb]: l = b[0] l_max = max(l_max, l) if l >= max_shells+1: continue if isinstance(b[1], int): e_c = numpy.array(b[2:]) else: e_c = numpy.array(b[1:]) es = e_c[:,0] cs = e_c[:,1:] es = es[abs(cs).max(axis=1) > 1e-3] emax_by_l[l] = max(es.max(), emax_by_l[l]) emin_by_l[l] = min(es.min(), emin_by_l[l]) l_max1 = l_max + 1 emin_by_l = numpy.array(emin_by_l[:l_max1]) emax_by_l = numpy.array(emax_by_l[:l_max1]) # Estimate the exponents ranges by geometric average emax = numpy.sqrt(numpy.einsum('i,j->ij', emax_by_l, emax_by_l)) emin = numpy.sqrt(numpy.einsum('i,j->ij', emin_by_l, emin_by_l)) liljsum = numpy.arange(l_max1)[:,None] + numpy.arange(l_max1) emax_by_l = [emax[liljsum==ll].max() for ll in range(l_max1*2-1)] emin_by_l = [emin[liljsum==ll].min() for ll in range(l_max1*2-1)] # Tune emin and emax emin_by_l = numpy.array(emin_by_l) * 2 # *2 for alpha+alpha on same center emax_by_l = numpy.array(emax_by_l) * 2 #/ (numpy.arange(l_max1*2-1)*.5+1) ns = numpy.log((emax_by_l+emin_by_l)/emin_by_l) / numpy.log(beta) etb = [] for l, n in enumerate(numpy.ceil(ns).astype(int)): if n > 0: etb.append((l, n, emin_by_l[l], beta)) newbasis[symb] = gto.expand_etbs(etb) return newbasis
def build_nuc_mole(self, atom_index, frac=None): ''' Return a Mole object for specified quantum nuclei. Nuclear basis: H: PB4-D J. Chem. Phys. 152, 244123 (2020) D: scaled PB4-D other atoms: 12s12p12d, alpha=2*sqrt(2)*mass, beta=sqrt(3) ''' nuc = gto.Mole() # a Mole object for quantum nuclei nuc.atom_index = atom_index nuc.super_mol = self dirnow = os.path.realpath(os.path.join(__file__, '..')) if self.atom_symbol(atom_index) == 'H@2': basis = gto.basis.parse(open(os.path.join(dirnow, 'basis/s-pb4d.dat')).read()) elif self.atom_pure_symbol(atom_index) == 'H': basis = gto.basis.parse(open(os.path.join(dirnow, 'basis/pb4d.dat')).read()) #alpha = 2 * numpy.sqrt(2) * self.mass[atom_index] #beta = numpy.sqrt(2) #n = 8 #basis = gto.expand_etbs([(0, n, alpha, beta), (1, n, alpha, beta), (2, n, alpha, beta)]) else: # even-tempered basis alpha = 2 * numpy.sqrt(2) * self.mass[atom_index] beta = numpy.sqrt(3) n = 12 basis = gto.expand_etbs([(0, n, alpha, beta), (1, n, alpha, beta), (2, n, alpha, beta)]) #logger.info(self, 'Nuclear basis for %s: n %s alpha %s beta %s' %(self.atom_symbol(atom_index), n, alpha, beta)) nuc.build(atom = self.atom, basis={self.atom_symbol(atom_index): basis}, charge = self.charge, cart = self.cart, spin = self.spin) # set all quantum nuclei to have zero charges quantum_nuclear_charge = 0 for i in range(self.natm): if self.quantum_nuc[i] is True: quantum_nuclear_charge -= nuc._atm[i, 0] nuc._atm[i, 0] = 0 # set nuclear charges of quantum nuclei to 0 nuc.charge += quantum_nuclear_charge # avoid UHF nuc.spin = 0 nuc.nelectron = 2 # fractional if frac is not None: nuc.nnuc = frac else: nuc.nnuc = 1 return nuc
def aug_etb_for_dfbasis(mol, dfbasis='weigend', beta=2.3, start_at='Rb'): '''augment weigend basis with even tempered gaussian basis exps = alpha*beta^i for i = 1..N ''' nuc_start = gto.mole._charge(start_at) uniq_atoms = set([a[0] for a in mol._atom]) newbasis = {} for symb in uniq_atoms: nuc_charge = gto.mole._charge(symb) if nuc_charge < nuc_start: newbasis[symb] = dfbasis #?elif symb in mol._ecp: else: conf = lib.parameters.ELEMENTS[nuc_charge][2] max_shells = 4 - conf.count(0) emin_by_l = [1e99] * 8 emax_by_l = [0] * 8 for b in mol._basis[symb]: l = b[0] if l >= max_shells+1: continue if isinstance(b[1], int): e_c = numpy.array(b[2:]) else: e_c = numpy.array(b[1:]) es = e_c[:,0] cs = e_c[:,1:] es = es[abs(cs).max(axis=1) > 1e-3] emax_by_l[l] = max(es.max(), emax_by_l[l]) emin_by_l[l] = min(es.min(), emin_by_l[l]) l_max = 8 - emax_by_l.count(0) emin_by_l = numpy.array(emin_by_l[:l_max]) emax_by_l = numpy.array(emax_by_l[:l_max]) # Estimate the exponents ranges by geometric average emax = numpy.sqrt(numpy.einsum('i,j->ij', emax_by_l, emax_by_l)) emin = numpy.sqrt(numpy.einsum('i,j->ij', emin_by_l, emin_by_l)) liljsum = numpy.arange(l_max)[:,None] + numpy.arange(l_max) emax_by_l = [emax[liljsum==ll].max() for ll in range(l_max*2-1)] emin_by_l = [emin[liljsum==ll].min() for ll in range(l_max*2-1)] # Tune emin and emax emin_by_l = numpy.array(emin_by_l) * 2 # *2 for alpha+alpha on same center emax_by_l = numpy.array(emax_by_l) * 2 #/ (numpy.arange(l_max*2-1)*.5+1) ns = numpy.log((emax_by_l+emin_by_l)/emin_by_l) / numpy.log(beta) etb = [(l, max(n,1), emin_by_l[l], beta) for l, n in enumerate(numpy.ceil(ns).astype(int))] newbasis[symb] = gto.expand_etbs(etb) return newbasis
O SP 5.0331513 -0.09996723 0.15591627 1.1695961 0.39951283 0.60768372 0.3803890 0.70011547 0.39195739 '''), 'H1': gto.load(basis_file_from_user, 'H'), 'H2': gto.load('sto-3g', 'He') # or use basis of another atom } ) mol = gto.M( atom = '''O 0 0 0; H1 0 1 0; H2 0 0 1''', basis = {'O': 'unc-ccpvdz', # prefix "unc-" will uncontract the ccpvdz basis. # It is equivalent to assigning # 'O': gto.uncontract(gto.load('ccpvdz', 'O')), 'H': 'ccpvdz' # H1 H2 will use the same basis ccpvdz } ) mol = gto.M( atom = '''O 0 0 0; H1 0 1 0; H2 0 0 1''', basis = {'H': 'sto3g', # even-temper gaussians alpha*beta^i, where i = 0,..,n # (l, n, alpha, beta) 'O': gto.expand_etbs([(0, 4, 1.5, 2.2), # s-function (1, 2, 0.5, 2.2)]) # p-function } )
# better resolution of auxiliary basis) is the use of function gto.expand_etbs. # # Note the PBC Gaussian DF module will automatically remove diffused Gaussian # fitting functions. It is controlled by the parameter eta. The default value is # 0.2 which removes all Gaussians whose exponents are smaller than 0.2. # When your input DF basis has diffused functions, you need to reduce the # value of mf.with_df.eta to reserve the diffused functions. However, # keeping diffused functions occasionally lead numerical noise in the GDF # method. # auxbasis = { 'C': # (l, N, alpha, beta) mol_gto.expand_etbs([ (0, 25, 0.15, 1.6), # 25s (1, 20, 0.15, 1.6), # 20p (2, 10, 0.15, 1.6), # 10d (3, 5, 0.15, 1.6), # 5f ]) } mf = scf.RHF(cell).density_fit(auxbasis=auxbasis) mf.with_df.eta = 0.1 mf.kernel() # # The 3-index density fitting tensor can be loaded from the _cderi file. # Using the 3-index tensor, the 4-center integrals can be constructed: # (pq|rs) = \sum_L A_lpq A_lrs # # The 3-index tensor for gamma point can be accessed with the code snippet # below. Assuming in the first pass, the GDF 3-index tensors are saved with # the following code
mf = scf.RHF(mol) mf.kernel() # # First method is to explicit call the functions provided by molden.py # with open("C6H6mo.molden", "w") as f1: molden.header(mol, f1) molden.orbital_coeff(mol, f1, mf.mo_coeff, ene=mf.mo_energy, occ=mf.mo_occ) # # Second method is to simply call from_mo function to write the orbitals # c_loc_orth = lo.orth.orth_ao(mol) molden.from_mo(mol, "C6H6loc.molden", c_loc_orth) # # Molden format does not support high angular momentum basis. To handle the # orbitals which have l>=5 functions, a hacky way is to call molden.remove_high_l # function. However, the resultant orbitals may not be orthnormal. # mol = gto.M(atom="He 0 0 0", basis={"He": gto.expand_etbs(((0, 3, 1.0, 2.0), (5, 2, 1.0, 2.0)))}) mf = scf.RHF(mol).run() try: molden.from_mo(mol, "He_without_h.molden", mf.mo_coeff) except RuntimeError: print(" Found l=5 in basis.") molden.from_mo(mol, "He_without_h.molden", mf.mo_coeff, ignore_h=True)
import numpy as np from pyscf import gto, scf from kspies import wy mol = gto.M(atom='N 0 0 0 ; N 1.1 0 0', basis='cc-pVDZ') mf = scf.RHF(mol).run() dm_tar = mf.make_rdm1() PBS = gto.expand_etbs([(0, 13, 2**-4, 2), (1, 3, 2**-2, 2)]) mw = wy.RWY(mol, dm_tar, pbas=PBS) #Note that for this designed-to-be ill-conditioned problem, #Hessian-based optimization algorithms are problematic. mw.method = 'bfgs' mw.tol = 2e-7 mw.run() mw.info() Ws_fin = mw.Ws etas = [2.**(-a) for a in np.linspace(5., 27., 45)] v = np.zeros(len(etas)) W = np.zeros(len(etas)) for i, eta in enumerate(etas): mw.reg = eta mw.run() v[i] = mw.Dvb() W[i] = mw.Ws mw.info() import matplotlib.pyplot as plt fig, ax = plt.subplots(2) ax[0].scatter(np.log10(Ws_fin - W), np.log10(v))
mf.kernel() # # First method is to explicit call the functions provided by molden.py # with open('C6H6mo.molden', 'w') as f1: molden.header(mol, f1) molden.orbital_coeff(mol, f1, mf.mo_coeff, ene=mf.mo_energy, occ=mf.mo_occ) # # Second method is to simply call from_mo function to write the orbitals # c_loc_orth = lo.orth.orth_ao(mol) molden.from_mo(mol, 'C6H6loc.molden', c_loc_orth) # # Molden format does not support high angular momentum basis. To handle the # orbitals which have l>=5 functions, a hacky way is to call molden.remove_high_l # function. However, the resultant orbitals may not be orthnormal. # mol = gto.M( atom = 'He 0 0 0', basis = {'He': gto.expand_etbs(((0, 3, 1., 2.), (5, 2, 1., 2.)))}) mf = scf.RHF(mol).run() try: molden.from_mo(mol, 'He_without_h.molden', mf.mo_coeff) except RuntimeError: print(' Found l=5 in basis.') molden.from_mo(mol, 'He_without_h.molden', mf.mo_coeff, ignore_h=True)
# Another straightforward way to input even-tempered Gaussian basis (for # better resolution of auxiliary basis) is the use of function gto.expand_etbs. # # Note the PBC Gaussian DF module will automatically remove diffused Gaussian # fitting functions. It is controlled by the parameter eta. The default value is # 0.2 which removes all Gaussians whose exponents are smaller than 0.2. # When your input DF basis has diffused functions, you need to reduce the # value of mf.with_df.eta to reserve the diffused functions. However, # keeping diffused functions occasionally lead numerical noise in the GDF # method. # auxbasis = {'C': # (l, N, alpha, beta) mol_gto.expand_etbs([(0, 25, 0.15, 1.6), # 25s (1, 20, 0.15, 1.6), # 20p (2, 10, 0.15, 1.6), # 10d (3, 5 , 0.15, 1.6), # 5f ]) } mf = scf.RHF(cell).density_fit(auxbasis=auxbasis) mf.with_df.eta = 0.1 mf.kernel() # # The 3-index density fitting tensor can be loaded from the _cderi file. # Using the 3-index tensor, the 4-center integrals can be constructed: # (pq|rs) = \sum_L A_lpq A_lrs # # The 3-index tensor for gamma point can be accessed with the code snippet # below. Assuming in the first pass, the GDF 3-index tensors are saved with