def hmi_continuum(l, m, E): """ compute continuum orbitals of the hydrogen molecular ion H2+ Parameters ---------- l,m : angular quantum numbers of asymptotic solution e.g. l=0,m=0 s-orbital l=1,m=+1 px-orbital E : energy (in a.u.) of continuum orbital, E = 1/2 k^2 """ # H2^+ # bond length in bohr R = 2.0 atomlist = [(1, (0.0, 0.0, -R / 2.0)), (1, (0.0, 0.0, +R / 2.0))] # choose resolution of multicenter grids for continuum orbitals settings.radial_grid_factor = 120 # controls size of radial grid settings.lebedev_order = 25 # controls size of angular grid RDFT = BasissetFreeDFT(atomlist, None, charge=+1) # This is a one-electron system, so there are no other occupied orbitals def rho(x, y, z): return 0 * x def h**o(x, y, z): return 0 * x delta, phi = RDFT.solveScatteringProblem(rho, h**o, E, l, m)
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 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)
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)
def lithium_cation_continuum(l, m, k): """ compute continuum orbital in the electrostatic potential of the Li^+ core Parameters ---------- l,m : angular quantum numbers of asymptotic solution e.g. l=0,m=0 s-orbital l=1,m=+1 px-orbital k : length of wavevector in a.u., the energy of the continuum orbital is E=1/2 k^2 """ # Li^+ atom atomlist = [(3, (0.0, 0.0, 0.0))] charge = +1 # choose resolution of multicenter grids for bound orbitals settings.radial_grid_factor = 20 # controls size of radial grid settings.lebedev_order = 25 # controls size of angular grid # 1s core orbitals for Li+^ atom RDFT = BasissetFreeDFT(atomlist, None, charge=charge) # bound_orbitals = RDFT.getOrbitalGuess() Etot, bound_orbitals, orbital_energies = RDFT.solveKohnSham() # choose resolution of multicenter grids for continuum orbitals settings.radial_grid_factor = 120 # controls size of radial grid settings.lebedev_order = 41 # controls size of angular grid # show number of radial and angular points in multicenter grid print_grid_summary(atomlist, settings.lebedev_order, settings.radial_grid_factor) print "electron density..." # electron density of two electrons in the 1s core orbital rho = density_func(bound_orbitals) print "effective potential..." # potential energy for Li nucleus and 2 core electrons potential = effective_potential_func(atomlist, rho, None, nelec=2) def v0(x, y, z): r = np.sqrt(x * x + y * y + z * z) return -1.0 / r def v1(x, y, z): return potential(x, y, z) - v0(x, y, z) # The continuum orbital is specified by its energy and asymptotic # angular momentum (E,l,m) # energy of continuum orbital E = 0.5 * k**2 # angular quantum numbers of asymptotic solution assert abs(m) <= l print " " print "Asymptotic continuum wavefunction" print "=================================" print " energy E= %e Hartree ( %e eV )" % ( E, E * AtomicData.hartree_to_eV) print " wavevector k= %e a.u." % k print " angular moment l= %d m= %+d" % (l, m) print " " # asymptotically correct solution for V0 = -1/r (hydrogen) Cf = regular_coulomb_func(E, charge, l, m, 0.0) phi0 = Cf # right-hand side of inhomogeneous Schroedinger equation def source(x, y, z): return -v1(x, y, z) * phi0(x, y, z) # # solve (H0 + V1 - E) dphi = - V1 phi0 # for orbital correction dphi atomic_numbers, atomic_coordinates = atomlist2arrays(atomlist) print "Schroedinger equation..." dphi = multicenter_inhomogeneous_schroedinger( potential, source, E, atomic_coordinates, atomic_numbers, radial_grid_factor=settings.radial_grid_factor, lebedev_order=settings.lebedev_order) # Combine asymptotically correct solution with correction # phi = phi0 + dphi phi = add_two_functions(atomlist, phi0, dphi, 1.0, 1.0) # residual for phi0 R0 = (H-E)phi0 residual0 = residual_func(atomlist, phi0, potential, E) # residual for final solution R = (H-E)phi residual = residual_func(atomlist, phi, potential, E) # spherical average of residual function residual_avg = spherical_average_residual_func(atomlist[0], residual) # The phase shift is determined by matching the radial wavefunction # to a shifted and scaled Coulomb function at a number of radial # sampling points drawn from the interval [rmin, rmax]. # On the one hand rmin < rmax should be chosen large enough, # so that the continuum orbital approaches its asymptotic form, # on the other hand rmax should be small enough that the accuracy # of the solution due to the sparse r-grid is still high enough. # A compromise has to be struck depending on the size of the radial grid. # The matching points are spread over several periods, # but not more than 30 bohr. wavelength = 2.0 * np.pi / k print "wavelength = %e" % wavelength rmin = 70.0 rmax = rmin + max(10 * wavelength, 30.0) Npts = 100 # determine phase shift and scaling factor by a least square # fit the the regular Coulomb function scale, delta = phaseshift_lstsq(atomlist, phi, E, charge, l, m, rmin, rmax, Npts) print "scale factor (relative to Coulomb wave) = %s" % scale print "phase shift (relative to Coulomb wave) = %e " % delta # normalize wavefunction, so that 1/scale phi(x,y,z) approaches # asymptotically a phase-shifted Coulomb wave phi_norm = multicenter_operation( [phi], lambda fs: fs[0] / scale, atomic_coordinates, atomic_numbers, radial_grid_factor=settings.radial_grid_factor, lebedev_order=settings.lebedev_order) # The continuum orbital should be orthogonal to the bound # orbitals belonging to the same Hamiltonian. I think this # should come out correctly by default. print " " print " Overlaps between bound orbitals and continuum orbital" print " =====================================================" for ib, bound_orbital in enumerate(bound_orbitals): olap_bc = overlap(atomlist, bound_orbital, phi_norm) print " <bound %d| continuum> = %e" % (ib + 1, olap_bc) print "" # shifted regular coulomb function Cf_shift = regular_coulomb_func(E, charge, l, m, delta) # save radial wavefunctions and spherically averaged residual # radial part of Coulomb wave without phase shift phi0_rad = radial_wave_func(atomlist, phi0, l, m) # radial part of shifted Coulomb wave Cf_shift_rad = radial_wave_func(atomlist, Cf_shift, l, m) # radial part of scattering solution phi_norm_rad = radial_wave_func(atomlist, phi_norm, l, m) print "" print "# RADIAL_WAVEFUNCTIONS" print "# Asymptotic wavefunction:" print "# charge Z= %+d" % charge print "# energy E= %e k= %e" % (E, k) print "# angular momentum l= %d m= %+d" % (l, m) print "# phase shift delta= %e rad" % delta print "# " print "# R/bohr Coulomb Coulomb radial wavefunction spherical avg. residual" print "# shifted R_{l,m}(r) <|(H-E)phi|^2>" import sys # write table to console r = np.linspace(1.0e-3, 100, 1000) data = np.vstack((r, phi0_rad(r), Cf_shift_rad(r), phi_rad(r), residual_avg(r))).transpose() np.savetxt(sys.stdout, data, fmt=" %+e ") print "# END" print ""
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()
from DFTB.MolecularIntegrals import settings from DFTB.SlaterKoster import XCFunctionals import numpy as np import matplotlib.pyplot as plt if __name__ == "__main__": # Li^+ atom atomlist = [(3, (0.0, 0.0, 0.0))] charge = +1 # choose resolution of multicenter grids for bound orbitals settings.radial_grid_factor = 20 # controls size of radial grid settings.lebedev_order = 25 # controls size of angular grid # 1s core orbitals for Li+^ atom RDFT = BasissetFreeDFT(atomlist, None, charge=charge) bound_orbitals = RDFT.getOrbitalGuess() print("electron density...") # electron density of two electrons in the 1s core orbital rho = density_func(bound_orbitals) 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"), ]