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.397547376235 -0.90 5.2 26.3ms
2 -8.400189504963 -2.58 -1.72 1.0 18.2ms
3 -8.400397228022 -3.68 -3.03 1.5 112ms
4 -8.400427786427 -4.51 -2.95 3.2 25.2ms
5 -8.400428074624 -6.54 -3.32 1.0 18.8ms
6 -8.400428149511 -7.13 -4.98 1.0 18.9ms
7 -8.400428152046 -8.60 -4.66 3.2 25.0ms
8 -8.400428152187 -9.85 -5.13 1.0 19.2ms
9 -8.400428152208 -10.68 -6.61 1.0 19.0ms
Potential-based SCF
scfres_scfv = DFTK.scf_potential_mixing(basis; tol);n Energy log10(ΔE) log10(Δρ) α Diag Δtime
--- --------------- --------- --------- ---- ---- ------
1 -8.397526947266 -0.90 5.2 1.89s
2 -8.400384400915 -2.54 -1.79 0.80 2.0 711ms
3 -8.400423439247 -4.41 -3.00 0.80 1.0 356ms
4 -8.400428119668 -5.33 -3.50 0.80 2.5 20.9ms
5 -8.400428149401 -7.53 -4.95 0.80 1.0 16.8ms
6 -8.400428152204 -8.55 -5.81 0.80 3.2 23.0ms
7 -8.400428152209 -11.30 -6.32 0.80 2.0 19.2ms
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.768383939682 -1.06 3.76s
2 -1.985291885426 0.44 -0.69 176ms
3 -4.718546065378 0.44 -0.41 118ms
4 -6.373119270069 0.22 -0.52 44.5ms
5 -7.808987855985 0.16 -0.76 43.9ms
6 -8.117275244651 -0.51 -1.28 32.5ms
7 -8.264101779478 -0.83 -1.69 32.5ms
8 -8.325377116755 -1.21 -1.86 32.6ms
9 -8.359491226300 -1.47 -2.18 66.8ms
10 -8.375148720432 -1.81 -2.33 32.9ms
11 -8.384879426870 -2.01 -2.44 33.0ms
12 -8.389786609289 -2.31 -2.79 32.9ms
13 -8.392298936012 -2.60 -2.85 32.9ms
14 -8.393337480888 -2.98 -3.08 32.6ms
15 -8.393768405962 -3.37 -3.70 32.8ms
16 -8.394170182345 -3.40 -3.55 41.7ms
17 -8.394715575373 -3.26 -3.28 32.7ms
18 -8.395868328655 -2.94 -2.73 32.7ms
19 -8.397288786214 -2.85 -2.97 32.8ms
20 -8.399159784168 -2.73 -3.04 32.7ms
21 -8.399958263242 -3.10 -3.76 39.4ms
22 -8.400211856210 -3.60 -3.44 33.0ms
23 -8.400358470380 -3.83 -3.95 32.7ms
24 -8.400381830985 -4.63 -3.92 32.7ms
25 -8.400411391341 -4.53 -4.34 32.8ms
26 -8.400418444481 -5.15 -4.16 39.4ms
27 -8.400424615619 -5.21 -4.97 33.1ms
28 -8.400425971987 -5.87 -4.30 33.1ms
29 -8.400427575178 -5.80 -4.69 32.6ms
30 -8.400427868719 -6.53 -4.93 44.1ms
31 -8.400428043817 -6.76 -5.17 40.0ms
32 -8.400428103566 -7.22 -5.21 33.0ms
33 -8.400428135701 -7.49 -5.77 33.0ms
34 -8.400428141056 -8.27 -5.44 32.7ms
35 -8.400428149142 -8.09 -5.85 32.8ms
36 -8.400428150157 -8.99 -5.74 39.9ms
37 -8.400428151748 -8.80 -5.87 32.8ms
38 -8.400428151943 -9.71 -6.55 32.9ms
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.397515962947 -0.90 5.2 26.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.400427980481 -1.79 11.7s
2 -8.400428152209 -6.77 -4.03 3.76s
3 -8.400428152209 -14.75 -7.85 75.1ms
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| = 5.77362856843328e-7
|ρ_newton - ρ_scfv| = 2.3368383343805158e-7
|ρ_newton - ρ_dm| = 6.246168601287243e-7