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.397534019310 -0.90 5.5 27.0ms
2 -8.400214938849 -2.57 -1.72 1.0 18.1ms
3 -8.400392867940 -3.75 -2.97 1.2 18.5ms
4 -8.400427662012 -4.46 -2.90 3.2 107ms
5 -8.400428106359 -6.35 -3.48 1.0 18.2ms
6 -8.400428149230 -7.37 -4.47 1.0 18.3ms
7 -8.400428152107 -8.54 -4.85 2.2 22.6ms
8 -8.400428152196 -10.05 -5.36 1.0 18.3ms
9 -8.400428152208 -10.92 -6.26 1.8 20.1ms
Potential-based SCF
scfres_scfv = DFTK.scf_potential_mixing(basis; tol);n Energy log10(ΔE) log10(Δρ) α Diag Δtime
--- --------------- --------- --------- ---- ---- ------
1 -8.397493653699 -0.90 5.2 1.69s
2 -8.400383742047 -2.54 -1.78 0.80 2.0 656ms
3 -8.400423166357 -4.40 -2.99 0.80 1.0 336ms
4 -8.400428102145 -5.31 -3.46 0.80 2.2 20.4ms
5 -8.400428148027 -7.34 -4.79 0.80 1.2 17.1ms
6 -8.400428152198 -8.38 -5.40 0.80 3.2 22.6ms
7 -8.400428152208 -10.97 -6.81 0.80 1.2 17.4ms
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.701853675602 -1.08 3.29s
2 -1.849017931266 0.41 -0.66 146ms
3 -4.636944847902 0.45 -0.39 105ms
4 -6.423057203887 0.25 -0.48 43.8ms
5 -7.758110659317 0.13 -0.83 45.2ms
6 -8.108895492792 -0.45 -1.33 32.7ms
7 -8.206990099885 -1.01 -1.65 32.4ms
8 -8.295576652992 -1.05 -1.90 32.2ms
9 -8.325227911712 -1.53 -2.13 62.1ms
10 -8.360866013725 -1.45 -2.30 32.6ms
11 -8.379894611369 -1.72 -2.04 32.3ms
12 -8.389826707140 -2.00 -2.31 32.3ms
13 -8.395697484976 -2.23 -2.60 32.3ms
14 -8.398279198017 -2.59 -3.18 32.1ms
15 -8.399577423996 -2.89 -3.28 32.5ms
16 -8.400080770561 -3.30 -3.54 39.7ms
17 -8.400281178495 -3.70 -3.52 32.5ms
18 -8.400371632670 -4.04 -3.90 32.5ms
19 -8.400402123870 -4.52 -3.75 32.4ms
20 -8.400416720110 -4.84 -4.13 32.8ms
21 -8.400423409630 -5.17 -4.08 40.1ms
22 -8.400425835304 -5.62 -4.43 32.6ms
23 -8.400427203210 -5.86 -4.70 32.6ms
24 -8.400427715321 -6.29 -4.90 32.8ms
25 -8.400427970171 -6.59 -4.96 32.4ms
26 -8.400428079586 -6.96 -5.10 38.2ms
27 -8.400428119961 -7.39 -5.25 32.4ms
28 -8.400428139712 -7.70 -5.36 32.3ms
29 -8.400428147622 -8.10 -5.79 32.2ms
30 -8.400428150336 -8.57 -5.85 32.1ms
31 -8.400428151454 -8.95 -6.32 37.4ms
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.397522006672 -0.90 5.0 26.3ms
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.400427983177 -1.79 11.1s
2 -8.400428152209 -6.77 -4.04 3.61s
3 -8.400428152209 -14.45 -7.86 90.6ms
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| = 2.946446237994852e-7
|ρ_newton - ρ_scfv| = 3.861534150920846e-7
|ρ_newton - ρ_dm| = 1.9297730292991e-6