Comparison of DFT solvers
We compare four different approaches for solving the DFT minimisation problem, namely a density-based SCF, a potential-based SCF, direct minimisation and Newton.
First we setup our problem
using AtomsBuilder
using DFTK
using LinearAlgebra
using PseudoPotentialData
pseudopotentials = PseudoFamily("dojo.nc.sr.pbesol.v0_4_1.standard.upf")
model = model_DFT(bulk(:Si); functionals=PBEsol(), pseudopotentials)
basis = PlaneWaveBasis(model; Ecut=5, kgrid=[3, 3, 3])
# Convergence we desire in the density
tol = 1e-61.0e-6Density-based self-consistent field
scfres_scf = self_consistent_field(basis; tol);n Energy log10(ΔE) log10(Δρ) Diag Δtime
--- --------------- --------- --------- ---- ------
1 -8.397784993516 -0.90 5.0 27.7ms
2 -8.400242366402 -2.61 -1.74 1.0 20.4ms
3 -8.400399386720 -3.80 -2.94 1.5 21.3ms
4 -8.400427774461 -4.55 -2.92 3.0 37.7ms
5 -8.400427937432 -6.79 -3.02 1.0 20.4ms
6 -8.400428144721 -6.68 -4.90 1.0 20.3ms
7 -8.400428151718 -8.16 -4.39 3.5 27.2ms
8 -8.400428152194 -9.32 -5.82 1.2 21.1ms
9 -8.400428152209 -10.83 -6.37 2.0 23.3msPotential-based SCF
scfres_scfv = DFTK.scf_potential_mixing(basis; tol);n Energy log10(ΔE) log10(Δρ) α Diag Δtime
--- --------------- --------- --------- ---- ---- ------
1 -8.397798252234 -0.90 5.2 28.7ms
2 -8.400376774580 -2.59 -1.77 0.80 2.2 20.5ms
3 -8.400422723782 -4.34 -2.96 0.80 1.0 17.3ms
4 -8.400428105275 -5.27 -3.51 0.80 2.5 21.2ms
5 -8.400428148047 -7.37 -5.20 0.80 1.2 18.3ms
6 -8.400428152206 -8.38 -5.22 0.80 3.8 25.0ms
7 -8.400428152209 -11.60 -6.34 0.80 1.0 17.6msDirect minimization
scfres_dm = direct_minimization(basis; tol);┌ Warning: x_tol is deprecated. Use x_abstol or x_reltol instead. The provided value (-1) will be used as x_abstol.
└ @ Optim ~/.julia/packages/Optim/7krni/src/types.jl:110
┌ Warning: f_tol is deprecated. Use f_abstol or f_reltol instead. The provided value (-1) will be used as f_reltol.
└ @ Optim ~/.julia/packages/Optim/7krni/src/types.jl:120
n Energy log10(ΔE) log10(Δρ) Δtime
--- --------------- --------- --------- ------
1 +1.138759181862 -1.10 67.7ms
2 -1.617531458491 0.44 -0.63 33.6ms
3 -4.250502228829 0.42 -0.32 45.5ms
4 -5.671731198349 0.15 -0.41 45.3ms
5 -7.448415030139 0.25 -0.52 51.8ms
6 -7.556091592187 -0.97 -1.23 33.5ms
7 -8.175130719880 -0.21 -1.33 33.7ms
8 -8.266315813733 -1.04 -1.78 33.8ms
9 -8.322491472162 -1.25 -1.97 34.0ms
10 -8.355173290880 -1.49 -2.09 41.6ms
11 -8.376266636642 -1.68 -2.43 33.7ms
12 -8.388260235780 -1.92 -2.80 33.7ms
13 -8.394491894338 -2.21 -2.53 33.6ms
14 -8.398096572867 -2.44 -2.82 33.8ms
15 -8.399448283173 -2.87 -3.25 33.7ms
16 -8.400018972910 -3.24 -3.38 41.3ms
17 -8.400206770763 -3.73 -3.55 34.1ms
18 -8.400342601191 -3.87 -3.44 33.6ms
19 -8.400383585910 -4.39 -3.81 33.9ms
20 -8.400410661684 -4.57 -3.93 34.0ms
21 -8.400418806240 -5.09 -4.10 33.7ms
22 -8.400423908374 -5.29 -4.41 41.4ms
23 -8.400425850109 -5.71 -4.73 33.9ms
24 -8.400427075096 -5.91 -4.61 33.5ms
25 -8.400427678392 -6.22 -5.31 33.8ms
26 -8.400427958292 -6.55 -4.92 33.7ms
27 -8.400428052572 -7.03 -5.25 33.7ms
28 -8.400428113606 -7.21 -5.24 39.5ms
29 -8.400428132372 -7.73 -5.42 33.8ms
30 -8.400428145814 -7.87 -5.55 33.6ms
31 -8.400428149396 -8.45 -5.87 33.7ms
32 -8.400428151065 -8.78 -6.17 33.7msNewton algorithm
Start not too far from the solution to ensure convergence: We run first a very crude SCF to get close and then switch to Newton.
scfres_start = self_consistent_field(basis; tol=0.5);n Energy log10(ΔE) log10(Δρ) Diag Δtime
--- --------------- --------- --------- ---- ------
1 -8.397891778556 -0.90 5.2 28.6msRemove the virtual orbitals (which Newton cannot treat yet)
ψ = DFTK.select_occupied_orbitals(basis, scfres_start.ψ, scfres_start.occupation).ψ
scfres_newton = newton(basis, ψ; tol);n Energy log10(ΔE) log10(Δρ) Δtime
--- --------------- --------- --------- ------
1 -8.400427989879 -1.79 616ms
2 -8.400428152209 -6.79 -4.04 400ms
3 -8.400428152209 -14.45 -7.86 103msComparison of results
println("|ρ_newton - ρ_scf| = ", norm(scfres_newton.ρ - scfres_scf.ρ))
println("|ρ_newton - ρ_scfv| = ", norm(scfres_newton.ρ - scfres_scfv.ρ))
println("|ρ_newton - ρ_dm| = ", norm(scfres_newton.ρ - scfres_dm.ρ))|ρ_newton - ρ_scf| = 5.265036059276644e-7
|ρ_newton - ρ_scfv| = 3.1391134817814887e-7
|ρ_newton - ρ_dm| = 2.571024482390791e-6