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
system = attach_psp(bulk(:Si); Si="hgh/lda/Si-q4")
model = model_DFT(system; functionals=PBEsol())
basis = PlaneWaveBasis(model; Ecut=5, kgrid=[3, 3, 3])
# Convergence we desire in the density
tol = 1e-6
1.0e-6
Density-based self-consistent field
scfres_scf = self_consistent_field(basis; tol);
n Energy log10(ΔE) log10(Δρ) Diag Δtime
--- --------------- --------- --------- ---- ------
1 -7.844826470045 -0.71 4.5 35.1ms
2 -7.848885785438 -2.39 -1.53 1.0 24.8ms
3 -7.849099650509 -3.67 -2.49 1.2 25.5ms
4 -7.849134992103 -4.45 -2.78 2.5 30.3ms
5 -7.849135710717 -6.14 -2.96 1.0 32.9ms
6 -7.849136041012 -6.48 -4.02 1.0 25.1ms
7 -7.849136054049 -7.88 -4.83 2.0 28.8ms
8 -7.849136054369 -9.49 -5.15 2.0 28.7ms
9 -7.849136054390 -10.68 -5.67 1.2 32.0ms
10 -7.849136054392 -11.68 -6.25 1.0 26.1ms
Potential-based SCF
scfres_scfv = DFTK.scf_potential_mixing(basis; tol);
n Energy log10(ΔE) log10(Δρ) α Diag Δtime
--- --------------- --------- --------- ---- ---- ------
1 -7.844893190179 -0.71 4.8 35.7ms
2 -7.849060851015 -2.38 -1.66 0.80 2.0 32.0ms
3 -7.849129354398 -4.16 -2.75 0.80 1.0 22.1ms
4 -7.849135909440 -5.18 -3.31 0.80 2.0 25.6ms
5 -7.849136044987 -6.87 -4.36 0.80 1.2 22.8ms
6 -7.849136054314 -8.03 -5.12 0.80 2.0 25.9ms
7 -7.849136054390 -10.12 -5.61 0.80 1.5 23.8ms
8 -7.849136054392 -11.61 -6.89 0.80 1.2 29.0ms
Direct minimization
scfres_dm = direct_minimization(basis; tol);
n Energy log10(ΔE) log10(Δρ) Δtime
--- --------------- --------- --------- ------
1 +1.410593455830 -1.01 75.8ms
2 -1.347811410028 0.44 -0.68 43.6ms
3 -3.658104485535 0.36 -0.45 65.6ms
4 -4.940100256223 0.11 -0.59 66.0ms
5 -6.592509357714 0.22 -0.75 63.2ms
6 -7.250146423404 -0.18 -1.23 58.5ms
7 -7.560667326600 -0.51 -1.44 43.5ms
8 -7.690448332350 -0.89 -1.86 43.0ms
9 -7.740532613015 -1.30 -1.98 48.8ms
10 -7.773722994413 -1.48 -2.25 43.4ms
11 -7.802668970872 -1.54 -2.02 43.4ms
12 -7.822044618640 -1.71 -2.25 43.3ms
13 -7.836134829832 -1.85 -2.30 48.0ms
14 -7.840591976793 -2.35 -2.57 43.3ms
15 -7.841273153663 -3.17 -3.17 43.6ms
16 -7.841671136660 -3.40 -2.88 43.3ms
17 -7.845233860945 -2.45 -2.91 48.6ms
18 -7.847749961520 -2.60 -2.99 43.4ms
19 -7.848546148032 -3.10 -3.18 43.2ms
20 -7.848938412796 -3.41 -3.45 43.5ms
21 -7.849077510415 -3.86 -3.82 48.3ms
22 -7.849116793517 -4.41 -3.88 43.7ms
23 -7.849130691152 -4.86 -4.55 43.5ms
24 -7.849134422032 -5.43 -4.71 43.3ms
25 -7.849135464470 -5.98 -4.92 49.1ms
26 -7.849135855273 -6.41 -5.02 46.0ms
27 -7.849135987604 -6.88 -5.65 48.7ms
28 -7.849136034937 -7.32 -5.44 44.1ms
29 -7.849136047497 -7.90 -6.39 48.4ms
Newton 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 -7.844881523071 -0.71 4.8 35.4ms
Remove 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 -7.849135371178 -1.65 572ms
2 -7.849136054392 -6.17 -3.72 430ms
3 -7.849136054393 -13.21 -7.21 168ms
Comparison 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| = 4.068993874732651e-7
|ρ_newton - ρ_scfv| = 1.716931260669828e-7
|ρ_newton - ρ_dm| = 1.21327835625516e-6