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-6
1.0e-6
Density-based self-consistent field
scfres_scf = self_consistent_field(basis; tol);
n Energy log10(ΔE) log10(Δρ) Diag Δtime
--- --------------- --------- --------- ---- ------
1 -8.397783097643 -0.90 5.2 26.3ms
2 -8.400232125236 -2.61 -1.74 1.0 18.8ms
3 -8.400404610549 -3.76 -2.97 1.5 26.2ms
4 -8.400427818704 -4.63 -2.97 3.0 23.8ms
5 -8.400427902253 -7.08 -3.02 1.0 18.8ms
6 -8.400428144293 -6.62 -4.53 1.0 22.9ms
7 -8.400428151620 -8.14 -4.37 3.0 24.2ms
8 -8.400428152188 -9.25 -5.48 1.0 19.2ms
9 -8.400428152208 -10.71 -6.10 1.8 21.3ms
Potential-based SCF
scfres_scfv = DFTK.scf_potential_mixing(basis; tol);
n Energy log10(ΔE) log10(Δρ) α Diag Δtime
--- --------------- --------- --------- ---- ---- ------
1 -8.397794151797 -0.90 5.0 25.8ms
2 -8.400378653892 -2.59 -1.78 0.80 2.2 19.1ms
3 -8.400422261617 -4.36 -2.98 0.80 1.0 16.1ms
4 -8.400428094630 -5.23 -3.40 0.80 2.5 24.3ms
5 -8.400428148335 -7.27 -4.59 0.80 1.2 17.3ms
6 -8.400428152173 -8.42 -5.38 0.80 2.5 19.8ms
7 -8.400428152207 -10.47 -6.29 0.80 1.8 18.3ms
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/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.127154337369 -1.05 62.1ms
2 -1.733596683750 0.46 -0.63 32.8ms
3 -4.643059596334 0.46 -0.38 43.8ms
4 -6.329362109434 0.23 -0.47 47.4ms
5 -7.622975725904 0.11 -0.80 43.9ms
6 -8.007867463797 -0.41 -1.39 32.6ms
7 -8.191576771524 -0.74 -1.64 36.0ms
8 -8.275875311660 -1.07 -1.87 32.5ms
9 -8.313777596077 -1.42 -2.18 32.5ms
10 -8.354013752573 -1.40 -2.33 32.8ms
11 -8.378643970930 -1.61 -2.14 36.1ms
12 -8.390911315511 -1.91 -2.34 32.8ms
13 -8.396611497525 -2.24 -2.86 32.5ms
14 -8.398705974326 -2.68 -2.76 35.9ms
15 -8.399733245477 -2.99 -2.97 32.5ms
16 -8.400123106356 -3.41 -3.55 32.4ms
17 -8.400292001743 -3.77 -3.31 32.3ms
18 -8.400376254990 -4.07 -4.01 35.6ms
19 -8.400408188799 -4.50 -3.56 32.3ms
20 -8.400420687697 -4.90 -4.24 32.4ms
21 -8.400425103118 -5.36 -4.12 35.7ms
22 -8.400426779087 -5.78 -4.60 32.5ms
23 -8.400427539916 -6.12 -4.66 32.4ms
24 -8.400427860922 -6.49 -4.87 32.3ms
25 -8.400428043198 -6.74 -4.99 35.7ms
26 -8.400428096394 -7.27 -5.22 32.3ms
27 -8.400428131427 -7.46 -5.38 32.6ms
28 -8.400428142596 -7.95 -5.43 32.3ms
29 -8.400428148705 -8.21 -5.95 35.8ms
30 -8.400428150419 -8.77 -5.76 32.7ms
31 -8.400428151528 -8.95 -6.57 32.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.397846609589 -0.90 5.2 26.1ms
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.400427986823 -1.79 590ms
2 -8.400428152209 -6.78 -4.04 396ms
3 -8.400428152209 -14.75 -7.85 103ms
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| = 1.5169881095948585e-6
|ρ_newton - ρ_scfv| = 5.470216222855008e-7
|ρ_newton - ρ_dm| = 1.7241801397733728e-6