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.397859715427 -0.90 5.2 30.9ms
2 -8.400244549470 -2.62 -1.74 1.0 21.6ms
3 -8.400404884656 -3.79 -2.97 1.5 22.1ms
4 -8.400427855685 -4.64 -2.97 3.0 27.6ms
5 -8.400427918944 -7.20 -3.01 1.0 36.3ms
6 -8.400428144658 -6.65 -4.64 1.0 21.3ms
7 -8.400428151720 -8.15 -4.41 2.8 27.0ms
8 -8.400428152174 -9.34 -5.04 1.0 22.6ms
9 -8.400428152207 -10.48 -6.33 1.0 21.7msPotential-based SCF
scfres_scfv = DFTK.scf_potential_mixing(basis; tol);n Energy log10(ΔE) log10(Δρ) α Diag Δtime
--- --------------- --------- --------- ---- ---- ------
1 -8.397888199463 -0.90 5.5 44.8ms
2 -8.400382702182 -2.60 -1.77 0.80 2.0 21.6ms
3 -8.400423437013 -4.39 -2.97 0.80 1.0 18.6ms
4 -8.400428109114 -5.33 -3.48 0.80 2.2 22.4ms
5 -8.400428148565 -7.40 -4.99 0.80 1.2 18.3ms
6 -8.400428152204 -8.44 -5.29 0.80 3.2 25.2ms
7 -8.400428152208 -11.30 -6.57 0.80 1.0 18.5msDirect 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 +0.803836481554 -1.08 74.0ms
2 -1.757237103634 0.41 -0.65 34.6ms
3 -4.480260876681 0.44 -0.37 46.3ms
4 -5.940225066462 0.16 -0.45 46.8ms
5 -7.471375716783 0.19 -0.70 53.5ms
6 -7.506094127091 -1.46 -1.41 34.7ms
7 -7.922888276770 -0.38 -1.41 36.2ms
8 -8.213982608467 -0.54 -1.12 46.8ms
9 -8.253643871422 -1.40 -1.82 35.1ms
10 -8.339385978615 -1.07 -2.43 44.5ms
11 -8.356267519297 -1.77 -2.32 36.0ms
12 -8.379601246680 -1.63 -2.56 34.9ms
13 -8.387822795578 -2.09 -2.37 34.9ms
14 -8.395591318888 -2.11 -2.77 34.4ms
15 -8.398154523478 -2.59 -2.87 34.7ms
16 -8.399536862771 -2.86 -3.19 41.2ms
17 -8.399957911674 -3.38 -3.04 34.5ms
18 -8.400237500102 -3.55 -3.53 36.2ms
19 -8.400331902592 -4.03 -3.27 34.3ms
20 -8.400388376074 -4.25 -4.00 33.9ms
21 -8.400404942190 -4.78 -3.65 34.5ms
22 -8.400418462281 -4.87 -4.42 43.5ms
23 -8.400423740155 -5.28 -3.98 34.2ms
24 -8.400426699525 -5.53 -4.54 34.0ms
25 -8.400427557860 -6.07 -4.37 34.6ms
26 -8.400427903517 -6.46 -5.02 34.4ms
27 -8.400428044534 -6.85 -4.80 34.4ms
28 -8.400428112974 -7.16 -5.14 42.5ms
29 -8.400428138255 -7.60 -5.11 34.7ms
30 -8.400428145610 -8.13 -5.47 36.5ms
31 -8.400428149265 -8.44 -5.66 34.4ms
32 -8.400428150568 -8.88 -5.71 34.7ms
33 -8.400428151538 -9.01 -6.00 34.3msNewton 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.397839294351 -0.90 5.0 29.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.400427985826 -1.79 612ms
2 -8.400428152209 -6.78 -4.04 406ms
3 -8.400428152209 -14.75 -7.84 124msComparison 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| = 7.034236832991148e-7
|ρ_newton - ρ_scfv| = 3.473726560179103e-7
|ρ_newton - ρ_dm| = 2.2438275793953397e-6