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.397537016312 -0.90 5.2 15.8ms
2 -8.400212914427 -2.57 -1.72 1.0 11.2ms
3 -8.400393708936 -3.74 -2.97 1.5 11.8ms
4 -8.400427722869 -4.47 -2.91 3.2 14.3ms
5 -8.400428105400 -6.42 -3.46 1.0 11.4ms
6 -8.400428149382 -7.36 -4.63 1.0 11.4ms
7 -8.400428152092 -8.57 -4.82 2.2 13.3ms
8 -8.400428152181 -10.05 -5.07 1.0 11.7ms
9 -8.400428152207 -10.58 -6.06 1.0 11.3ms
Potential-based SCF
scfres_scfv = DFTK.scf_potential_mixing(basis; tol);n Energy log10(ΔE) log10(Δρ) α Diag Δtime
--- --------------- --------- --------- ---- ---- ------
1 -8.397488664258 -0.90 5.5 1.08s
2 -8.400385998823 -2.54 -1.78 0.80 2.0 663ms
3 -8.400423438876 -4.43 -2.96 0.80 1.0 132ms
4 -8.400428099598 -5.33 -3.46 0.80 2.5 12.2ms
5 -8.400428150114 -7.30 -4.72 0.80 1.2 10.5ms
6 -8.400428152178 -8.69 -5.69 0.80 2.5 12.2ms
7 -8.400428152209 -10.51 -5.93 0.80 2.5 12.3ms
8 -8.400428152209 -12.65 -7.26 0.80 1.0 10.1ms
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.802925759647 -1.12 2.21s
2 -1.630746337825 0.39 -0.68 159ms
3 -4.237442741058 0.42 -0.43 28.3ms
4 -5.588623354990 0.13 -0.54 28.0ms
5 -7.230263725330 0.22 -0.65 29.0ms
6 -7.836331878749 -0.22 -1.07 28.7ms
7 -8.055938681926 -0.66 -1.29 20.8ms
8 -8.208795089567 -0.82 -1.72 20.5ms
9 -8.274637206606 -1.18 -1.76 54.3ms
10 -8.330163409718 -1.26 -1.97 20.3ms
11 -8.365901058848 -1.45 -2.03 20.6ms
12 -8.385119660502 -1.72 -2.00 20.7ms
13 -8.393754625766 -2.06 -2.78 20.1ms
14 -8.397620800771 -2.41 -2.70 19.9ms
15 -8.399335701315 -2.77 -3.15 19.9ms
16 -8.399939125076 -3.22 -3.21 26.0ms
17 -8.400251926749 -3.50 -3.28 20.1ms
18 -8.400369332341 -3.93 -3.90 20.1ms
19 -8.400403420125 -4.47 -3.86 19.9ms
20 -8.400418140586 -4.83 -3.97 20.4ms
21 -8.400422165410 -5.40 -4.06 20.4ms
22 -8.400425430307 -5.49 -4.57 27.7ms
23 -8.400426796627 -5.86 -4.17 20.8ms
24 -8.400427602453 -6.09 -4.85 20.6ms
25 -8.400427910435 -6.51 -4.58 20.7ms
26 -8.400428066482 -6.81 -5.00 20.5ms
27 -8.400428101590 -7.45 -4.99 27.1ms
28 -8.400428135148 -7.47 -5.41 20.5ms
29 -8.400428142263 -8.15 -5.49 20.6ms
30 -8.400428149638 -8.13 -6.35 20.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.397514397610 -0.90 5.2 37.6ms
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.400427984308 -1.79 6.32s
2 -8.400428152209 -6.77 -4.04 2.18s
3 -8.400428152209 -14.45 -7.86 43.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| = 9.17707223534843e-7
|ρ_newton - ρ_scfv| = 5.144617778324957e-8
|ρ_newton - ρ_dm| = 2.47741057634323e-6