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.397492705270 -0.90 5.2 27.5ms
2 -8.400183003496 -2.57 -1.72 1.0 18.7ms
3 -8.400397103459 -3.67 -3.04 1.5 19.9ms
4 -8.400427796703 -4.51 -2.97 3.0 24.2ms
5 -8.400428072605 -6.56 -3.32 1.0 19.1ms
6 -8.400428149312 -7.12 -4.99 1.0 18.8ms
7 -8.400428152062 -8.56 -4.69 3.2 25.1ms
8 -8.400428152192 -9.88 -5.19 1.0 52.8ms
9 -8.400428152208 -10.80 -6.67 1.0 19.1ms
Potential-based SCF
scfres_scfv = DFTK.scf_potential_mixing(basis; tol);n Energy log10(ΔE) log10(Δρ) α Diag Δtime
--- --------------- --------- --------- ---- ---- ------
1 -8.397541900527 -0.90 5.0 1.90s
2 -8.400386343134 -2.55 -1.78 0.80 2.0 527ms
3 -8.400423699294 -4.43 -2.96 0.80 1.0 241ms
4 -8.400428113232 -5.36 -3.47 0.80 2.5 20.9ms
5 -8.400428149290 -7.44 -4.77 0.80 1.2 17.6ms
6 -8.400428152190 -8.54 -5.50 0.80 2.5 21.6ms
7 -8.400428152208 -10.73 -6.19 0.80 2.0 19.7ms
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.903105440088 -1.03 3.58s
2 -1.704197207711 0.42 -0.64 150ms
3 -4.259524850913 0.41 -0.35 44.4ms
4 -5.513699787408 0.10 -0.41 44.1ms
5 -7.282946395942 0.25 -0.51 79.4ms
6 -7.902990153931 -0.21 -1.02 44.3ms
7 -8.115170893175 -0.67 -1.26 32.9ms
8 -8.257032680626 -0.85 -1.77 33.2ms
9 -8.328810266029 -1.14 -1.82 33.0ms
10 -8.365158009826 -1.44 -2.12 32.9ms
11 -8.385723799705 -1.69 -2.39 57.6ms
12 -8.392593543593 -2.16 -2.31 33.2ms
13 -8.397930694856 -2.27 -2.78 33.0ms
14 -8.398842588706 -3.04 -2.82 32.7ms
15 -8.399906314447 -2.97 -3.00 32.5ms
16 -8.400144841965 -3.62 -3.17 32.9ms
17 -8.400313862540 -3.77 -3.76 40.6ms
18 -8.400365535006 -4.29 -3.66 32.8ms
19 -8.400409966585 -4.35 -4.02 32.9ms
20 -8.400417670670 -5.11 -3.89 33.2ms
21 -8.400424251378 -5.18 -4.62 32.8ms
22 -8.400425730155 -5.83 -4.32 39.1ms
23 -8.400427218010 -5.83 -4.95 32.8ms
24 -8.400427668263 -6.35 -4.60 32.9ms
25 -8.400427983346 -6.50 -5.11 32.7ms
26 -8.400428080548 -7.01 -4.90 32.5ms
27 -8.400428127963 -7.32 -5.73 38.5ms
28 -8.400428136647 -8.06 -5.44 33.0ms
29 -8.400428145819 -8.04 -5.96 33.0ms
30 -8.400428148825 -8.52 -5.73 32.5ms
31 -8.400428150689 -8.73 -6.24 32.6ms
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.397558030985 -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.400427984907 -1.79 11.8s
2 -8.400428152209 -6.78 -4.03 3.87s
3 -8.400428152209 -14.45 -7.86 1.27s
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.015353288271713e-7
|ρ_newton - ρ_scfv| = 3.720706192050978e-7
|ρ_newton - ρ_dm| = 1.547039825464894e-6