{
 "cells": [
  {
   "cell_type": "markdown",
   "source": [
    "# Comparison of DFT solvers"
   ],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "We compare four different approaches for solving the DFT minimisation problem,\n",
    "namely a density-based SCF, a potential-based SCF, direct minimisation and Newton."
   ],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "First we setup our problem"
   ],
   "metadata": {}
  },
  {
   "outputs": [
    {
     "output_type": "execute_result",
     "data": {
      "text/plain": "1.0e-6"
     },
     "metadata": {},
     "execution_count": 1
    }
   ],
   "cell_type": "code",
   "source": [
    "using AtomsBuilder\n",
    "using DFTK\n",
    "using LinearAlgebra\n",
    "using PseudoPotentialData\n",
    "\n",
    "pseudopotentials = PseudoFamily(\"dojo.nc.sr.pbesol.v0_4_1.standard.upf\")\n",
    "model = model_DFT(bulk(:Si); functionals=PBEsol(), pseudopotentials)\n",
    "basis = PlaneWaveBasis(model; Ecut=5, kgrid=[3, 3, 3])\n",
    "\n",
    "# Convergence we desire in the density\n",
    "tol = 1e-6"
   ],
   "metadata": {},
   "execution_count": 1
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Density-based self-consistent field"
   ],
   "metadata": {}
  },
  {
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "n     Energy            log10(ΔE)   log10(Δρ)   Diag   Δtime\n",
      "---   ---------------   ---------   ---------   ----   ------\n",
      "  1   -8.397850398111                   -0.90    5.2   27.0ms\n",
      "  2   -8.400256071796       -2.62       -1.74    1.0   18.7ms\n",
      "  3   -8.400406663600       -3.82       -2.96    1.5   19.8ms\n",
      "  4   -8.400427833193       -4.67       -2.98    3.0   57.9ms\n",
      "  5   -8.400427949655       -6.93       -3.05    1.0   18.9ms\n",
      "  6   -8.400428149316       -6.70       -4.70    1.0   19.0ms\n",
      "  7   -8.400428155862       -8.18       -4.45    3.2   26.0ms\n",
      "  8   -8.400428156256       -9.40       -5.21    1.0   19.6ms\n",
      "  9   -8.400428156275      -10.72       -6.13    1.0   19.7ms\n"
     ]
    }
   ],
   "cell_type": "code",
   "source": [
    "scfres_scf = self_consistent_field(basis; tol);"
   ],
   "metadata": {},
   "execution_count": 2
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Potential-based SCF"
   ],
   "metadata": {}
  },
  {
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "n     Energy            log10(ΔE)   log10(Δρ)   α      Diag   Δtime\n",
      "---   ---------------   ---------   ---------   ----   ----   ------\n",
      "  1   -8.397726925764                   -0.90           4.8    553ms\n",
      "  2   -8.400374639656       -2.58       -1.77   0.80    2.0    495ms\n",
      "  3   -8.400422170514       -4.32       -3.00   0.80    1.0    180ms\n",
      "  4   -8.400428104597       -5.23       -3.46   0.80    2.2   19.9ms\n",
      "  5   -8.400428151685       -7.33       -4.97   0.80    1.2   17.8ms\n",
      "  6   -8.400428156269       -8.34       -5.35   0.80    3.0   23.0ms\n",
      "  7   -8.400428156276      -11.12       -6.86   0.80    1.0   16.4ms\n"
     ]
    }
   ],
   "cell_type": "code",
   "source": [
    "scfres_scfv = DFTK.scf_potential_mixing(basis; tol);"
   ],
   "metadata": {},
   "execution_count": 3
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Direct minimization"
   ],
   "metadata": {}
  },
  {
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "n     Energy            log10(ΔE)   log10(Δρ)   Δtime\n",
      "---   ---------------   ---------   ---------   ------\n",
      "  1   +0.926488639176                   -1.09    2.77s\n",
      "  2   -1.848359491024        0.44       -0.65    106ms\n",
      "  3   -4.582656986494        0.44       -0.39   39.3ms\n",
      "  4   -6.169239948250        0.20       -0.47   73.3ms\n",
      "  5   -7.680944399394        0.18       -0.73   39.6ms\n",
      "  6   -7.933004251426       -0.60       -1.45   29.2ms\n",
      "  7   -8.218204309711       -0.54       -1.62   29.0ms\n",
      "  8   -8.227933182068       -2.01       -1.94   28.8ms\n",
      "  9   -8.275254161630       -1.32       -1.79   49.0ms\n",
      " 10   -8.319166652806       -1.36       -1.67   39.4ms\n",
      " 11   -8.353780606343       -1.46       -1.75   39.5ms\n",
      " 12   -8.374376330935       -1.69       -2.43   29.0ms\n",
      " 13   -8.389239941286       -1.83       -2.40   33.4ms\n",
      " 14   -8.396952636531       -2.11       -2.50   29.1ms\n",
      " 15   -8.398593985646       -2.78       -2.59   29.0ms\n",
      " 16   -8.399631212256       -2.98       -3.11   29.0ms\n",
      " 17   -8.400022884144       -3.41       -3.11   32.3ms\n",
      " 18   -8.400262490188       -3.62       -3.37   29.0ms\n",
      " 19   -8.400353215508       -4.04       -3.59   29.1ms\n",
      " 20   -8.400407239636       -4.27       -4.05   32.2ms\n",
      " 21   -8.400417995679       -4.97       -3.82   28.9ms\n",
      " 22   -8.400425286419       -5.14       -4.36   29.0ms\n",
      " 23   -8.400426555823       -5.90       -4.17   32.1ms\n",
      " 24   -8.400427343278       -6.10       -4.71   29.1ms\n",
      " 25   -8.400427745067       -6.40       -4.57   32.0ms\n",
      " 26   -8.400427971511       -6.65       -5.01   29.0ms\n",
      " 27   -8.400428076202       -6.98       -5.06   29.5ms\n",
      " 28   -8.400428128024       -7.29       -5.21   33.7ms\n",
      " 29   -8.400428141728       -7.86       -5.46   29.0ms\n",
      " 30   -8.400428151034       -8.03       -5.36   29.0ms\n",
      " 31   -8.400428154120       -8.51       -5.67   32.2ms\n",
      " 32   -8.400428155458       -8.87       -5.85   29.0ms\n",
      " 33   -8.400428155871       -9.38       -6.61   32.2ms\n"
     ]
    }
   ],
   "cell_type": "code",
   "source": [
    "scfres_dm = direct_minimization(basis; tol);"
   ],
   "metadata": {},
   "execution_count": 4
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Newton algorithm"
   ],
   "metadata": {}
  },
  {
   "cell_type": "markdown",
   "source": [
    "Start not too far from the solution to ensure convergence:\n",
    "We run first a very crude SCF to get close and then switch to Newton."
   ],
   "metadata": {}
  },
  {
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "n     Energy            log10(ΔE)   log10(Δρ)   Diag   Δtime\n",
      "---   ---------------   ---------   ---------   ----   ------\n",
      "  1   -8.397856585042                   -0.90    5.0   26.7ms\n"
     ]
    }
   ],
   "cell_type": "code",
   "source": [
    "scfres_start = self_consistent_field(basis; tol=0.5);"
   ],
   "metadata": {},
   "execution_count": 5
  },
  {
   "cell_type": "markdown",
   "source": [
    "Remove the virtual orbitals (which Newton cannot treat yet)"
   ],
   "metadata": {}
  },
  {
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "n     Energy            log10(ΔE)   log10(Δρ)   Δtime\n",
      "---   ---------------   ---------   ---------   ------\n",
      "  1   -8.400427983085                   -1.78    24.2s\n",
      "  2   -8.400428156277       -6.76       -4.02    2.19s\n",
      "  3   -8.400428156277      -14.75       -7.82    115ms\n"
     ]
    }
   ],
   "cell_type": "code",
   "source": [
    "ψ = DFTK.select_occupied_orbitals(basis, scfres_start.ψ, scfres_start.occupation).ψ\n",
    "scfres_newton = newton(basis, ψ; tol);"
   ],
   "metadata": {},
   "execution_count": 6
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Comparison of results"
   ],
   "metadata": {}
  },
  {
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "|ρ_newton - ρ_scf|  = 1.318651071213495e-6\n",
      "|ρ_newton - ρ_scfv| = 1.2366889710809778e-7\n",
      "|ρ_newton - ρ_dm|   = 1.5628380220615619e-6\n"
     ]
    }
   ],
   "cell_type": "code",
   "source": [
    "println(\"|ρ_newton - ρ_scf|  = \", norm(scfres_newton.ρ - scfres_scf.ρ))\n",
    "println(\"|ρ_newton - ρ_scfv| = \", norm(scfres_newton.ρ - scfres_scfv.ρ))\n",
    "println(\"|ρ_newton - ρ_dm|   = \", norm(scfres_newton.ρ - scfres_dm.ρ))"
   ],
   "metadata": {},
   "execution_count": 7
  }
 ],
 "nbformat_minor": 3,
 "metadata": {
  "language_info": {
   "file_extension": ".jl",
   "mimetype": "application/julia",
   "name": "julia",
   "version": "1.11.4"
  },
  "kernelspec": {
   "name": "julia-1.11",
   "display_name": "Julia 1.11.4",
   "language": "julia"
  }
 },
 "nbformat": 4
}