def test(): # bond length in bohr dist = 2.0 # positions of protons posH1 = (0.0, 0.0, -dist / 2.0) posH2 = (0.0, 0.0, +dist / 2.0) atomlist = [(1, posH1), (1, posH2)] # Set resolution of multicenter grid settings.radial_grid_factor = 20 settings.lebedev_order = 23 # energy of continuum orbital E = 1.0 # same functional as used in the calculation of pseudo orbitals xc = XCFunctionals.libXCFunctional(Parameters.pseudo_orbital_x, Parameters.pseudo_orbital_c) dft = BasissetFreeDFT(atomlist, xc) print "initial orbital guess from DFTB calculation" orbitals = dft.getOrbitalGuess() norb = len(orbitals) # all orbitals are doubly occupied nelec = 2 * norb bound_orbitals = dft.getOrbitalGuess() # effective potential rho = density_func(bound_orbitals) veff = effective_potential_func(atomlist, rho, xc, nelec=nelec) # radius that separates inner from outer region r0 = vdw_sphere_radius(atomlist, fac=2.0) # basis sets bs_core = AtomicBasisSet(atomlist, orbital_set="core") bs_valence = AtomicBasisSet(atomlist, orbital_set="valence") bs_continuum = AtomicScatteringBasisSet(atomlist, E, lmax=1) # combine basis functions from all basis sets bfs = bs_core.bfs + bs_valence.bfs + bs_continuum.bfs A, D, S = fvvm_matrix_elements(atomlist, bfs, veff, E, r0) # solve generalized eigenvalue problem # A.C = b.D.C b, C = sla.eigh(A, D) return b, C
def onsite_integrals(atom_name='h', confined=True): """ compute on-site Coulomb and exchange integrals for an atom Parameters ---------- atom_name : name of atom, e.g. 'h', 'c', etc. Optional -------- confined : controls where confined atoms (True) or free atoms (False) are used """ print( "computing on-site Coulomb and exchange integrals between valence orbitals of '%s'" % atom_name) Zat = atomic_number(atom_name) atomlist = [(Zat, (0, 0, 0))] basis = AtomicBasisSet(atomlist, confined=confined) density = AtomicDensitySuperposition(atomlist, confined=confined) #xc_functional = XCFunctionals.libXCFunctional("lda_x", "lda_c_pw") xc_functional = XCFunctionals.libXCFunctional("gga_x_pbe", "gga_c_pbe") for a, bfA in enumerate(basis.bfs): stra = "%d%s" % (bfA.n, angmom_to_xyz[(bfA.l, bfA.m)] ) # name of valence orbital, e.g. 1s, 2px, etc. for b, bfB in enumerate(basis.bfs): strb = "%d%s" % (bfB.n, angmom_to_xyz[(bfB.l, bfB.m)]) # Coulomb integral (aa|(1/r12 + fxc[rho0])|bb) eri_aabb = electron_repulsion_integral(atomlist, bfA, bfA, bfB, bfB, density, xc_functional) print("Coulomb (%s,%s|{1/r12+f_xc[rho0]}|%s,%s)= %e" % (stra, stra, strb, strb, eri_aabb)) if a != b: # exchange integral (ab|(1/r12 + fxc[rho0])|ab) eri_abab = electron_repulsion_integral(atomlist, bfA, bfB, bfA, bfB, density, xc_functional) print("exchange (%s,%s|{1/r12+f_xc[rho0]}|%s,%s)= %e" % (stra, strb, stra, strb, eri_abab))
def test_h2_continuum_orbital(): """ The sigma continuum orbital is approximated as a linear combination of two s continuum orbitals and is then improved iteratively """ # bond length in bohr dist = 2.0 # positions of protons posH1 = (0.0, 0.0, -dist / 2.0) posH2 = (0.0, 0.0, +dist / 2.0) atomlist = [(1, posH1), (1, posH2)] # Set resolution of multicenter grid settings.radial_grid_factor = 20 settings.lebedev_order = 23 # energy of continuum orbital E = 1.0 # same functional as used in the calculation of pseudo orbitals xc = XCFunctionals.libXCFunctional(Parameters.pseudo_orbital_x, Parameters.pseudo_orbital_c) dft = BasissetFreeDFT(atomlist, xc) print("initial orbital guess from DFTB calculation") orbitals = dft.getOrbitalGuess() norb = len(orbitals) # all orbitals are doubly occupied nelec = 2 * norb bound_orbitals = dft.getOrbitalGuess() # electron density (closed shell) rho = density_func(bound_orbitals) # effective Kohn-Sham potential veff = effective_potential_func(atomlist, rho, xc, nelec=nelec, nuclear=True) # effective Kohn-Sham potential without nuclear attraction # (only electron-electron interaction) veff_ee = effective_potential_func(atomlist, rho, xc, nelec=nelec, nuclear=False) ps = AtomicPotentialSet(atomlist) lmax = 0 bs = AtomicScatteringBasisSet(atomlist, E, lmax=lmax) #test_AO_basis(atomlist, bs, ps, E) R = residual2_matrix(atomlist, veff, ps, bs) S = continuum_overlap(bs.bfs, E) print("continuum overlap") print(S) print("residual^2 matrix") print(R) eigvals, eigvecs = sla.eigh(R, S) print(eigvals) print("eigenvector belonging to lowest eigenvalue") print(eigvecs[:, 0]) # LCAO continuum orbitals continuum_orbitals = orbital_transformation(atomlist, bs.bfs, eigvecs) # improve continuum orbital by adding a correction term # # phi = phi0 + dphi # # The orbital correction dphi is the solution of the inhomogeneous # Schroedinger equation # # (H-E)dphi = -(H-E)phi0 # print("orbital correction...") phi0 = continuum_orbitals[0] phi = improve_continuum_orbital(atomlist, phi0, veff_ee, E)
s = sigma(r, 0 * r, 0 * r) n = rho(r, 0 * r, 0 * r) # dimensional quantity x = |grad rho|/rho^{4/3} x = np.sqrt(s) / n**(4.0 / 3.0) # van Leeuven and Baerends correction to exchange-correction # potential with asymptotic -1/r behaviour. The functional # contains one parameter beta beta = 0.05 vx_LB_correction = -beta * n**(1.0 / 3.0) * x**2 / ( 1.0 + 3 * beta * x * np.arcsinh(x)) # LDA exchange xc_LDA = XCFunctionals.libXCFunctional("lda_x", "lda_c_xalpha") vx_LDA = xc_LDA.func_x.vxc(n.flatten(), s.flatten()) vx_LB = vx_LDA + vx_LB_correction # libxc's implementation xc_LB = XCFunctionals.libXCFunctional("gga_x_lb", "lda_c_xalpha") # only exchange part vx_LB_libxc = xc_LB.func_x.vxc(n.flatten(), s.flatten()) # LB approximation l, = plt.plot(r, vx_LB, label=r"$v_{x}^{LB}$ $\alpha=%e$" % alpha) plt.plot(r, vx_LB_libxc, ls="-.", label=r"$v_{x}^{LB}$ (libxc) $\alpha=%e$" % alpha,
def onsite_integrals_unique(atom_name='h', confined=True): """ compute the 5 unique on-site electron integrals for an atom. Only s- and p-valence orbitals are considered. The 5 integrals are (ss|ss) (sp|sp) = (s px|s px) = (s py|s py) = (s pz|s pz) (ss|pp) = (s s |pxpx) = (s s |pypy) = (s s |pzpz) (pp|pp) = (pxpx|pxpx) = (pypy|pypy) = (pzpz|pzpz) (pp'|pp') = (pxpy|pxpy) = (pxpz|pxpz) = (pypz|pypz) Optional -------- confined : controls where confined atoms (True) or free atoms (False) are used Returns ------- unique_integrals : numpy array with unique on-site integrals [(ss|ss), (sp|sp), (ss|pp), (pp|pp), (pp'|pp')] References ---------- [1] http://openmopac.net/manual/1c2e.html """ print( "computing unique on-site electron integrals between valence orbitals of '%s'" % atom_name) print("only s- and p-functions are considered") Zat = atomic_number(atom_name) atomlist = [(Zat, (0, 0, 0))] basis = AtomicBasisSet(atomlist, confined=confined) density = AtomicDensitySuperposition(atomlist, confined=confined) #xc_functional = XCFunctionals.libXCFunctional("lda_x", "lda_c_pw") xc_functional = XCFunctionals.libXCFunctional("gga_x_pbe", "gga_c_pbe") unique_integrals = np.zeros(5) for a, bfA in enumerate(basis.bfs): for b, bfB in enumerate(basis.bfs): # choose index into unique_integrals to which the integrals is written if (bfA.l == 0 and bfB.l == 0): # (ss|ss) i = 0 elif (bfA.l == 0 and bfB.l == 1 and bfB.m == 0): # (sp|sp) and (ss|pp) i = 1 elif (bfA.l == 1 and bfA.m == 0 and bfB.l == 1 and bfB.m == 0): # (pp|pp) i = 3 elif (bfA.l == 1 and bfA.m == 0 and bfB.l == 1 and bfB.m == 1): # (pp'|pp') i = 4 else: continue # compute Coulomb integral (ab|(1/r12 + fxc[rho0])|ab) eri_abab = electron_repulsion_integral(atomlist, bfA, bfB, bfA, bfB, density, xc_functional) unique_integrals[i] = eri_abab if (i == 1): # in addition to (sp|sp) we also need to calculated (ss|pp) eri_aabb = electron_repulsion_integral(atomlist, bfA, bfA, bfB, bfB, density, xc_functional) unique_integrals[2] = eri_aabb elif (i == 4): # in addition to (pp'|pp') we also compute (pp|p'p') and verify the identity # (pp|p'p') = (pp|pp) - 2 (pp'|pp') eri_aabb = electron_repulsion_integral(atomlist, bfA, bfA, bfB, bfB, density, xc_functional) assert ( eri_aabb - (unique_integrals[3] - 2 * unique_integrals[4])) < 1.0e-5 print("unique 1-center integrals (in eV) for atom '%s'" % atom_name) print(" (ss|ss) (sp|sp) (ss|pp) (pp|pp) (pp'|pp')") print(" %+.7f %+.7f %+.7f %+.7f %+.7f" % tuple(unique_integrals * hartree_to_eV)) return unique_integrals
from DFTB.SlaterKoster import XCFunctionals from DFTB.MolecularIntegrals.BasissetFreeDFT import BasissetFreeDFT from DFTB.MolecularIntegrals import settings import os.path import sys if __name__ == "__main__": if len(sys.argv) < 4: print "Usage: %s xyz-file rfac Lmax" % os.path.basename(sys.argv[0]) print " compute DFT ground state" exit(-1) # load geometry xyz_file = sys.argv[1] atomlist = XYZ.read_xyz(xyz_file)[0] # set resolution of multicenter grid rfac = int(sys.argv[2]) Lmax = int(sys.argv[3]) settings.radial_grid_factor = rfac # controls size of radial grid settings.lebedev_order = Lmax # controls size of angular grid charge = 0 # PBE functional xc = XCFunctionals.libXCFunctional('gga_x_pbe', 'gga_c_pbe') RDFT = BasissetFreeDFT(atomlist, xc, charge=charge) RDFT.solveKohnSham_new(thresh=1.0e-8)
(0, 0): "s ", (1, -1): "px", (1, 1): "py", (1, 0): "pz", (2, -2): "dxy", (2, -1): "dyz", (2, 0): "dz2", (2, 1): "dzx", (2, 2): "dx2y2" } if __name__ == "__main__": # set accuracy of multicenter grid settings.radial_grid_factor = 3 settings.lebedev_order = 23 atomlist = [(6, (0, 0, 0))] basis = AtomicBasisSet(atomlist) density = AtomicDensitySuperposition(atomlist) xc_functional = XCFunctionals.libXCFunctional("lda_x", "lda_c_pw") for a, bfA in enumerate(basis.bfs): for b, bfB in enumerate(basis.bfs): for c, bfC in enumerate(basis.bfs): for d, bfD in enumerate(basis.bfs): eri = electron_repulsion_integral(atomlist, bfA, bfB, bfC, bfD, density, xc_functional) print "(%d,%d|{1/r12+f_xc[rho0]}|%d,%d)= %e" % (a, b, c, d, eri)
def test_lcao_continuum(): import matplotlib.pyplot as plt # bond length in bohr dist = 2.0 # positions of protons posH1 = (0.0, 0.0, -dist / 2.0) posH2 = (0.0, 0.0, +dist / 2.0) atomlist = [(1, posH1), (1, posH2)] # Set resolution of multicenter grid settings.radial_grid_factor = 20 settings.lebedev_order = 23 # energy of continuum orbital E = 1.0 # same functional as used in the calculation of pseudo orbitals xc = XCFunctionals.libXCFunctional(Parameters.pseudo_orbital_x, Parameters.pseudo_orbital_c) dft = BasissetFreeDFT(atomlist, xc) print("initial orbital guess from DFTB calculation") orbitals = dft.getOrbitalGuess() norb = len(orbitals) # all orbitals are doubly occupied nelec = 2 * norb bound_orbitals = dft.getOrbitalGuess() # effective potential rho = density_func(bound_orbitals) veff = effective_potential_func(atomlist, rho, xc, nelec=nelec) ps = AtomicPotentialSet(atomlist) r = np.linspace(-15.0, 15.0, 10000) x = 0.0 * r y = 0.0 * r z = r for lmax in [0, 1, 2, 3]: bs = AtomicScatteringBasisSet(atomlist, E, lmax=lmax) #test_AO_basis(atomlist, bs, ps, E) R = residual2_matrix(atomlist, veff, ps, bs) S = continuum_overlap(bs.bfs, E) print("continuum overlap") print(S) print("residual^2 matrix") print(R) eigvals, eigvecs = sla.eigh(R, S) print(eigvals) print("eigenvector belonging to lowest eigenvalue") print(eigvecs[:, 0]) # LCAO continuum orbitals continuum_orbitals = orbital_transformation(atomlist, bs.bfs, eigvecs) # improve continuum orbital by adding a correction term # # phi = phi0 + dphi # # The orbital correction dphi is the solution of the inhomogeneous # Schroedinger equation # # (H-E)dphi = -(H-E)phi0 # print("orbital correction...") phi0 = continuum_orbitals[0] phi = improve_continuum_orbital(atomlist, phi0, veff, E) exit(-1) residual_0 = residual_func(atomlist, phi0, veff, E) def source(x, y, z): return -residual_0(x, y, z) delta_phi = inhomogeneous_schroedinger(atomlist, veff, source, E) residual_d = residual_func(atomlist, delta_phi, veff, E) a, b = variational_mixture_continuum(atomlist, phi0, delta_phi, veff, E) phi = add_two_functions(atomlist, phi0, delta_phi, a, b) residual = residual_func(atomlist, phi, veff, E) plt.plot(r, 1.0 / np.sqrt(2.0) * bs.bfs[0](x, y, z), label=r"AO") plt.plot(r, phi0(x, y, z), label=r"$\phi_0$") plt.plot(r, delta_phi(x, y, z), label=r"$\Delta \phi$") plt.plot(r, phi(x, y, z), label=r"$\phi_0 + \Delta \phi$") plt.legend() plt.show() """ dphi = delta_phi(x,y,z) imin = np.argmin(abs(r-1.0)) dphi[abs(r) < 1.0] = dphi[imin] - (dphi[abs(r) < 1.0] - dphi[imin]) plt.plot(r, dphi, label=r"$\Delta \phi$") """ plt.plot(r, residual_0(x, y, z), label=r"$(H-E) \phi_0$") plt.plot(r, residual_d(x, y, z), label=r"$(H-E)\Delta \phi$") plt.plot(r, residual(x, y, z), label=r"$(H-E)(a \phi_0 + b \Delta \phi)$") plt.plot(r, a * residual_0(x, y, z) + b * residual_d(x, y, z), ls="-.", label=r"$(H-E)(a \phi_0 + b \Delta \phi)$ (separate)") plt.legend() plt.show() averaged_angular_distribution(atomlist, bound_orbitals, continuum_orbitals, E) # save continuum MOs to cubefiles for i, phi in enumerate(continuum_orbitals): def func(grid, dV): x, y, z = grid return phi(x, y, z) Cube.function_to_cubefile( atomlist, func, filename="/tmp/cmo_lmax_%2.2d_orb%4.4d.cube" % (lmax, i), ppb=5.0) # for i, phi in enumerate(continuum_orbitals): residual = residual_func(atomlist, phi, veff, E) delta_e = energy_correction(atomlist, residual, phi, method="Becke") print(" orbital %d energy <%d|H-E|%d> = %e" % (i, i, i, delta_e)) l, = plt.plot(r, phi(x, y, z), label=r"$\phi_{%d}$ ($l_{max}$ = %d)" % (i, lmax)) plt.plot(r, residual(x, y, z), ls="-.", label=r"$(H-E)\phi_{%d}$" % i, color=l.get_color()) plt.legend() plt.show()
def numerical_gamma_integrals(atom_nameA, atom_nameB, distances, confined=True): """ compute the integrals gamma_{A,lA,B,lB} = (F_{A,lA}|1/r12 + f_xc[rho0A+rho0B]|F_{B,lB}) numerically on a multicenter grid Parameters ---------- atom_nameA, atom_nameB : names of interacting atoms, e.g. 'h' or 'c' distances : numpy array with interatomic separations (in bohr) for which the gamma integrals should be calculated Optional -------- confined : controls where confined atoms (True) or free atoms (False) are used Returns ------- gamma_dic : dictionary with values of gamma integrals on the distance grid, gamma_dic[(lA,lB)] is a numpy array holding the integrals between shell lA on atom A and shell lB on atom B """ # atomic numbers Za = atomic_number(atom_nameA) Zb = atomic_number(atom_nameB) # charge fluctuation functions for each shell lsA, FsA = charge_fluctuation_functions(atom_nameA, confined=confined) lsB, FsB = charge_fluctuation_functions(atom_nameB, confined=confined) xc_functional = XCFunctionals.libXCFunctional("lda_x", "lda_c_pw") gamma_dic = {} for la, Fa in zip(lsA, FsA): for lb, Fb in zip(lsB, FsB): print(" integral between %s-shell and %s-shell" % (l2spec[la], l2spec[lb])) gamma_ab = np.zeros(len(distances)) for i, r_ab in enumerate(distances): print(" %3.d of %d interatomic distance : %4.7f bohr" % (i + 1, len(distances), r_ab)) # atoms A and B are placed symmetrically on the z-axis, # separated by a distance of r_ab atomlist = [(Za, (0, 0, -0.5 * r_ab)), (Zb, (0, 0, +0.5 * r_ab))] # define displaced charge fluctuation functions def rhoAB(x, y, z): return Fa(x, y, z - 0.5 * r_ab) def rhoCD(x, y, z): return Fb(x, y, z + 0.5 * r_ab) # rho0 = AtomicDensitySuperposition(atomlist, confined=confined) # evaluate integral gamma_ab[i] = electron_repulsion_integral_rho( atomlist, rhoAB, rhoCD, rho0, xc_functional) # save gamma integral for the interaction of a shell with angular momentum la on atom A # and a shell with angular momentum lb on atom B gamma_dic[(la, lb)] = gamma_ab return gamma_dic
print("effective potential...") # List of (exchange, correlation) functionals implemented # in libXC functionals = [ ("lda_x", "lda_c_xalpha"), ("lda_x_erf", "lda_c_xalpha"), ("lda_x_rae", "lda_c_xalpha"), ("gga_x_lb", "lda_c_xalpha"), ] r = np.linspace(0.1, 100.0, 1000) plt.xlabel(r"distance r / bohr") plt.ylabel(r"potential / Hartree") # correct asymptotic HF potential plt.plot(r, -2.0 / r, "-.", lw=2, label=r"$-2/r$") for (x_func, c_func) in functionals: xc = XCFunctionals.libXCFunctional(x_func, c_func) # potential energy for Li nucleus and 2 core electrons potential = effective_potential_func(atomlist, rho, xc) plt.plot(r, potential(r, 0 * r, 0 * r), label=r"%s, %s" % (x_func, c_func)) plt.ylim((-5.0, +0.1)) plt.legend() plt.show()