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.397836327215 -0.90 5.0 27.3ms
2 -8.400254094267 -2.62 -1.74 1.0 19.6ms
3 -8.400401015308 -3.83 -2.93 1.2 19.7ms
4 -8.400427776864 -4.57 -2.92 3.2 25.4ms
5 -8.400427864782 -7.06 -2.95 1.0 31.6ms
6 -8.400428144530 -6.55 -4.71 1.0 19.7ms
7 -8.400428151598 -8.15 -4.35 3.2 25.6ms
8 -8.400428152189 -9.23 -5.60 1.0 20.1ms
9 -8.400428152209 -10.71 -5.94 2.0 23.0ms
10 -8.400428152209 -13.08 -6.12 1.0 20.2msPotential-based SCF
scfres_scfv = DFTK.scf_potential_mixing(basis; tol);n Energy log10(ΔE) log10(Δρ) α Diag Δtime
--- --------------- --------- --------- ---- ---- ------
1 -8.397851979858 -0.90 5.2 28.3ms
2 -8.400384309608 -2.60 -1.79 0.80 2.0 20.1ms
3 -8.400422296693 -4.42 -3.02 0.80 1.0 17.1ms
4 -8.400428104806 -5.24 -3.40 0.80 2.5 21.1ms
5 -8.400428148532 -7.36 -4.54 0.80 1.0 16.8ms
6 -8.400428152180 -8.44 -5.93 0.80 2.5 21.1ms
7 -8.400428152209 -10.54 -5.98 0.80 3.2 32.1ms
8 -8.400428152209 -12.98 -7.20 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/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.627633972220 -1.13 58.6ms
2 -1.609282063153 0.35 -0.67 33.7ms
3 -4.838616526367 0.51 -0.40 44.6ms
4 -6.469094884107 0.21 -0.52 52.7ms
5 -7.745535535309 0.11 -0.84 44.0ms
6 -8.135542340726 -0.41 -1.24 32.6ms
7 -8.254683404827 -0.92 -1.72 32.7ms
8 -8.333650530402 -1.10 -1.84 33.3ms
9 -8.356100846995 -1.65 -2.28 40.6ms
10 -8.378145442172 -1.66 -2.51 32.8ms
11 -8.389295518810 -1.95 -2.16 33.3ms
12 -8.396159524440 -2.16 -2.43 34.2ms
13 -8.398556642290 -2.62 -2.74 34.8ms
14 -8.399632648904 -2.97 -3.07 40.4ms
15 -8.400041729243 -3.39 -3.01 33.1ms
16 -8.400266951883 -3.65 -3.46 32.6ms
17 -8.400354827046 -4.06 -3.43 32.9ms
18 -8.400394549276 -4.40 -3.65 32.8ms
19 -8.400413498843 -4.72 -3.87 33.1ms
20 -8.400421341827 -5.11 -3.90 40.5ms
21 -8.400425595635 -5.37 -4.22 33.4ms
22 -8.400426783197 -5.93 -4.41 33.0ms
23 -8.400427483135 -6.15 -5.26 32.8ms
24 -8.400427820929 -6.47 -4.61 32.9ms
25 -8.400428005442 -6.73 -5.16 32.5ms
26 -8.400428086362 -7.09 -4.93 40.9ms
27 -8.400428124561 -7.42 -5.62 32.8ms
28 -8.400428134936 -7.98 -5.32 32.9ms
29 -8.400428145992 -7.96 -5.71 32.7ms
30 -8.400428148720 -8.56 -5.69 33.4ms
31 -8.400428150713 -8.70 -6.05 40.8msNewton 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.397873013063 -0.90 5.0 27.4msRemove 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.400427981527 -1.78 607ms
2 -8.400428152209 -6.77 -4.03 414ms
3 -8.400428152209 -14.45 -7.83 107msComparison 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| = 6.500430119291558e-7
|ρ_newton - ρ_scfv| = 5.81697582032615e-8
|ρ_newton - ρ_dm| = 8.70689564998361e-7