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.397869930941 -0.90 5.0 27.0ms
2 -8.400242650011 -2.62 -1.74 1.0 19.6ms
3 -8.400406177549 -3.79 -2.98 1.5 20.6ms
4 -8.400427850036 -4.66 -2.98 3.2 25.3ms
5 -8.400427941838 -7.04 -3.05 1.0 19.7ms
6 -8.400428145821 -6.69 -4.51 1.0 19.8ms
7 -8.400428151695 -8.23 -4.42 2.2 23.1ms
8 -8.400428152179 -9.31 -5.16 1.0 19.8ms
9 -8.400428152207 -10.56 -6.16 1.5 64.3msPotential-based SCF
scfres_scfv = DFTK.scf_potential_mixing(basis; tol);n Energy log10(ΔE) log10(Δρ) α Diag Δtime
--- --------------- --------- --------- ---- ---- ------
1 -8.397830272404 -0.90 5.0 27.5ms
2 -8.400383902420 -2.59 -1.78 0.80 2.2 20.8ms
3 -8.400422943373 -4.41 -2.99 0.80 1.0 17.3ms
4 -8.400428105784 -5.29 -3.45 0.80 2.8 21.6ms
5 -8.400428149701 -7.36 -4.72 0.80 1.5 18.7ms
6 -8.400428152188 -8.60 -5.68 0.80 2.5 21.1ms
7 -8.400428152209 -10.67 -6.16 0.80 2.2 21.2msDirect 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.866686241541 -1.04 58.9ms
2 -1.499489568951 0.37 -0.65 32.7ms
3 -4.547845687275 0.48 -0.39 43.8ms
4 -6.068610645817 0.18 -0.49 43.7ms
5 -7.577347519852 0.18 -0.78 43.8ms
6 -7.996827859288 -0.38 -1.29 32.5ms
7 -8.201972864217 -0.69 -1.50 32.5ms
8 -8.252972604863 -1.29 -1.75 32.6ms
9 -8.296007314027 -1.37 -1.88 33.1ms
10 -8.301859057674 -2.23 -1.98 45.6ms
11 -8.317105693141 -1.82 -1.77 33.5ms
12 -8.361203195060 -1.36 -1.70 45.2ms
13 -8.380169696928 -1.72 -2.00 45.3ms
14 -8.393851984409 -1.86 -2.56 33.5ms
15 -8.394967150696 -2.95 -3.05 33.9ms
16 -8.397669212604 -2.57 -2.97 33.6ms
17 -8.398746961765 -2.97 -3.00 33.6ms
18 -8.399588418315 -3.07 -3.23 33.3ms
19 -8.400044259016 -3.34 -3.29 33.2ms
20 -8.400262556747 -3.66 -3.52 33.4ms
21 -8.400375133763 -3.95 -3.77 33.6ms
22 -8.400412036900 -4.43 -3.84 32.8ms
23 -8.400421315196 -5.03 -4.10 33.0ms
24 -8.400425869884 -5.34 -4.23 42.6ms
25 -8.400426988800 -5.95 -4.65 33.5ms
26 -8.400427751839 -6.12 -4.75 33.3ms
27 -8.400427997660 -6.61 -4.93 33.3ms
28 -8.400428099384 -6.99 -5.00 33.3ms
29 -8.400428126504 -7.57 -4.97 33.9ms
30 -8.400428143226 -7.78 -5.33 33.4ms
31 -8.400428146649 -8.47 -5.64 32.7ms
32 -8.400428149910 -8.49 -5.63 32.5ms
33 -8.400428151003 -8.96 -5.88 32.3ms
34 -8.400428151836 -9.08 -6.16 32.4msNewton 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.397802414684 -0.90 5.2 34.6msRemove 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.400427981975 -1.79 605ms
2 -8.400428152209 -6.77 -4.03 405ms
3 -8.400428152209 -14.45 -7.84 101msComparison 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| = 3.8517478841090336e-7
|ρ_newton - ρ_scfv| = 1.6844234814559423e-7
|ρ_newton - ρ_dm| = 1.4441002405698352e-6