コード例 #1
0
def test_hmi_continuum():
    """
    check that the continuum wavefunction of H2+ really are solutions
    of Schroedinger's equation, i.e. have (H-E)\phi = 0 everywhere

    starting from an LCAO guess for the continuum orbital, try to find
    the exact solution by adding orbital corrections iteratively
    """
    # First we compute the exact wavefunction of the hydrogen molecular ion.
    from DFTB.Scattering import HMI

    # The bond length and charges cannot be changed, since the
    # separation constants were calculated only for the H2+ ion at R=2!
    R = 2.0
    Za = 1.0
    Zb = 1.0

    # energy of continuum orbital
    E = 0.5

    ## sigma (m=0) orbital
    m = 0
    n = 0
    trig = 'cos'

    # separation constant
    Lsep = HMI.SeparationConstants(R, Za, Zb)
    Lsep.load_separation_constants()
    Lfunc = Lsep.L_interpolated(m, n)

    c2 = 0.5 * E * R**2
    mL, nL, L = Lfunc(c2)

    parity = (-1)**(mL + nL)
    phi_exact = HMI.create_wavefunction(mL, L, R * (Za + Zb), 0.0, R, c2,
                                        parity, trig)

    # Old implementation of H2+ wavefunctions, the wavefunction
    # looks indistinguishable from the exact wavefunction, but the
    # non-zero residue shows that is contains large errors.
    from DFTB.Scattering.hydrogen_molecular_ion import DimerWavefunctions
    wfn = DimerWavefunctions(R, Za, Zb, plot=False)

    delta, (Rfunc, Sfunc, Pfunc), wavefunction_exact = wfn.getContinuumOrbital(
        m, n, trig, E)

    def phi_exact_DW(x, y, z):
        return wavefunction_exact((x, y, z), None)

    # Set resolution of multicenter grid
    settings.radial_grid_factor = 10
    settings.lebedev_order = 41

    # Next we compute the wavefunction using the basis set free method
    atomlist = [(int(Za), (0.0, 0.0, -R / 2.0)),
                (int(Zb), (0.0, 0.0, +R / 2.0))]

    # no other electrons, only nuclear potential
    def potential(x, y, z):
        nuc = 0.0 * x
        for Zi, posi in atomlist:
            ri = np.sqrt((x - posi[0])**2 + (y - posi[1])**2 +
                         (z - posi[2])**2)
            nuc += -Zi / ri
        return nuc

    # electron-electron interaction
    def potential_ee(x, y, z):
        return 0.0 * x

    # Set resolution of multicenter grid
    settings.radial_grid_factor = 10
    settings.lebedev_order = 41

    # residual of exact wavefunction (should be zero)
    residual_exact = residual_func(atomlist, phi_exact, potential, E)
    residual_ee_exact = residual_ee_func(atomlist, phi_exact, potential_ee, E)
    residual_exact_DW = residual_func(atomlist, phi_exact_DW, potential, E)

    # Laplacian
    laplacian_exact = laplacian_func(atomlist, phi_exact)

    import matplotlib.pyplot as plt
    plt.clf()
    r = np.linspace(-15.0, 15.0, 5000)
    x = 0 * r
    y = 0 * r
    z = r

    # plot exact wavefunction
    plt.plot(r, phi_exact(x, y, z), label="$\phi$ exact")

    #
    phi_exact_xyz = phi_exact(x, y, z)
    phi_exact_DW_xyz = phi_exact_DW(x, y, z)
    scale = phi_exact_xyz.max() / phi_exact_DW_xyz.max()
    plt.plot(r,
             scale * phi_exact_DW_xyz,
             label="$\phi$ exact (DimerWavefunction)")

    # and residual
    plt.plot(r, residual_exact(x, y, z), label=r"$(H-E)\phi$ (exact, old)")
    plt.plot(r,
             residual_exact_DW(x, y, z),
             ls="-.",
             label=r"$(H-E)\phi$ (exact, DimerWavefunction, old)")

    plt.plot(r,
             residual_ee_exact(x, y, z),
             ls="--",
             label=r"$(H-E)\phi$ (exact, new)")
    # kinetic energy
    plt.plot(r,
             -0.5 * laplacian_exact(x, y, z),
             ls="--",
             label=r"$-\frac{1}{2}\nabla^2 \phi$")
    # potential energy
    plt.plot(r, (potential(x, y, z) - E) * phi_exact(x, y, z),
             ls="--",
             label=r"$(V-E)\phi$")

    ## The initial guess for the \sigma continuum orbital
    ## is a regular Coulomb function centered on the midpoint
    ## between the two protons.
    #phi0 = regular_coulomb_func(E, +2, 0, 0, 0.0, center=(0.0, 0.0, 0.0))
    """
    ## The initial guess for the \sigma continuum orbital is
    ## the sum of two hydrogen s continuum orbitals
    bs = AtomicScatteringBasisSet(atomlist, E, lmax=0)

    phi0 = add_two_functions(atomlist,
                             bs.bfs[0], bs.bfs[1],
                             1.0/np.sqrt(2.0), 1.0/np.sqrt(2.0))
    """
    """
    ## start with exact wavefunction
    phi0 = phi_exact
    """

    # The initial guess for the \sigma continuum orbital is
    # a hydrogen continuum orbital in the center
    bs = AtomicScatteringBasisSet([(1, (0.0, 0.0, 0.0))], E, lmax=0)
    phi0 = bs.bfs[0]

    plt.plot(r, phi0(x, y, z), ls="-.", label="guess $\phi_0$")

    plt.legend()
    plt.show()

    #phi = improve_continuum_orbital(atomlist, phi0, potential_ee, E, thresh=1.0e-6)
    phi = relax_continuum_orbital(atomlist,
                                  phi0,
                                  potential_ee,
                                  E,
                                  thresh=1.0e-6)

    import matplotlib.pyplot as plt
    plt.clf()
    r = np.linspace(-15.0, 15.0, 5000)
    x = 0 * r
    y = 0 * r
    z = r

    phi_exact_xyz = phi_exact(x, y, z)
    phi_xyz = phi(x, y, z)
    # scale numerical phi such that the maxima agree
    scale = phi_exact_xyz.max() / phi_xyz.max()
    phi_xyz *= scale
    print("scaling factor  s = %s" % scale)

    plt.plot(r, phi_exact_xyz, label="exact")
    plt.plot(r, phi_xyz, label="numerical")
    plt.legend()

    plt.show()
コード例 #2
0
def test_hmi_lcao_continuum():
    """

    """
    # First we compute the exact wavefunction of the hydrogen molecular ion.
    from DFTB.Scattering import HMI

    R = 2.0
    Za = 1.0
    Zb = 1.0
    E = 0.5

    ## sigma (m=0) orbital
    m = 0
    n = 0
    L = m + n
    trig = 'cos'

    # separation constant
    Lsep = HMI.SeparationConstants(R, Za, Zb)
    Lsep.load_separation_constants()
    Lfunc = Lsep.L_interpolated(m, n)

    c2 = 0.5 * E * R**2
    mL, nL, L = Lfunc(c2)

    parity = (-1)**(mL + nL)
    phi_exact = HMI.create_wavefunction(mL, L, R * (Za + Zb), 0.0, R, c2,
                                        parity, trig)
    """
    from DFTB.Scattering.hydrogen_molecular_ion import DimerWavefunctions
    wfn = DimerWavefunctions(R,Za,Zb, plot=False)

    delta, (Rfunc,Sfunc,Pfunc),wavefunction_exact = wfn.getContinuumOrbital(m,n,trig,E)
    def phi_exact(x,y,z):
        return wavefunction_exact((x,y,z), None)
    """

    # Next we compute the wavefunction using the basis set free method
    atomlist = [(int(Za), (0.0, 0.0, -R / 2.0)),
                (int(Zb), (0.0, 0.0, +R / 2.0))]

    # no other electrons, only nuclear potential
    def potential(x, y, z):
        nuc = 0.0 * x
        for Zi, posi in atomlist:
            ri = np.sqrt((x - posi[0])**2 + (y - posi[1])**2 +
                         (z - posi[2])**2)
            nuc += -Zi / ri
        return nuc

    # Set resolution of multicenter grid
    settings.radial_grid_factor = 40
    settings.lebedev_order = 21

    # residual of exact wavefunction (should be zero)
    residual_exact = residual_func(atomlist, phi_exact, potential, E)
    # Laplacian
    laplacian_exact = laplacian_func(atomlist, phi_exact)

    import matplotlib.pyplot as plt
    plt.clf()
    r = np.linspace(-15.0, 15.0, 5000)
    x = 0 * r
    y = 0 * r
    z = r

    # plot exact wavefunction
    plt.plot(r, phi_exact(x, y, z), label="$\phi$ exact")
    # and residual
    plt.plot(r, residual_exact(x, y, z), label=r"$(H-E)\phi$ (exact)")
    # kinetic energy
    plt.plot(r,
             -0.5 * laplacian_exact(x, y, z),
             ls="--",
             label=r"$-\frac{1}{2}\nabla^2 \phi$")
    # potential energy
    plt.plot(r, (potential(x, y, z) - E) * phi_exact(x, y, z),
             ls="--",
             label=r"$(V-E)\phi$")

    # LCAO continuum orbitals
    ps = AtomicPotentialSet(atomlist)
    lmax = 4
    bs = AtomicScatteringBasisSet(atomlist, E, lmax=lmax)

    R = residual2_matrix(atomlist, potential, 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])

    continuum_orbitals = orbital_transformation(atomlist, bs.bfs, eigvecs)

    plt.cla()
    plt.plot(r, phi_exact(x, y, z), ls="--", label="$\phi$ (exact)")
    for i in range(0, len(continuum_orbitals)):
        plt.plot(r, continuum_orbitals[i](x, y, z))

    plt.legend()
    plt.show()