{ "cells": [ { "cell_type": "markdown", "source": [ "# Creating and modelling metallic supercells\n", "\n", "In this section we will be concerned with modelling supercells of aluminium.\n", "When dealing with periodic problems there is no unique definition of the\n", "lattice: Clearly any duplication of the lattice along an axis is also a valid\n", "repetitive unit to describe exactly the same system.\n", "This is exactly what a **supercell** is: An $n$-fold repetition along one (or multiple)\n", "axes of the original lattice.\n", "\n", "The following code achieves this for aluminium:" ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "using AtomsBuilder\n", "using DFTK\n", "using LinearAlgebra\n", "using Unitful\n", "using UnitfulAtomic\n", "using PseudoPotentialData\n", "\n", "function aluminium_setup(repeat=1; Ecut=7.0, kgrid=[2, 2, 2])\n", " # Use AtomsBuilder to setup aluminium cubic unit cell (4 Al atoms)\n", " # with provided lattice constant, see AtomsBase integration for details.\n", " unit_cell = bulk(:Al; a=7.65339u\"bohr\", cubic=true)\n", " supercell = unit_cell * (repeat, 1, 1) # Make a supercell\n", "\n", " # Select standard pseudodojo pseudopotentials, construct an LDA model, discretize\n", " # Note: We disable symmetries explicitly here. Otherwise the problem sizes\n", " # we are able to run on the CI are too simple to observe the numerical\n", " # instabilities we want to trigger here.\n", " pseudopotentials = PseudoFamily(\"dojo.nc.sr.lda.v0_4_1.standard.upf\")\n", " model = model_DFT(supercell; pseudopotentials, functionals=LDA(),\n", " temperature=1e-3, symmetries=false)\n", " PlaneWaveBasis(model; Ecut, kgrid)\n", "end;" ], "metadata": {}, "execution_count": 1 }, { "cell_type": "markdown", "source": [ "As expected we obtain the unit cell for `repeat=1`:" ], "metadata": {} }, { "outputs": [ { "output_type": "execute_result", "data": { "text/plain": "PlaneWaveBasis discretization:\n architecture : DFTK.CPU()\n num. mpi processes : 1\n num. julia threads : 1\n num. DFTK threads : 1\n num. blas threads : 2\n num. fft threads : 1\n\n Ecut : 7.0 Ha\n fft_size : (24, 24, 24), 13824 total points\n kgrid : MonkhorstPack([2, 2, 2])\n num. red. kpoints : 8\n num. irred. kpoints : 8\n\n Discretized Model(lda_x+lda_c_pw, 3D):\n lattice (in Bohr) : [7.65339 , 0 , 0 ]\n [0 , 7.65339 , 0 ]\n [0 , 0 , 7.65339 ]\n unit cell volume : 448.29 Bohr³\n \n atoms : Al₄\n atom potentials : ElementPsp(Al, \"/home/runner/.julia/artifacts/326db5c901e2681584ec5c06fc17f6c96e516ff9/Al.upf\")\n ElementPsp(Al, \"/home/runner/.julia/artifacts/326db5c901e2681584ec5c06fc17f6c96e516ff9/Al.upf\")\n ElementPsp(Al, \"/home/runner/.julia/artifacts/326db5c901e2681584ec5c06fc17f6c96e516ff9/Al.upf\")\n ElementPsp(Al, \"/home/runner/.julia/artifacts/326db5c901e2681584ec5c06fc17f6c96e516ff9/Al.upf\")\n \n num. electrons : 12\n spin polarization : none\n temperature : 0.001 Ha\n smearing : DFTK.Smearing.FermiDirac()\n \n terms : Kinetic()\n AtomicLocal()\n AtomicNonlocal()\n Ewald(nothing)\n PspCorrection()\n Hartree()\n Xc(lda_x, lda_c_pw)\n Entropy()" }, "metadata": {}, "execution_count": 2 } ], "cell_type": "code", "source": [ "aluminium_setup(1)" ], "metadata": {}, "execution_count": 2 }, { "cell_type": "markdown", "source": [ "and 5-fold as large supercell with `repeat=5`:" ], "metadata": {} }, { "outputs": [ { "output_type": "execute_result", "data": { "text/plain": "PlaneWaveBasis discretization:\n architecture : DFTK.CPU()\n num. mpi processes : 1\n num. julia threads : 1\n num. DFTK threads : 1\n num. blas threads : 2\n num. fft threads : 1\n\n Ecut : 7.0 Ha\n fft_size : (96, 24, 24), 55296 total points\n kgrid : MonkhorstPack([2, 2, 2])\n num. red. kpoints : 8\n num. irred. kpoints : 8\n\n Discretized Model(lda_x+lda_c_pw, 3D):\n lattice (in Bohr) : [38.267 , 0 , 0 ]\n [0 , 7.65339 , 0 ]\n [0 , 0 , 7.65339 ]\n unit cell volume : 2241.5 Bohr³\n \n atoms : Al₂₀\n atom potentials : ElementPsp(Al, \"/home/runner/.julia/artifacts/326db5c901e2681584ec5c06fc17f6c96e516ff9/Al.upf\")\n ElementPsp(Al, \"/home/runner/.julia/artifacts/326db5c901e2681584ec5c06fc17f6c96e516ff9/Al.upf\")\n ElementPsp(Al, \"/home/runner/.julia/artifacts/326db5c901e2681584ec5c06fc17f6c96e516ff9/Al.upf\")\n ElementPsp(Al, \"/home/runner/.julia/artifacts/326db5c901e2681584ec5c06fc17f6c96e516ff9/Al.upf\")\n ElementPsp(Al, \"/home/runner/.julia/artifacts/326db5c901e2681584ec5c06fc17f6c96e516ff9/Al.upf\")\n ElementPsp(Al, \"/home/runner/.julia/artifacts/326db5c901e2681584ec5c06fc17f6c96e516ff9/Al.upf\")\n ElementPsp(Al, \"/home/runner/.julia/artifacts/326db5c901e2681584ec5c06fc17f6c96e516ff9/Al.upf\")\n ElementPsp(Al, \"/home/runner/.julia/artifacts/326db5c901e2681584ec5c06fc17f6c96e516ff9/Al.upf\")\n ElementPsp(Al, \"/home/runner/.julia/artifacts/326db5c901e2681584ec5c06fc17f6c96e516ff9/Al.upf\")\n ElementPsp(Al, \"/home/runner/.julia/artifacts/326db5c901e2681584ec5c06fc17f6c96e516ff9/Al.upf\")\n ElementPsp(Al, \"/home/runner/.julia/artifacts/326db5c901e2681584ec5c06fc17f6c96e516ff9/Al.upf\")\n ElementPsp(Al, \"/home/runner/.julia/artifacts/326db5c901e2681584ec5c06fc17f6c96e516ff9/Al.upf\")\n ElementPsp(Al, \"/home/runner/.julia/artifacts/326db5c901e2681584ec5c06fc17f6c96e516ff9/Al.upf\")\n ElementPsp(Al, \"/home/runner/.julia/artifacts/326db5c901e2681584ec5c06fc17f6c96e516ff9/Al.upf\")\n ElementPsp(Al, \"/home/runner/.julia/artifacts/326db5c901e2681584ec5c06fc17f6c96e516ff9/Al.upf\")\n ElementPsp(Al, \"/home/runner/.julia/artifacts/326db5c901e2681584ec5c06fc17f6c96e516ff9/Al.upf\")\n ElementPsp(Al, \"/home/runner/.julia/artifacts/326db5c901e2681584ec5c06fc17f6c96e516ff9/Al.upf\")\n ElementPsp(Al, \"/home/runner/.julia/artifacts/326db5c901e2681584ec5c06fc17f6c96e516ff9/Al.upf\")\n ElementPsp(Al, \"/home/runner/.julia/artifacts/326db5c901e2681584ec5c06fc17f6c96e516ff9/Al.upf\")\n ElementPsp(Al, \"/home/runner/.julia/artifacts/326db5c901e2681584ec5c06fc17f6c96e516ff9/Al.upf\")\n \n num. electrons : 60\n spin polarization : none\n temperature : 0.001 Ha\n smearing : DFTK.Smearing.FermiDirac()\n \n terms : Kinetic()\n AtomicLocal()\n AtomicNonlocal()\n Ewald(nothing)\n PspCorrection()\n Hartree()\n Xc(lda_x, lda_c_pw)\n Entropy()" }, "metadata": {}, "execution_count": 3 } ], "cell_type": "code", "source": [ "aluminium_setup(5)" ], "metadata": {}, "execution_count": 3 }, { "cell_type": "markdown", "source": [ "As we will see in this notebook the modelling of a system generally becomes\n", "harder if the system becomes larger.\n", "\n", "- This sounds like a trivial statement as *per se* the cost per SCF step increases\n", " as the system (and thus $N$) gets larger.\n", "- But there is more to it:\n", " If one is not careful also the *number of SCF iterations* increases\n", " as the system gets larger.\n", "- The aim of a proper computational treatment of such supercells is therefore\n", " to ensure that the **number of SCF iterations remains constant** when the\n", " system size increases." ], "metadata": {} }, { "cell_type": "markdown", "source": [ "For achieving the latter DFTK by default employs the `LdosMixing`\n", "preconditioner [^HL2021] during the SCF iterations. This mixing approach is\n", "completely parameter free, but still automatically adapts to the treated\n", "system in order to efficiently prevent charge sloshing. As a result,\n", "modelling aluminium slabs indeed takes roughly the same number of SCF iterations\n", "irrespective of the supercell size:\n", "\n", "[^HL2021]:\n", " M. F. Herbst and A. Levitt.\n", " *Black-box inhomogeneous preconditioning for self-consistent field iterations in density functional theory.*\n", " J. Phys. Cond. Matt *33* 085503 (2021). [ArXiv:2009.01665](https://arxiv.org/abs/2009.01665)" ], "metadata": {} }, { "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "n Energy log10(ΔE) log10(Δρ) Diag Δtime\n", "--- --------------- --------- --------- ---- ------\n", " 1 -9.355192087429 -1.10 6.1 428ms\n", " 2 -9.356782960534 -2.80 -1.43 1.0 78.5ms\n", " 3 -9.357072155302 -3.54 -2.78 2.2 95.0ms\n", " 4 -9.357119492113 -4.32 -3.03 6.6 196ms\n", " 5 -9.357119865033 -6.43 -3.17 1.1 77.3ms\n", " 6 -9.357120085864 -6.66 -3.32 6.2 171ms\n", " 7 -9.357120222843 -6.86 -3.48 1.0 75.4ms\n", " 8 -9.357120282676 -7.22 -3.65 1.1 77.3ms\n", " 9 -9.357120314566 -7.50 -3.93 2.2 95.6ms\n", " 10 -9.357120321735 -8.14 -4.18 1.1 78.6ms\n" ] } ], "cell_type": "code", "source": [ "self_consistent_field(aluminium_setup(1); tol=1e-4);" ], "metadata": {}, "execution_count": 4 }, { "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "n Energy log10(ΔE) log10(Δρ) Diag Δtime\n", "--- --------------- --------- --------- ---- ------\n", " 1 -18.74782587059 -0.97 6.4 525ms\n", "┌ Warning: Eigensolver not converged\n", "│ n_iter =\n", "│ 8-element Vector{Int64}:\n", "│ 1\n", "│ 1\n", "│ 1\n", "│ 6\n", "│ 1\n", "│ 7\n", "│ 1\n", "│ 1\n", "└ @ DFTK ~/work/DFTK.jl/DFTK.jl/src/scf/self_consistent_field.jl:76\n", " 2 -18.75924443948 -1.94 -1.32 2.4 356ms\n", " 3 -18.79217479336 -1.48 -2.21 3.9 566ms\n", " 4 -18.79261586414 -3.36 -2.52 5.1 401ms\n", " 5 -18.79262082936 -5.30 -3.18 2.9 257ms\n", " 6 -18.79262376235 -5.53 -3.58 6.2 377ms\n", " 7 -18.79262416471 -6.40 -3.96 2.4 243ms\n", " 8 -18.79262417627 -7.94 -4.46 2.0 241ms\n" ] } ], "cell_type": "code", "source": [ "self_consistent_field(aluminium_setup(2); tol=1e-4);" ], "metadata": {}, "execution_count": 5 }, { "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "n Energy log10(ΔE) log10(Δρ) Diag Δtime\n", "--- --------------- --------- --------- ---- ------\n", " 1 -37.54938441249 -0.84 9.9 2.13s\n", " 2 -37.55822040752 -2.05 -1.22 3.4 903ms\n", "┌ Warning: Eigensolver not converged\n", "│ n_iter =\n", "│ 8-element Vector{Int64}:\n", "│ 12\n", "│ 6\n", "│ 17\n", "│ 14\n", "│ 24\n", "│ 6\n", "│ 12\n", "│ 11\n", "└ @ DFTK ~/work/DFTK.jl/DFTK.jl/src/scf/self_consistent_field.jl:76\n", " 3 -37.56446791305 -2.20 -2.15 12.8 1.70s\n", " 4 -37.56484227746 -3.43 -2.37 10.5 2.10s\n", " 5 -37.56497385310 -3.88 -3.03 3.1 974ms\n", " 6 -37.56497720341 -5.47 -3.40 6.8 1.30s\n", " 7 -37.56498444115 -5.14 -3.80 2.9 902ms\n", " 8 -37.56498518704 -6.13 -4.48 3.9 1.12s\n" ] } ], "cell_type": "code", "source": [ "self_consistent_field(aluminium_setup(4); tol=1e-4);" ], "metadata": {}, "execution_count": 6 }, { "cell_type": "markdown", "source": [ "When switching off explicitly the `LdosMixing`, by selecting `mixing=SimpleMixing()`,\n", "the performance of number of required SCF steps starts to increase as we increase\n", "the size of the modelled problem:" ], "metadata": {} }, { "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "n Energy log10(ΔE) log10(Δρ) Diag Δtime\n", "--- --------------- --------- --------- ---- ------\n", " 1 -9.355228685331 -1.09 6.4 156ms\n", " 2 -9.356843293351 -2.79 -1.91 1.0 61.2ms\n", " 3 -9.357094899209 -3.60 -2.63 4.2 124ms\n", " 4 -9.357095495032 -6.22 -2.55 4.4 126ms\n", " 5 -9.357119904885 -4.61 -3.56 1.0 62.1ms\n", " 6 -9.357120213909 -6.51 -3.80 5.8 133ms\n", " 7 -9.357120321069 -6.97 -4.58 1.5 70.0ms\n" ] } ], "cell_type": "code", "source": [ "self_consistent_field(aluminium_setup(1); tol=1e-4, mixing=SimpleMixing());" ], "metadata": {}, "execution_count": 7 }, { "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "┌ Warning: Eigensolver not converged\n", "│ n_iter =\n", "│ 8-element Vector{Int64}:\n", "│ 11\n", "│ 3\n", "│ 13\n", "│ 13\n", "│ 17\n", "│ 13\n", "│ 16\n", "│ 2\n", "└ @ DFTK ~/work/DFTK.jl/DFTK.jl/src/scf/self_consistent_field.jl:76\n", "n Energy log10(ΔE) log10(Δρ) Diag Δtime\n", "--- --------------- --------- --------- ---- ------\n", " 1 -37.53784283860 -0.84 11.0 2.11s\n", " 2 -32.44804571825 + 0.71 -0.71 5.5 1.05s\n", " 3 +146.5738015668 + 2.25 0.08 17.6 3.41s\n", " 4 -24.39053013586 2.23 -0.37 8.0 2.64s\n", " 5 -36.06006869784 1.07 -0.93 4.9 1.47s\n", " 6 -36.92340356736 -0.06 -1.13 6.0 1.23s\n", " 7 -34.71926226884 + 0.34 -0.84 5.9 1.24s\n", " 8 -37.34474077953 0.42 -1.33 5.4 1.48s\n", " 9 -37.34347176973 + -2.90 -1.35 1.9 760ms\n", " 10 -37.43371685856 -1.04 -1.47 1.0 711ms\n", " 11 -37.54085560392 -0.97 -1.81 2.4 856ms\n", " 12 -37.56094929909 -1.70 -2.21 3.8 1.05s\n", " 13 -37.56481750469 -2.41 -2.69 3.8 1.23s\n", " 14 -37.56479665961 + -4.68 -2.88 4.8 1.57s\n", " 15 -37.56353153815 + -2.90 -2.46 4.8 1.18s\n", " 16 -37.56494517512 -2.85 -3.04 4.8 1.25s\n", " 17 -37.56497285634 -4.56 -3.43 2.9 942ms\n", " 18 -37.56498390410 -4.96 -3.87 2.5 943ms\n", " 19 -37.56485160180 + -3.88 -3.00 5.5 1.79s\n", " 20 -37.56498436759 -3.88 -3.99 6.4 1.38s\n", " 21 -37.56498505923 -6.16 -4.34 2.5 828ms\n" ] } ], "cell_type": "code", "source": [ "self_consistent_field(aluminium_setup(4); tol=1e-4, mixing=SimpleMixing());" ], "metadata": {}, "execution_count": 8 }, { "cell_type": "markdown", "source": [ "For completion let us note that the more traditional `mixing=KerkerMixing()`\n", "approach would also help in this particular setting to obtain a constant\n", "number of SCF iterations for an increasing system size (try it!). In contrast\n", "to `LdosMixing`, however, `KerkerMixing` is only suitable to model bulk metallic\n", "system (like the case we are considering here). When modelling metallic surfaces\n", "or mixtures of metals and insulators, `KerkerMixing` fails, while `LdosMixing`\n", "still works well. See the Modelling a gallium arsenide surface example\n", "or [^HL2021] for details. Due to the general applicability of `LdosMixing` this\n", "method is the default mixing approach in DFTK." ], "metadata": {} } ], "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 }