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.397539502634 -0.90 5.0 27.1ms
2 -8.400195871695 -2.58 -1.72 1.0 18.9ms
3 -8.400398110394 -3.69 -3.02 1.5 19.9ms
4 -8.400427766454 -4.53 -2.94 3.2 98.0ms
5 -8.400428048210 -6.55 -3.24 1.0 19.3ms
6 -8.400428149314 -7.00 -4.80 1.0 19.3ms
7 -8.400428152017 -8.57 -4.65 2.8 23.8ms
8 -8.400428152192 -9.76 -5.24 1.0 19.8ms
9 -8.400428152208 -10.80 -6.44 1.0 20.0ms
Potential-based SCF
scfres_scfv = DFTK.scf_potential_mixing(basis; tol);n Energy log10(ΔE) log10(Δρ) α Diag Δtime
--- --------------- --------- --------- ---- ---- ------
1 -8.397521905396 -0.90 5.8 1.82s
2 -8.400387290136 -2.54 -1.78 0.80 2.2 553ms
3 -8.400423721157 -4.44 -3.00 0.80 1.0 261ms
4 -8.400428117489 -5.36 -3.52 0.80 2.5 21.5ms
5 -8.400428149100 -7.50 -5.01 0.80 1.0 17.6ms
6 -8.400428152201 -8.51 -5.38 0.80 3.5 24.5ms
7 -8.400428152208 -11.12 -6.13 0.80 1.0 17.9ms
Direct 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/gmigl/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/gmigl/src/types.jl:120
n Energy log10(ΔE) log10(Δρ) Δtime
--- --------------- --------- --------- ------
1 +0.964874060889 -1.07 4.98s
2 -1.402789038380 0.37 -0.66 158ms
3 -4.021552573625 0.42 -0.38 45.7ms
4 -5.359226123539 0.13 -0.45 46.0ms
5 -7.114977115250 0.24 -0.57 46.4ms
6 -7.737812476674 -0.21 -1.03 45.6ms
7 -8.001476161793 -0.58 -1.37 33.8ms
8 -8.213132832119 -0.67 -1.54 34.2ms
9 -8.309687717281 -1.02 -1.65 34.1ms
10 -8.355478584503 -1.34 -2.09 33.7ms
11 -8.378987017113 -1.63 -2.83 33.9ms
12 -8.388264796329 -2.03 -2.56 34.1ms
13 -8.394146655577 -2.23 -2.75 34.0ms
14 -8.396235210067 -2.68 -3.04 34.3ms
15 -8.397832460939 -2.80 -3.21 33.9ms
16 -8.398857114642 -2.99 -3.13 33.7ms
17 -8.399653855209 -3.10 -3.09 33.8ms
18 -8.400159188710 -3.30 -3.18 33.6ms
19 -8.400325656600 -3.78 -3.67 34.4ms
20 -8.400393043016 -4.17 -3.75 33.7ms
21 -8.400413442919 -4.69 -3.81 92.5ms
22 -8.400422332062 -5.05 -4.45 34.0ms
23 -8.400426068171 -5.43 -4.18 34.1ms
24 -8.400427214899 -5.94 -4.58 34.1ms
25 -8.400427774090 -6.25 -5.05 34.2ms
26 -8.400428026003 -6.60 -5.33 34.0ms
27 -8.400428086486 -7.22 -5.15 34.0ms
28 -8.400428122199 -7.45 -5.27 33.9ms
29 -8.400428136371 -7.85 -5.76 33.6ms
30 -8.400428144976 -8.07 -5.51 34.5ms
31 -8.400428149373 -8.36 -6.23 34.3ms
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 -8.397523099214 -0.90 5.5 28.7ms
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 -8.400427982952 -1.79 12.0s
2 -8.400428152209 -6.77 -4.04 3.84s
3 -8.400428152209 -14.45 -7.85 102ms
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.7551806089688964e-7
|ρ_newton - ρ_scfv| = 4.7313696123730925e-7
|ρ_newton - ρ_dm| = 5.409855931616314e-6