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-6
1.0e-6
Density-based self-consistent field
scfres_scf = self_consistent_field(basis; tol);
n Energy log10(ΔE) log10(Δρ) Diag Δtime
--- --------------- --------- --------- ---- ------
1 -8.397866984384 -0.90 5.0 25.5ms
2 -8.400249087824 -2.62 -1.73 1.0 17.4ms
3 -8.400403575903 -3.81 -2.94 1.8 18.9ms
4 -8.400427778396 -4.62 -2.92 3.0 23.1ms
5 -8.400427960019 -6.74 -3.05 1.0 17.6ms
6 -8.400428149280 -6.72 -4.78 1.0 17.6ms
7 -8.400428155835 -8.18 -4.42 3.2 24.3ms
8 -8.400428156260 -9.37 -5.68 1.0 17.8ms
9 -8.400428156276 -10.78 -6.37 2.0 20.9ms
Potential-based SCF
scfres_scfv = DFTK.scf_potential_mixing(basis; tol);
n Energy log10(ΔE) log10(Δρ) α Diag Δtime
--- --------------- --------- --------- ---- ---- ------
1 -8.397876647065 -0.90 5.0 26.3ms
2 -8.400384967689 -2.60 -1.79 0.80 2.0 18.3ms
3 -8.400423056586 -4.42 -3.03 0.80 1.0 15.2ms
4 -8.400428112264 -5.30 -3.45 0.80 2.2 18.7ms
5 -8.400428152753 -7.39 -4.80 0.80 1.0 15.0ms
6 -8.400428156259 -8.46 -5.46 0.80 2.8 20.1ms
7 -8.400428156276 -10.77 -6.31 0.80 1.8 17.0ms
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/8dE7C/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/8dE7C/src/types.jl:120
n Energy log10(ΔE) log10(Δρ) Δtime
--- --------------- --------- --------- ------
1 +0.686388109699 -1.08 50.1ms
2 -2.026207779030 0.43 -0.64 28.0ms
3 -4.662941822030 0.42 -0.38 37.6ms
4 -6.258392780343 0.20 -0.44 37.6ms
5 -7.774343735594 0.18 -0.70 37.5ms
6 -8.107744114751 -0.48 -1.38 27.8ms
7 -8.304136123386 -0.71 -1.67 27.7ms
8 -8.344514369723 -1.39 -2.04 27.8ms
9 -8.377729451176 -1.48 -2.47 34.5ms
10 -8.385700232703 -2.10 -2.27 52.9ms
11 -8.393442443570 -2.11 -2.69 73.0ms
12 -8.396251425547 -2.55 -2.71 28.6ms
13 -8.398235239972 -2.70 -2.90 28.5ms
14 -8.399181497601 -3.02 -3.14 28.5ms
15 -8.399799289298 -3.21 -3.37 28.5ms
16 -8.400153247858 -3.45 -3.26 28.5ms
17 -8.400300764328 -3.83 -3.39 28.4ms
18 -8.400381985291 -4.09 -3.41 28.4ms
19 -8.400408649669 -4.57 -3.88 28.3ms
20 -8.400420212134 -4.94 -3.85 28.0ms
21 -8.400424326760 -5.39 -4.45 28.3ms
22 -8.400426512010 -5.66 -4.30 28.5ms
23 -8.400427367576 -6.07 -5.08 28.2ms
24 -8.400427870430 -6.30 -4.66 28.3ms
25 -8.400428026132 -6.81 -4.96 28.4ms
26 -8.400428100952 -7.13 -5.11 28.3ms
27 -8.400428131867 -7.51 -5.20 40.4ms
28 -8.400428145508 -7.87 -5.43 28.4ms
29 -8.400428151205 -8.24 -5.63 28.1ms
30 -8.400428154170 -8.53 -5.72 27.9ms
31 -8.400428155305 -8.94 -6.03 28.0ms
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.397841269786 -0.90 5.2 28.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.400427977946 -1.78 554ms
2 -8.400428156277 -6.75 -4.02 345ms
3 -8.400428156277 -14.75 -7.81 107ms
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| = 7.425866763761935e-7
|ρ_newton - ρ_scfv| = 4.324782705746229e-7
|ρ_newton - ρ_dm| = 1.494024332992863e-6