{ "cells": [ { "cell_type": "markdown", "source": [ "# Modelling a gallium arsenide surface\n", "\n", "This example shows how to use the atomistic simulation environment or ASE for short,\n", "to set up and run a particular calculation of a gallium arsenide surface.\n", "ASE is a Python package to simplify the process of setting up,\n", "running and analysing results from atomistic simulations across different simulation codes.\n", "For more details on the integration DFTK provides with ASE,\n", "see Atomistic simulation environment.\n", "\n", "In this example we will consider modelling the (1, 1, 0) GaAs surface separated by vacuum." ], "metadata": {} }, { "cell_type": "markdown", "source": [ "Parameters of the calculation. Since this surface is far from easy to converge,\n", "we made the problem simpler by choosing a smaller `Ecut` and smaller values\n", "for `n_GaAs` and `n_vacuum`.\n", "More interesting settings are `Ecut = 15` and `n_GaAs = n_vacuum = 20`." ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "miller = (1, 1, 0) # Surface Miller indices\n", "n_GaAs = 2 # Number of GaAs layers\n", "n_vacuum = 4 # Number of vacuum layers\n", "Ecut = 5 # Hartree\n", "kgrid = (4, 4, 1); # Monkhorst-Pack mesh" ], "metadata": {}, "execution_count": 1 }, { "cell_type": "markdown", "source": [ "Use ASE to build the structure:" ], "metadata": {} }, { "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " CondaPkg Found dependencies: /home/runner/.julia/packages/ASEconvert/kvmT8/CondaPkg.toml\n", " CondaPkg Found dependencies: /home/runner/.julia/packages/PythonCall/WMWY0/CondaPkg.toml\n", " CondaPkg Resolving changes\n", " + ase\n", " + libstdcxx-ng\n", " + openssl\n", " + python\n", " CondaPkg Initialising pixi\n", " │ /home/runner/.julia/artifacts/cefba4912c2b400756d043a2563ef77a0088866b/bin/pixi\n", " │ init\n", " │ --format pixi\n", " └ /home/runner/work/DFTK.jl/DFTK.jl/docs/.CondaPkg\n", "✔ Created /home/runner/work/DFTK.jl/DFTK.jl/docs/.CondaPkg/pixi.toml\n", " CondaPkg Wrote /home/runner/work/DFTK.jl/DFTK.jl/docs/.CondaPkg/pixi.toml\n", " │ [dependencies]\n", " │ openssl = \">=3, <3.1\"\n", " │ libstdcxx-ng = \">=3.4,<13.0\"\n", " │ ase = \">=3.23,<3.24\"\n", " │ \n", " │ [dependencies.python]\n", " │ channel = \"conda-forge\"\n", " │ build = \"*cpython*\"\n", " │ version = \">=3.8,<4\"\n", " │ \n", " │ [project]\n", " │ name = \".CondaPkg\"\n", " │ platforms = [\"linux-64\"]\n", " │ channels = [\"conda-forge\"]\n", " │ channel-priority = \"strict\"\n", " └ description = \"automatically generated by CondaPkg.jl\"\n", " CondaPkg Installing packages\n", " │ /home/runner/.julia/artifacts/cefba4912c2b400756d043a2563ef77a0088866b/bin/pixi\n", " │ install\n", " └ --manifest-path /home/runner/work/DFTK.jl/DFTK.jl/docs/.CondaPkg/pixi.toml\n", "✔ The default environment has been installed.\n" ] } ], "cell_type": "code", "source": [ "using ASEconvert\n", "using PythonCall\n", "\n", "a = 5.6537 # GaAs lattice parameter in Ångström (because ASE uses Å as length unit)\n", "gaas = ase.build.bulk(\"GaAs\", \"zincblende\"; a)\n", "surface = ase.build.surface(gaas, miller, n_GaAs, 0, periodic=true);" ], "metadata": {}, "execution_count": 2 }, { "cell_type": "markdown", "source": [ "Get the amount of vacuum in Ångström we need to add" ], "metadata": {} }, { "outputs": [], "cell_type": "code", "source": [ "d_vacuum = maximum(maximum, surface.cell) / n_GaAs * n_vacuum\n", "surface = ase.build.surface(gaas, miller, n_GaAs, d_vacuum, periodic=true);" ], "metadata": {}, "execution_count": 3 }, { "cell_type": "markdown", "source": [ "Write an image of the surface and embed it as a nice illustration:" ], "metadata": {} }, { "outputs": [ { "output_type": "execute_result", "data": { "text/plain": "Python: None" }, "metadata": {}, "execution_count": 4 } ], "cell_type": "code", "source": [ "ase.io.write(\"surface.png\", surface * pytuple((3, 3, 1)), rotation=\"-90x, 30y, -75z\")" ], "metadata": {}, "execution_count": 4 }, { "cell_type": "markdown", "source": [ "<img src=\"https://docs.dftk.org/stable/surface.png\" width=500 height=500 />" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "Use the `pyconvert` function from `PythonCall` to convert the ASE atoms\n", "to an AtomsBase-compatible system.\n", "This can then be used in the same way as other `AtomsBase` systems\n", "(see AtomsBase integration for details) to construct a DFTK model:" ], "metadata": {} }, { "outputs": [ { "output_type": "execute_result", "data": { "text/plain": "Model(gga_x_pbe+gga_c_pbe, 3D):\n lattice (in Bohr) : [7.55469 , 0 , 0 ]\n [0 , 7.55469 , 0 ]\n [0 , 0 , 40.0648 ]\n unit cell volume : 2286.6 Bohr³\n\n atoms : As₂Ga₂\n atom potentials : ElementPsp(Ga, \"/home/runner/.julia/artifacts/9a2a5dc89d1b33bff2ad61eaf2d000191050d15c/Ga.gth\")\n ElementPsp(As, \"/home/runner/.julia/artifacts/9a2a5dc89d1b33bff2ad61eaf2d000191050d15c/As.gth\")\n ElementPsp(Ga, \"/home/runner/.julia/artifacts/9a2a5dc89d1b33bff2ad61eaf2d000191050d15c/Ga.gth\")\n ElementPsp(As, \"/home/runner/.julia/artifacts/9a2a5dc89d1b33bff2ad61eaf2d000191050d15c/As.gth\")\n\n num. electrons : 16\n spin polarization : none\n temperature : 0.001 Ha\n smearing : DFTK.Smearing.Gaussian()\n\n terms : Kinetic()\n AtomicLocal()\n AtomicNonlocal()\n Ewald(nothing)\n PspCorrection()\n Hartree()\n Xc(gga_x_pbe, gga_c_pbe)\n Entropy()" }, "metadata": {}, "execution_count": 5 } ], "cell_type": "code", "source": [ "using DFTK\n", "using PseudoPotentialData\n", "\n", "pseudopotentials = PseudoFamily(\"cp2k.nc.sr.pbe.v0_1.largecore.gth\")\n", "model = model_DFT(pyconvert(AbstractSystem, surface);\n", " functionals=PBE(),\n", " temperature=1e-3,\n", " smearing=DFTK.Smearing.Gaussian(),\n", " pseudopotentials)" ], "metadata": {}, "execution_count": 5 }, { "cell_type": "markdown", "source": [ "In the above we use the `pseudopotential` keyword argument to\n", "assign the respective pseudopotentials to the imported `model.atoms`.\n", "Try lowering the SCF convergence tolerance (`tol`)\n", "or try `mixing=KerkerMixing()` to see the full challenge of this system." ], "metadata": {} }, { "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "n Energy log10(ΔE) log10(Δρ) Diag Δtime\n", "--- --------------- --------- --------- ---- ------\n", " 1 -16.58731169617 -0.58 5.3 1.06s\n", " 2 -16.72499645787 -0.86 -1.01 1.0 591ms\n", " 3 -16.73052609602 -2.26 -1.57 2.1 278ms\n", " 4 -16.73121597015 -3.16 -2.16 1.0 224ms\n", " 5 -16.73132220762 -3.97 -2.58 2.1 264ms\n", " 6 -16.73133188404 -5.01 -2.83 2.0 258ms\n", " 7 -16.73078007811 + -3.26 -2.44 2.2 284ms\n", " 8 -16.73126715740 -3.31 -2.77 2.4 265ms\n", " 9 -16.73114223005 + -3.90 -2.65 2.0 264ms\n", " 10 -16.73133977758 -3.70 -3.65 1.2 215ms\n", " 11 -16.73133595709 + -5.42 -3.45 3.2 309ms\n", " 12 -16.73134011151 -5.38 -3.99 1.2 217ms\n", " 13 -16.73133944032 + -6.17 -3.83 1.8 569ms\n", " 14 -16.73134017301 -6.14 -4.53 1.4 222ms\n", " 15 -16.73134019963 -7.57 -5.04 1.9 244ms\n", " 16 -16.73134019502 + -8.34 -4.86 2.1 283ms\n", " 17 -16.73134019980 -8.32 -5.27 1.1 208ms\n", " 18 -16.73134019997 -9.78 -5.44 1.0 207ms\n", " 19 -16.73134020043 -9.34 -6.05 1.9 238ms\n" ] } ], "cell_type": "code", "source": [ "basis = PlaneWaveBasis(model; Ecut, kgrid)\n", "scfres = self_consistent_field(basis; tol=1e-6, mixing=LdosMixing());" ], "metadata": {}, "execution_count": 6 }, { "outputs": [ { "output_type": "execute_result", "data": { "text/plain": "Energy breakdown (in Ha):\n Kinetic 5.8593983 \n AtomicLocal -105.6100293\n AtomicNonlocal 2.3494815 \n Ewald 35.5044300\n PspCorrection 0.2016043 \n Hartree 49.5614425\n Xc -4.5976641\n Entropy -0.0000035\n\n total -16.731340200428" }, "metadata": {}, "execution_count": 7 } ], "cell_type": "code", "source": [ "scfres.energies" ], "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 }