Пример #1
0
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
Пример #2
0
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)
Пример #3
0
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 ""
Пример #4
0
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()
Пример #5
0
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"),
    ]

    r = np.linspace(0.1, 100.0, 1000)
    plt.xlabel(r"distance r / bohr")
    plt.ylabel(r"potential / Hartree")