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()
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()