a = 10 lattice = a .* [[1 0 0.]; [0 0 0]; [0 0 0]]; pot(x) = (x - a/2)^2; C = 1.0 α = 2; using DFTK using LinearAlgebra n_electrons = 1 # Increase this for fun terms = [Kinetic(), ExternalFromReal(r -> pot(r[1])), PowerNonlinearity(C, α), ] model = Model(lattice; n_electrons=n_electrons, terms=terms, spin_polarization=:spinless); # use "spinless electrons" Ecut = 500 basis = PlaneWaveBasis(model, Ecut, kgrid=(1, 1, 1)) scfres = direct_minimization(basis, tol=1e-8) # This is a constrained preconditioned LBFGS scfres.energies ρ = real(scfres.ρ.real)[:, 1, 1] # converged density ψ_fourier = scfres.ψ[1][:, 1]; # first kpoint, all G components, first eigenvector ψ = G_to_r(basis, basis.kpoints[1], ψ_fourier)[:, 1, 1] ψ /= (ψ[div(end, 2)] / abs(ψ[div(end, 2)])); x = a * vec(first.(DFTK.r_vectors(basis))) N = length(x) dx = a / N # real-space grid spacing @assert sum(abs2.(ψ)) * dx ≈ 1.0 norm(scfres.ρ.real - abs2.(ψ)) using Plots p = plot(x, real.(ψ), label="real(ψ)") plot!(p, x, imag.(ψ), label="imag(ψ)") plot!(p, x, ρ, label="ρ") E, ham = energy_hamiltonian(basis, scfres.ψ, scfres.occupation; ρ=scfres.ρ) @assert E.total == scfres.energies.total H = ham.blocks[1]; ψ11 = scfres.ψ[1][:, 1] # first kpoint, first eigenvector Hmat = Array(H) # This is now just a plain Julia matrix, # which we can compute and store in this simple 1D example @assert norm(Hmat * ψ11 - H * ψ11) < 1e-10 norm(H * ψ11 - dot(ψ11, H * ψ11) * ψ11) A = Array(Tridiagonal(-ones(N - 1), 2ones(N), -ones(N - 1))) A[1, end] = A[end, 1] = -1 K = A / dx^2 / 2 V = Diagonal(pot.(x) + C .* α .* (ρ.^(α-1))) H_findiff = K + V; maximum(abs.(H_findiff*ψ - (dot(ψ, H_findiff*ψ) / dot(ψ, ψ)) * ψ))