├── .gitignore ├── img ├── dftkfields.png ├── silicon_bands.png ├── Silicon_crystal.jpg ├── Silicon_crystal.jpg.source ├── Brillouin_Zone.svg.source └── Brillouin_Zone.svg ├── environment.yml ├── solutions ├── 5_ex1_aluminium_Kerker_repeat_3.pdf ├── 5_ex1_aluminium_Kerker_repeat_6.pdf ├── 5_ex1_aluminium_NoKerker_repeat_3.pdf ├── 5_ex1_aluminium_NoKerker_repeat_6.pdf ├── README.md ├── 4_ex1_convergence_plot.md ├── 4_ex3_anderson.md ├── 3_ex1_modelling_aluminium.jl ├── 7_ex1_computing_stresses.jl ├── 6_ex1_generic_floats.jl ├── 4_ex2_damped_iterations.jl ├── 4_ex4_preconditioned_iterations.jl ├── 5_ex2_helium.jl └── 5_ex1_aluminium_Kerker.jl ├── CITATIONS.bib ├── Project.toml ├── README.md ├── 0_Getting_started.ipynb ├── 1_Installation.ipynb ├── 8_Direct_minimisation.ipynb ├── 7_Properties_automatic_differentation.ipynb ├── 6_Floating_point_error.ipynb ├── 5_Analysing_SCF_convergence.ipynb ├── 2_Periodic_problems_and_plane_waves.ipynb ├── 4_Solving_the_SCF_problem.ipynb ├── 3_Density_functional_theory.ipynb └── Manifest.toml /.gitignore: -------------------------------------------------------------------------------- 1 | .ipynb_checkpoints/ 2 | *~ 3 | .*.swp 4 | -------------------------------------------------------------------------------- /img/dftkfields.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfherbst/juliacon_dft_workshop/HEAD/img/dftkfields.png -------------------------------------------------------------------------------- /img/silicon_bands.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfherbst/juliacon_dft_workshop/HEAD/img/silicon_bands.png -------------------------------------------------------------------------------- /img/Silicon_crystal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfherbst/juliacon_dft_workshop/HEAD/img/Silicon_crystal.jpg -------------------------------------------------------------------------------- /environment.yml: -------------------------------------------------------------------------------- 1 | name: dftk 2 | channels: 3 | - defaults 4 | - conda-forge 5 | dependencies: 6 | - pymatgen 7 | -------------------------------------------------------------------------------- /img/Silicon_crystal.jpg.source: -------------------------------------------------------------------------------- 1 | https://en.wikipedia.org/wiki/File:Silicon.jpg 2 | Creative Commons Attribution 3.0 Unported 3 | -------------------------------------------------------------------------------- /img/Brillouin_Zone.svg.source: -------------------------------------------------------------------------------- 1 | https://upload.wikimedia.org/wikipedia/commons/c/c1/Brillouin_Zone_%281st%2C_FCC%29.svg 2 | Public domain 3 | -------------------------------------------------------------------------------- /solutions/5_ex1_aluminium_Kerker_repeat_3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfherbst/juliacon_dft_workshop/HEAD/solutions/5_ex1_aluminium_Kerker_repeat_3.pdf -------------------------------------------------------------------------------- /solutions/5_ex1_aluminium_Kerker_repeat_6.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfherbst/juliacon_dft_workshop/HEAD/solutions/5_ex1_aluminium_Kerker_repeat_6.pdf -------------------------------------------------------------------------------- /solutions/5_ex1_aluminium_NoKerker_repeat_3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfherbst/juliacon_dft_workshop/HEAD/solutions/5_ex1_aluminium_NoKerker_repeat_3.pdf -------------------------------------------------------------------------------- /solutions/5_ex1_aluminium_NoKerker_repeat_6.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfherbst/juliacon_dft_workshop/HEAD/solutions/5_ex1_aluminium_NoKerker_repeat_6.pdf -------------------------------------------------------------------------------- /solutions/README.md: -------------------------------------------------------------------------------- 1 | These are the solutions to the various exercises in the notebook 2 | as plain julia scripts or as Jupyter notebooks. Please first try 3 | to do the exercises by yourself before looking up the solutions here. 4 | 5 | Each file name starts with the same number as the corresponding notebook 6 | and the respective exercise number it solves. 7 | -------------------------------------------------------------------------------- /CITATIONS.bib: -------------------------------------------------------------------------------- 1 | @software{Juliacondftworkshop, 2 | author = {Michael F. Herbst}, 3 | title = {Juliacon DFT workshop}, 4 | month = jul, 5 | year = 2021, 6 | publisher = {Zenodo}, 7 | version = {juliacon2021}, 8 | doi = {10.5281/zenodo.5140898}, 9 | url = {https://doi.org/10.5281/zenodo.5140898} 10 | } 11 | -------------------------------------------------------------------------------- /solutions/4_ex1_convergence_plot.md: -------------------------------------------------------------------------------- 1 | ### Solution for the exercise "Gaining insight" in 4_Solving_the_SCF_problem.ipynb 2 | 3 | As the number of repeats is increasing the convergence plot becomes more and more rough 4 | and less monotonous. In particular: 5 | - The density change from iteration to iteration sometimes shows spikes, instead 6 | of a nice monotonous decrease. 7 | - In the initial phase of the SCF both density and energy show drastic oscillations 8 | (including energy changes to very positive energies) -------------------------------------------------------------------------------- /solutions/4_ex3_anderson.md: -------------------------------------------------------------------------------- 1 | ### Solution for the exercise "Anderson acceleration" in 4_Solving_the_SCF_problem.ipynb 2 | 3 | In contrast to the damped iterations of exercise 2, 4 | the iteration with Anderson acceleration converges for all repeats (2, 4, 6, 8) 5 | with the damping value of 0.8 (which failed even for a single repeat in exercise 2!). 6 | 7 | As the system size increases also the number of SCF iterations increases, 8 | roughly as follows: 9 | 10 | repeat | iterations 11 | ------ | ----------- 12 | 1 | 6 13 | 2 | 8 14 | 4 | 11 15 | 6 | 16 16 | 8 | 29 17 | 18 | The goal of a size-independent number of iterations has thus not yet been achieved. -------------------------------------------------------------------------------- /solutions/3_ex1_modelling_aluminium.jl: -------------------------------------------------------------------------------- 1 | # Solution to the exercise "Modelling aluminium" 2 | # in the notebook 3_Density_functional_theory.ipynb 3 | 4 | using DFTK 5 | using LinearAlgebra 6 | 7 | a = 7.65339 8 | lattice = diagm(fill(a, 3)) 9 | Al = ElementPsp(:Al, psp=load_psp("hgh/lda/al-q3")) 10 | atoms = [Al => [[0.0, 0.0, 0.0], [0.0, 0.5, 0.5], [0.5, 0.0, 0.5], [0.5, 0.5, 0.0]]] 11 | 12 | # Without smearing (won't work!) 13 | # model = model_LDA(lattice, atoms) 14 | 15 | # With smearing: Setup model and discretise 16 | model = model_LDA(lattice, atoms, temperature=1e-3) 17 | basis = PlaneWaveBasis(model; Ecut=15, kgrid=[2, 2, 2]) 18 | 19 | # Run the SCF 20 | scfres = self_consistent_field(basis) 21 | 22 | # Plot the bands 23 | plot_bandstructure(scfres) -------------------------------------------------------------------------------- /Project.toml: -------------------------------------------------------------------------------- 1 | [deps] 2 | DFTK = "acf6eb54-70d9-11e9-0013-234b7a5f5337" 3 | DoubleFloats = "497a8b3b-efae-58df-a0af-a86822472b78" 4 | FiniteDiff = "6a86dc24-6348-571c-b903-95158fe2bd41" 5 | ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" 6 | GenericLinearAlgebra = "14197337-ba66-59df-a3e3-ca00e7dcff7a" 7 | Infiltrator = "5903a43b-9cc3-4c30-8d17-598619ec4e9b" 8 | IntervalArithmetic = "d1acc4aa-44c8-5952-acd4-ba5d80a2a253" 9 | KrylovKit = "0b1a1467-8014-51b9-945f-bf0ae24f4b77" 10 | LineSearches = "d3d80556-e9d4-5f37-9878-2ab0fcc64255" 11 | NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" 12 | Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" 13 | PyCall = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" 14 | Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d" 15 | UnitfulAtomic = "a7773ee8-282e-5fa2-be4e-bd808c38a91a" 16 | -------------------------------------------------------------------------------- /solutions/7_ex1_computing_stresses.jl: -------------------------------------------------------------------------------- 1 | # Solution to the exercise "Computing stresses" 2 | # in the notebook 7_Properties_automatic_differentation.ipynb 3 | 4 | using ForwardDiff 5 | using DFTK 6 | scfres = compute_silicon(zeros(3)) 7 | 8 | function recompute_silicon_energy_stresses(lattice) 9 | atoms = scfres.basis.model.atoms 10 | new_model = model_DFT(lattice, atoms, [:lda_x, :lda_c_vwn]; symmetries=false) 11 | new_basis = PlaneWaveBasis(new_model; Ecut=13, kgrid=[2, 2, 2]); 12 | ρ = DFTK.compute_density(new_basis, scfres.ψ, scfres.occupation) 13 | energy_hamiltonian(new_basis, scfres.ψ, scfres.occupation; ρ=scfres.ρ).E.total 14 | end 15 | 16 | L = scfres.basis.model.lattice 17 | 18 | # Just tranform the stress definition into Julia code: 19 | ForwardDiff.gradient(M -> recompute_silicon_energy_stresses((I + M) * L), zero(L)) / det(L) -------------------------------------------------------------------------------- /solutions/6_ex1_generic_floats.jl: -------------------------------------------------------------------------------- 1 | # Solution to the exercise "Computing stresses" 2 | # in the notebook 6_Floating_point_error.ipynb 3 | 4 | using DFTK 5 | using GenericLinearAlgebra # Needed to enable generic fallbacks in DFTK 6 | using DoubleFloats # Defines Double64 7 | 8 | # Silicon lattice 9 | a = 10.26 10 | lattice = a / 2 .* [[0 1 1.]; [1 0 1.]; [1 1 0.]] 11 | Si = ElementPsp(:Si, psp=load_psp("hgh/lda/Si-q4")) 12 | atoms = [Si => [ones(3)/8, -ones(3)/8]] 13 | 14 | # Repeat the Float32 calculation here for the sake of having everything 15 | # in one place. 16 | println("Running Float32 ...") 17 | model = model_DFT(Array{Float32}(lattice), atoms, [:lda_x, :lda_c_vwn]) 18 | basis = PlaneWaveBasis(model; Ecut=7, kgrid=[1, 1, 1], fft_size=(16, 16, 16)) 19 | scfres = self_consistent_field(basis, tol=1e-16, maxiter=40) 20 | results = Dict{DataType, Any}(Float32 => scfres.energies.total) 21 | 22 | println("\nRunning Float64 ...") 23 | model = model_DFT(Array{Float64}(lattice), atoms, [:lda_x, :lda_c_vwn]) 24 | basis = PlaneWaveBasis(model; Ecut=7, kgrid=[1, 1, 1], fft_size=(16, 16, 16)) 25 | scfres = self_consistent_field(basis, tol=1e-16, maxiter=40) 26 | results[Float64] = scfres.energies.total 27 | 28 | 29 | println("\nRunning Double64 ...") 30 | model = model_DFT(Array{Double64}(lattice), atoms, [:lda_x, :lda_c_vwn]) 31 | basis = PlaneWaveBasis(model; Ecut=7, kgrid=[1, 1, 1], fft_size=(16, 16, 16)) 32 | scfres = self_consistent_field(basis, tol=1e-16, maxiter=40) 33 | results[Double64] = scfres.energies.total 34 | 35 | println() 36 | println("Float32: $(results[Float32])") 37 | println("Float64: $(results[Float64])") 38 | println("Double64: $(results[Double64])") 39 | 40 | println() 41 | println("Errors versus Double64:") 42 | println("Float32: $(results[Float32] - results[Double64])") # Order of 1e-7 43 | println("Float64: $(results[Float64] - results[Double64])") # Order of 1e-14 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Juliacon DFT workshop [![][binder-img]][binder-url] 2 | 3 | These notebooks provide a brief mathematically-oriented introduction 4 | into plane-wave density-functional theory (DFT) 5 | and were prepared for the 6 | [*A mathematical look at electronic structure theory*](https://pretalx.com/juliacon2021/talk/KK9KS7/) 7 | workshop at Juliacon 2021. 8 | 9 | The main topics of the notebooks are: 10 | - Algorithms and numerical procedures to solve DFT (in particular SCF methods) 11 | - Tools to understand and analyse convergence 12 | - Opportunities to modern software engineering techniques 13 | (e.g. tracking floating-point error, automatic differentiation) 14 | - Presentation of the [density-functional toolkit](https://dftk.org) (DFTK) 15 | - Integration of DFTK within the Julia package ecosystem 16 | 17 | For more details and to get started, see the 18 | [Getting started](https://nbviewer.jupyter.org/github/mfherbst/juliacon_dft_workshop/blob/master/0_Getting_started.ipynb) 19 | and [Installation](https://nbviewer.jupyter.org/github/mfherbst/juliacon_dft_workshop/blob/master/1_Installation.ipynb) 20 | notebooks. 21 | 22 | Solutions to the exercises can be found in the [solutions](solutions) subfolder 23 | ordered by the number of the Jupyter notebook and the exerciese number. 24 | 25 | ## Working with these notes online 26 | If you do not want to install Julia, just run these notes 27 | [on binder][binder-url], 28 | which will allow you to play with the notebooks in your browser. 29 | Note that for some of the exercises the computational performance 30 | available on binder might not be sufficient. 31 | 32 | ## Citation 33 | These notes can be cited using this DOI: 34 | [![DOI](https://zenodo.org/badge/387545954.svg)](https://zenodo.org/badge/latestdoi/387545954) 35 | 36 | 37 | [binder-url]: https://mybinder.org/v2/gh/mfherbst/juliacon_dft_workshop/master 38 | [binder-img]: https://mybinder.org/badge_logo.svg 39 | -------------------------------------------------------------------------------- /solutions/4_ex2_damped_iterations.jl: -------------------------------------------------------------------------------- 1 | # Solution for the exercise "Damped iterations" 2 | # in 4_Solving_the_SCF_problem.ipynb 3 | 4 | # Setup copied to have a stand-alone script 5 | using DFTK 6 | using LinearAlgebra 7 | 8 | function aluminium_setup(repeat=1; Ecut=13.0, kgrid=[2, 2, 2]) 9 | a = 7.65339 10 | lattice = diagm(fill(a, 3)) 11 | Al = ElementPsp(:Al, psp=load_psp("hgh/lda/al-q3")) 12 | atoms = [Al => [[0.0, 0.0, 0.0], [0.0, 0.5, 0.5], [0.5, 0.0, 0.5], [0.5, 0.5, 0.0]]] 13 | 14 | # Make supercell in pymatgen: 15 | # We convert our lattice to the conventions used in pymatgen 16 | # and then back ... 17 | mg_struct = pymatgen_structure(lattice, atoms) 18 | mg_struct.make_supercell([1, 1, repeat]) 19 | lattice = load_lattice(mg_struct) 20 | atoms = [Al => [s.frac_coords for s in mg_struct.sites]]; 21 | 22 | # Construct the LDA model and discretise 23 | model = model_LDA(lattice, atoms, temperature=1e-3) 24 | PlaneWaveBasis(model; Ecut, kgrid) 25 | end 26 | 27 | 28 | function damped_fixed_point_iteration(F, ρ₀, maxiter; tol) 29 | # F: The SCF step function 30 | # ρ₀: The initial guess density 31 | # maxiter: The maximal number of iterations to be performed 32 | # tol: The selected convergence tolerance 33 | 34 | α = 0.77 # <-- Set damping value here 35 | 36 | ρ = ρ₀ 37 | Fρ = F(ρ) 38 | for n = 1:maxiter 39 | # If change less than tolerance, break iterations: 40 | if norm(Fρ - ρ) < tol 41 | break 42 | end 43 | 44 | Rρ = Fρ - ρ # Compute residual 45 | ρnew = ρ + α * Rρ # Damped update 46 | 47 | # Compute next step 48 | ρ = ρnew 49 | Fρ = F(ρ) 50 | end 51 | 52 | # Return some stuff DFTK needs ... 53 | (fixpoint=ρ, converged=norm(Fρ - ρ) < tol) 54 | end; 55 | 56 | # use this algorithm inside DFTK's SCF 57 | self_consistent_field(aluminium_setup(); 58 | solver=damped_fixed_point_iteration, 59 | damping=1.0, 60 | maxiter=40) 61 | nothing 62 | 63 | 64 | # Very fast convergence is obtained for about α = 0.75 in only 6 SCF steps 65 | # Already slightly larger values break convergence (e.g. α = 0.78 fails to converge) -------------------------------------------------------------------------------- /solutions/4_ex4_preconditioned_iterations.jl: -------------------------------------------------------------------------------- 1 | # Solution for the exercise "Preconditioned iterations" 2 | # in 4_Solving_the_SCF_problem.ipynb 3 | 4 | # Setup copied to have a stand-alone script 5 | using DFTK 6 | using LinearAlgebra 7 | setup_threading() 8 | 9 | function aluminium_setup(repeat=1; Ecut=13.0, kgrid=[2, 2, 2]) 10 | a = 7.65339 11 | lattice = diagm(fill(a, 3)) 12 | Al = ElementPsp(:Al, psp=load_psp("hgh/lda/al-q3")) 13 | atoms = [Al => [[0.0, 0.0, 0.0], [0.0, 0.5, 0.5], [0.5, 0.0, 0.5], [0.5, 0.5, 0.0]]] 14 | 15 | # Make supercell in pymatgen: 16 | # We convert our lattice to the conventions used in pymatgen 17 | # and then back ... 18 | mg_struct = pymatgen_structure(lattice, atoms) 19 | mg_struct.make_supercell([1, 1, repeat]) 20 | lattice = load_lattice(mg_struct) 21 | atoms = [Al => [s.frac_coords for s in mg_struct.sites]]; 22 | 23 | # Construct the LDA model and discretise 24 | model = model_LDA(lattice, atoms, temperature=1e-3) 25 | PlaneWaveBasis(model; Ecut, kgrid) 26 | end 27 | 28 | function run_scf(repeat, mixing) 29 | scfres = self_consistent_field(aluminium_setup(repeat); 30 | damping=0.8, mixing=mixing(), tol=1e-6) 31 | scfres.n_iter 32 | end 33 | 34 | using DataFrames 35 | df = DataFrame(mixings=Symbol[], repeats=Int[], n_iter=Int[]) 36 | for repeat in [1, 2, 4, 6, 8] 37 | for mixing in [KerkerMixing, DielectricMixing, LdosMixing] 38 | println("$mixing --- $repeat") 39 | push!(df, (Symbol(mixing), repeat, run_scf(repeat, mixing))) 40 | println() 41 | println() 42 | end 43 | end 44 | 45 | println(df) 46 | #15×3 DataFrame 47 | # Row │ mixings repeats n_iter 48 | # │ Symbol Int64 Int64 49 | #─────┼─────────────────────────────────── 50 | # 1 │ KerkerMixing 1 5 51 | # 2 │ DielectricMixing 1 5 52 | # 3 │ LdosMixing 1 11 53 | # 54 | # 4 │ KerkerMixing 2 5 55 | # 5 │ DielectricMixing 2 5 56 | # 6 │ LdosMixing 2 7 57 | # 58 | # 7 │ KerkerMixing 4 6 59 | # 8 │ DielectricMixing 4 7 60 | # 9 │ LdosMixing 4 9 61 | # 62 | # 10 │ KerkerMixing 6 8 63 | # 11 │ DielectricMixing 6 12 64 | # 12 │ LdosMixing 6 9 65 | # 66 | # 13 │ KerkerMixing 8 8 67 | # 14 │ DielectricMixing 8 12 68 | # 15 │ LdosMixing 8 9 69 | 70 | # For the small system sizes LdosMixing does a little worse, but between Dielectric 71 | # and Kerker there is basically no difference, since for the small sizes the system-specific 72 | # details of aluminium do not yet become visible. 73 | 74 | # As the system size increases, LdosMixing catches up and becomes as good as Kerker. 75 | # Dielectric (which is best suited for semiconductors) becomes less and less able to help 76 | # the convergence and the number of required iterations increases slowly with system size. 77 | -------------------------------------------------------------------------------- /solutions/5_ex2_helium.jl: -------------------------------------------------------------------------------- 1 | # Solution to the exercise computing the Helium dielectric eigenvalues 2 | # in 5_Analysing_SCF_convergence.jl 3 | 4 | # Copy to make script self-contained 5 | using DFTK 6 | using LinearAlgebra 7 | using KrylovKit 8 | 9 | function helium_setup(repeat=40; Ecut=7.0, kgrid=[1, 1, 1]) 10 | a = 5 11 | lattice = diagm(fill(a, 3)) 12 | He = ElementPsp(:He, psp=load_psp("hgh/lda/he-q2")) 13 | atoms = [He => [[0.0, 0.0, 0.0]]] 14 | 15 | # Make supercell in pymatgen 16 | mg_struct = pymatgen_structure(lattice, atoms) 17 | mg_struct.make_supercell([1, 1, repeat]) 18 | lattice = load_lattice(mg_struct) 19 | atoms = [He => [s.frac_coords for s in mg_struct.sites]]; 20 | 21 | # Construct the model 22 | model = model_LDA(lattice, atoms, temperature=1e-3, symmetries=false) 23 | PlaneWaveBasis(model; Ecut, kgrid) 24 | end 25 | 26 | function construct_Pinv_epsilon(scfres) 27 | basis = scfres.basis 28 | 29 | Pinv_Kerker(δρ) = DFTK.mix_density(KerkerMixing(), basis, δρ) 30 | 31 | function epsilon(δρ) # Apply ε† = 1 - χ0 Khxc 32 | δV = apply_kernel(basis, δρ; ρ=scfres.ρ) 33 | χ0δV = apply_χ0(scfres.ham, scfres.ψ, scfres.εF, scfres.eigenvalues, δV) 34 | δρ - χ0δV 35 | end 36 | 37 | epsilon, Pinv_Kerker 38 | end 39 | 40 | scfres = self_consistent_field(helium_setup(30); tol=1e-12); 41 | epsilon, Pinv_Kerker = construct_Pinv_epsilon(scfres) 42 | 43 | for (label, operator) in [("ε", epsilon), ("P⁻¹ε", Pinv_Kerker ∘ epsilon)] 44 | println() 45 | println("--------") 46 | println() 47 | println("Compute λ_large for $label") 48 | λ_large, X_large, info = eigsolve(operator, randn(size(scfres.ρ)), 2, :LM; 49 | tol=1e-3, eager=true, verbosity=2) 50 | @assert info.converged ≥ 2 51 | λ_max = maximum(real.(λ_large)) 52 | 53 | println("Compute λ_small for $label") 54 | λ_small, X_small, info = eigsolve(operator, randn(size(scfres.ρ)), 2, EigSorter(abs, rev=false); 55 | tol=1e-3, eager=true, verbosity=2) 56 | @assert info.converged ≥ 2 57 | λ_min = minimum(real.(λ_small)) 58 | 59 | cond = λ_max / λ_min 60 | println() 61 | println("Smallest eigenvalue $label: $(λ_min)") 62 | println("Largest eigenvalue $label: $(λ_max)") 63 | println("Condition number $label: $cond") 64 | end 65 | 66 | 67 | # Example output: 68 | # 69 | # Smallest eigenvalue ε: 0.9517149905415806 70 | # Largest eigenvalue ε: 1.4438934058378814 71 | # Condition number ε: 1.517148957605704 72 | # 73 | # 74 | # Smallest eigenvalue P⁻¹ε: 0.0036831161341721696 75 | # Largest eigenvalue P⁻¹ε: 1.1491558189981426 76 | # Condition number P⁻¹ε: 312.0064035820665 77 | # 78 | # Using the Kerker mixing on the Helium system has little effect on the largest eigenvalue, but it 79 | # dramatically lowers the smallest eigenvalue (from 0.95 to about 3e-2) and as a result the condition 80 | # number *increases* from a dream value of 1.5 to about 300. As a result SCF convergence is much worse 81 | # when using the Kerker mixing on this insulating system. -------------------------------------------------------------------------------- /solutions/5_ex1_aluminium_Kerker.jl: -------------------------------------------------------------------------------- 1 | # Solution to the exercise computing the Kerker-preconditioned eigenvalues 2 | # of aluminium in 5_Analysing_SCF_convergence.jl 3 | 4 | # Copy to make script self-contained 5 | using DFTK 6 | using LinearAlgebra 7 | using Plots 8 | using Statistics 9 | setup_threading() 10 | 11 | function aluminium_setup(repeat=1; Ecut=7.0, kgrid=[1, 1, 1]) 12 | a = 7.65339 13 | lattice = diagm(fill(a, 3)) 14 | Al = ElementPsp(:Al, psp=load_psp("hgh/lda/al-q3")) 15 | atoms = [Al => [[0.0, 0.0, 0.0], [0.0, 0.5, 0.5], [0.5, 0.0, 0.5], [0.5, 0.5, 0.0]]] 16 | 17 | # Make supercell in pymatgen 18 | mg_struct = pymatgen_structure(lattice, atoms) 19 | mg_struct.make_supercell([1, 1, repeat]) 20 | lattice = load_lattice(mg_struct) 21 | atoms = [Al => [s.frac_coords for s in mg_struct.sites]]; 22 | 23 | # Construct the model 24 | model = model_LDA(lattice, atoms, temperature=1e-3, symmetries=false) 25 | PlaneWaveBasis(model; Ecut, kgrid) 26 | end 27 | 28 | function construct_Pinv_epsilon(scfres) 29 | basis = scfres.basis 30 | 31 | Pinv_Kerker(δρ) = DFTK.mix_density(KerkerMixing(), basis, δρ) 32 | 33 | function epsilon(δρ) # Apply ε† = 1 - χ0 Khxc 34 | δV = apply_kernel(basis, δρ; ρ=scfres.ρ) 35 | χ0δV = apply_χ0(scfres.ham, scfres.ψ, scfres.εF, scfres.eigenvalues, δV) 36 | δρ - χ0δV 37 | end 38 | 39 | epsilon, Pinv_Kerker 40 | end 41 | 42 | function plot_mode(mode) 43 | # Average along x axis 44 | mode_yz = mean(real.(mode), dims=1)[1, :, :, 1] 45 | heatmap(mode_yz, c=:RdBu_11, aspect_ratio=1, grid=false, 46 | legend=false, clim=(-0.006, 0.006)) 47 | end 48 | 49 | # Start of new stuff ... 50 | using KrylovKit 51 | 52 | repeat = 3 53 | scfres = self_consistent_field(aluminium_setup(repeat); tol=1e-12, mixing=KerkerMixing()); 54 | epsilon, Pinv_Kerker = construct_Pinv_epsilon(scfres) 55 | operator = Pinv_Kerker ∘ epsilon # ∘ = \circ 56 | 57 | λ_large, X_large, info = eigsolve(operator, randn(size(scfres.ρ)), 4, :LM; 58 | tol=1e-4, eager=true, verbosity=2) 59 | @assert info.converged ≥ 4 60 | λ_max = maximum(real.(λ_large)) 61 | println("Largest eigenvalue: $(λ_max)") 62 | 63 | # Getting the smallest eigenvalue here is quite a pain ... we will just assume it is 0.8 64 | # λ_small, X_small, info = eigsolve(epsilon, randn(size(scfres.ρ)), 2, EigSorter(abs, rev=false); 65 | # tol=1e-3, eager=true, verbosity=2) 66 | # @assert info.converged ≥ 2 67 | # λ_min = minimum(real.(λ_small)) 68 | λ_min = 0.8 69 | cond = λ_max / λ_min 70 | 71 | println("Smallest eigenvalue: $(λ_min)") # about 0.8 72 | println("Largest eigenvalue: $(λ_max)") # about 8.6 73 | println("Condition number: $cond") # about 10 74 | 75 | # Plot largest mode to pdf 76 | savefig(plot_mode(X_large[1]), "5_ex1_aluminium_Kerker_repeat_$repeat.pdf") 77 | 78 | # So by using the Kerker preconditioner for the repeat 3 the condition number reduced from 30 to 10. 79 | # 80 | # For repeat 6: 81 | # largest eigenvalue without Kerker: 100 82 | # largest eigenvalue with Kerker: 5.5 83 | # So by using Kerker the condition number is reduced from 105 to 6.8. -------------------------------------------------------------------------------- /0_Getting_started.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "statewide-honey", 6 | "metadata": {}, 7 | "source": [ 8 | "# A mathematical look at electronic structure theory" 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "id": "dried-concrete", 14 | "metadata": {}, 15 | "source": [ 16 | "## About this workshop\n", 17 | "\n", 18 | "\n", 19 | "\n", 20 | "- Electronic structure theory is a fascinating interdisciplinary field\n", 21 | "- Why bother? -> See [my JuliaCon 2020 talk](https://www.youtube.com/watch?v=-RomkxjlIcQ)\n", 22 | "\n", 23 | "\n", 24 | "- Multiple philosophies and general approaches exist\n", 25 | "- Focus of this workshop:\n", 26 | " * Solid-state problems (crystals, lattices, ...)\n", 27 | " * Plane-wave discretisations\n", 28 | " * Density functional theory (DFT)\n", 29 | " * Highly successful, but still open mathematical questions\n", 30 | "\n", 31 | "\n", 32 | "- Topics:\n", 33 | " * Specialities of periodic problems\n", 34 | " * Mathematical formulation of the DFT\n", 35 | " * Numerical solution using the self-consistent field (SCF) procedure\n", 36 | " * Numerical tools for analysis and understanding convergence\n", 37 | " * Opportunities for modern software programming techniques (tracking floating-point error, automatic differentation).\n", 38 | "\n", 39 | "\n", 40 | "- Goals:\n", 41 | " * Allow applied mathematicians to gain access to the topic\n", 42 | " * Allow practitioners to deepen mathematical insight\n", 43 | " * Introduce the [density-functional toolkit](https://dftk.org) (DFTK)\n", 44 | " and its interplay with the Julia package ecosystem." 45 | ] 46 | }, 47 | { 48 | "cell_type": "markdown", 49 | "id": "several-receipt", 50 | "metadata": {}, 51 | "source": [ 52 | "## Whoami and whoareyou?\n", 53 | "\n", 54 | "* Michael F. Herbst\n", 55 | " - Postdoc at Applied and Computational Mathematics departmant at RWTH Aachen University\n", 56 | " - Chemistry degree, but switched in between departments in the past years\n", 57 | " - Active Julia user since about Julia 0.6\n", 58 | " - Switched to Julia as main language about 3 years ago\n", 59 | " - Contacts:\n", 60 | " \n", 61 | "\n", 62 | " Email: herbst@acom.rwth-aachen.de\n", 63 | " Web: https://michael-herbst.com\n", 64 | " \n", 65 | " \n", 66 | "* So who are you?\n", 67 | " - Quick poll: INSERT URL HERE" 68 | ] 69 | }, 70 | { 71 | "cell_type": "markdown", 72 | "id": "representative-employment", 73 | "metadata": {}, 74 | "source": [ 75 | "## Some general remarks\n", 76 | "\n", 77 | "- The examples in this notebook were primarily chosen to be quick to run and yield mathematical insight. In particular:\n", 78 | " * Parameters will not give fully converged results\n", 79 | " * Not all examples make physical sense (i.e. it might be better to model things differently in practice)\n", 80 | "\n", 81 | "\n", 82 | "- I have prepared:\n", 83 | " * Some theory\n", 84 | " * Many examples\n", 85 | " * Short exercises (with [solutions](solutions))\n", 86 | " \n", 87 | " \n", 88 | "- This is meant to be interactive:\n", 89 | " * Please ask questions ..." 90 | ] 91 | } 92 | ], 93 | "metadata": { 94 | "kernelspec": { 95 | "display_name": "Julia 1.6.1", 96 | "language": "julia", 97 | "name": "julia-1.6" 98 | }, 99 | "language_info": { 100 | "file_extension": ".jl", 101 | "mimetype": "application/julia", 102 | "name": "julia", 103 | "version": "1.6.1" 104 | } 105 | }, 106 | "nbformat": 4, 107 | "nbformat_minor": 5 108 | } 109 | -------------------------------------------------------------------------------- /1_Installation.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "burning-pharmacology", 6 | "metadata": {}, 7 | "source": [ 8 | "# Installation and setup" 9 | ] 10 | }, 11 | { 12 | "cell_type": "markdown", 13 | "id": "coated-execution", 14 | "metadata": {}, 15 | "source": [ 16 | "## Requirements\n", 17 | "\n", 18 | "- **Julia 1.6** recommeded\n", 19 | " * Note: Our test suite segfaults in 1.7 (see this PR: https://github.com/JuliaLang/julia/pull/41516)\n", 20 | "- Some working python setup\n", 21 | "\n", 22 | "\n", 23 | "- These notes have been made targeting **DFTK 0.3.9**.
\n", 24 | " Some interface additions and bug fixes of this version are required for these notes,\n", 25 | " so please ensure you update from a previous version of the code." 26 | ] 27 | }, 28 | { 29 | "cell_type": "markdown", 30 | "id": "mysterious-snake", 31 | "metadata": {}, 32 | "source": [ 33 | "## Jupyter notebooks\n", 34 | "\n", 35 | "To get these notebooks run from a shell as usual:\n", 36 | "```shell\n", 37 | "$ git clone https://github.com/mfherbst/juliacon_dft_workshop.git\n", 38 | "```" 39 | ] 40 | }, 41 | { 42 | "cell_type": "markdown", 43 | "id": "permanent-syndication", 44 | "metadata": {}, 45 | "source": [ 46 | "## 1. Julia dependencies\n", 47 | "\n", 48 | "Either instantiate the Manifest of this git repository or run the following code to install the packages needed for this workshop:" 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": null, 54 | "id": "automotive-citizen", 55 | "metadata": {}, 56 | "outputs": [], 57 | "source": [ 58 | "using Pkg\n", 59 | "Pkg.add([\n", 60 | "\"DFTK\", \"DoubleFloats\", \"FiniteDiff\", \"ForwardDiff\",\n", 61 | "\"GenericLinearAlgebra\", \"Infiltrator\", \"IntervalArithmetic\",\n", 62 | "\"KrylovKit\", \"LineSearches\", \"NLsolve\", \"Plots\", \"PyCall\",\n", 63 | "\"Unitful\", \"UnitfulAtomic\"\n", 64 | "])" 65 | ] 66 | }, 67 | { 68 | "cell_type": "markdown", 69 | "id": "baking-young", 70 | "metadata": {}, 71 | "source": [ 72 | "## 2. Python dependencies\n", 73 | "\n", 74 | "DFTK has a python dependency, that is unfortunately required for a few tasks. We are [currently working](https://github.com/JuliaMolSim/DFTK.jl/issues/483) on switching to a pure-Julia solution, however.\n", 75 | "\n", 76 | "But for the moment you need to install `pymatgen`.\n", 77 | "\n", 78 | "- If you use `Conda.jl`, the DFTK build script has already installed this package to Julia's conda environment.\n", 79 | "\n", 80 | "- If you use `pip` to manage your packages, run:" 81 | ] 82 | }, 83 | { 84 | "cell_type": "code", 85 | "execution_count": null, 86 | "id": "experimental-fifty", 87 | "metadata": {}, 88 | "outputs": [], 89 | "source": [ 90 | "using PyCall\n", 91 | "if !isempty(PyCall.python)\n", 92 | " run(`$(PyCall.python) -m pip install pymatgen`)\n", 93 | "end" 94 | ] 95 | }, 96 | { 97 | "cell_type": "markdown", 98 | "id": "opponent-federal", 99 | "metadata": {}, 100 | "source": [ 101 | "- If you use an external conda environment then install `pymatgen` from the `conda-forge` channel." 102 | ] 103 | }, 104 | { 105 | "cell_type": "markdown", 106 | "id": "american-hello", 107 | "metadata": {}, 108 | "source": [ 109 | "## 3. Verify things are working\n", 110 | "\n", 111 | "Run this code to see the relevant packages can be found:" 112 | ] 113 | }, 114 | { 115 | "cell_type": "code", 116 | "execution_count": null, 117 | "id": "stuffed-motion", 118 | "metadata": {}, 119 | "outputs": [], 120 | "source": [ 121 | "using PyCall\n", 122 | "@show pyimport(\"pymatgen\").__name__ # \"pymatgen\"\n", 123 | "\n", 124 | "using DFTK\n", 125 | "DFTK.setup_threading() # Prints some threading info" 126 | ] 127 | } 128 | ], 129 | "metadata": { 130 | "kernelspec": { 131 | "display_name": "Julia 1.6.1", 132 | "language": "julia", 133 | "name": "julia-1.6" 134 | }, 135 | "language_info": { 136 | "file_extension": ".jl", 137 | "mimetype": "application/julia", 138 | "name": "julia", 139 | "version": "1.6.1" 140 | } 141 | }, 142 | "nbformat": 4, 143 | "nbformat_minor": 5 144 | } 145 | -------------------------------------------------------------------------------- /8_Direct_minimisation.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "local-transmission", 6 | "metadata": {}, 7 | "source": [ 8 | "# Direct minimisation\n", 9 | "\n", 10 | "- Recall that we introduced DFT as the minimisation problem\n", 11 | " $$ \\displaystyle \\text{min}_{\\{\\psi_i\\}} \\mathcal{E}_\\text{DFT}(\\{\\psi_i\\}) $$\n", 12 | "where the energy expression $\\mathcal{E}_\\text{DFT}(\\{\\psi_i\\})$ is a known analytic function and the $\\{\\psi_i\\}$ are orthonormal orbitals.\n", 13 | "\n", 14 | "\n", 15 | "- Taking a closer look at this minimisation problem one might rightfully wonder why one should bother going through the SCF procedure at all. Could one not just minimise the energy wrt. the orbitals?\n", 16 | "- The answer is yes and leads to a procedure called **direct minimisation** (DM). In practice DM provides an alternative route to access a DFT ground state." 17 | ] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "id": "alien-microphone", 22 | "metadata": {}, 23 | "source": [ 24 | "While the basic principle of a DM algorithms is relatively straightforward\n", 25 | "a practical implementation faces a few subtle points that require some thought:\n", 26 | "\n", 27 | "- Due to the orthogonality constraints on the orbitals $\\{\\psi_i\\}$,\n", 28 | " the set of admissible orbitals does not form a vector space,\n", 29 | " but much rather the unknowns of $\\{\\psi_i\\}$ belong to a Stiefel manifold.\n", 30 | " This needs to be taken into account\n", 31 | " (via appropriate projections) in order to get the correct minimum.\n", 32 | " Fortunately `Optim.jl` can do that out of the box ...\n", 33 | "\n", 34 | "- DM in combination with metals (i.e. without a band gap) is tricky,\n", 35 | " because of possible degeneracies of the orbitals at the Fermi level ($i = N$).\n", 36 | " This problem manifests when computing the gradient of $\\mathcal{E}_\\text{DFT}$\n", 37 | " in such a setting, where thus special care is needed to not run into\n", 38 | " \"division by zero\" issues.\n", 39 | " \n", 40 | "- In this workbook we will restrict ourseves to insulators,\n", 41 | " which have a band gap and thus don't feature this numerical problem.\n", 42 | " Furthermore we will restrict ourselves to a single $k$-Point\n", 43 | " as going beyond that requires a little more bookkeeping\n", 44 | " (see the [DFTK implementation](https://github.com/JuliaMolSim/DFTK.jl/blob/master/src/scf/direct_minimization.jl)).\n", 45 | " \n", 46 | "All right, now let's consider computing the gradient.\n", 47 | "Since the total energy can also be written as\n", 48 | "$$ \\mathcal{E}_\\text{DFT}(\\{\\psi_i\\}) = 2 \\sum_i \\int \\psi_i^\\ast H \\psi_i + E_\\text{nuclear} $$\n", 49 | "(where $E_\\text{nuclear}$ is a constant), the **gradient of $\\mathcal{E}_\\text{DFT}$**\n", 50 | "can be represented as $4 H \\psi_i $.\n", 51 | "\n", 52 | "We can proceed to a simple implementation:" 53 | ] 54 | }, 55 | { 56 | "cell_type": "code", 57 | "execution_count": null, 58 | "id": "instrumental-causing", 59 | "metadata": {}, 60 | "outputs": [], 61 | "source": [ 62 | "using DFTK\n", 63 | "using Optim\n", 64 | "using LineSearches\n", 65 | "\n", 66 | "# Standard silicon setup\n", 67 | "a = 10.26\n", 68 | "lattice = a / 2 * [[0 1 1.];\n", 69 | " [1 0 1.];\n", 70 | " [1 1 0.]]\n", 71 | "Si = ElementPsp(:Si, psp=load_psp(\"hgh/lda/si-q4\"))\n", 72 | "atoms = [Si => [ones(3)/8, -ones(3)/8]]\n", 73 | "model = model_DFT(lattice, atoms, [:lda_x, :lda_c_vwn])\n", 74 | "basis = PlaneWaveBasis(model; Ecut=10, kgrid=[1, 1, 1]);\n", 75 | "\n", 76 | "# One unit cell has 2 Silicon atoms.\n", 77 | "# In the model we use (where only valence electrons are explictly treated)\n", 78 | "# this makes 8 electrons, which requires 4 bands with 2 electrons each:\n", 79 | "occupation = [2.0, 2.0, 2.0, 2.0]\n", 80 | "\n", 81 | "# We specify a random initial guess for the 4 orbitals:\n", 82 | "n_G = length(G_vectors(only(basis.kpoints)))\n", 83 | "ψ0 = Matrix(qr(randn(ComplexF64, n_G, 4)).Q);\n", 84 | "\n", 85 | "# Function to compute energies and gradients\n", 86 | "function fg!(E, G, ψ)\n", 87 | " ρ = compute_density(basis, [ψ], [occupation])\n", 88 | " energies, H = energy_hamiltonian(basis, [ψ], [occupation]; ρ=ρ)\n", 89 | "\n", 90 | " if G !== nothing\n", 91 | " # Optim expects the gradient in G\n", 92 | " G .= 4 * (H.blocks[1] * ψ)\n", 93 | " end\n", 94 | " energies.total\n", 95 | "end\n", 96 | "\n", 97 | "# Select a quasi-Newton algorithm with backtracking linesearches\n", 98 | "# to avoid to many costly gradient evaluations\n", 99 | "algorithm = Optim.LBFGS(manifold=Optim.Stiefel(),\n", 100 | " linesearch=LineSearches.BackTracking())\n", 101 | "\n", 102 | "# Set some convergence options in Optim:\n", 103 | "options = Optim.Options(; allow_f_increases=true, show_trace=true, x_tol=1e-6)\n", 104 | "\n", 105 | "# Run the direct minimisation\n", 106 | "res = Optim.optimize(Optim.only_fg!(fg!), ψ0, algorithm, options)\n", 107 | "\n", 108 | "@show res.minimum" 109 | ] 110 | }, 111 | { 112 | "cell_type": "markdown", 113 | "id": "thrown-highland", 114 | "metadata": {}, 115 | "source": [ 116 | "#### More details\n", 117 | "- [Geometry of algorithms with orthogonality constraints](https://doi.org/10.1137/S0895479895290954)\n", 118 | "- [Convergence analysis of direct minimisation and self-consistent field iterations](https://doi.org/10.1137/20M1332864)" 119 | ] 120 | } 121 | ], 122 | "metadata": { 123 | "kernelspec": { 124 | "display_name": "Julia 1.6.1", 125 | "language": "julia", 126 | "name": "julia-1.6" 127 | }, 128 | "language_info": { 129 | "file_extension": ".jl", 130 | "mimetype": "application/julia", 131 | "name": "julia", 132 | "version": "1.6.1" 133 | } 134 | }, 135 | "nbformat": 4, 136 | "nbformat_minor": 5 137 | } 138 | -------------------------------------------------------------------------------- /7_Properties_automatic_differentation.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "sufficient-southwest", 6 | "metadata": {}, 7 | "source": [ 8 | "# Computing properties and automatic differentiation\n", 9 | "\n", 10 | "Even though we have now spent about quite some notebooks discussing the SCF, its convergence and errors, the resulting quantity --- the DFT total energy --- is not very interesting." 11 | ] 12 | }, 13 | { 14 | "cell_type": "markdown", 15 | "id": "revolutionary-membership", 16 | "metadata": {}, 17 | "source": [ 18 | "- From a physical point of view the total energy is arbitrary and can always be shifted around.\n", 19 | "- What is of great interest, however, are **differences** or **changes** in the energy\n", 20 | " in response to a perturbation.\n", 21 | "- In fact such responses often represent quantities, which are directly measurable\n", 22 | " in experiment (or are at least they are closely linked to measurements).\n", 23 | "- A few examples:\n", 24 | " * *dipole moment* (response of the energy to a change in electric field)\n", 25 | " * *forces* (response to a change in atomic positions)\n", 26 | " * ...\n", 27 | "\n", 28 | "Notice that \"response\" is just a different term for \"taking an energy derivative\". So that's a good opportunity to try some automatic differentation tools in combination with DFTK." 29 | ] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "id": "immune-mills", 34 | "metadata": {}, 35 | "source": [ 36 | "## Computing forces\n", 37 | "\n", 38 | "Given a crystal with atomic positions $x$ and DFT ground state energy $E_\\text{SCF}$ (implicitly depending on $x$ via the external potential $V_\\text{ext}$), the force is defined as\n", 39 | "\n", 40 | "$$ \\text{Force} = - \\frac{d E_\\text{SCF}}{d x} $$\n", 41 | "\n", 42 | "For a silicon crystal one could define the DFT ground state in terms of a shift vector ($x$) between\n", 43 | "both silicon atoms as follows:" 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": null, 49 | "id": "seventh-exchange", 50 | "metadata": {}, 51 | "outputs": [], 52 | "source": [ 53 | "using DFTK\n", 54 | "\n", 55 | "function compute_silicon(x)\n", 56 | " a = 10.26\n", 57 | " lattice = a / 2 * [[0 1 1.];\n", 58 | " [1 0 1.];\n", 59 | " [1 1 0.]]\n", 60 | " Si = ElementPsp(:Si, psp=load_psp(\"hgh/lda/si-q4\"))\n", 61 | " atoms = [Si => [ones(3)/8, -ones(3)/8 + x]]\n", 62 | " \n", 63 | " T = eltype(x)\n", 64 | " model = model_DFT(Array{T}(lattice), atoms,[:lda_x, :lda_c_vwn]; symmetries=false)\n", 65 | " basis = PlaneWaveBasis(model; Ecut=13, kgrid=[2, 2, 2]);\n", 66 | " \n", 67 | " self_consistent_field(basis; tol=1e-14, callback=identity)\n", 68 | "end" 69 | ] 70 | }, 71 | { 72 | "cell_type": "markdown", 73 | "id": "cellular-airplane", 74 | "metadata": {}, 75 | "source": [ 76 | "With this function we compute the silicon force in DFTK as:" 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": null, 82 | "id": "occasional-residence", 83 | "metadata": {}, 84 | "outputs": [], 85 | "source": [ 86 | "ε = 1e-2randn(3) # Slight distortion to get something non-boring\n", 87 | "scfres = compute_silicon(ε)\n", 88 | "compute_forces(scfres)[1][2] # Select force on displaced silicon atom" 89 | ] 90 | }, 91 | { 92 | "cell_type": "markdown", 93 | "id": "frozen-married", 94 | "metadata": {}, 95 | "source": [ 96 | "The `compute_forces` uses analytical derivative expressions implemented manually inside DFTK. Implementing these by hand for a few standard properties and DFT models is fine. However, the number of DFT models is rather large and so is the number of interesting properties. Some properties even require higher order derivatives, e.g. 2nd and 3rd energy derivatives are also not unusual.\n", 97 | "\n", 98 | "Deriving and implementing all these derivatives is tedious, error-prone and time consuming. Let's see if we can at least replicate this force result using some of Julia's **automatic differentiation** tools.\n", 99 | "\n", 100 | "First we baseline with **finite differences**. Instead of running the SCF algorithm twice (once for $x$ and once for $x + \\epsilon$), we explicitly exploit the *Hellmann-Feynman theorem*,\n", 101 | "which states that near an SCF ground state\n", 102 | "\n", 103 | "$$ \\frac{d E_\\text{SCF}}{d x} = \\frac{\\partial E_\\text{SCF}}{\\partial x} + \\frac{\\partial E_\\text{SCF}}{\\partial \\Psi} \\frac{\\partial \\Psi}{\\partial x} = \\frac{\\partial E_\\text{SCF}}{\\partial x}$$\n", 104 | "\n", 105 | "i.e. that the dependency of $E_\\text{SCF}$ on the orbitals $\\Psi = \\{\\psi_i\\}$ does not need to be considered.\n", 106 | "\n", 107 | "With this simplication:" 108 | ] 109 | }, 110 | { 111 | "cell_type": "code", 112 | "execution_count": null, 113 | "id": "determined-wrapping", 114 | "metadata": {}, 115 | "outputs": [], 116 | "source": [ 117 | "using FiniteDiff\n", 118 | "scfres = compute_silicon(ε)\n", 119 | "\n", 120 | "function recompute_silicon_energy(x)\n", 121 | " T = eltype(x)\n", 122 | " model = scfres.basis.model\n", 123 | " \n", 124 | " Si = ElementPsp(:Si, psp=load_psp(\"hgh/lda/si-q4\"))\n", 125 | " atoms = [Si => [ones(3)/8, -ones(3)/8 + x]]\n", 126 | " new_model = model_DFT(Array{T}(model.lattice),\n", 127 | " atoms,\n", 128 | " [:lda_x, :lda_c_vwn];\n", 129 | " symmetries=false)\n", 130 | " new_basis = PlaneWaveBasis(new_model; Ecut=13, kgrid=[2, 2, 2]);\n", 131 | " \n", 132 | " ρ = DFTK.compute_density(new_basis, scfres.ψ, scfres.occupation)\n", 133 | " energy_hamiltonian(new_basis, scfres.ψ, scfres.occupation; ρ=scfres.ρ).E.total\n", 134 | "end\n", 135 | "\n", 136 | "- FiniteDiff.finite_difference_gradient(recompute_silicon_energy, ε)" 137 | ] 138 | }, 139 | { 140 | "cell_type": "markdown", 141 | "id": "transparent-graphics", 142 | "metadata": {}, 143 | "source": [ 144 | "Sort of agrees ... next we try `ForwardDiff` (tip of the hat to our GSoC Niklas Schmitz, who recently made this possible):" 145 | ] 146 | }, 147 | { 148 | "cell_type": "code", 149 | "execution_count": null, 150 | "id": "palestinian-tender", 151 | "metadata": {}, 152 | "outputs": [], 153 | "source": [ 154 | "using ForwardDiff\n", 155 | "- ForwardDiff.gradient(recompute_silicon_energy, ε)" 156 | ] 157 | }, 158 | { 159 | "cell_type": "markdown", 160 | "id": "mobile-australian", 161 | "metadata": {}, 162 | "source": [ 163 | "## Computing stresses\n", 164 | "\n", 165 | "To close off this section on property computation, let's use **forward-mode AD** to implement a property computation that is not yet available in DFTK.\n", 166 | "\n", 167 | "We will consider the computation of stresses. Denoting the `lattice` matrix by $\\textbf{L}$ for simplicty, the stress is computed as" 168 | ] 169 | }, 170 | { 171 | "cell_type": "markdown", 172 | "id": "typical-magnet", 173 | "metadata": {}, 174 | "source": [ 175 | "$$ \\text{Stress} = \\frac{1}{\\text{det}(\\mathbf{L})} \\left. \\frac{d E_\\text{SCF}}{d [(I + \\mathbf{M}) \\, \\mathbf{L}]} \\right|_{\\mathbf{M}=0} = \\frac{1}{\\text{det}(\\mathbf{L})} \\left. \\frac{\\partial E_\\text{SCF}}{\\partial [(I + \\mathbf{M}) \\, \\mathbf{L}]} \\right|_{\\mathbf{M}=0},\n", 176 | "$$" 177 | ] 178 | }, 179 | { 180 | "cell_type": "markdown", 181 | "id": "organic-sender", 182 | "metadata": {}, 183 | "source": [ 184 | "where again we made use of the Hellman-Feynman theorem." 185 | ] 186 | }, 187 | { 188 | "cell_type": "markdown", 189 | "id": "middle-ownership", 190 | "metadata": {}, 191 | "source": [ 192 | "**Exercise 1:** Use the following code fragment to implement stresses using `ForwardDiff`:" 193 | ] 194 | }, 195 | { 196 | "cell_type": "code", 197 | "execution_count": null, 198 | "id": "pretty-antigua", 199 | "metadata": {}, 200 | "outputs": [], 201 | "source": [ 202 | "using ForwardDiff\n", 203 | "using DFTK\n", 204 | "scfres = compute_silicon(zeros(3))\n", 205 | "\n", 206 | "function recompute_silicon_energy_stresses(lattice)\n", 207 | " atoms = scfres.basis.model.atoms\n", 208 | " new_model = model_DFT(lattice, atoms, [:lda_x, :lda_c_vwn]; symmetries=false)\n", 209 | " new_basis = PlaneWaveBasis(new_model; Ecut=13, kgrid=[2, 2, 2]);\n", 210 | " ρ = DFTK.compute_density(new_basis, scfres.ψ, scfres.occupation)\n", 211 | " energy_hamiltonian(new_basis, scfres.ψ, scfres.occupation; ρ=scfres.ρ).E.total\n", 212 | "end\n", 213 | "\n", 214 | "L = scfres.basis.model.lattice\n", 215 | "\n", 216 | "# Your code here" 217 | ] 218 | }, 219 | { 220 | "cell_type": "markdown", 221 | "id": "radio-relations", 222 | "metadata": {}, 223 | "source": [ 224 | "#### Takeaways:\n", 225 | "- Practical DFT simulations require not only energies, but also energy derivatives.\n", 226 | "- While analytical derivatives are fast, implementing higher order derivatives\n", 227 | " by hand is very, very time-consuming.\n", 228 | "- Only a subset of possibilities is usually implemented in standard codes (like DFTK)\n", 229 | "- Automatic differentation provides an easy way to go beyond the intrinsic properties available in a code\n", 230 | "\n", 231 | "\n", 232 | "- In DFTK we are currently working on more complicated setups for automatic differentation (reverse mode, going beyond Hellmann-Feynman)." 233 | ] 234 | } 235 | ], 236 | "metadata": { 237 | "kernelspec": { 238 | "display_name": "Julia 1.6.1", 239 | "language": "julia", 240 | "name": "julia-1.6" 241 | }, 242 | "language_info": { 243 | "file_extension": ".jl", 244 | "mimetype": "application/julia", 245 | "name": "julia", 246 | "version": "1.6.1" 247 | } 248 | }, 249 | "nbformat": 4, 250 | "nbformat_minor": 5 251 | } 252 | -------------------------------------------------------------------------------- /6_Floating_point_error.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "polyphonic-disabled", 6 | "metadata": {}, 7 | "source": [ 8 | "# Tracking the floating-point error\n", 9 | "\n", 10 | "In the previous notebooks we were concerned with the convergence of the SCF procedure itself.\n", 11 | "Now we change gears a little and take a look at analysing the error within an obtained SCF solution.\n", 12 | "\n", 13 | "There are multiple sources of error in DFT (see [this paper](https://doi.org/10.1039/D0FD00048E) for details):\n", 14 | "1. An obvious one is the DFT model itself\n", 15 | "1. The error due to the discretisation (`Ecut` and `kgrid`)\n", 16 | "1. The error due to aborting the SCF before getting the residual to zero (`tol`)\n", 17 | "1. The error due to using a finite-precision floating-point arithmetic, the **floating-point error**\n", 18 | "\n", 19 | "In this notebook we will focus on the floating-point error and to try and understand the floating-point error in a converged SCF solution. Or in other words:\n", 20 | "$$ \\text{How many digits of my solution are trustworthy?} $$" 21 | ] 22 | }, 23 | { 24 | "cell_type": "markdown", 25 | "id": "competent-census", 26 | "metadata": {}, 27 | "source": [ 28 | "## Solving DFT with different floating-point types\n", 29 | "\n", 30 | "One approximate way to get an idea of the floating-point error\n", 31 | "in a procedure is to solve the problem using higher precision\n", 32 | "floating-point types and compare the matching digits.\n", 33 | "\n", 34 | "To make things a little more interesting we will use 32bit floating-point arithmetic and we will try to converge the energy to the rarely required accuracy of `1e-16`." 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": null, 40 | "id": "radio-association", 41 | "metadata": {}, 42 | "outputs": [], 43 | "source": [ 44 | "using DFTK\n", 45 | "\n", 46 | "# Silicon lattice\n", 47 | "a = 10.26\n", 48 | "lattice = a / 2 .* [[0 1 1.]; [1 0 1.]; [1 1 0.]]\n", 49 | "Si = ElementPsp(:Si, psp=load_psp(\"hgh/lda/Si-q4\"))\n", 50 | "atoms = [Si => [ones(3)/8, -ones(3)/8]]\n", 51 | "\n", 52 | "# DFTK will use the floating-point type used to represent the lattice\n", 53 | "# to deduce the floating-point type for the computation\n", 54 | "model = model_DFT(Array{Float32}(lattice), atoms, [:lda_x, :lda_c_vwn])\n", 55 | "basis = PlaneWaveBasis(model; Ecut=7, kgrid=[1, 1, 1], fft_size=(16, 16, 16))\n", 56 | "scfres = self_consistent_field(basis, tol=1e-16, maxiter=40)\n", 57 | "\n", 58 | "results = Dict{DataType, Any}(\n", 59 | " Float32 => scfres.energies.total\n", 60 | ")\n", 61 | "\n", 62 | "@show results[Float32];" 63 | ] 64 | }, 65 | { 66 | "cell_type": "markdown", 67 | "id": "direct-idaho", 68 | "metadata": {}, 69 | "source": [ 70 | "**Exercise 1:** To get a rough idea how many of these energy digits can be trusted,\n", 71 | "re-run the computation using `Float64` and `Double64` (a floating point type offering even higher accuracy that 64bits). How many digits of the energy can be trusted at `Float32` and `Float64` level?" 72 | ] 73 | }, 74 | { 75 | "cell_type": "code", 76 | "execution_count": null, 77 | "id": "traditional-round", 78 | "metadata": {}, 79 | "outputs": [], 80 | "source": [ 81 | "using GenericLinearAlgebra # Needed to enable generic fallbacks in DFTK\n", 82 | "using DoubleFloats # Defines Double64\n", 83 | "\n", 84 | "# Your solution here\n", 85 | "results[Float64] = zero(Float64)\n", 86 | "results[Double64] = zero(Double64)\n", 87 | "\n", 88 | "println()\n", 89 | "println(\"Float32: $(results[Float32])\")\n", 90 | "println(\"Float64: $(results[Float64])\")\n", 91 | "println(\"Double64: $(results[Double64])\")\n", 92 | "\n", 93 | "println()\n", 94 | "println(\"Errors versus Double64:\")\n", 95 | "println(\"Float32: $(results[Float32] - results[Double64])\")\n", 96 | "println(\"Float64: $(results[Float64] - results[Double64])\")" 97 | ] 98 | }, 99 | { 100 | "cell_type": "markdown", 101 | "id": "iraqi-measurement", 102 | "metadata": {}, 103 | "source": [ 104 | "## Using IntervalArithmetic to get a solid answer\n", 105 | "\n", 106 | "Next we want to use the [`IntervalArithmetic`](https://github.com/JuliaIntervals/IntervalArithmetic.jl) package to rigorously track the error of the `Float32` computation.\n", 107 | "\n", 108 | "The idea of interval arithmetic is to represent a number by two floats in form of an interval $[a, b]$. This interval is constructed in a way that the exact number is always inside the interval. Moreover this representation is tracked through the full flow of the program. I.e. all operations (addition, multiplication, more involved calls) are performed on both numbers $a$ and $b$ simultanously, but making sure that operations on $a$ always round down and those on $b$ always round up.\n", 109 | "The result is thus again obtained as an interval,\n", 110 | "which is moreover guaranteed to bracket the exact answer. As a result: The tighter the interval, the smaller the floating-point error.\n", 111 | "\n", 112 | "To apply this to `DFTK` we first do the `Float32` computation as normal:" 113 | ] 114 | }, 115 | { 116 | "cell_type": "code", 117 | "execution_count": null, 118 | "id": "confident-score", 119 | "metadata": {}, 120 | "outputs": [], 121 | "source": [ 122 | "using DFTK\n", 123 | "\n", 124 | "# Silicon lattice\n", 125 | "a = 10.26\n", 126 | "lattice = a / 2 .* [[0 1 1.]; [1 0 1.]; [1 1 0.]]\n", 127 | "Si = ElementPsp(:Si, psp=load_psp(\"hgh/lda/Si-q4\"))\n", 128 | "atoms = [Si => [ones(3)/8, -ones(3)/8]]\n", 129 | "\n", 130 | "model = model_DFT(Array{Float32}(lattice), atoms, [:lda_x, :lda_c_vwn], symmetries=false)\n", 131 | "basis = PlaneWaveBasis(model; Ecut=7, kgrid=[1, 1, 1], fft_size=(16, 16, 16))\n", 132 | "scfres = self_consistent_field(basis, tol=1e-16, maxiter=40);" 133 | ] 134 | }, 135 | { 136 | "cell_type": "markdown", 137 | "id": "generic-alliance", 138 | "metadata": {}, 139 | "source": [ 140 | "Next we check how far the resulting `scfres` is from being a fixed point.\n", 141 | "Since iterative algorithms (e.g. diagonalisation) in interval arithmetic are tricky,\n", 142 | "we will ensure $\\rho = F(V(\\rho))$ by checking\n", 143 | "$$ H[\\rho] \\psi_i = \\varepsilon_i \\psi_i \\qquad \\text{for $\\rho = \\sum_i |\\psi_i|^2$},$$\n", 144 | "i.e. that the orbitals used for building a $\\rho$ and from this the Hamiltonian $H[\\rho]$\n", 145 | "still diagonalise $H[\\rho]$.\n", 146 | "If this is the case this implies that a subsequent diagonalisation of the $H[\\rho]$\n", 147 | "can only get me the same $\\rho$ back.\n", 148 | "\n", 149 | "The floating-point error in this computation of this check we will fully track using `IntervalArithmetic`:" 150 | ] 151 | }, 152 | { 153 | "cell_type": "code", 154 | "execution_count": null, 155 | "id": "interpreted-corner", 156 | "metadata": {}, 157 | "outputs": [], 158 | "source": [ 159 | "using GenericLinearAlgebra\n", 160 | "using IntervalArithmetic\n", 161 | "\n", 162 | "# TODO Missing in IntervalArithmetic for Float32:\n", 163 | "# Interval ^ Interval not defined\n", 164 | "# Fixing PR: https://github.com/JuliaIntervals/IntervalArithmetic.jl/pull/482\n", 165 | "import Base: ^\n", 166 | "^(a::Interval{Float32}, x::Interval) = IntervalArithmetic.atomic(Interval{Float32}, IntervalArithmetic.bigequiv(a)^x)\n", 167 | "# end \n", 168 | "\n", 169 | "# Get interval equivalents of key quantities\n", 170 | "intModel = model_DFT(Array{Interval{Float32}}(lattice), atoms, [:lda_x, :lda_c_vwn], symmetries=false)\n", 171 | "intBasis = PlaneWaveBasis(intModel; Ecut=7, kgrid=[1, 1, 1], fft_size=(16, 16, 16))\n", 172 | "intOccupation = [Interval.(occk) for occk in scfres.occupation]\n", 173 | "intEigvals = [Interval.(λk) for λk in scfres.eigenvalues]\n", 174 | "intEigvecs = [Interval.(ψk) for ψk in scfres.ψ]\n", 175 | "\n", 176 | "# Form density in interval arithmetic (i.e. evaluate F)\n", 177 | "intρ = DFTK.compute_density(intBasis, intEigvecs, intOccupation)\n", 178 | "@show maximum(radius, intρ)\n", 179 | "\n", 180 | "# Compute energy and Hamiltionian in interval arithmetic using this density (i.e. evaluate V)\n", 181 | "intEne, intHam = energy_hamiltonian(intBasis, intEigvecs, intOccupation;\n", 182 | " ρ=intρ, eigenvalues=intEigvals,\n", 183 | " εF=Interval(scfres.εF))\n", 184 | "@show radius(intEne.total)\n", 185 | "\n", 186 | "# Check the obtained eigenpairs are eigenpairs of this Hamiltonian\n", 187 | "# (i.e. check we are at a fixed point)\n", 188 | "residual_norm = similar(intEigvals)\n", 189 | "for ik in 1:length(intBasis.kpoints)\n", 190 | " # Form Ritz values via Rayleigh quotient in interval arithmetic\n", 191 | " Λks = intEigvecs[ik]' * (intHam.blocks[ik] * intEigvecs[ik])\n", 192 | " residual_norm[ik] = norm.(eachcol(Λks - Diagonal(intEigvals[ik])))\n", 193 | "end\n", 194 | "\n", 195 | "n_converged = length(intEigvals[1]) - 3 # SCF contains 3 bands, which are not converged.\n", 196 | "@show maximum(maximum(mid, knorm[1:n_converged]) for knorm in residual_norm)\n", 197 | "@show maximum(maximum(radius, knorm[1:n_converged]) for knorm in residual_norm)\n", 198 | "nothing" 199 | ] 200 | }, 201 | { 202 | "cell_type": "markdown", 203 | "id": "fuzzy-database", 204 | "metadata": {}, 205 | "source": [ 206 | "Clearly this calculation looses quite a bit of precision ...\n", 207 | "Unfortunately IntervalArithmetic only guarantees that one or not even a single digit of the energy\n", 208 | "can be trusted (depends a bit on the way the iteration progresses).\n", 209 | "Moreover it is not at all guaranteed that calculation has even converged!\n", 210 | "\n", 211 | "There are two things one should notice with respect to this result:\n", 212 | " - Interval arithmetic in general overestimates the floating-point error. In our experiments we saw that about 3-4 digits of the energy agree with the higher-precision data types, which is in fact more the order one would expect from practial calculations at single-precision level.\n", 213 | " - Nevertheless interval arithmetic is a great tool to identify places where precision is potentially lost. For example in this case one can already see that the density computation looses about 3-4 signifficant digits. If we improve upon this part of the code (e.g. compute the density in `Float64`), then we still have a reasonable number of trustworthy digits in the energy (about 3-4).\n", 214 | "\n", 215 | "\n", 216 | "#### Takeaway\n", 217 | "- Trustworthy DFT calculations in pure `Float32` are tricky.\n", 218 | "- IntervalArithmetic allows to identify routines where much precision is lost.\n", 219 | "- If in doubt DFTK allows you to check your DFT calculation in higher precision (e.g. `Double64`) ... but of course that comes at a cost." 220 | ] 221 | } 222 | ], 223 | "metadata": { 224 | "kernelspec": { 225 | "display_name": "Julia 1.6.1", 226 | "language": "julia", 227 | "name": "julia-1.6" 228 | }, 229 | "language_info": { 230 | "file_extension": ".jl", 231 | "mimetype": "application/julia", 232 | "name": "julia", 233 | "version": "1.6.1" 234 | } 235 | }, 236 | "nbformat": 4, 237 | "nbformat_minor": 5 238 | } 239 | -------------------------------------------------------------------------------- /5_Analysing_SCF_convergence.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "sought-vector", 6 | "metadata": {}, 7 | "source": [ 8 | "# Analysing SCF convergence\n", 9 | "\n", 10 | "In the previous notebook we saw that using the `KerkerMixing` as a preconditioner $P^{-1}$ to the SCF problem\n", 11 | "greatly improved the convergence of the SCF for aluminium. In this notebook we will use some numerical tools to understand what is going on.\n", 12 | "\n", 13 | "The standard damped, preconditioned fixed-point iterations are written as\n", 14 | "$$ \\rho_{n+1} = \\rho_{n} + \\alpha P^{-1} [D(V(\\rho_n)) - \\rho_n]. $$\n", 15 | "\n", 16 | "\n", 17 | "Near the fixed point $\\rho_\\ast = D(V(\\rho_\\ast))$ the error $e_n = \\rho_n - \\rho_\\ast$ is small and we can expand to first order:\n", 18 | "$$ \\begin{align*}\n", 19 | "D(V(\\rho_\\ast + e_n)) &\\simeq D\\left[V(\\rho_\\ast) + V'|_{\\rho_\\ast} e_n\\right] \\\\\n", 20 | "&\\simeq D(V(\\rho_\\ast)) + D'|_{V(\\rho_\\ast)} V'|_{\\rho_\\ast} e_n\\\\\n", 21 | "&= \\rho_\\ast + D'|_{V(\\rho_\\ast)} V'|_{\\rho_\\ast} e_n\n", 22 | "\\end{align*}$$\n", 23 | "\n", 24 | "The derivatives $D'$ and $V'$ are again important quantities and are given special symbols:\n", 25 | "- Hartree-exchange-correlation **kernel** $K_\\text{Hxc} = V'$\n", 26 | "- Independent-particle **susceptibility** $\\chi_0 = D'$\n", 27 | "\n", 28 | "where for simplicity it has been dropped that these quantities are evaluated at the fixed-point,\n", 29 | " i.e. at $\\rho_\\ast$ and $V(\\rho_\\ast)$, respectively." 30 | ] 31 | }, 32 | { 33 | "cell_type": "markdown", 34 | "id": "secondary-stability", 35 | "metadata": {}, 36 | "source": [ 37 | "The above expansion allows to relate the **error between SCF iterations** (near the fixed point):\n", 38 | "$$ \\begin{align*}\n", 39 | "e_{n+1} = \\rho_{n+1} - \\rho_\\ast \n", 40 | "&\\simeq \\rho_{n} - \\rho_\\ast + \\alpha P^{-1} [\\rho_\\ast + \\chi_0 K_\\text{Hxc} e_n - \\rho_n] \\\\\n", 41 | "&= e_n - \\alpha P^{-1} [1 - \\chi_0 K_\\text{Hxc}] e_n\n", 42 | "\\end{align*}$$\n", 43 | "\n", 44 | "Introducing the **dielectric matrix** adjoint\n", 45 | "$$ \\varepsilon^\\dagger = [1 - \\chi_0 K_\\text{Hxc}] $$\n", 46 | "leads to the final relationship\n", 47 | "$$ e_{n+1} \\simeq [1 - \\alpha P^{-1} \\varepsilon^\\dagger] e_n = [1 - \\alpha P^{-1} \\varepsilon^\\dagger]^n e_0$$\n", 48 | "with $e_0$ being the initial error." 49 | ] 50 | }, 51 | { 52 | "cell_type": "markdown", 53 | "id": "earlier-expression", 54 | "metadata": {}, 55 | "source": [ 56 | "In other words:\n", 57 | "$$\\text{SCF converges} \\qquad \\Leftrightarrow \\qquad \\text{eigenvalues of $1 - \\alpha P^{-1} \\varepsilon^\\dagger$ are between $-1$ and $1$}$$\n", 58 | "This implies that the **convergence** properties of an SCF\n", 59 | "are related to $\\varepsilon$, the dielectric operator,\n", 60 | "which **depends on** the **dielectric properties** of the system under study." 61 | ] 62 | }, 63 | { 64 | "cell_type": "markdown", 65 | "id": "biblical-waterproof", 66 | "metadata": {}, 67 | "source": [ 68 | "## Making an SCF converge\n", 69 | "\n", 70 | "It turns out that for the largest chunk of cases the eigenvalues of $\\varepsilon^\\dagger$ are positive. To make the SCF converge one can therefore:\n", 71 | "- Choose $\\alpha$ small enough. Even for $P = I$ this always works, but convergence can be painfully slow.\n", 72 | "- Find a good $P^{-1} \\simeq (\\varepsilon^\\dagger)^{-1}$. Then the eigenvalues of $(P^{-1} \\varepsilon^\\dagger)$ are close to 1, $\\alpha \\simeq 1$ is a good choice and the SCF converges in few steps. Hooray!\n", 73 | "- The optimal $\\alpha$ and the optimal rate of convergence are related to the condition number\n", 74 | " $$ \\kappa = \\frac{\\lambda_\\text{max}}{\\lambda_\\text{min}}$$\n", 75 | " of the dielectric matrix. The smaller the condition number, the better the convergence.\n", 76 | "\n", 77 | "**Note:** If the preconditoner is very bad, the eigenvalues of $(P^{-1} \\varepsilon^\\dagger)$ might even be worse than $\\varepsilon^\\dagger$, such that convergence is actually hampered.\n", 78 | "\n", 79 | "We will now investigate the eigenvalues of $(P^{-1} \\varepsilon^\\dagger)$ for a few examples." 80 | ] 81 | }, 82 | { 83 | "cell_type": "markdown", 84 | "id": "institutional-procedure", 85 | "metadata": {}, 86 | "source": [ 87 | "## Aluminium\n", 88 | "\n", 89 | "We start by taking a look at a slightly cruder (thus computationally cheaper) version of our aluminium setup from before: " 90 | ] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "execution_count": null, 95 | "id": "blank-architect", 96 | "metadata": {}, 97 | "outputs": [], 98 | "source": [ 99 | "using DFTK\n", 100 | "using LinearAlgebra\n", 101 | "\n", 102 | "function aluminium_setup(repeat=1; Ecut=7.0, kgrid=[1, 1, 1])\n", 103 | " a = 7.65339\n", 104 | " lattice = diagm(fill(a, 3))\n", 105 | " Al = ElementPsp(:Al, psp=load_psp(\"hgh/lda/al-q3\"))\n", 106 | " atoms = [Al => [[0.0, 0.0, 0.0], [0.0, 0.5, 0.5], [0.5, 0.0, 0.5], [0.5, 0.5, 0.0]]]\n", 107 | "\n", 108 | " # Make supercell in pymatgen\n", 109 | " mg_struct = pymatgen_structure(lattice, atoms)\n", 110 | " mg_struct.make_supercell([1, 1, repeat])\n", 111 | " lattice = load_lattice(mg_struct)\n", 112 | " atoms = [Al => [s.frac_coords for s in mg_struct.sites]];\n", 113 | "\n", 114 | " # Construct the model\n", 115 | " model = model_LDA(lattice, atoms, temperature=1e-3, symmetries=false)\n", 116 | " PlaneWaveBasis(model; Ecut, kgrid)\n", 117 | "end" 118 | ] 119 | }, 120 | { 121 | "cell_type": "markdown", 122 | "id": "faced-criminal", 123 | "metadata": {}, 124 | "source": [ 125 | "We already know that for moderate `repeat`s the convergence without mixing / preconditioner is slow:" 126 | ] 127 | }, 128 | { 129 | "cell_type": "code", 130 | "execution_count": null, 131 | "id": "comic-nursery", 132 | "metadata": {}, 133 | "outputs": [], 134 | "source": [ 135 | "scfres = self_consistent_field(aluminium_setup(3); tol=1e-12);" 136 | ] 137 | }, 138 | { 139 | "cell_type": "markdown", 140 | "id": "worst-strategy", 141 | "metadata": {}, 142 | "source": [ 143 | "while when using the Kerker preconditioner it is much faster:" 144 | ] 145 | }, 146 | { 147 | "cell_type": "code", 148 | "execution_count": null, 149 | "id": "furnished-impossible", 150 | "metadata": {}, 151 | "outputs": [], 152 | "source": [ 153 | "scfres = self_consistent_field(aluminium_setup(3); tol=1e-12, mixing=KerkerMixing());" 154 | ] 155 | }, 156 | { 157 | "cell_type": "markdown", 158 | "id": "funky-claim", 159 | "metadata": {}, 160 | "source": [ 161 | "Given an `scfres` one easily constructs functions representing $\\varepsilon^\\dagger$ and $P^{-1}$ with DFTK:" 162 | ] 163 | }, 164 | { 165 | "cell_type": "code", 166 | "execution_count": null, 167 | "id": "upper-egypt", 168 | "metadata": {}, 169 | "outputs": [], 170 | "source": [ 171 | "function construct_Pinv_epsilon(scfres)\n", 172 | " basis = scfres.basis\n", 173 | " \n", 174 | " Pinv_Kerker(δρ) = DFTK.mix_density(KerkerMixing(), basis, δρ)\n", 175 | "\n", 176 | " function epsilon(δρ) # Apply ε† = 1 - χ0 Khxc\n", 177 | " δV = apply_kernel(basis, δρ; ρ=scfres.ρ)\n", 178 | " χ0δV = apply_χ0(scfres.ham, scfres.ψ, scfres.εF, scfres.eigenvalues, δV)\n", 179 | " δρ - χ0δV \n", 180 | " end \n", 181 | " \n", 182 | " epsilon, Pinv_Kerker\n", 183 | "end" 184 | ] 185 | }, 186 | { 187 | "cell_type": "markdown", 188 | "id": "suspended-george", 189 | "metadata": {}, 190 | "source": [ 191 | "Based on these functions we can find the largest eigenvalue of $\\varepsilon^\\dagger$ for this aluminium case using `KrylovKit`" 192 | ] 193 | }, 194 | { 195 | "cell_type": "code", 196 | "execution_count": null, 197 | "id": "hawaiian-watershed", 198 | "metadata": {}, 199 | "outputs": [], 200 | "source": [ 201 | "using KrylovKit\n", 202 | "\n", 203 | "scfres = self_consistent_field(aluminium_setup(3); tol=1e-12, mixing=KerkerMixing());\n", 204 | "epsilon, Pinv_Kerker = construct_Pinv_epsilon(scfres)\n", 205 | "\n", 206 | "λ_large, X_large, info = eigsolve(epsilon, randn(size(scfres.ρ)), 4, :LM;\n", 207 | " tol=1e-4, eager=true, verbosity=2)\n", 208 | "@assert info.converged ≥ 4\n", 209 | "λ_max = maximum(real.(λ_large))\n", 210 | "\n", 211 | "println(\"Largest eigenvalue: $(λ_max)\")" 212 | ] 213 | }, 214 | { 215 | "cell_type": "markdown", 216 | "id": "extraordinary-action", 217 | "metadata": {}, 218 | "source": [ 219 | "The smallest eigenvalue can also be determined using KrylovKit. Getting this to work reliably is a little more tricky, however. I will only show a simple setup, which has the disadvantage of being pretty slow. " 220 | ] 221 | }, 222 | { 223 | "cell_type": "code", 224 | "execution_count": null, 225 | "id": "sonic-pledge", 226 | "metadata": {}, 227 | "outputs": [], 228 | "source": [ 229 | "λ_small, X_small, info = eigsolve(epsilon, randn(size(scfres.ρ)), 2, EigSorter(abs, rev=false);\n", 230 | " tol=1e-3, eager=true, verbosity=2)\n", 231 | "@assert info.converged ≥ 2\n", 232 | "λ_min = minimum(real.(λ_small))\n", 233 | "\n", 234 | "println(\"Smallest eigenvalue: $(λ_min)\")" 235 | ] 236 | }, 237 | { 238 | "cell_type": "code", 239 | "execution_count": null, 240 | "id": "literary-chocolate", 241 | "metadata": {}, 242 | "outputs": [], 243 | "source": [ 244 | "# If running the above takes too long for you just use this estimate:\n", 245 | "# λ_min = 0.952" 246 | ] 247 | }, 248 | { 249 | "cell_type": "markdown", 250 | "id": "engaged-israel", 251 | "metadata": {}, 252 | "source": [ 253 | "To summarise our results:" 254 | ] 255 | }, 256 | { 257 | "cell_type": "code", 258 | "execution_count": null, 259 | "id": "applied-collector", 260 | "metadata": {}, 261 | "outputs": [], 262 | "source": [ 263 | "@show λ_min\n", 264 | "@show λ_max\n", 265 | "cond = λ_max / λ_min\n", 266 | "@show cond" 267 | ] 268 | }, 269 | { 270 | "cell_type": "markdown", 271 | "id": "offensive-architecture", 272 | "metadata": {}, 273 | "source": [ 274 | "The condition number of $\\varepsilon^\\dagger$ for this system is about $30$.\n", 275 | "This does not sound large compared to the condition numbers you might know\n", 276 | "from linear systems.\n", 277 | "\n", 278 | "However, this is sufficient to cause a notable slowdown, which would be even more\n", 279 | "pronounced if we did not use Anderson, since we also would need to drastically\n", 280 | "reduce the damping (try it!)." 281 | ] 282 | }, 283 | { 284 | "cell_type": "markdown", 285 | "id": "colored-processing", 286 | "metadata": {}, 287 | "source": [ 288 | "Having computed the eigenvalues of the dielectric matrix\n", 289 | "we can now also look at the eigenmodes, which are responsible for the bad convergence behaviour.\n", 290 | "For example we plot the larges Aluminium mode:" 291 | ] 292 | }, 293 | { 294 | "cell_type": "code", 295 | "execution_count": null, 296 | "id": "incident-disney", 297 | "metadata": {}, 298 | "outputs": [], 299 | "source": [ 300 | "using Plots\n", 301 | "using Statistics\n", 302 | "\n", 303 | "function plot_mode(mode)\n", 304 | " # Average along x axis\n", 305 | " mode_yz = mean(real.(mode), dims=1)[1, :, :, 1]\n", 306 | " heatmap(mode_yz, c=:RdBu_11, aspect_ratio=1, grid=false,\n", 307 | " legend=false, clim=(-0.006, 0.006))\n", 308 | "end\n", 309 | "\n", 310 | "plot_mode(X_large[1])" 311 | ] 312 | }, 313 | { 314 | "cell_type": "markdown", 315 | "id": "radio-contrary", 316 | "metadata": {}, 317 | "source": [ 318 | "This mode essentially lumps electron density between the left end and the right hand of the cell.\n", 319 | "\n", 320 | "For this reason the usual term to refer to the origin of the degrading SCF convergence behaviour\n", 321 | "in large metallic systems is **charge sloshing**." 322 | ] 323 | }, 324 | { 325 | "cell_type": "markdown", 326 | "id": "exclusive-exclusive", 327 | "metadata": {}, 328 | "source": [ 329 | "**Exercise 1:** Let's see what the Kerker preconditioner can do when it comes to charge sloshing.\n", 330 | "\n", 331 | "Find the largest eigenvalue for the Aluminium SCF in case the Kerker preconditioner is used.\n", 332 | "*Hint:* You can construct the operator $P^{-1} \\varepsilon^\\dagger$ by simply chaining the functions (`Pinv_Kerker ∘ epsilon`). Assuming that the smallest eigenvalue is about $0.8$, what is the condition number now? Feel free to take a look at the shape of the largest eigenvalue. What do you notice?\n", 333 | "\n", 334 | "If you want, repeat the exercise for `repeat = 6`. You can assume the smallest eigenvalue is still about $0.95$ or $0.8$, respectively. How does the condition number change if you double the system size?\n", 335 | "\n", 336 | "Keeping in mind that the condition number is linked to the convergence speed: Which is setup should be employed to keep the number of required SCF iterations independent of system size." 337 | ] 338 | }, 339 | { 340 | "cell_type": "code", 341 | "execution_count": null, 342 | "id": "palestinian-energy", 343 | "metadata": {}, 344 | "outputs": [], 345 | "source": [ 346 | "# Your solution here ..." 347 | ] 348 | }, 349 | { 350 | "cell_type": "markdown", 351 | "id": "regulation-migration", 352 | "metadata": {}, 353 | "source": [ 354 | "#### Takeaways:\n", 355 | "- For metals the conditioning of the dielectric matrix increases steaply with system size.\n", 356 | "- The Kerker preconditioner tames this and makes SCFs on large metallic systems feasible by keeping the condition number of order 1." 357 | ] 358 | }, 359 | { 360 | "cell_type": "markdown", 361 | "id": "statistical-tooth", 362 | "metadata": {}, 363 | "source": [ 364 | "## Helium chain\n", 365 | "\n", 366 | "To prove the point that a single preconditioner (like `KerkerMixing`) is not good for all systems,\n", 367 | "we now consider an (insulating) chain of Helium atoms:" 368 | ] 369 | }, 370 | { 371 | "cell_type": "code", 372 | "execution_count": null, 373 | "id": "offshore-citizen", 374 | "metadata": {}, 375 | "outputs": [], 376 | "source": [ 377 | "using DFTK\n", 378 | "using LinearAlgebra\n", 379 | "\n", 380 | "function helium_setup(repeat=40; Ecut=7.0, kgrid=[1, 1, 1])\n", 381 | " a = 5\n", 382 | " lattice = diagm(fill(a, 3))\n", 383 | " He = ElementPsp(:He, psp=load_psp(\"hgh/lda/he-q2\"))\n", 384 | " atoms = [He => [[0.0, 0.0, 0.0]]]\n", 385 | "\n", 386 | " # Make supercell in pymatgen\n", 387 | " mg_struct = pymatgen_structure(lattice, atoms)\n", 388 | " mg_struct.make_supercell([1, 1, repeat])\n", 389 | " lattice = load_lattice(mg_struct)\n", 390 | " atoms = [He => [s.frac_coords for s in mg_struct.sites]];\n", 391 | "\n", 392 | " # Construct the model\n", 393 | " model = model_LDA(lattice, atoms, temperature=1e-3, symmetries=false)\n", 394 | " PlaneWaveBasis(model; Ecut, kgrid)\n", 395 | "end" 396 | ] 397 | }, 398 | { 399 | "cell_type": "markdown", 400 | "id": "signal-minister", 401 | "metadata": {}, 402 | "source": [ 403 | "From running the SCFs using `KerkerMixing` seems like a bad idea:" 404 | ] 405 | }, 406 | { 407 | "cell_type": "code", 408 | "execution_count": null, 409 | "id": "hollywood-continuity", 410 | "metadata": {}, 411 | "outputs": [], 412 | "source": [ 413 | "scfres = self_consistent_field(helium_setup(30); tol=1e-12, mixing=KerkerMixing());" 414 | ] 415 | }, 416 | { 417 | "cell_type": "code", 418 | "execution_count": null, 419 | "id": "leading-broadcasting", 420 | "metadata": {}, 421 | "outputs": [], 422 | "source": [ 423 | "scfres = self_consistent_field(helium_setup(30); tol=1e-12);" 424 | ] 425 | }, 426 | { 427 | "cell_type": "markdown", 428 | "id": "straight-attempt", 429 | "metadata": {}, 430 | "source": [ 431 | "**Exercise 2:** This can be confirmed by investigating the eigenvalues. Here are some good settings for you to play on this problem. Find the condition numbers with and without `KerkerMixing` and explain the observations in the SCFs on the Helium system we just ran." 432 | ] 433 | }, 434 | { 435 | "cell_type": "code", 436 | "execution_count": null, 437 | "id": "forty-argentina", 438 | "metadata": {}, 439 | "outputs": [], 440 | "source": [ 441 | "using KrylovKit\n", 442 | "\n", 443 | "scfres = self_consistent_field(helium_setup(30); tol=1e-12);\n", 444 | "epsilon, Pinv_Kerker = construct_Pinv_epsilon(scfres)\n", 445 | "\n", 446 | "operator = epsilon\n", 447 | "\n", 448 | "λ_large, X_large, info = eigsolve(operator, randn(size(scfres.ρ)), 2, :LM;\n", 449 | " tol=1e-3, eager=true, verbosity=2)\n", 450 | "@assert info.converged ≥ 2\n", 451 | "λ_max = maximum(real.(λ_large))\n", 452 | " \n", 453 | "λ_small, X_small, info = eigsolve(operator, randn(size(scfres.ρ)), 2, EigSorter(abs, rev=false);\n", 454 | " tol=1e-3, eager=true, verbosity=2)\n", 455 | "@assert info.converged ≥ 2\n", 456 | "λ_min = minimum(real.(λ_small))\n", 457 | "\n", 458 | "println(\"Smallest eigenvalue: $(λ_min)\")\n", 459 | "println(\"Largest eigenvalue: $(λ_max)\")" 460 | ] 461 | }, 462 | { 463 | "cell_type": "code", 464 | "execution_count": null, 465 | "id": "maritime-factory", 466 | "metadata": {}, 467 | "outputs": [], 468 | "source": [ 469 | "@show λ_min\n", 470 | "@show λ_max\n", 471 | "cond = λ_max / λ_min\n", 472 | "@show cond" 473 | ] 474 | }, 475 | { 476 | "cell_type": "markdown", 477 | "id": "formal-alexander", 478 | "metadata": {}, 479 | "source": [ 480 | "#### Takeaways:\n", 481 | "- For insulating systems the best approach is to not use any mixing.\n", 482 | "- **The ideal mixing** strongly depends on the dielectric properties of system which is studied (metal versus insulator versus semiconductor).\n", 483 | "- A more detailed discussion as well as some ideas how to deal with inhomogeneous systems (where both metals and insulators coexist) is given in [a recently published paper](https://doi.org/10.1088/1361-648X/abcbdb)." 484 | ] 485 | } 486 | ], 487 | "metadata": { 488 | "kernelspec": { 489 | "display_name": "Julia 1.6.1", 490 | "language": "julia", 491 | "name": "julia-1.6" 492 | }, 493 | "language_info": { 494 | "file_extension": ".jl", 495 | "mimetype": "application/julia", 496 | "name": "julia", 497 | "version": "1.6.1" 498 | } 499 | }, 500 | "nbformat": 4, 501 | "nbformat_minor": 5 502 | } 503 | -------------------------------------------------------------------------------- /2_Periodic_problems_and_plane_waves.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "latest-correspondence", 6 | "metadata": {}, 7 | "source": [ 8 | "# Periodic problems and plane-wave discretisations\n", 9 | "\n", 10 | "Before digging into big real-world problems, i.e. solving density-functional theory in 3D, we will first take a step back and briefly look at some specifics of periodic problems and plane-wave discretisations.\n", 11 | "\n", 12 | "To make things simple, we first stay in 1D where things are nice and gentle ..." 13 | ] 14 | }, 15 | { 16 | "cell_type": "markdown", 17 | "id": "awful-utilization", 18 | "metadata": {}, 19 | "source": [ 20 | "## Lattices\n", 21 | "\n", 22 | "### The Bloch transform\n", 23 | "\n", 24 | "- Consider a 1D periodic **lattice** with lattice constant $a$:\n", 25 | " ```\n", 26 | " |-------|-------|-------|\n", 27 | " a a a\n", 28 | " ```\n", 29 | "- We take its **unit cell** as the interval $A = [-a/2, a/2)$\n", 30 | "- Consider free-electron **Hamiltonian** (== a differential operator)\n", 31 | " $$ H = -\\frac12 \\Delta $$\n", 32 | " and we are interested in seeking its eigenfunctions $ H \\psi_i = \\varepsilon_i \\psi_i $.\n", 33 | " \n", 34 | " \n", 35 | "- The free-electron model is a model where electrons can freely move and there motion\n", 36 | " in only governed by their own kinetic energy.\n", 37 | " The Hamiltonians for solving density-functional theory (our ultimte goal)\n", 38 | " is more involved, but many ideas we will discuss here carry forward." 39 | ] 40 | }, 41 | { 42 | "cell_type": "markdown", 43 | "id": "gross-praise", 44 | "metadata": {}, 45 | "source": [ 46 | "- Perodicity of the problem implies that the Hamiltonian commutes with lattice translations $T_{n a}$\n", 47 | " $$ T_{n a} H = H T_{n a} \\qquad \\forall n \\in \\mathbb{Z}$$\n", 48 | " \n", 49 | " \n", 50 | "- In this case **Bloch's theorem** says the solution has the form $ \\psi = e^{i k \\cdot x} u_k(x) $\n", 51 | " where $u_k(x)$ has the perodicity of the lattice\n", 52 | " $$ u_k(x + na) = u_k(x) \\qquad \\forall n \\in \\mathbb{Z}$$\n", 53 | " and is indexed in a real number $k$ (more on this in a sec).\n", 54 | " \n", 55 | " \n", 56 | "- Apply $-\\Delta = -\\frac{d^2}{dx^2}$ to this ansatz:\n", 57 | " $$\n", 58 | " -\\Delta \\left(e^{i k \\cdot x} u_k(x)\\right) = (k^2 - 2ik \\nabla - \\Delta) ) e^{i k \\cdot x} u_k(x) = (-i \\nabla + k)^2 e^{i k \\cdot x} u_k(x)\n", 59 | " $$\n", 60 | " \n", 61 | " \n", 62 | "- With this in mind it is natural to define a family\n", 63 | " $$ H_k = \\frac12 (-i \\nabla + k)^2 $$\n", 64 | " of $k$-specific blocks of $H$." 65 | ] 66 | }, 67 | { 68 | "cell_type": "markdown", 69 | "id": "moral-sterling", 70 | "metadata": {}, 71 | "source": [ 72 | "- In fact one can find a unitary transformation $U$ (the **Bloch transform**) (represented as a familiy of unitary operators $U_k$) such that for any $k$:\n", 73 | "$$ (U_k H U_k^{-1}) = H_k. $$\n", 74 | "\n", 75 | "\n", 76 | "- This is a remarkable result, because it tells us that for seeking all eigenpairs of $H$ we actually only need to seek all eigenpairs of $H_k$ and concatenate them." 77 | ] 78 | }, 79 | { 80 | "cell_type": "markdown", 81 | "id": "adaptive-steam", 82 | "metadata": {}, 83 | "source": [ 84 | "### The Brillouin zone\n", 85 | "\n", 86 | "The big mystery in the discussion so far is the parameter $k$ of the operator families.\n", 87 | "\n", 88 | "- In principle $k$ can take *any* real value. It turns out, however, that some of these values will give rise\n", 89 | " to operators related by unitary transformations\n", 90 | "- Since such operators have the same eigenspectrum, only one version needs to be considered.\n", 91 | "- The smallest subset from which $k$ is chosen is the **Brillouin zone** (BZ).\n", 92 | "\n", 93 | "\n", 94 | "- The BZ is the unit cell of the **reciprocal lattice**, which may be constructed from the **real-space lattice**\n", 95 | " by a Fourier transform.\n", 96 | "- In our simple 1D case the reciprocal lattice is just\n", 97 | " ```\n", 98 | " |--------|--------|--------|\n", 99 | " 2π/a 2π/a 2π/a\n", 100 | " ```\n", 101 | " i.e. like the real-space lattice, but just with a different lattice constant $b = 2\\pi / a$.\n", 102 | "- The BZ in this example is $B = [-π/a, π/a)$" 103 | ] 104 | }, 105 | { 106 | "cell_type": "markdown", 107 | "id": "fossil-girlfriend", 108 | "metadata": {}, 109 | "source": [ 110 | "### Discretising the problem\n", 111 | "\n", 112 | "- To solve the problem, we just need to find the eigenspectrum of all $H_k$ with $k \\in B$\n", 113 | "\n", 114 | "\n", 115 | "- **Problem 1:** $B$ is an overcountable set $\\Rightarrow$ **$k$-point sampling**: Instead of considering the full Brillouin zone we just consider a regular grid of values for $k$, the so-called **$k$-points**\n", 116 | "\n", 117 | "\n", 118 | "- **Problem 2:** Each $H_k$ is an operator over an infinite-dimensional domain $\\Rightarrow$ Project the problem into a finite basis diagonalise the resulting matrix (Ritz-Galerkin ansatz)." 119 | ] 120 | }, 121 | { 122 | "cell_type": "markdown", 123 | "id": "hollow-addiction", 124 | "metadata": {}, 125 | "source": [ 126 | "### Plane-wave basis sets\n", 127 | "\n", 128 | "Multiple basis sets are used in practice. One basis set agreeing particularly well with the nature of periodic problems\n", 129 | "are plane waves. For our 1D example normalised plane waves are defined as the functions\n", 130 | "$$ e_{G}(x) = \\frac{e^{i G x}}{\\sqrt{a}} \\qquad G \\in b\\mathbb{Z} $$\n", 131 | "and typically one forms basis sets from these by specifying a so-called **kinetic energy cutoff** $E_\\text{cut}$:\n", 132 | "$$ \\left\\{ e_{G} \\, \\big| \\, (G + k)^2 \\leq 2E_\\text{cut} \\right\\} $$\n", 133 | "\n", 134 | "Notice that (our) $H_k$ is already diagonal with this basis:\n", 135 | "\\begin{align}\n", 136 | "\\langle e_{G} | H_k e_{G'} \\rangle\n", 137 | "&= \\frac12 \\left\\langle e_{G} \\middle| (-i \\nabla + k)^2 \\, e_{G'} \\right\\rangle \\\\\n", 138 | "&= \\frac12 (G + k)^2 \\left\\langle e_{G} \\middle|e_{G'}\\right\\rangle \\\\\n", 139 | "&= \\frac12 (G + k)^2 \\delta_{GG'}\n", 140 | "\\end{align}" 141 | ] 142 | }, 143 | { 144 | "cell_type": "markdown", 145 | "id": "swedish-sherman", 146 | "metadata": {}, 147 | "source": [ 148 | "## Let's crunch some numbers!\n", 149 | "\n", 150 | "One typical approach to get physical insight into a Hamiltonian $H$ is to plot a so-called **band structure**, that is the eigenvalues of $H_k$ versus $k$. The rough steps to plot a band structure are:\n", 151 | "\n", 152 | "1. Select a set of $k$-points ($k$-point sampling)\n", 153 | "1. Select plane-wave cutoff, thus the basis for discretising $H_k$\n", 154 | "1. Build and diagonalise $H_k$ for each $k$.\n", 155 | "1. Plot eigenvalues versus $k$" 156 | ] 157 | }, 158 | { 159 | "cell_type": "code", 160 | "execution_count": null, 161 | "id": "incorporated-earthquake", 162 | "metadata": {}, 163 | "outputs": [], 164 | "source": [ 165 | "using LinearAlgebra\n", 166 | "using Plots\n", 167 | "\n", 168 | "# Parameters\n", 169 | "a = 100 # Lattice constant\n", 170 | "Ecut = 300 # in Hartree\n", 171 | "kgrid = 50 # Number of points on equally-spaced grid for k\n", 172 | "\n", 173 | "# Derived quantities\n", 174 | "b = 2π / a # Reciprocal lattice\n", 175 | "\n", 176 | "# Step 1: k-Points\n", 177 | "kpoints = b * (collect(1:kgrid) .- ceil(Int, kgrid / 2)) ./ kgrid\n", 178 | "\n", 179 | "# Step 2: Basis for H_k\n", 180 | "# Represented as one array of all valid G*b per kpoint\n", 181 | "Gmax = ceil(Int, sqrt(2Ecut) + b) # Rough upper bound for G\n", 182 | "Gs = [[Gidx*b for Gidx in -Gmax:Gmax if abs2(Gidx*b + k) ≤ 2Ecut]\n", 183 | " for k in kpoints]\n", 184 | "\n", 185 | "# Step 3: Build the discretised Hk. In this case it is diagonal,\n", 186 | "# i.e. its diagonal values (== eigenvalues) are all we need.\n", 187 | "# We directly determine them and sort them ascendingly\n", 188 | "ev_Hk = [sort([abs2(G + k)/2 for G in Gs[ik]])\n", 189 | " for (ik, k) in enumerate(kpoints)]\n", 190 | "\n", 191 | "# Step 4: Plot the bands\n", 192 | "n_bands = 6\n", 193 | "bands = [[ev_Hk[ik][iband] for ik in 1:length(kpoints)]\n", 194 | " for iband in 1:n_bands]\n", 195 | "\n", 196 | "p = plot()\n", 197 | "for iband in 1:n_bands\n", 198 | " plot!(p, kpoints, bands[iband], color=:blue, label=\"\")\n", 199 | "end\n", 200 | "p" 201 | ] 202 | }, 203 | { 204 | "cell_type": "markdown", 205 | "id": "honest-ticket", 206 | "metadata": {}, 207 | "source": [ 208 | "Exactly the same can be achieved using DFTK, albeit in essentially only four lines of code:" 209 | ] 210 | }, 211 | { 212 | "cell_type": "code", 213 | "execution_count": null, 214 | "id": "abroad-probe", 215 | "metadata": {}, 216 | "outputs": [], 217 | "source": [ 218 | "using DFTK\n", 219 | "using Unitful\n", 220 | "using UnitfulAtomic\n", 221 | "using Plots\n", 222 | "using LinearAlgebra\n", 223 | "\n", 224 | "# Build the 1D lattice. DFTK is mostly tailored for 3D problems.\n", 225 | "# Therefore quantities related to the problem space are have a fixed\n", 226 | "# dimension 3. The convention is that for 1D / 2D problems the\n", 227 | "# tailling entries are always zero and ignored in the computation.\n", 228 | "# For the lattice we therefore construct a 3x3 matrix with only one entry.\n", 229 | "lattice = zeros(3, 3)\n", 230 | "lattice[1, 1] = 100.\n", 231 | "\n", 232 | "# Select a model. In this case we choose a free-electron model,\n", 233 | "# which is the same as saying that there is only a Kinetic term\n", 234 | "# (and no potential) in the model. The `n_electrons` is dummy here.\n", 235 | "model = Model(lattice; n_electrons=0, terms=[Kinetic()])\n", 236 | "@show model.n_dim\n", 237 | "\n", 238 | "# Step 2: Define a plane-wave basis using this model and the same cutoff\n", 239 | "# as before. The kpoint grid is given as a regular grid in the BZ.\n", 240 | "# Here we select only one k-Point (1x1x1). The kpoints for calculating and plotting\n", 241 | "# the bands are selected below. (This distinction between k-Points for the basis\n", 242 | "# and the plotting is needed for more complicated models like DFT)\n", 243 | "basis = PlaneWaveBasis(model; Ecut=300, kgrid=(1, 1, 1));\n", 244 | "\n", 245 | "# Steps 1, 3 & 4: K-Point selection, discretisation, diagonalisation\n", 246 | "n_bands = 6\n", 247 | "ρ0 = guess_density(basis) # Just dummy, has no meaning in this model\n", 248 | "p = plot_bandstructure(basis, ρ0, n_bands, kline_density=15, unit=u\"hartree\")" 249 | ] 250 | }, 251 | { 252 | "cell_type": "markdown", 253 | "id": "legislative-warrior", 254 | "metadata": {}, 255 | "source": [ 256 | "## Adding potentials\n", 257 | "\n", 258 | "So far so good. But free electrons are actually a little boring,\n", 259 | "so let's add a potential interacting with the electrons.\n", 260 | "\n", 261 | "- The modified problem we will look at consists of diagonalising\n", 262 | "\n", 263 | "$$ H_k = \\frac12 (-i \\nabla + k)^2 + V $$\n", 264 | "\n", 265 | "for all $k \\in \\text{BZ}$ with a periodic potential $V$ interacting with the electrons.\n", 266 | "\n", 267 | "- A number of \"standard\" potentials are readily implemented in DFTK and\n", 268 | " can be assembled using the `terms` kwarg of the model.\n", 269 | " This allows to seamlessly construct\n", 270 | " \n", 271 | " * density-functial theory models for treating electronic structures\n", 272 | " (see the next notebook)\n", 273 | " * Gross-Pitaevskii models for bosonic systems\n", 274 | " * even some more unusual cases like anyonic models. \n", 275 | " \n", 276 | " \n", 277 | "In this workbook we will go a little more low-level and directly provide\n", 278 | "an analytic potential describing the interaction with the electrons to DFTK.\n", 279 | "\n", 280 | "First we define a custom Gaussian potential as a new \"element\" inside DFTK:" 281 | ] 282 | }, 283 | { 284 | "cell_type": "code", 285 | "execution_count": null, 286 | "id": "noble-primary", 287 | "metadata": {}, 288 | "outputs": [], 289 | "source": [ 290 | "using DFTK\n", 291 | "\n", 292 | "struct ElementGaussian <: DFTK.Element\n", 293 | " α # Prefactor\n", 294 | " L # Extend\n", 295 | "end\n", 296 | "# Dummy (needed for cases modelling actual atoms)\n", 297 | "DFTK.charge_ionic(el::ElementGaussian) = 0\n", 298 | "DFTK.charge_nuclear(el::ElementGaussian) = 0\n", 299 | "\n", 300 | "# Some default values\n", 301 | "ElementGaussian() = ElementGaussian(0.3, 10.0)\n", 302 | "\n", 303 | "# Real-space representation of a Gaussian\n", 304 | "function DFTK.local_potential_real(el::ElementGaussian, r::Real)\n", 305 | " -el.α / (√(2π) * el.L) * exp(- (r / el.L)^2 / 2)\n", 306 | "end\n", 307 | "\n", 308 | "# Fourier-space representation of the Gaussian\n", 309 | "function DFTK.local_potential_fourier(el::ElementGaussian, q::Real)\n", 310 | " # = ∫ -α exp(-(r/L)^2 exp(-ir⋅q) dr\n", 311 | " -el.α * exp(- (q * el.L)^2 / 2)\n", 312 | "end" 313 | ] 314 | }, 315 | { 316 | "cell_type": "markdown", 317 | "id": "extraordinary-mechanism", 318 | "metadata": {}, 319 | "source": [ 320 | "A single potential looks like this:" 321 | ] 322 | }, 323 | { 324 | "cell_type": "code", 325 | "execution_count": null, 326 | "id": "recovered-rendering", 327 | "metadata": {}, 328 | "outputs": [], 329 | "source": [ 330 | "using Plots\n", 331 | "nucleus = ElementGaussian()\n", 332 | "plot(r -> DFTK.local_potential_real(nucleus, norm(r)), xlims=(-50, 50))" 333 | ] 334 | }, 335 | { 336 | "cell_type": "markdown", 337 | "id": "experimental-latino", 338 | "metadata": {}, 339 | "source": [ 340 | "With this element at hand we can easily construct a setting\n", 341 | "where two potentials of this form are located at positions\n", 342 | "$20$ and $80$ inside the lattice $[0, 100]$:" 343 | ] 344 | }, 345 | { 346 | "cell_type": "code", 347 | "execution_count": null, 348 | "id": "victorian-spank", 349 | "metadata": {}, 350 | "outputs": [], 351 | "source": [ 352 | "using LinearAlgebra\n", 353 | "\n", 354 | "# Define the 1D lattice [0, 100]\n", 355 | "lattice = diagm([100., 0, 0])\n", 356 | "\n", 357 | "# Place them at 20 and 80 in *fractional coordinates*,\n", 358 | "# that is 0.2 and 0.8, since the lattice is 100 wide.\n", 359 | "nucleus = ElementGaussian()\n", 360 | "atoms = [nucleus => [[0.2, 0, 0], [0.8, 0, 0]]]\n", 361 | "\n", 362 | "# Assemble the model, discretise and build the Hamiltonian\n", 363 | "model = Model(lattice; atoms=atoms, terms=[Kinetic(), AtomicLocal()])\n", 364 | "basis = PlaneWaveBasis(model; Ecut=300, kgrid=(1, 1, 1));\n", 365 | "ham = Hamiltonian(basis)\n", 366 | "\n", 367 | "# Extract the total potential term of the Hamiltonian and plot it\n", 368 | "potential = DFTK.total_local_potential(ham)[:, 1, 1]\n", 369 | "rvecs = collect(r_vectors_cart(basis))[:, 1, 1] # slice along the x axis\n", 370 | "x = [r[1] for r in rvecs] # only keep the x coordinate\n", 371 | "plot(x, potential, label=\"\", xlabel=\"x\", ylabel=\"V(x)\")" 372 | ] 373 | }, 374 | { 375 | "cell_type": "markdown", 376 | "id": "complimentary-tokyo", 377 | "metadata": {}, 378 | "source": [ 379 | "Notice how DFTK took care of the periodic wrapping of the potential values going from $0$ and $100$.\n", 380 | "\n", 381 | "With this setup, let's look at the bands:" 382 | ] 383 | }, 384 | { 385 | "cell_type": "code", 386 | "execution_count": null, 387 | "id": "scientific-inspection", 388 | "metadata": {}, 389 | "outputs": [], 390 | "source": [ 391 | "using Unitful\n", 392 | "using UnitfulAtomic\n", 393 | "\n", 394 | "n_bands = 6\n", 395 | "ρ0 = zeros(eltype(basis), basis.fft_size..., 1) # Just dummy, has no meaning in this model\n", 396 | "p = plot_bandstructure(basis, ρ0, n_bands, kline_density=15, unit=u\"hartree\")" 397 | ] 398 | }, 399 | { 400 | "cell_type": "markdown", 401 | "id": "liquid-intake", 402 | "metadata": {}, 403 | "source": [ 404 | "The bands are noticably different.\n", 405 | "- The bands no longer overlap, meaning that the spectrum of $H$ is no longer continous but has gaps.\n", 406 | "\n", 407 | "- The two lowest bands are almost flat, which means that they represent\n", 408 | " two tightly bound and localised electrons inside the two Gaussians. \n", 409 | " \n", 410 | "- The higher the bands, the more curved they become. In other words the higher the kinetic energy of the electrons the more delocalised they become and the less they feel the effect of the two Gaussian potentials.\n", 411 | "\n", 412 | "**Exercise:** Try playing with the parameters of the Gaussian potentials by setting\n", 413 | "```julia\n", 414 | "nucleus = ElementGaussian(α, L)\n", 415 | "```\n", 416 | "with different $\\alpha$ and $L$ in the above procedure." 417 | ] 418 | }, 419 | { 420 | "cell_type": "markdown", 421 | "id": "gothic-native", 422 | "metadata": {}, 423 | "source": [ 424 | "## Going to 3D\n", 425 | "\n", 426 | "- Our example: Silicon\n", 427 | "\n", 428 | "| |\n", 429 | "| --------------- |\n", 430 | "| silicon crystal |\n", 431 | "\n", 432 | "- $A$ becomes a matrix, e.g. for silicon (diamond structure)\n", 433 | " $$ A = \\frac{a}{2} \\left( \\begin{array}{ccc} 0&1&1\\\\1&0&1\\\\1&1&0 \\end{array} \\right) \\qquad a = 10.26\\,\\text{bohr}. $$\n", 434 | "- Brillouin zones become more involved:\n", 435 | "\n", 436 | "| |\n", 437 | "| --------------------------------------------------------- |\n", 438 | "| face-centred cubic BZ (applies to silicon) |\n", 439 | " \n", 440 | "- $k$-points are vectors taken from a rectangular 3D grid inside the BZ\n", 441 | "- Plane-wave wave vectors $G$ are vectorial:\n", 442 | " $$ e_G = \\frac{1}{\\sqrt{\\text{det}(A)}} e^{i G\\cdot r} $$\n", 443 | "- Cutoff taken over norm:\n", 444 | " $$ \\{ e_G | \\|G + k\\|^2 \\leq 2E_\\text{cut} \\} $$" 445 | ] 446 | }, 447 | { 448 | "cell_type": "markdown", 449 | "id": "domestic-america", 450 | "metadata": {}, 451 | "source": [ 452 | "- The bandstructure of silicon:\n", 453 | "" 454 | ] 455 | }, 456 | { 457 | "cell_type": "markdown", 458 | "id": "economic-wagon", 459 | "metadata": {}, 460 | "source": [ 461 | "#### Takeaway\n", 462 | "\n", 463 | "- For periodic problems the Bloch transform allows to find the eigenpairs of an operator $k$-Point by $k$-Point\n", 464 | "- The $k$ points are taken in a discrete mesh from the Brillouin zone.\n", 465 | "- A common way to visualise the eigenvalues is as a plot versus $k$, the band structure." 466 | ] 467 | } 468 | ], 469 | "metadata": { 470 | "kernelspec": { 471 | "display_name": "Julia 1.6.1", 472 | "language": "julia", 473 | "name": "julia-1.6" 474 | }, 475 | "language_info": { 476 | "file_extension": ".jl", 477 | "mimetype": "application/julia", 478 | "name": "julia", 479 | "version": "1.6.1" 480 | } 481 | }, 482 | "nbformat": 4, 483 | "nbformat_minor": 5 484 | } 485 | -------------------------------------------------------------------------------- /4_Solving_the_SCF_problem.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "psychological-praise", 6 | "metadata": {}, 7 | "source": [ 8 | "# Solving the SCF problem\n", 9 | "\n", 10 | "For the work in this notebook we will stick with the aluminum setup introduced before with one additional hinge: We will allow to make the problem harder or easier, by forming a supercell.\n", 11 | "\n", 12 | "- Since we are dealing with periodic problems there is no unique definition of the lattice. Clearly any duplication of the lattice along an axis is also a valid lattice.\n", 13 | "- This is exactly what a **supercell** is: An $n$-fold repetition in one of the lattice axes.\n", 14 | "\n", 15 | "The following code achieves this for aluminium:" 16 | ] 17 | }, 18 | { 19 | "cell_type": "code", 20 | "execution_count": null, 21 | "id": "psychological-arrangement", 22 | "metadata": {}, 23 | "outputs": [], 24 | "source": [ 25 | "using DFTK\n", 26 | "using LinearAlgebra\n", 27 | "\n", 28 | "function aluminium_setup(repeat=1; Ecut=13.0, kgrid=[2, 2, 2])\n", 29 | " a = 7.65339\n", 30 | " lattice = diagm(fill(a, 3))\n", 31 | " Al = ElementPsp(:Al, psp=load_psp(\"hgh/lda/al-q3\"))\n", 32 | " atoms = [Al => [[0.0, 0.0, 0.0], [0.0, 0.5, 0.5], [0.5, 0.0, 0.5], [0.5, 0.5, 0.0]]]\n", 33 | "\n", 34 | " # Make supercell in pymatgen:\n", 35 | " # We convert our lattice to the conventions used in pymatgen\n", 36 | " # and then back ...\n", 37 | " mg_struct = pymatgen_structure(lattice, atoms)\n", 38 | " mg_struct.make_supercell([1, 1, repeat])\n", 39 | " lattice = load_lattice(mg_struct)\n", 40 | " atoms = [Al => [s.frac_coords for s in mg_struct.sites]];\n", 41 | "\n", 42 | " # Construct the LDA model and discretise\n", 43 | " model = model_LDA(lattice, atoms, temperature=1e-3)\n", 44 | " PlaneWaveBasis(model; Ecut, kgrid)\n", 45 | "end" 46 | ] 47 | }, 48 | { 49 | "cell_type": "markdown", 50 | "id": "parental-thickness", 51 | "metadata": {}, 52 | "source": [ 53 | "As we will see in this notebook the modelling of a system generally becomes harder if the system becomes larger. \n", 54 | "\n", 55 | "- This sounds like a trival statement as *per se* the cost per SCF step increases\n", 56 | " as the system (and thus $N$) gets larger.\n", 57 | "- But there is more to it:\n", 58 | " If one is not careful also the *number of SCF iterations* increases\n", 59 | " as the system gets larger.\n", 60 | " \n", 61 | " \n", 62 | "- The aim of many tricks I will show in this workbook is to ensure the **number of SCF iterations remains constant** when the system size increases." 63 | ] 64 | }, 65 | { 66 | "cell_type": "markdown", 67 | "id": "latter-session", 68 | "metadata": {}, 69 | "source": [ 70 | "## Gaining insight\n", 71 | "\n", 72 | "In DFTK one can easily patch or extend the SCF procedure\n", 73 | "by replacing parts of the code with custom callback functions.\n", 74 | "\n", 75 | "We will use this in this notebook to construct our own SCF solver,\n", 76 | "but without needing to worry about all the nasty bits\n", 77 | "(proper normalisation, numerically stable formation of the density etc.).\n", 78 | "\n", 79 | "Before we do that, let's demonstrate first how to use callbacks to extract information from a running SCF:" 80 | ] 81 | }, 82 | { 83 | "cell_type": "code", 84 | "execution_count": null, 85 | "id": "alone-stroke", 86 | "metadata": {}, 87 | "outputs": [], 88 | "source": [ 89 | "using DFTK\n", 90 | "using Plots\n", 91 | "\n", 92 | "p = plot(yaxis=:log) # Setup an empty plot canvas\n", 93 | "density_differences = Float64[]\n", 94 | "function plot_callback(info) \n", 95 | " if info.stage == :finalize\n", 96 | " # When done with the SCF: Plot it!\n", 97 | " plot!(p, density_differences, label=\"|ρout - ρin|\", markershape=:x)\n", 98 | " else\n", 99 | " # Just add the density difference of this step\n", 100 | " push!(density_differences, norm(info.ρout - info.ρin))\n", 101 | " end\n", 102 | " \n", 103 | " info # Pass info through to allow callback chaining\n", 104 | "end\n", 105 | "\n", 106 | "# Chain the custom callback with the default one\n", 107 | "# (printing the convergence table)\n", 108 | "callback = DFTK.ScfDefaultCallback() ∘ plot_callback\n", 109 | " \n", 110 | "# Run the SCF and show the plot\n", 111 | "scfres = self_consistent_field(aluminium_setup(); tol=1e-12, callback=callback);\n", 112 | "p" 113 | ] 114 | }, 115 | { 116 | "cell_type": "markdown", 117 | "id": "furnished-congress", 118 | "metadata": {}, 119 | "source": [ 120 | "**Exercise 1:** Try making this problem harder by running on `aluminium_setup(2)` and `aluminium_setup(5)` (or higher if you can efford it). What do you observe in the plot?" 121 | ] 122 | }, 123 | { 124 | "cell_type": "markdown", 125 | "id": "administrative-manufacturer", 126 | "metadata": {}, 127 | "source": [ 128 | "**Remark:** This callback allows to read or modify the full state of the SCF iteration,\n", 129 | "which is a valuable tool when debugging an SCF algorithm.\n", 130 | "When working in the REPL or with scripts one of my favourite callbacks is\n", 131 | "```julia\n", 132 | "using Infiltrator\n", 133 | "function infiltrate_callback(info)\n", 134 | " @infiltrate info.n_iter == 5\n", 135 | " info \n", 136 | "end\n", 137 | "scfres = self_consistent_field(aluminium_setup(); tol=1e-6,\n", 138 | " callback=infiltrate_callback);\n", 139 | "```\n", 140 | "to take you right to the SCF state at a surprising iteration." 141 | ] 142 | }, 143 | { 144 | "cell_type": "markdown", 145 | "id": "herbal-concentration", 146 | "metadata": {}, 147 | "source": [ 148 | "Now we have all the tools in place ... let's do some numerics:\n", 149 | "\n", 150 | "## Building our own SCF 1: Fixed-point iterations" 151 | ] 152 | }, 153 | { 154 | "cell_type": "markdown", 155 | "id": "incorporated-woman", 156 | "metadata": {}, 157 | "source": [ 158 | "As we saw before the self-consistent field procedure required to solve the DFT problem can be written as a fixed-point problem\n", 159 | "$$ F(\\rho) = \\rho $$\n", 160 | "where $F(\\rho) = D(V(\\rho))$ is the basic SCF step. That is the construction of the Kohn-Sham Hamiltonian $H(\\rho)$ given the density $\\rho$, followed its diagonalisation to obtain its eigenpairs $(\\varepsilon_{k i}, \\psi_{ki})$\n", 161 | "and from these a new density\n", 162 | "$$ \\rho(r) = \\sum_{k\\in\\text{BZ}} \\sum_i \\psi_{ki}(r) \\, \\psi_{ki}^\\ast(r).$$\n", 163 | "\n", 164 | "We will not be concerned with $F$ itself, which we will take for \"granted\" (i.e. delivered by DFTK).\n", 165 | "What we will consider, however, is multiple ways to solve the DFT fixed-point problem.\n", 166 | "\n", 167 | "The easiest are plain **fixed-point iterations**, i.e." 168 | ] 169 | }, 170 | { 171 | "cell_type": "markdown", 172 | "id": "binary-thinking", 173 | "metadata": {}, 174 | "source": [ 175 | "$$ \\rho_{n+1} = F(\\rho_n), $$\n", 176 | "starting from a hopefully good initial guess $\\rho_0$. DFTK automatically provides a reasonable\n", 177 | "guess density, such that we only need to take care of the iterations themselves.\n", 178 | "In the language of DFTK this algorithm is written as:" 179 | ] 180 | }, 181 | { 182 | "cell_type": "code", 183 | "execution_count": null, 184 | "id": "reported-hardware", 185 | "metadata": {}, 186 | "outputs": [], 187 | "source": [ 188 | "function fixed_point_iteration(F, ρ₀, maxiter; tol)\n", 189 | " # F: The SCF step function\n", 190 | " # ρ₀: The initial guess density\n", 191 | " # maxiter: The maximal number of iterations to be performed\n", 192 | " # tol: The selected convergence tolerance\n", 193 | " \n", 194 | " ρ = ρ₀\n", 195 | " Fρ = F(ρ)\n", 196 | " for n = 1:maxiter \n", 197 | " # If change less than tolerance, break iterations:\n", 198 | " if norm(Fρ - ρ) < tol\n", 199 | " break\n", 200 | " end\n", 201 | " ρ = Fρ\n", 202 | " Fρ = F(ρ)\n", 203 | " end\n", 204 | " \n", 205 | " # Return some stuff DFTK needs ...\n", 206 | " (fixpoint=ρ, converged=norm(Fρ - ρ) < tol)\n", 207 | "end;\n", 208 | "\n", 209 | "# use this algorithm inside DFTK's SCF for solving the silicon problem\n", 210 | "# (the other parameters are needed to overwrite some DFTK defaults\n", 211 | "# we don't want to use just yet).\n", 212 | "self_consistent_field(aluminium_setup(); solver=fixed_point_iteration, damping=1.0, maxiter=40);" 213 | ] 214 | }, 215 | { 216 | "cell_type": "markdown", 217 | "id": "selective-zambia", 218 | "metadata": {}, 219 | "source": [ 220 | "As can be observed this algorithm is not very good and completely fails to converge. This is a known limitation of this algorithm, which is why it is not used in practice." 221 | ] 222 | }, 223 | { 224 | "cell_type": "markdown", 225 | "id": "composite-springfield", 226 | "metadata": {}, 227 | "source": [ 228 | "## Step 2: Damped iterations\n", 229 | "\n", 230 | "The next step is to introduce a so-called damping parameter $\\alpha$, which is given a value between $0$ and $1$. One now iterates as follows:\n", 231 | "$$ \\rho_{n+1} = \\rho_{n} + \\alpha (F(\\rho_n) - \\rho_n) $$\n", 232 | "In other words the update $F(\\rho_n) - \\rho_n$ proposed in the $n$-th SCF step is not fully taken, but scaled-down by the damping $\\alpha$.\n", 233 | "\n", 234 | "**Exercise 2:** Modify `fixed_point_iteration` such that it supports this *damped* fixed-point iteration. Try different values for $\\alpha$ between $0$ and $1$ and estimate roughly the $\\alpha$ which gives fastest convergence. For which $\\alpha$ do you observe no convergence at all?" 235 | ] 236 | }, 237 | { 238 | "cell_type": "code", 239 | "execution_count": null, 240 | "id": "arabic-haiti", 241 | "metadata": {}, 242 | "outputs": [], 243 | "source": [ 244 | "# Your solution here ..." 245 | ] 246 | }, 247 | { 248 | "cell_type": "markdown", 249 | "id": "radio-phase", 250 | "metadata": {}, 251 | "source": [ 252 | "**Remark:** The observations you make here are general. We will argue in the next notebook why every SCF converges (locally) if a small enough $\\alpha > 0$ is chosen." 253 | ] 254 | }, 255 | { 256 | "cell_type": "markdown", 257 | "id": "continuous-genius", 258 | "metadata": {}, 259 | "source": [ 260 | "## Step 3: Anderson acceleration\n", 261 | "\n", 262 | "The `fixed_point_iteration` function above (with the damping extension) already covers the main gist of standard DFT algorithms. To make things converge faster the next step to follow is Anderson acceleration, where not only $\\rho_n$ and $F(\\rho_n)$, but also older iterates are used to propose the next density.\n", 263 | "\n", 264 | "For Anderson one exploits that the update $R(\\rho) = F(\\rho) - \\rho$ is also the residual of the fixed-point problem $F(\\rho) = \\rho$, i.e. how far away we are from the fixed-point density. A good next density $\\rho_{n+1}$ therefore should be found by minimising an approximation for $R(\\rho_{n+1})$. Assuming the SCF was linear in the density (which it is not), a good idea is to find a linear combination of residuals\n", 265 | "$$\\min_{\\beta_i} \\left\\| \\sum_i \\beta_i R(\\rho_i) \\right\\|^2$$\n", 266 | "which has the smallest possible norm and to use these coefficients $\\beta_i$ to extrapolate the next\n", 267 | "density\n", 268 | "$$ \\rho_{n+1} = \\sum_i \\beta_i (\\rho_i + \\alpha R(\\rho_i)) $$\n", 269 | "where you notice the \"standard\" damped fixed-point iteration in the summed terms.\n", 270 | "\n", 271 | "In terms of an algorithm this is " 272 | ] 273 | }, 274 | { 275 | "cell_type": "code", 276 | "execution_count": null, 277 | "id": "cultural-individual", 278 | "metadata": {}, 279 | "outputs": [], 280 | "source": [ 281 | "function anderson_iteration(F, ρ₀, maxiter; tol)\n", 282 | " # F: The SCF step function\n", 283 | " # ρ₀: The initial guess density\n", 284 | " # maxiter: The maximal number of iterations to be performed\n", 285 | " # tol: The selected convergence tolerance\n", 286 | " \n", 287 | " converged = false\n", 288 | " ρ = ρ₀\n", 289 | " ρs = []\n", 290 | " Rs = []\n", 291 | " for n = 1:maxiter\n", 292 | " Fρ = F(ρ)\n", 293 | " Rρ = Fρ - ρ\n", 294 | " converged = norm(Rρ) < tol\n", 295 | " converged && break\n", 296 | " \n", 297 | " ρnext = vec(ρ) .+ vec(Rρ)\n", 298 | " if !isempty(Rs)\n", 299 | " M = hcat(Rs...) .- vec(Rρ)\n", 300 | " βs = -(M \\ vec(Rρ))\n", 301 | " \n", 302 | " for (iβ, β) in enumerate(βs)\n", 303 | " ρnext .+= β .* (ρs[iβ] .- vec(ρ) .+ Rs[iβ] .- vec(Rρ))\n", 304 | " end\n", 305 | " end\n", 306 | " \n", 307 | " push!(ρs, vec(ρ))\n", 308 | " push!(Rs, vec(Rρ))\n", 309 | " ρ = reshape(ρnext, size(ρ₀)...)\n", 310 | " end\n", 311 | " \n", 312 | " # Return some stuff DFTK needs ...\n", 313 | " (fixpoint=ρ, converged=converged)\n", 314 | "end" 315 | ] 316 | }, 317 | { 318 | "cell_type": "markdown", 319 | "id": "cultural-neighborhood", 320 | "metadata": {}, 321 | "source": [ 322 | "To work with this algorithm we will use DFTK's intrinsic mechanism to choose a damping. The syntax for this is\n", 323 | "\n", 324 | "```julia\n", 325 | "repeat = 1\n", 326 | "self_consistent_field(aluminium_setup(repeat);\n", 327 | " solver=anderson_iteration,\n", 328 | " damping=0.8, maxiter=40);\n", 329 | "```\n", 330 | "to choose a damping of $\\alpha = 0.8$ and run for at most `maxiter` iterations.\n", 331 | "\n", 332 | "**Exercise 3:** Pick $\\alpha = 0.8$ and make the problem harder by increasing `repeat` (e.g. `2`, `4`, `6`, `8`). Can you make Anderson fail to converge? What do you notice in terms of the number of iterations and runtimes?" 333 | ] 334 | }, 335 | { 336 | "cell_type": "markdown", 337 | "id": "modular-delta", 338 | "metadata": {}, 339 | "source": [ 340 | "**Remark:** Anderson acceleration comes in many names and variants. It is sometimes also called Pulay mixing or DIIS (direct inversion of the iterative subspace). Closely related are also Broyden's methods. For more details on the relationship of these methods see this [review on SCF methods](http://doi.org/10.1088/1361-648x/ab31c0) as well as this [paper on the convergence analysis of DIIS methods](https://arxiv.org/abs/2002.12850)." 341 | ] 342 | }, 343 | { 344 | "cell_type": "markdown", 345 | "id": "wireless-baseball", 346 | "metadata": {}, 347 | "source": [ 348 | "## Step 4: Using NLsolve\n", 349 | "\n", 350 | "Of course it is never a good idea to recode standard algorithms such as Anderson acceleration when they are already implemented in other Julia packages.\n", 351 | "In DFTK we actually rely on the Anderson solver from [NLsolve.jl](https://github.com/JuliaNLSolvers/NLsolve.jl), which is even a bit smarter than the simple version we coded up above.\n", 352 | "\n", 353 | "[Our code](https://github.com/JuliaMolSim/DFTK.jl/blob/master/src/scf/scf_solvers.jl#L16--L23) to invoke NLsolve is pretty much just:" 354 | ] 355 | }, 356 | { 357 | "cell_type": "code", 358 | "execution_count": null, 359 | "id": "sealed-basement", 360 | "metadata": {}, 361 | "outputs": [], 362 | "source": [ 363 | "using NLsolve\n", 364 | "function nlsolve_solver(F, ρ₀, maxiter; tol)\n", 365 | " res = nlsolve(ρ -> F(ρ) - ρ, ρ₀; method=:anderson, m=10, xtol=tol,\n", 366 | " ftol=0.0, show_trace=false, iterations=maxiter)\n", 367 | " (fixpoint=res.zero, converged=converged(res))\n", 368 | "end\n", 369 | "\n", 370 | "self_consistent_field(basis; solver=nlsolve_solver, damping=0.8, maxiter=40, tol=1e-6);" 371 | ] 372 | }, 373 | { 374 | "cell_type": "markdown", 375 | "id": "communist-yorkshire", 376 | "metadata": {}, 377 | "source": [ 378 | "## Step 5: Using preconditioned iterations" 379 | ] 380 | }, 381 | { 382 | "cell_type": "markdown", 383 | "id": "previous-impossible", 384 | "metadata": {}, 385 | "source": [ 386 | "Anderson allows us to push the boundary for SCF methods, but for larger or more challenging systems it is not fully sufficient. The next ingredient for a stable SCF procedure is based on the insight we already had previously: The convergence properties of an SCF depends on the material which is modelled.\n", 387 | "As a result the ideal SCF procedure should be slightly different for each material.\n", 388 | "In our discussion so far we did not yet take that into account.\n", 389 | "\n", 390 | "The standard approach to include material specificity into the SCF is to employ *preconditioned* damped fixed-point iterations.\n", 391 | "To explain the idea, let us consider again a framework without Anderson acceleration.\n", 392 | "Preconditioned iterations are then\n", 393 | "$$ \\rho_{n+1} = \\rho_{n} + \\alpha P^{-1} (F(\\rho_n) - \\rho_n), $$\n", 394 | "where $P^{-1}$ is a preconditioner that hopefully improve convergence.\n", 395 | "To re-introduce Anderson around this iteration\n", 396 | "just replace the previous definition of $R$ by\n", 397 | "$R(\\rho) = P^{-1} (F(\\rho_n) - \\rho_n)$. That's it.\n", 398 | "\n", 399 | "As we will discuss in the next notebook the ideal preconditioning $P$\n", 400 | "depends on the dielectric properties of the material (e.g. whether it is a\n", 401 | "metal, insulator or semiconductor as well as other details). \n", 402 | "Finding a good $P$ is not always easy and for some cases satisfactory options are not yet known. For our aluminium case, however, we are lucky. The `KerkerMixing` implemented in DFTK provides a good $P$ for aluminium.\n", 403 | "\n", 404 | "You might wonder about the term *mixing*. In an interdisciplinary community like DFT, different scientists use different vocabulary and \"mixing\" is the \"physicists' term\" used for preconditioning.\n", 405 | "\n", 406 | "To use `KerkerMixing` with DFTK run the SCF as follows\n", 407 | "```julia\n", 408 | "self_consistent_field(basis; damping=0.8, mixing=KerkerMixing());\n", 409 | "```\n", 410 | "\n", 411 | "\n", 412 | "**Exercise 4:** Try this setup for different values of `repeat` and check the number of iterations needed. Other mixings DFTK has to offer are `DielectricMixing` (best for semiconductors) or `LdosMixing` (self-adapting, suitable for both metals *or* insulators *or* inhomogeneous mixtures). Try them as well and summarise your findings.\n" 413 | ] 414 | }, 415 | { 416 | "cell_type": "markdown", 417 | "id": "hollywood-walker", 418 | "metadata": {}, 419 | "source": [ 420 | "You should notice that choosing a preconditioner matching the material under study aids a fast SCF convergence, but that sometimes being off does not seem to do much harm for our case. In the next notebook we will introduce some tools to analyse this more systematically.\n", 421 | "\n", 422 | "#### Takeaways:\n", 423 | "- Large systems require a matching preconditioner to converge in few SCF iterations\n", 424 | "- Anderson acceleration and/or small damping aids convergence\n", 425 | "- Provided Anderson is used one often gets away using a non-matching preconditioner\n", 426 | "\n", 427 | "\n", 428 | "- The callback infrastructure of DFTK's SCF allows to to modify a few more aspects of the iteration\n", 429 | " very easily. See [this example](https://docs.dftk.org/stable/examples/custom_solvers/) in the documentation for details." 430 | ] 431 | } 432 | ], 433 | "metadata": { 434 | "kernelspec": { 435 | "display_name": "Julia 1.6.1", 436 | "language": "julia", 437 | "name": "julia-1.6" 438 | }, 439 | "language_info": { 440 | "file_extension": ".jl", 441 | "mimetype": "application/julia", 442 | "name": "julia", 443 | "version": "1.6.1" 444 | } 445 | }, 446 | "nbformat": 4, 447 | "nbformat_minor": 5 448 | } 449 | -------------------------------------------------------------------------------- /3_Density_functional_theory.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "divided-institution", 6 | "metadata": {}, 7 | "source": [ 8 | "# Density-functional theory\n", 9 | "\n", 10 | "In this notebook we will dive into density-functional theory (DFT).\n", 11 | "As I will describe simulating electrons in periodic systems with DFT\n", 12 | "is a common setting where the periodic one-particle Hamiltonians $H$\n", 13 | "described in the previous notebook arise." 14 | ] 15 | }, 16 | { 17 | "cell_type": "markdown", 18 | "id": "annual-alcohol", 19 | "metadata": {}, 20 | "source": [ 21 | "## Motivation and quantum-mechanical setting\n", 22 | "\n", 23 | "- The goal of electronic structure is to describe the behaviour of electrons in matter.\n", 24 | "- This allows to understand the chemical and physical properties of materials.\n", 25 | "\n", 26 | "\n", 27 | "\n", 28 | "\n", 29 | "- For accurately predicting properties from first principles a quantum-mechanical description of electrons is required.\n", 30 | "- The **states** describing the motion and behaviour of electrons are complex-valued\n", 31 | " functions in an infinite-dimensional function space, which is a Hilbert space.\n", 32 | "- The **operators** are mappings defined on this Hilbert space.\n", 33 | "\n", 34 | "\n", 35 | "\n", 36 | "\n", 37 | "- The motion of electrons is highly correlated. Pictorially speaking the motion of one electron depends on the motion of all others.\n", 38 | "- This makes an accurate modelling of the electronic structure rather involved.\n", 39 | "- In this workshop we focus on **density-functional theory** (DFT).\n", 40 | " While this approximate model has a number of limitations,\n", 41 | " it has become one of the most widely used practical methods due to its balance \n", 42 | " between cost and accuracy. \n", 43 | "- Moreover problems of the form of DFT are usually the first step in modelling\n", 44 | " the electronic structure, even when a more accurate methods will eventually be\n", 45 | " targeted. So understanding how DFT works represents a good step in either case.\n", 46 | " \n", 47 | "**More details**\n", 48 | "- My [2020 Juliacon talk](https://www.youtube.com/watch?v=-RomkxjlIcQ) (motivation for electronic-structure theory and DFT)\n", 49 | "- Chapter 2 of my [PhD thesis](https://michael-herbst.com/publications/2018.05_phd_corrected.pdf) (Mathematical formulation of quantum mechanics)" 50 | ] 51 | }, 52 | { 53 | "cell_type": "markdown", 54 | "id": "civil-science", 55 | "metadata": {}, 56 | "source": [ 57 | "## Formulation of the DFT problem\n", 58 | "\n", 59 | "- In DFT an electronic state is described by a set of orthonormal **orbitals**\n", 60 | " $\\{\\psi_i\\}$ ($i = 1, 2, \\ldots N$).\n", 61 | "- Each of these orbitals is a function from $\\mathbb{R}^3$ to $\\mathbb{C}$.\n", 62 | "- To a good approximation one can think of one orbital $\\psi_i$ as the description\n", 63 | " of the behaviour of one electron pair.\n", 64 | "- If there are $2 N$ electrons in the system, we therefore need $N$ orbitals." 65 | ] 66 | }, 67 | { 68 | "cell_type": "markdown", 69 | "id": "noted-render", 70 | "metadata": {}, 71 | "source": [ 72 | "- Of largest physical interest is the ground state of a system, that is the state\n", 73 | " which features the lowest energy.\n", 74 | "- At the level of DFT this translates to the minimisation problem\n", 75 | " $$ \\displaystyle \\text{min}_{\\{\\psi_i\\}} \\mathcal{E}_\\text{DFT}(\\{\\psi_i\\}) $$\n", 76 | " where we seek the lowest-energy orbitals given a DFT energy functional.\n", 77 | "\n", 78 | "\n", 79 | "- The details of the energy functional depend on the chosen DFT model.\n", 80 | " The common structure is as follows:\n", 81 | "\n", 82 | " $$ \\mathcal{E}_\\text{DFT}(\\{\\psi_i\\}) = \\sum_{i=1}^N 2 \\int \\psi_i^\\ast \\left(-\\frac12 \\Delta\\right) \\psi_i\n", 83 | " + \\int V_\\text{ext} \\rho + \\int V_\\text{H}[\\rho] \\rho + \\int V_\\text{xc}[\\rho] \\rho + E_\\text{nuclear}$$\n", 84 | " \n", 85 | " with\n", 86 | " * the electron **density** $\\rho = \\sum_i^N 2 |\\psi_i|^2$\n", 87 | " being directly dependent on *all* orbitals.\n", 88 | " * $\\sum_i 2 \\int \\psi_i^\\ast \\left(-\\frac12 \\Delta\\right) \\psi_i$ describing\n", 89 | " the **kinetic** energy of the electrons\n", 90 | " (i.e. the term we discussed in the previous notebook)\n", 91 | " * $\\int V_\\text{ext} \\rho$ being the **external** potential energy,\n", 92 | " i.e. the electron-nuclear interaction.\n", 93 | " * $\\int V_\\text{H}[\\rho] \\rho$ being the **Hartree** energy,\n", 94 | " i.e. the classical Coulombic electron-electron repulsion\n", 95 | " * $\\int V_\\text{xc}[\\rho] \\rho$ being the **exchange-correlation**\n", 96 | " (or XC) energy, which describes the electron-electron interaction beyond\n", 97 | " the classical model.\n", 98 | " * $E_\\text{nuclear}$: A fixed energy offset due to the repulsion of the nuclei\n", 99 | " from each other.\n", 100 | "\n", 101 | "**Note:** The Hartree potential $V_\\text{H}$ and the XC potential $V_\\text{xc}$ themselves depend on the density $\\rho$. Therefore $\\mathcal{E}_\\text{DFT}$ is non-linear in the orbitals!" 102 | ] 103 | }, 104 | { 105 | "cell_type": "markdown", 106 | "id": "tested-improvement", 107 | "metadata": {}, 108 | "source": [ 109 | "For our numerical experiments we will use the [density-functional toolkit](https://dftk.org) (DFTK).\n", 110 | "In DFTK such a DFT model can be conveniently assembled by collecting the respective energy terms:" 111 | ] 112 | }, 113 | { 114 | "cell_type": "code", 115 | "execution_count": null, 116 | "id": "written-thesaurus", 117 | "metadata": {}, 118 | "outputs": [], 119 | "source": [ 120 | "using DFTK\n", 121 | "\n", 122 | "# Build up the LDA model by assembling the energy terms\n", 123 | "terms_LDA = [Kinetic(), # -1/2 Δ\n", 124 | " AtomicLocal(), # part of Vₑₓₜ\n", 125 | " AtomicNonlocal(), # part of Vₑₓₜ\n", 126 | " PspCorrection(), # part of Vₑₓₜ\n", 127 | " Hartree(), # Vₕ\n", 128 | " Xc(:lda_xc_teter93), # Vxc\n", 129 | " Ewald()] # part of Eₙᵤᵪₗₑₐᵣ" 130 | ] 131 | }, 132 | { 133 | "cell_type": "markdown", 134 | "id": "urban-effects", 135 | "metadata": {}, 136 | "source": [ 137 | "DFTK has many more terms to offer (e.g. external fields, magnetism, etc.). See [the source code](https://dftk.org/tree/master/src/terms) for the full list." 138 | ] 139 | }, 140 | { 141 | "cell_type": "markdown", 142 | "id": "competitive-smell", 143 | "metadata": {}, 144 | "source": [ 145 | "## Solving DFT: The self-consistent field problem\n", 146 | "\n", 147 | "The stationarity conditions (Euler-Lagrange equations) corresponding to the DFT minimisation problem are\n", 148 | "\n", 149 | "$$\\left\\{\\begin{aligned}\n", 150 | " &\\forall 1 \\leq i \\leq N: &\\left(-\\frac12 \\Delta + V[\\rho] \\right) \\psi_i &= \\varepsilon_i \\psi_i\n", 151 | " \\qquad \\text{(with $\\varepsilon_1, \\varepsilon_2, \\ldots, \\varepsilon_N$ smallest)} \\\\\n", 152 | " &\\forall 1 \\leq i, j \\leq N: &\\int \\psi_i^\\ast \\psi_j &= \\delta_{ij} \\\\\n", 153 | " &&V[\\rho] &= V_\\text{ext} + V_\\text{H}[\\rho] + V_\\text{xc}[\\rho] \\\\\n", 154 | " &&\\rho &= \\sum_{i=1}^N 2 |\\psi_i|^2\n", 155 | "\\end{aligned}\\right.$$\n", 156 | "\n", 157 | "in which $H[\\rho] = -\\frac12 \\Delta + V[\\rho]$ is the **DFT Hamiltonian**. These equations are called the **self-consistent field** (SCF) problem.\n", 158 | "\n", 159 | "- The first and second line are basically an eigenvalue problem\n", 160 | " with the usual orthogonality between the resulting eigenfunctions.\n", 161 | "- Since $V$ depends on $\\rho$ (3rd line), which itself depends on $\\psi_i$ (last line),\n", 162 | " solving the SCF equations implies solving a *non-linear* eigenvalue problem.\n", 163 | "- In this sense the DFT Hamiltonian is a generalisation of the diagonalisation problems\n", 164 | " we discussed in the previous notebook." 165 | ] 166 | }, 167 | { 168 | "cell_type": "markdown", 169 | "id": "amino-grounds", 170 | "metadata": {}, 171 | "source": [ 172 | "To allow for writing the SCF problem more compact\n", 173 | "we define the **potential-to-density map**\n", 174 | "$$\n", 175 | "D(V) = \\sum_{i=1}^N 2 |\\psi_i|^2 \\qquad \\text{$\\psi_i$ are the $N$ lowest eigenvectors of $-\\frac12 \\Delta + V$}.\n", 176 | "$$\n", 177 | "With it the SCF problem can be written as\n", 178 | "$$ \\rho = D(V(\\rho)). $$\n", 179 | "Clearly an SCF is nothing else but a **fixed-point problem**." 180 | ] 181 | }, 182 | { 183 | "cell_type": "markdown", 184 | "id": "changing-maine", 185 | "metadata": {}, 186 | "source": [ 187 | "**Note:** In the picture I sketch in this notebook I make a few assumptions for simplicity (e.g. no unpaired electrons, no spin, only integer occupation, existence of a gap, etc.). Adding in these extra complications does not change much of the bottom line, so I've decided to leave these aspects out for clarity. You can find more details (at various levels) in the [references given in the DFTK documentation](https://juliamolsim.github.io/DFTK.jl/stable/guide/density_functional_theory/)." 188 | ] 189 | }, 190 | { 191 | "cell_type": "markdown", 192 | "id": "metallic-newspaper", 193 | "metadata": {}, 194 | "source": [ 195 | "## Modelling silicon\n", 196 | "\n", 197 | "Puh ... that was quite a lot of equations. Let's see some numbers!\n", 198 | "\n", 199 | "First we will use the LDA model defined above to model silicon,\n", 200 | "a nicely periodic lattice.\n", 201 | "\n", 202 | "| |\n", 203 | "| --------------- |\n", 204 | "| silicon crystal |" 205 | ] 206 | }, 207 | { 208 | "cell_type": "code", 209 | "execution_count": null, 210 | "id": "celtic-colon", 211 | "metadata": {}, 212 | "outputs": [], 213 | "source": [ 214 | "using DFTK\n", 215 | "\n", 216 | "# Look up the structure of silicon in a book\n", 217 | "# and define the lattice and the atomic positions\n", 218 | "a = 10.26\n", 219 | "lattice = a / 2 * [[0 1 1.];\n", 220 | " [1 0 1.];\n", 221 | " [1 1 0.]]\n", 222 | "Si = ElementPsp(:Si, psp=load_psp(\"hgh/lda/si-q4\"))\n", 223 | "atoms = [Si => [ones(3)/8, -ones(3)/8]]\n", 224 | "\n", 225 | "# Setup a model in DFTK from the terms we defined above\n", 226 | "model = Model(lattice; atoms, terms=terms_LDA)\n", 227 | "# Note: For common models DFTK has shortcuts. In this case\n", 228 | "# model = model_LDA(lattice, atoms)\n", 229 | "# does exactly the same\n", 230 | "\n", 231 | "# Discretise the problem in a plane-wave basis\n", 232 | "# We use a mesh of 2x2x2 k-Points in the Brillouin zone\n", 233 | "# and an energy cutoff of 13 Hartree\n", 234 | "basis = PlaneWaveBasis(model; Ecut=15, kgrid=[2, 2, 2])\n", 235 | "\n", 236 | "# Run the SCF and catch the result:\n", 237 | "scfres = self_consistent_field(basis);" 238 | ] 239 | }, 240 | { 241 | "cell_type": "markdown", 242 | "id": "integrated-alpha", 243 | "metadata": {}, 244 | "source": [ 245 | "Ok so this did something, but what?\n", 246 | "\n", 247 | "- First DFTK inspects the molecule to guess an initial density $\\rho_0$.\n", 248 | "- Then we solve $ \\rho = D(V(\\rho)) $ by computing\n", 249 | " $D(V(\\rho_n))$ for a sequence of iterates $\\rho_n$ until input and output\n", 250 | " are close enough, i.e. the residual\n", 251 | " $$ R(\\rho_n) = D(V(\\rho_n)) - \\rho_n$$\n", 252 | " is small. Then DFTK flags convergence.\n", 253 | "- We will discuss these algorithms with more details in the next notebook.\n", 254 | "\n", 255 | "In the end we obtained the ground-state energy of silicon as" 256 | ] 257 | }, 258 | { 259 | "cell_type": "code", 260 | "execution_count": null, 261 | "id": "mighty-istanbul", 262 | "metadata": {}, 263 | "outputs": [], 264 | "source": [ 265 | "scfres.energies" 266 | ] 267 | }, 268 | { 269 | "cell_type": "markdown", 270 | "id": "single-avenue", 271 | "metadata": {}, 272 | "source": [ 273 | "We can also look at the density:" 274 | ] 275 | }, 276 | { 277 | "cell_type": "code", 278 | "execution_count": null, 279 | "id": "searching-condition", 280 | "metadata": {}, 281 | "outputs": [], 282 | "source": [ 283 | "using Plots\n", 284 | "heatmap(scfres.ρ[:, :, 5], c=:Blues)" 285 | ] 286 | }, 287 | { 288 | "cell_type": "markdown", 289 | "id": "genuine-aging", 290 | "metadata": {}, 291 | "source": [ 292 | "... or access the eigenpairs of the final Hamiltonian diagonalisation\n", 293 | "in `scfres.ψ` and `scfres.eigenvalues`:" 294 | ] 295 | }, 296 | { 297 | "cell_type": "code", 298 | "execution_count": null, 299 | "id": "going-thompson", 300 | "metadata": {}, 301 | "outputs": [], 302 | "source": [ 303 | "scfres.eigenvalues" 304 | ] 305 | }, 306 | { 307 | "cell_type": "markdown", 308 | "id": "fifty-simple", 309 | "metadata": {}, 310 | "source": [ 311 | "It might come to a surprise for your why this does not return a flat list,\n", 312 | "but in fact a list of two lists. This will be clarified in the following\n", 313 | "\n", 314 | "\n", 315 | "**Remark:** Since silicon (and in fact all problems we will consider) are periodic,\n", 316 | "the DFT Hamiltonian $H$ is also periodic.\n", 317 | "Therefore we are in the periodic setting discussed in the previous notebook\n", 318 | "and one is able to apply the Bloch transform to $H$.\n", 319 | "This allows to reformulate the SCF problem as \n", 320 | "\n", 321 | "$$\\left\\{\\begin{aligned}\n", 322 | " &\\forall k\\in\\text{BZ}, \\ \\ 1 \\leq i \\leq N: &\\left(\\frac12 (-i \\nabla + k)^2 + V[\\rho] \\right) \\psi_{ki} &= \\varepsilon_{ki} \\psi_{ki}\\\\\n", 323 | " &\\forall k\\in\\text{BZ}, \\ \\ 1 \\leq i, j \\leq N: &\\int \\psi_{ki}^\\ast \\psi_{kj} &= \\delta_{ij} \\\\\n", 324 | " &&V[\\rho] &= V_\\text{ext} + V_\\text{H}[\\rho] + V_\\text{xc}[\\rho] \\\\\n", 325 | " &&\\rho &= \\sum_{k\\in\\text{BZ}} \\sum_{i=1}^N 2 |\\psi_{ki}|^2\n", 326 | "\\end{aligned}\\right.$$\n", 327 | "\n", 328 | "In other words we can diagonalisate $H$ $k$-Point by $k$-Point\n", 329 | "and only at the level of computing the density we need to\n", 330 | "sum over $k$-Points.\n", 331 | "\n", 332 | "In DFTK most quantities in the `scfres` are therefore stored\n", 333 | "as a list over $k$-Points. Therefore\n", 334 | "```julia\n", 335 | " scfres.eigenvalues[1]\n", 336 | "```\n", 337 | "gives access to the $\\varepsilon_{ki}$ for the first $k$-Point." 338 | ] 339 | }, 340 | { 341 | "cell_type": "markdown", 342 | "id": "allied-tract", 343 | "metadata": {}, 344 | "source": [ 345 | "In our problem we used `kgrid=[2,2,2]`. One would therefore expect 8 $k$-Points\n", 346 | "to be present in the discretisation. As it turns out there are only" 347 | ] 348 | }, 349 | { 350 | "cell_type": "code", 351 | "execution_count": null, 352 | "id": "delayed-installation", 353 | "metadata": {}, 354 | "outputs": [], 355 | "source": [ 356 | "length(basis.kpoints)" 357 | ] 358 | }, 359 | { 360 | "cell_type": "markdown", 361 | "id": "charming-portugal", 362 | "metadata": {}, 363 | "source": [ 364 | "The reason for this is that the symmetries of the problem allow to make further reductions in effort. If we disable symmetries, we get the expected 8 $k$-Points:" 365 | ] 366 | }, 367 | { 368 | "cell_type": "code", 369 | "execution_count": null, 370 | "id": "manual-jordan", 371 | "metadata": {}, 372 | "outputs": [], 373 | "source": [ 374 | "model_nosym = Model(lattice; atoms, terms=terms_LDA, symmetries=false)\n", 375 | "length(PlaneWaveBasis(model_nosym; Ecut=15, kgrid=(2, 2, 2)).kpoints)" 376 | ] 377 | }, 378 | { 379 | "cell_type": "markdown", 380 | "id": "perceived-undergraduate", 381 | "metadata": {}, 382 | "source": [ 383 | "To conclude this section, let us plot the band structure of silicon,\n", 384 | "i.e. the relationship between the eigenvalues of $H$\n", 385 | "and the position $k$ inside the Brillouin zone.\n", 386 | "(For more details see the previous notebook)." 387 | ] 388 | }, 389 | { 390 | "cell_type": "code", 391 | "execution_count": null, 392 | "id": "single-poultry", 393 | "metadata": {}, 394 | "outputs": [], 395 | "source": [ 396 | "plot_bandstructure(scfres)" 397 | ] 398 | }, 399 | { 400 | "cell_type": "markdown", 401 | "id": "scheduled-finance", 402 | "metadata": {}, 403 | "source": [ 404 | "## Modelling aluminum\n", 405 | "\n", 406 | "**Exercise 1:** Try running a simulation of aluminium yourself.\n", 407 | "\n", 408 | "For aluminum a possible structural setup is\n", 409 | "```julia\n", 410 | "a = 7.65339\n", 411 | "lattice = diagm(fill(a, 3))\n", 412 | "Al = ElementPsp(:Al, psp=load_psp(\"hgh/lda/al-q3\"))\n", 413 | "atoms = [Al => [[0.0, 0.0, 0.0], [0.0, 0.5, 0.5], [0.5, 0.0, 0.5], [0.5, 0.5, 0.0]]]\n", 414 | "```\n", 415 | "\n", 416 | "First use the same LDA model as before, defined using the DFTK shortcut\n", 417 | "```julia\n", 418 | "model = model_LDA(lattice, atoms)\n", 419 | "```\n", 420 | "and use `Ecut=15` and `kgrid=[2, 2, 2]` to discretise the problem.\n", 421 | "\n", 422 | "When running the SCF like this you should observe either slow or no convergence.\n", 423 | "This points to the fact that modelling aluminium is clearly a little different\n", 424 | "than silicon.\n", 425 | "In fact the issue is due to aluminium being a metal,\n", 426 | "while silicon is an insulator / semiconductor.\n", 427 | "More on this below.\n", 428 | "\n", 429 | "To make progress and achieve SCF convergence add the parameter\n", 430 | "```julia\n", 431 | "model = model_LDA(lattice, atoms, temperature=1e-3)\n", 432 | "```\n", 433 | "This is called **smearing** and is a numerical trick\n", 434 | "to improve the convergence for quantities which involve\n", 435 | "sums over $k$-Points in metals.\n", 436 | "As the density $\\rho$ involves such a sum, the SCF typically fails\n", 437 | "to converge in metals without smearing.\n", 438 | "\n", 439 | "With this setup it the SCF should succeed. Use the obtained scfres to compute the band structure of aluminium with `plot_bandstructure(scfres)`." 440 | ] 441 | }, 442 | { 443 | "cell_type": "code", 444 | "execution_count": null, 445 | "id": "bearing-donna", 446 | "metadata": {}, 447 | "outputs": [], 448 | "source": [ 449 | "using DFTK\n", 450 | "using LinearAlgebra\n", 451 | "\n", 452 | "a = 7.65339\n", 453 | "lattice = diagm(fill(a, 3))\n", 454 | "Al = ElementPsp(:Al, psp=load_psp(\"hgh/lda/al-q3\"))\n", 455 | "atoms = [Al => [[0.0, 0.0, 0.0], [0.0, 0.5, 0.5], [0.5, 0.0, 0.5], [0.5, 0.5, 0.0]]]\n", 456 | "\n", 457 | "# your solution here " 458 | ] 459 | }, 460 | { 461 | "cell_type": "markdown", 462 | "id": "joint-purple", 463 | "metadata": {}, 464 | "source": [ 465 | "## Contrasting aluminium and silicon" 466 | ] 467 | }, 468 | { 469 | "cell_type": "markdown", 470 | "id": "exceptional-license", 471 | "metadata": {}, 472 | "source": [ 473 | "With these two calculations we have computed two band structures,\n", 474 | "one for a metal (aluminium) and one for a semiconductor (silicon).\n", 475 | "\n", 476 | "- All details of the band structure do not matter for our purposes.\n", 477 | "- The important difference is that silicon has a so-called **band gap**,\n", 478 | " i.e. a region near the Fermi level (which is at $0$ in the shown band plots)\n", 479 | " where there are no eigenvalues, i.e. no blue bands.\n", 480 | " In contrast aluminium does not have this gap.\n", 481 | "- This makes aluminium a metal and silicon an insulator respectively semiconductor.\n", 482 | "\n", 483 | "For the numerical treatment the absence of a band gap has strong implications:\n", 484 | "- At the beginning of the SCF the DFT Hamiltonian $H[\\rho_n]$\n", 485 | " at the current density $\\rho_n$ is only a rough approximation to the\n", 486 | " converged Hamiltonian $H[\\rho_\\ast]$.\n", 487 | "- This means that the order of the $\\psi_{ki}$ near the Fermi level,\n", 488 | " i.e. near $i = N$, may be easily swapped as many $\\psi_{ki}$\n", 489 | " of similar eigenvalues $\\varepsilon_i$ are close.\n", 490 | "- From one iteration to the next the $\\psi_{ki}$ which are summed\n", 491 | " over in the density expression\n", 492 | " $$ \\rho = \\sum_{k\\in\\text{BZ}} \\sum_{i=1}^N 2 |\\psi_{ki}|^2 $$\n", 493 | " may thus change (as $N$ becomes $N+1$, thus not summed over, but $N+1$ becomes $N$).\n", 494 | "- Without going into details the smearing temperature reduces this\n", 495 | " problem by not enforcing a hard cut between the functions summed over in the density,\n", 496 | " but employing a smoother cutoff function.\n", 497 | "\n", 498 | "- As becomes apparent already in these first few experiments\n", 499 | " the numerics of an SCF and the physics of the system are closely linked.\n", 500 | "\n", 501 | "\n", 502 | "#### Takeaways\n", 503 | "- Insulators / semiconductors have a band gap\n", 504 | "- Metals have no band gap\n", 505 | "- Without a band gap a smearing is needed to aid convergence.\n", 506 | "- SCF convergence properties for metals and insulators differ quite drastically (more on this in the next notebooks)" 507 | ] 508 | } 509 | ], 510 | "metadata": { 511 | "kernelspec": { 512 | "display_name": "Julia 1.6.1", 513 | "language": "julia", 514 | "name": "julia-1.6" 515 | }, 516 | "language_info": { 517 | "file_extension": ".jl", 518 | "mimetype": "application/julia", 519 | "name": "julia", 520 | "version": "1.6.1" 521 | } 522 | }, 523 | "nbformat": 4, 524 | "nbformat_minor": 5 525 | } 526 | -------------------------------------------------------------------------------- /img/Brillouin_Zone.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 19 | 42 | 47 | 48 | 50 | 57 | 58 | 60 | 61 | 63 | image/svg+xml 64 | 66 | 67 | 68 | 69 | 74 | 83 | 92 | 93 | 96 | 101 | 106 | 111 | 116 | 121 | 126 | 131 | 136 | 140 | 144 | U 155 | X 166 | W 179 | K 190 | L 201 | Γ 212 | Λ 223 | Δ 234 | Σ 245 | 249 | z 260 | x 271 | 281 | 291 | 301 | 311 | 315 | 319 | 323 | 327 | 331 | 335 | y 346 | 350 | 355 | 365 | 369 | 379 | 380 | 381 | -------------------------------------------------------------------------------- /Manifest.toml: -------------------------------------------------------------------------------- 1 | # This file is machine-generated - editing it directly is not advised 2 | 3 | [[AbstractFFTs]] 4 | deps = ["LinearAlgebra"] 5 | git-tree-sha1 = "485ee0867925449198280d4af84bdb46a2a404d0" 6 | uuid = "621f4979-c628-5d54-868e-fcf4e3e8185c" 7 | version = "1.0.1" 8 | 9 | [[Adapt]] 10 | deps = ["LinearAlgebra"] 11 | git-tree-sha1 = "84918055d15b3114ede17ac6a7182f68870c16f7" 12 | uuid = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" 13 | version = "3.3.1" 14 | 15 | [[ArgTools]] 16 | uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" 17 | 18 | [[ArrayInterface]] 19 | deps = ["IfElse", "LinearAlgebra", "Requires", "SparseArrays", "Static"] 20 | git-tree-sha1 = "a71d224f61475b93c9e196e83c17c6ac4dedacfa" 21 | uuid = "4fba245c-0d91-5ea0-9b3e-6abc04ee57a9" 22 | version = "3.1.18" 23 | 24 | [[ArrayLayouts]] 25 | deps = ["FillArrays", "LinearAlgebra", "SparseArrays"] 26 | git-tree-sha1 = "0f7998147ff3d112fad027c894b6b6bebf867154" 27 | uuid = "4c555306-a7a7-4459-81d9-ec55ddd5c99a" 28 | version = "0.7.3" 29 | 30 | [[Artifacts]] 31 | uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" 32 | 33 | [[AxisAlgorithms]] 34 | deps = ["LinearAlgebra", "Random", "SparseArrays", "WoodburyMatrices"] 35 | git-tree-sha1 = "a4d07a1c313392a77042855df46c5f534076fab9" 36 | uuid = "13072b0f-2c55-5437-9ae7-d433b7a33950" 37 | version = "1.0.0" 38 | 39 | [[Base64]] 40 | uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" 41 | 42 | [[BlockArrays]] 43 | deps = ["ArrayLayouts", "FillArrays", "LinearAlgebra"] 44 | git-tree-sha1 = "4f248f06d5b636e5e0e93e0d53858e9ea9d9393d" 45 | uuid = "8e7c35d0-a365-5155-bbbb-fb81a777f24e" 46 | version = "0.16.3" 47 | 48 | [[Bzip2_jll]] 49 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 50 | git-tree-sha1 = "c3598e525718abcc440f69cc6d5f60dda0a1b61e" 51 | uuid = "6e34b625-4abd-537c-b88f-471c36dfa7a0" 52 | version = "1.0.6+5" 53 | 54 | [[CRlibm]] 55 | deps = ["Libdl"] 56 | git-tree-sha1 = "9d1c22cff9c04207f336b8e64840d0bd40d86e0e" 57 | uuid = "96374032-68de-5a5b-8d9e-752f78720389" 58 | version = "0.8.0" 59 | 60 | [[Cairo_jll]] 61 | deps = ["Artifacts", "Bzip2_jll", "Fontconfig_jll", "FreeType2_jll", "Glib_jll", "JLLWrappers", "LZO_jll", "Libdl", "Pixman_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll", "Zlib_jll", "libpng_jll"] 62 | git-tree-sha1 = "e2f47f6d8337369411569fd45ae5753ca10394c6" 63 | uuid = "83423d85-b0ee-5818-9007-b63ccbeb887a" 64 | version = "1.16.0+6" 65 | 66 | [[ChainRulesCore]] 67 | deps = ["Compat", "LinearAlgebra", "SparseArrays"] 68 | git-tree-sha1 = "f53ca8d41e4753c41cdafa6ec5f7ce914b34be54" 69 | uuid = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4" 70 | version = "0.10.13" 71 | 72 | [[ColorSchemes]] 73 | deps = ["ColorTypes", "Colors", "FixedPointNumbers", "Random", "StaticArrays"] 74 | git-tree-sha1 = "ed268efe58512df8c7e224d2e170afd76dd6a417" 75 | uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4" 76 | version = "3.13.0" 77 | 78 | [[ColorTypes]] 79 | deps = ["FixedPointNumbers", "Random"] 80 | git-tree-sha1 = "024fe24d83e4a5bf5fc80501a314ce0d1aa35597" 81 | uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" 82 | version = "0.11.0" 83 | 84 | [[Colors]] 85 | deps = ["ColorTypes", "FixedPointNumbers", "Reexport"] 86 | git-tree-sha1 = "417b0ed7b8b838aa6ca0a87aadf1bb9eb111ce40" 87 | uuid = "5ae59095-9a9b-59fe-a467-6f913c188581" 88 | version = "0.12.8" 89 | 90 | [[CommonSolve]] 91 | git-tree-sha1 = "68a0743f578349ada8bc911a5cbd5a2ef6ed6d1f" 92 | uuid = "38540f10-b2f7-11e9-35d8-d573e4eb0ff2" 93 | version = "0.2.0" 94 | 95 | [[CommonSubexpressions]] 96 | deps = ["MacroTools", "Test"] 97 | git-tree-sha1 = "7b8a93dba8af7e3b42fecabf646260105ac373f7" 98 | uuid = "bbf7d656-a473-5ed7-a52c-81e309532950" 99 | version = "0.3.0" 100 | 101 | [[Compat]] 102 | deps = ["Base64", "Dates", "DelimitedFiles", "Distributed", "InteractiveUtils", "LibGit2", "Libdl", "LinearAlgebra", "Markdown", "Mmap", "Pkg", "Printf", "REPL", "Random", "SHA", "Serialization", "SharedArrays", "Sockets", "SparseArrays", "Statistics", "Test", "UUIDs", "Unicode"] 103 | git-tree-sha1 = "dc7dedc2c2aa9faf59a55c622760a25cbefbe941" 104 | uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" 105 | version = "3.31.0" 106 | 107 | [[CompilerSupportLibraries_jll]] 108 | deps = ["Artifacts", "Libdl"] 109 | uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" 110 | 111 | [[Conda]] 112 | deps = ["JSON", "VersionParsing"] 113 | git-tree-sha1 = "299304989a5e6473d985212c28928899c74e9421" 114 | uuid = "8f4d0f93-b110-5947-807f-2305c1781a2d" 115 | version = "1.5.2" 116 | 117 | [[ConstructionBase]] 118 | deps = ["LinearAlgebra"] 119 | git-tree-sha1 = "f74e9d5388b8620b4cee35d4c5a618dd4dc547f4" 120 | uuid = "187b0558-2788-49d3-abe0-74a17ed4e7c9" 121 | version = "1.3.0" 122 | 123 | [[Contour]] 124 | deps = ["StaticArrays"] 125 | git-tree-sha1 = "9f02045d934dc030edad45944ea80dbd1f0ebea7" 126 | uuid = "d38c429a-6771-53c6-b99e-75d170b6e991" 127 | version = "0.5.7" 128 | 129 | [[DFTK]] 130 | deps = ["AbstractFFTs", "BlockArrays", "Conda", "FFTW", "ForwardDiff", "Interpolations", "IterTools", "IterativeSolvers", "JSON", "Libxc", "LineSearches", "LinearAlgebra", "LinearMaps", "MPI", "Markdown", "NLsolve", "Optim", "OrderedCollections", "PeriodicTable", "Polynomials", "Primes", "Printf", "ProgressMeter", "PyCall", "Requires", "Roots", "SpecialFunctions", "StaticArrays", "Statistics", "TimerOutputs", "Unitful", "UnitfulAtomic", "spglib_jll"] 131 | git-tree-sha1 = "bfcc4614a4053f81c7650980d301cd37dc4facbb" 132 | uuid = "acf6eb54-70d9-11e9-0013-234b7a5f5337" 133 | version = "0.3.9" 134 | 135 | [[DataAPI]] 136 | git-tree-sha1 = "ee400abb2298bd13bfc3df1c412ed228061a2385" 137 | uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" 138 | version = "1.7.0" 139 | 140 | [[DataStructures]] 141 | deps = ["Compat", "InteractiveUtils", "OrderedCollections"] 142 | git-tree-sha1 = "4437b64df1e0adccc3e5d1adbc3ac741095e4677" 143 | uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" 144 | version = "0.18.9" 145 | 146 | [[DataValueInterfaces]] 147 | git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6" 148 | uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464" 149 | version = "1.0.0" 150 | 151 | [[Dates]] 152 | deps = ["Printf"] 153 | uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" 154 | 155 | [[DelimitedFiles]] 156 | deps = ["Mmap"] 157 | uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab" 158 | 159 | [[DiffResults]] 160 | deps = ["StaticArrays"] 161 | git-tree-sha1 = "c18e98cba888c6c25d1c3b048e4b3380ca956805" 162 | uuid = "163ba53b-c6d8-5494-b064-1a9d43ac40c5" 163 | version = "1.0.3" 164 | 165 | [[DiffRules]] 166 | deps = ["NaNMath", "Random", "SpecialFunctions"] 167 | git-tree-sha1 = "214c3fcac57755cfda163d91c58893a8723f93e9" 168 | uuid = "b552c78f-8df3-52c6-915a-8e097449b14b" 169 | version = "1.0.2" 170 | 171 | [[Distances]] 172 | deps = ["LinearAlgebra", "Statistics", "StatsAPI"] 173 | git-tree-sha1 = "abe4ad222b26af3337262b8afb28fab8d215e9f8" 174 | uuid = "b4f34e82-e78d-54a5-968a-f98e89d6e8f7" 175 | version = "0.10.3" 176 | 177 | [[Distributed]] 178 | deps = ["Random", "Serialization", "Sockets"] 179 | uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" 180 | 181 | [[DocStringExtensions]] 182 | deps = ["LibGit2"] 183 | git-tree-sha1 = "a32185f5428d3986f47c2ab78b1f216d5e6cc96f" 184 | uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" 185 | version = "0.8.5" 186 | 187 | [[DoubleFloats]] 188 | deps = ["GenericLinearAlgebra", "LinearAlgebra", "Polynomials", "Printf", "Quadmath", "Random", "Requires", "SpecialFunctions"] 189 | git-tree-sha1 = "1c962cf7e75c09a5f1fbf504df7d6a06447a1129" 190 | uuid = "497a8b3b-efae-58df-a0af-a86822472b78" 191 | version = "1.1.23" 192 | 193 | [[Downloads]] 194 | deps = ["ArgTools", "LibCURL", "NetworkOptions"] 195 | uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" 196 | 197 | [[EarCut_jll]] 198 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 199 | git-tree-sha1 = "92d8f9f208637e8d2d28c664051a00569c01493d" 200 | uuid = "5ae413db-bbd1-5e63-b57d-d24a61df00f5" 201 | version = "2.1.5+1" 202 | 203 | [[ErrorfreeArithmetic]] 204 | git-tree-sha1 = "d6863c556f1142a061532e79f611aa46be201686" 205 | uuid = "90fa49ef-747e-5e6f-a989-263ba693cf1a" 206 | version = "0.5.2" 207 | 208 | [[Expat_jll]] 209 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 210 | git-tree-sha1 = "b3bfd02e98aedfa5cf885665493c5598c350cd2f" 211 | uuid = "2e619515-83b5-522b-bb60-26c02a35a201" 212 | version = "2.2.10+0" 213 | 214 | [[ExprTools]] 215 | git-tree-sha1 = "b7e3d17636b348f005f11040025ae8c6f645fe92" 216 | uuid = "e2ba6199-217a-4e67-a87a-7c52f15ade04" 217 | version = "0.1.6" 218 | 219 | [[FFMPEG]] 220 | deps = ["FFMPEG_jll"] 221 | git-tree-sha1 = "b57e3acbe22f8484b4b5ff66a7499717fe1a9cc8" 222 | uuid = "c87230d0-a227-11e9-1b43-d7ebe4e7570a" 223 | version = "0.4.1" 224 | 225 | [[FFMPEG_jll]] 226 | deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "LAME_jll", "LibVPX_jll", "Libdl", "Ogg_jll", "OpenSSL_jll", "Opus_jll", "Pkg", "Zlib_jll", "libass_jll", "libfdk_aac_jll", "libvorbis_jll", "x264_jll", "x265_jll"] 227 | git-tree-sha1 = "3cc57ad0a213808473eafef4845a74766242e05f" 228 | uuid = "b22a6f82-2f65-5046-a5b2-351ab43fb4e5" 229 | version = "4.3.1+4" 230 | 231 | [[FFTW]] 232 | deps = ["AbstractFFTs", "FFTW_jll", "LinearAlgebra", "MKL_jll", "Preferences", "Reexport"] 233 | git-tree-sha1 = "f985af3b9f4e278b1d24434cbb546d6092fca661" 234 | uuid = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341" 235 | version = "1.4.3" 236 | 237 | [[FFTW_jll]] 238 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 239 | git-tree-sha1 = "3676abafff7e4ff07bbd2c42b3d8201f31653dcc" 240 | uuid = "f5851436-0d7a-5f13-b9de-f02708fd171a" 241 | version = "3.3.9+8" 242 | 243 | [[FastRounding]] 244 | deps = ["ErrorfreeArithmetic", "Test"] 245 | git-tree-sha1 = "224175e213fd4fe112db3eea05d66b308dc2bf6b" 246 | uuid = "fa42c844-2597-5d31-933b-ebd51ab2693f" 247 | version = "0.2.0" 248 | 249 | [[FillArrays]] 250 | deps = ["LinearAlgebra", "Random", "SparseArrays"] 251 | git-tree-sha1 = "693210145367e7685d8604aee33d9bfb85db8b31" 252 | uuid = "1a297f60-69ca-5386-bcde-b61e274b549b" 253 | version = "0.11.9" 254 | 255 | [[FiniteDiff]] 256 | deps = ["ArrayInterface", "LinearAlgebra", "Requires", "SparseArrays", "StaticArrays"] 257 | git-tree-sha1 = "f6f80c8f934efd49a286bb5315360be66956dfc4" 258 | uuid = "6a86dc24-6348-571c-b903-95158fe2bd41" 259 | version = "2.8.0" 260 | 261 | [[FixedPointNumbers]] 262 | deps = ["Statistics"] 263 | git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc" 264 | uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" 265 | version = "0.8.4" 266 | 267 | [[Fontconfig_jll]] 268 | deps = ["Artifacts", "Bzip2_jll", "Expat_jll", "FreeType2_jll", "JLLWrappers", "Libdl", "Libuuid_jll", "Pkg", "Zlib_jll"] 269 | git-tree-sha1 = "35895cf184ceaab11fd778b4590144034a167a2f" 270 | uuid = "a3f928ae-7b40-5064-980b-68af3947d34b" 271 | version = "2.13.1+14" 272 | 273 | [[Formatting]] 274 | deps = ["Printf"] 275 | git-tree-sha1 = "8339d61043228fdd3eb658d86c926cb282ae72a8" 276 | uuid = "59287772-0a20-5a39-b81b-1366585eb4c0" 277 | version = "0.4.2" 278 | 279 | [[ForwardDiff]] 280 | deps = ["CommonSubexpressions", "DiffResults", "DiffRules", "LinearAlgebra", "NaNMath", "Printf", "Random", "SpecialFunctions", "StaticArrays"] 281 | git-tree-sha1 = "e2af66012e08966366a43251e1fd421522908be6" 282 | uuid = "f6369f11-7733-5829-9624-2563aa707210" 283 | version = "0.10.18" 284 | 285 | [[FreeType2_jll]] 286 | deps = ["Artifacts", "Bzip2_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] 287 | git-tree-sha1 = "cbd58c9deb1d304f5a245a0b7eb841a2560cfec6" 288 | uuid = "d7e528f0-a631-5988-bf34-fe36492bcfd7" 289 | version = "2.10.1+5" 290 | 291 | [[FriBidi_jll]] 292 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 293 | git-tree-sha1 = "aa31987c2ba8704e23c6c8ba8a4f769d5d7e4f91" 294 | uuid = "559328eb-81f9-559d-9380-de523a88c83c" 295 | version = "1.0.10+0" 296 | 297 | [[Future]] 298 | deps = ["Random"] 299 | uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820" 300 | 301 | [[GLFW_jll]] 302 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Libglvnd_jll", "Pkg", "Xorg_libXcursor_jll", "Xorg_libXi_jll", "Xorg_libXinerama_jll", "Xorg_libXrandr_jll"] 303 | git-tree-sha1 = "dba1e8614e98949abfa60480b13653813d8f0157" 304 | uuid = "0656b61e-2033-5cc2-a64a-77c0f6c09b89" 305 | version = "3.3.5+0" 306 | 307 | [[GR]] 308 | deps = ["Base64", "DelimitedFiles", "GR_jll", "HTTP", "JSON", "Libdl", "LinearAlgebra", "Pkg", "Printf", "Random", "Serialization", "Sockets", "Test", "UUIDs"] 309 | git-tree-sha1 = "9f473cdf6e2eb360c576f9822e7c765dd9d26dbc" 310 | uuid = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71" 311 | version = "0.58.0" 312 | 313 | [[GR_jll]] 314 | deps = ["Artifacts", "Bzip2_jll", "Cairo_jll", "FFMPEG_jll", "Fontconfig_jll", "GLFW_jll", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Libtiff_jll", "Pixman_jll", "Pkg", "Qt5Base_jll", "Zlib_jll", "libpng_jll"] 315 | git-tree-sha1 = "eaf96e05a880f3db5ded5a5a8a7817ecba3c7392" 316 | uuid = "d2c73de3-f751-5644-a686-071e5b155ba9" 317 | version = "0.58.0+0" 318 | 319 | [[GenericLinearAlgebra]] 320 | deps = ["LinearAlgebra", "Printf", "Random"] 321 | git-tree-sha1 = "ff291c1827030ffaacaf53e3c83ed92d4d5e6fb6" 322 | uuid = "14197337-ba66-59df-a3e3-ca00e7dcff7a" 323 | version = "0.2.5" 324 | 325 | [[GeometryBasics]] 326 | deps = ["EarCut_jll", "IterTools", "LinearAlgebra", "StaticArrays", "StructArrays", "Tables"] 327 | git-tree-sha1 = "15ff9a14b9e1218958d3530cc288cf31465d9ae2" 328 | uuid = "5c1252a2-5f33-56bf-86c9-59e7332b4326" 329 | version = "0.3.13" 330 | 331 | [[Gettext_jll]] 332 | deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "XML2_jll"] 333 | git-tree-sha1 = "9b02998aba7bf074d14de89f9d37ca24a1a0b046" 334 | uuid = "78b55507-aeef-58d4-861c-77aaff3498b1" 335 | version = "0.21.0+0" 336 | 337 | [[Glib_jll]] 338 | deps = ["Artifacts", "Gettext_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Libiconv_jll", "Libmount_jll", "PCRE_jll", "Pkg", "Zlib_jll"] 339 | git-tree-sha1 = "47ce50b742921377301e15005c96e979574e130b" 340 | uuid = "7746bdde-850d-59dc-9ae8-88ece973131d" 341 | version = "2.68.1+0" 342 | 343 | [[Grisu]] 344 | git-tree-sha1 = "53bb909d1151e57e2484c3d1b53e19552b887fb2" 345 | uuid = "42e2da0e-8278-4e71-bc24-59509adca0fe" 346 | version = "1.0.2" 347 | 348 | [[HTTP]] 349 | deps = ["Base64", "Dates", "IniFile", "Logging", "MbedTLS", "NetworkOptions", "Sockets", "URIs"] 350 | git-tree-sha1 = "c6a1fff2fd4b1da29d3dccaffb1e1001244d844e" 351 | uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3" 352 | version = "0.9.12" 353 | 354 | [[IfElse]] 355 | git-tree-sha1 = "28e837ff3e7a6c3cdb252ce49fb412c8eb3caeef" 356 | uuid = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173" 357 | version = "0.1.0" 358 | 359 | [[Infiltrator]] 360 | deps = ["REPL"] 361 | git-tree-sha1 = "2418a26375fb0fa5977bf4b2122b787d7097ceb2" 362 | uuid = "5903a43b-9cc3-4c30-8d17-598619ec4e9b" 363 | version = "1.0.3" 364 | 365 | [[IniFile]] 366 | deps = ["Test"] 367 | git-tree-sha1 = "098e4d2c533924c921f9f9847274f2ad89e018b8" 368 | uuid = "83e8ac13-25f8-5344-8a64-a9f2b223428f" 369 | version = "0.5.0" 370 | 371 | [[IntelOpenMP_jll]] 372 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 373 | git-tree-sha1 = "d979e54b71da82f3a65b62553da4fc3d18c9004c" 374 | uuid = "1d5cc7b8-4909-519e-a0f8-d0f5ad9712d0" 375 | version = "2018.0.3+2" 376 | 377 | [[InteractiveUtils]] 378 | deps = ["Markdown"] 379 | uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" 380 | 381 | [[Interpolations]] 382 | deps = ["AxisAlgorithms", "ChainRulesCore", "LinearAlgebra", "OffsetArrays", "Random", "Ratios", "Requires", "SharedArrays", "SparseArrays", "StaticArrays", "WoodburyMatrices"] 383 | git-tree-sha1 = "1470c80592cf1f0a35566ee5e93c5f8221ebc33a" 384 | uuid = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59" 385 | version = "0.13.3" 386 | 387 | [[IntervalArithmetic]] 388 | deps = ["CRlibm", "FastRounding", "LinearAlgebra", "Markdown", "Random", "RecipesBase", "RoundingEmulator", "SetRounding", "StaticArrays"] 389 | git-tree-sha1 = "4902a5ff073d6977e33baad4e8d5c9a77e26eabf" 390 | uuid = "d1acc4aa-44c8-5952-acd4-ba5d80a2a253" 391 | version = "0.18.2" 392 | 393 | [[Intervals]] 394 | deps = ["Dates", "Printf", "RecipesBase", "Serialization", "TimeZones"] 395 | git-tree-sha1 = "323a38ed1952d30586d0fe03412cde9399d3618b" 396 | uuid = "d8418881-c3e1-53bb-8760-2df7ec849ed5" 397 | version = "1.5.0" 398 | 399 | [[IterTools]] 400 | git-tree-sha1 = "05110a2ab1fc5f932622ffea2a003221f4782c18" 401 | uuid = "c8e1da08-722c-5040-9ed9-7db0dc04731e" 402 | version = "1.3.0" 403 | 404 | [[IterativeSolvers]] 405 | deps = ["LinearAlgebra", "Printf", "Random", "RecipesBase", "SparseArrays"] 406 | git-tree-sha1 = "1a8c6237e78b714e901e406c096fc8a65528af7d" 407 | uuid = "42fd0dbc-a981-5370-80f2-aaf504508153" 408 | version = "0.9.1" 409 | 410 | [[IteratorInterfaceExtensions]] 411 | git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856" 412 | uuid = "82899510-4779-5014-852e-03e436cf321d" 413 | version = "1.0.0" 414 | 415 | [[JLLWrappers]] 416 | deps = ["Preferences"] 417 | git-tree-sha1 = "642a199af8b68253517b80bd3bfd17eb4e84df6e" 418 | uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" 419 | version = "1.3.0" 420 | 421 | [[JSON]] 422 | deps = ["Dates", "Mmap", "Parsers", "Unicode"] 423 | git-tree-sha1 = "81690084b6198a2e1da36fcfda16eeca9f9f24e4" 424 | uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" 425 | version = "0.21.1" 426 | 427 | [[JpegTurbo_jll]] 428 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 429 | git-tree-sha1 = "d735490ac75c5cb9f1b00d8b5509c11984dc6943" 430 | uuid = "aacddb02-875f-59d6-b918-886e6ef4fbf8" 431 | version = "2.1.0+0" 432 | 433 | [[KrylovKit]] 434 | deps = ["LinearAlgebra", "Printf"] 435 | git-tree-sha1 = "0328ad9966ae29ccefb4e1b9bfd8c8867e4360df" 436 | uuid = "0b1a1467-8014-51b9-945f-bf0ae24f4b77" 437 | version = "0.5.3" 438 | 439 | [[LAME_jll]] 440 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 441 | git-tree-sha1 = "f6250b16881adf048549549fba48b1161acdac8c" 442 | uuid = "c1c5ebd0-6772-5130-a774-d5fcae4a789d" 443 | version = "3.100.1+0" 444 | 445 | [[LZO_jll]] 446 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 447 | git-tree-sha1 = "e5b909bcf985c5e2605737d2ce278ed791b89be6" 448 | uuid = "dd4b983a-f0e5-5f8d-a1b7-129d4a5fb1ac" 449 | version = "2.10.1+0" 450 | 451 | [[LaTeXStrings]] 452 | git-tree-sha1 = "c7f1c695e06c01b95a67f0cd1d34994f3e7db104" 453 | uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" 454 | version = "1.2.1" 455 | 456 | [[Latexify]] 457 | deps = ["Formatting", "InteractiveUtils", "LaTeXStrings", "MacroTools", "Markdown", "Printf", "Requires"] 458 | git-tree-sha1 = "a4b12a1bd2ebade87891ab7e36fdbce582301a92" 459 | uuid = "23fbe1c1-3f47-55db-b15f-69d7ec21a316" 460 | version = "0.15.6" 461 | 462 | [[LazyArtifacts]] 463 | deps = ["Artifacts", "Pkg"] 464 | uuid = "4af54fe1-eca0-43a8-85a7-787d91b784e3" 465 | 466 | [[LibCURL]] 467 | deps = ["LibCURL_jll", "MozillaCACerts_jll"] 468 | uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" 469 | 470 | [[LibCURL_jll]] 471 | deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] 472 | uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" 473 | 474 | [[LibGit2]] 475 | deps = ["Base64", "NetworkOptions", "Printf", "SHA"] 476 | uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" 477 | 478 | [[LibSSH2_jll]] 479 | deps = ["Artifacts", "Libdl", "MbedTLS_jll"] 480 | uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" 481 | 482 | [[LibVPX_jll]] 483 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 484 | git-tree-sha1 = "12ee7e23fa4d18361e7c2cde8f8337d4c3101bc7" 485 | uuid = "dd192d2f-8180-539f-9fb4-cc70b1dcf69a" 486 | version = "1.10.0+0" 487 | 488 | [[Libdl]] 489 | uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" 490 | 491 | [[Libffi_jll]] 492 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 493 | git-tree-sha1 = "761a393aeccd6aa92ec3515e428c26bf99575b3b" 494 | uuid = "e9f186c6-92d2-5b65-8a66-fee21dc1b490" 495 | version = "3.2.2+0" 496 | 497 | [[Libgcrypt_jll]] 498 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgpg_error_jll", "Pkg"] 499 | git-tree-sha1 = "64613c82a59c120435c067c2b809fc61cf5166ae" 500 | uuid = "d4300ac3-e22c-5743-9152-c294e39db1e4" 501 | version = "1.8.7+0" 502 | 503 | [[Libglvnd_jll]] 504 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll", "Xorg_libXext_jll"] 505 | git-tree-sha1 = "7739f837d6447403596a75d19ed01fd08d6f56bf" 506 | uuid = "7e76a0d4-f3c7-5321-8279-8d96eeed0f29" 507 | version = "1.3.0+3" 508 | 509 | [[Libgpg_error_jll]] 510 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 511 | git-tree-sha1 = "c333716e46366857753e273ce6a69ee0945a6db9" 512 | uuid = "7add5ba3-2f88-524e-9cd5-f83b8a55f7b8" 513 | version = "1.42.0+0" 514 | 515 | [[Libiconv_jll]] 516 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 517 | git-tree-sha1 = "42b62845d70a619f063a7da093d995ec8e15e778" 518 | uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531" 519 | version = "1.16.1+1" 520 | 521 | [[Libmount_jll]] 522 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 523 | git-tree-sha1 = "9c30530bf0effd46e15e0fdcf2b8636e78cbbd73" 524 | uuid = "4b2f31a3-9ecc-558c-b454-b3730dcb73e9" 525 | version = "2.35.0+0" 526 | 527 | [[Libtiff_jll]] 528 | deps = ["Artifacts", "JLLWrappers", "JpegTurbo_jll", "Libdl", "Pkg", "Zlib_jll", "Zstd_jll"] 529 | git-tree-sha1 = "340e257aada13f95f98ee352d316c3bed37c8ab9" 530 | uuid = "89763e89-9b03-5906-acba-b20f662cd828" 531 | version = "4.3.0+0" 532 | 533 | [[Libuuid_jll]] 534 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 535 | git-tree-sha1 = "7f3efec06033682db852f8b3bc3c1d2b0a0ab066" 536 | uuid = "38a345b3-de98-5d2b-a5d3-14cd9215e700" 537 | version = "2.36.0+0" 538 | 539 | [[Libxc]] 540 | deps = ["Libxc_jll"] 541 | git-tree-sha1 = "15fc54f2d0f39e80791df8e222e933c54fcda970" 542 | uuid = "66e17ffc-8502-11e9-23b5-c9248d0eb96d" 543 | version = "0.3.6" 544 | 545 | [[Libxc_jll]] 546 | deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] 547 | git-tree-sha1 = "d64d26f40adf21cb2844a04ac770b6da1e4f6489" 548 | uuid = "a56a6d9d-ad03-58af-ab61-878bf78270d6" 549 | version = "5.1.5+2" 550 | 551 | [[LineSearches]] 552 | deps = ["LinearAlgebra", "NLSolversBase", "NaNMath", "Parameters", "Printf"] 553 | git-tree-sha1 = "f27132e551e959b3667d8c93eae90973225032dd" 554 | uuid = "d3d80556-e9d4-5f37-9878-2ab0fcc64255" 555 | version = "7.1.1" 556 | 557 | [[LinearAlgebra]] 558 | deps = ["Libdl"] 559 | uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" 560 | 561 | [[LinearMaps]] 562 | deps = ["LinearAlgebra", "SparseArrays"] 563 | git-tree-sha1 = "0a7c8fb69162e88412540b6c7bb28691e219372d" 564 | uuid = "7a12625a-238d-50fd-b39a-03d52299707e" 565 | version = "3.4.0" 566 | 567 | [[LogExpFunctions]] 568 | deps = ["DocStringExtensions", "LinearAlgebra"] 569 | git-tree-sha1 = "7bd5f6565d80b6bf753738d2bc40a5dfea072070" 570 | uuid = "2ab3a3ac-af41-5b50-aa03-7779005ae688" 571 | version = "0.2.5" 572 | 573 | [[Logging]] 574 | uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" 575 | 576 | [[MKL_jll]] 577 | deps = ["Artifacts", "IntelOpenMP_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "Pkg"] 578 | git-tree-sha1 = "c253236b0ed414624b083e6b72bfe891fbd2c7af" 579 | uuid = "856f044c-d86e-5d09-b602-aeab76dc8ba7" 580 | version = "2021.1.1+1" 581 | 582 | [[MPI]] 583 | deps = ["Distributed", "DocStringExtensions", "Libdl", "MPICH_jll", "MicrosoftMPI_jll", "OpenMPI_jll", "Pkg", "Random", "Requires", "Serialization", "Sockets"] 584 | git-tree-sha1 = "00488c6fcaf828685c2bc5139bf0afff8c15c982" 585 | uuid = "da04e1cc-30fd-572f-bb4f-1f8673147195" 586 | version = "0.18.2" 587 | 588 | [[MPICH_jll]] 589 | deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] 590 | git-tree-sha1 = "c6cafe3f9747c0a0740611e2dffc4d37248fb691" 591 | uuid = "7cb0a576-ebde-5e09-9194-50597f1243b4" 592 | version = "3.4.2+0" 593 | 594 | [[MacroTools]] 595 | deps = ["Markdown", "Random"] 596 | git-tree-sha1 = "6a8a2a625ab0dea913aba95c11370589e0239ff0" 597 | uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" 598 | version = "0.5.6" 599 | 600 | [[Markdown]] 601 | deps = ["Base64"] 602 | uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" 603 | 604 | [[MbedTLS]] 605 | deps = ["Dates", "MbedTLS_jll", "Random", "Sockets"] 606 | git-tree-sha1 = "1c38e51c3d08ef2278062ebceade0e46cefc96fe" 607 | uuid = "739be429-bea8-5141-9913-cc70e7f3736d" 608 | version = "1.0.3" 609 | 610 | [[MbedTLS_jll]] 611 | deps = ["Artifacts", "Libdl"] 612 | uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" 613 | 614 | [[Measures]] 615 | git-tree-sha1 = "e498ddeee6f9fdb4551ce855a46f54dbd900245f" 616 | uuid = "442fdcdd-2543-5da2-b0f3-8c86c306513e" 617 | version = "0.3.1" 618 | 619 | [[MicrosoftMPI_jll]] 620 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 621 | git-tree-sha1 = "e5c90234b3967684c9c6f87b4a54549b4ce21836" 622 | uuid = "9237b28f-5490-5468-be7b-bb81f5f5e6cf" 623 | version = "10.1.3+0" 624 | 625 | [[Missings]] 626 | deps = ["DataAPI"] 627 | git-tree-sha1 = "4ea90bd5d3985ae1f9a908bd4500ae88921c5ce7" 628 | uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28" 629 | version = "1.0.0" 630 | 631 | [[Mmap]] 632 | uuid = "a63ad114-7e13-5084-954f-fe012c677804" 633 | 634 | [[Mocking]] 635 | deps = ["ExprTools"] 636 | git-tree-sha1 = "916b850daad0d46b8c71f65f719c49957e9513ed" 637 | uuid = "78c3b35d-d492-501b-9361-3d52fe80e533" 638 | version = "0.7.1" 639 | 640 | [[MozillaCACerts_jll]] 641 | uuid = "14a3606d-f60d-562e-9121-12d972cd8159" 642 | 643 | [[MutableArithmetics]] 644 | deps = ["LinearAlgebra", "SparseArrays", "Test"] 645 | git-tree-sha1 = "3927848ccebcc165952dc0d9ac9aa274a87bfe01" 646 | uuid = "d8a4904e-b15c-11e9-3269-09a3773c0cb0" 647 | version = "0.2.20" 648 | 649 | [[NLSolversBase]] 650 | deps = ["DiffResults", "Distributed", "FiniteDiff", "ForwardDiff"] 651 | git-tree-sha1 = "50608f411a1e178e0129eab4110bd56efd08816f" 652 | uuid = "d41bc354-129a-5804-8e4c-c37616107c6c" 653 | version = "7.8.0" 654 | 655 | [[NLsolve]] 656 | deps = ["Distances", "LineSearches", "LinearAlgebra", "NLSolversBase", "Printf", "Reexport"] 657 | git-tree-sha1 = "019f12e9a1a7880459d0173c182e6a99365d7ac1" 658 | uuid = "2774e3e8-f4cf-5e23-947b-6d7e65073b56" 659 | version = "4.5.1" 660 | 661 | [[NaNMath]] 662 | git-tree-sha1 = "bfe47e760d60b82b66b61d2d44128b62e3a369fb" 663 | uuid = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3" 664 | version = "0.3.5" 665 | 666 | [[NetworkOptions]] 667 | uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" 668 | 669 | [[OffsetArrays]] 670 | deps = ["Adapt"] 671 | git-tree-sha1 = "4f825c6da64aebaa22cc058ecfceed1ab9af1c7e" 672 | uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" 673 | version = "1.10.3" 674 | 675 | [[Ogg_jll]] 676 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 677 | git-tree-sha1 = "7937eda4681660b4d6aeeecc2f7e1c81c8ee4e2f" 678 | uuid = "e7412a2a-1a6e-54c0-be00-318e2571c051" 679 | version = "1.3.5+0" 680 | 681 | [[OpenMPI_jll]] 682 | deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] 683 | git-tree-sha1 = "e0914cbfcc96f1b9097ca99cef1ae73a7b0efda9" 684 | uuid = "fe0851c0-eecd-5654-98d4-656369965a5c" 685 | version = "4.1.1+1" 686 | 687 | [[OpenSSL_jll]] 688 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 689 | git-tree-sha1 = "15003dcb7d8db3c6c857fda14891a539a8f2705a" 690 | uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" 691 | version = "1.1.10+0" 692 | 693 | [[OpenSpecFun_jll]] 694 | deps = ["Artifacts", "CompilerSupportLibraries_jll", "JLLWrappers", "Libdl", "Pkg"] 695 | git-tree-sha1 = "13652491f6856acfd2db29360e1bbcd4565d04f1" 696 | uuid = "efe28fd5-8261-553b-a9e1-b2916fc3738e" 697 | version = "0.5.5+0" 698 | 699 | [[Optim]] 700 | deps = ["Compat", "FillArrays", "LineSearches", "LinearAlgebra", "NLSolversBase", "NaNMath", "Parameters", "PositiveFactorizations", "Printf", "SparseArrays", "StatsBase"] 701 | git-tree-sha1 = "d34366a3abc25c41f88820762ef7dfdfe9306711" 702 | uuid = "429524aa-4258-5aef-a3af-852621145aeb" 703 | version = "1.3.0" 704 | 705 | [[Opus_jll]] 706 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 707 | git-tree-sha1 = "51a08fb14ec28da2ec7a927c4337e4332c2a4720" 708 | uuid = "91d4177d-7536-5919-b921-800302f37372" 709 | version = "1.3.2+0" 710 | 711 | [[OrderedCollections]] 712 | git-tree-sha1 = "85f8e6578bf1f9ee0d11e7bb1b1456435479d47c" 713 | uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" 714 | version = "1.4.1" 715 | 716 | [[PCRE_jll]] 717 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 718 | git-tree-sha1 = "b2a7af664e098055a7529ad1a900ded962bca488" 719 | uuid = "2f80f16e-611a-54ab-bc61-aa92de5b98fc" 720 | version = "8.44.0+0" 721 | 722 | [[Parameters]] 723 | deps = ["OrderedCollections", "UnPack"] 724 | git-tree-sha1 = "2276ac65f1e236e0a6ea70baff3f62ad4c625345" 725 | uuid = "d96e819e-fc66-5662-9728-84c9c7592b0a" 726 | version = "0.12.2" 727 | 728 | [[Parsers]] 729 | deps = ["Dates"] 730 | git-tree-sha1 = "c8abc88faa3f7a3950832ac5d6e690881590d6dc" 731 | uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" 732 | version = "1.1.0" 733 | 734 | [[PeriodicTable]] 735 | deps = ["Base64", "Test", "Unitful"] 736 | git-tree-sha1 = "067ef5738ef3157f29749c32b64f0ff9b3d07ab2" 737 | uuid = "7b2266bf-644c-5ea3-82d8-af4bbd25a884" 738 | version = "1.1.0" 739 | 740 | [[Pixman_jll]] 741 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 742 | git-tree-sha1 = "b4f5d02549a10e20780a24fce72bea96b6329e29" 743 | uuid = "30392449-352a-5448-841d-b1acce4e97dc" 744 | version = "0.40.1+0" 745 | 746 | [[Pkg]] 747 | deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] 748 | uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" 749 | 750 | [[PlotThemes]] 751 | deps = ["PlotUtils", "Requires", "Statistics"] 752 | git-tree-sha1 = "a3a964ce9dc7898193536002a6dd892b1b5a6f1d" 753 | uuid = "ccf2f8ad-2431-5c83-bf29-c5338b663b6a" 754 | version = "2.0.1" 755 | 756 | [[PlotUtils]] 757 | deps = ["ColorSchemes", "Colors", "Dates", "Printf", "Random", "Reexport", "Statistics"] 758 | git-tree-sha1 = "501c20a63a34ac1d015d5304da0e645f42d91c9f" 759 | uuid = "995b91a9-d308-5afd-9ec6-746e21dbc043" 760 | version = "1.0.11" 761 | 762 | [[Plots]] 763 | deps = ["Base64", "Contour", "Dates", "FFMPEG", "FixedPointNumbers", "GR", "GeometryBasics", "JSON", "Latexify", "LinearAlgebra", "Measures", "NaNMath", "PlotThemes", "PlotUtils", "Printf", "REPL", "Random", "RecipesBase", "RecipesPipeline", "Reexport", "Requires", "Scratch", "Showoff", "SparseArrays", "Statistics", "StatsBase", "UUIDs"] 764 | git-tree-sha1 = "f3d4d35b8cb87adc844c05c722f505776ac29988" 765 | uuid = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" 766 | version = "1.19.2" 767 | 768 | [[Polynomials]] 769 | deps = ["Intervals", "LinearAlgebra", "MutableArithmetics", "RecipesBase"] 770 | git-tree-sha1 = "0bbfdcd8cda81b8144de4be8a67f5717e959a005" 771 | uuid = "f27b6e38-b328-58d1-80ce-0feddd5e7a45" 772 | version = "2.0.14" 773 | 774 | [[PositiveFactorizations]] 775 | deps = ["LinearAlgebra"] 776 | git-tree-sha1 = "17275485f373e6673f7e7f97051f703ed5b15b20" 777 | uuid = "85a6dd25-e78a-55b7-8502-1745935b8125" 778 | version = "0.2.4" 779 | 780 | [[Preferences]] 781 | deps = ["TOML"] 782 | git-tree-sha1 = "00cfd92944ca9c760982747e9a1d0d5d86ab1e5a" 783 | uuid = "21216c6a-2e73-6563-6e65-726566657250" 784 | version = "1.2.2" 785 | 786 | [[Primes]] 787 | git-tree-sha1 = "afccf037da52fa596223e5a0e331ff752e0e845c" 788 | uuid = "27ebfcd6-29c5-5fa9-bf4b-fb8fc14df3ae" 789 | version = "0.5.0" 790 | 791 | [[Printf]] 792 | deps = ["Unicode"] 793 | uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" 794 | 795 | [[ProgressMeter]] 796 | deps = ["Distributed", "Printf"] 797 | git-tree-sha1 = "afadeba63d90ff223a6a48d2009434ecee2ec9e8" 798 | uuid = "92933f4c-e287-5a05-a399-4b506db050ca" 799 | version = "1.7.1" 800 | 801 | [[PyCall]] 802 | deps = ["Conda", "Dates", "Libdl", "LinearAlgebra", "MacroTools", "Serialization", "VersionParsing"] 803 | git-tree-sha1 = "169bb8ea6b1b143c5cf57df6d34d022a7b60c6db" 804 | uuid = "438e738f-606a-5dbb-bf0a-cddfbfd45ab0" 805 | version = "1.92.3" 806 | 807 | [[Qt5Base_jll]] 808 | deps = ["Artifacts", "CompilerSupportLibraries_jll", "Fontconfig_jll", "Glib_jll", "JLLWrappers", "Libdl", "Libglvnd_jll", "OpenSSL_jll", "Pkg", "Xorg_libXext_jll", "Xorg_libxcb_jll", "Xorg_xcb_util_image_jll", "Xorg_xcb_util_keysyms_jll", "Xorg_xcb_util_renderutil_jll", "Xorg_xcb_util_wm_jll", "Zlib_jll", "xkbcommon_jll"] 809 | git-tree-sha1 = "ad368663a5e20dbb8d6dc2fddeefe4dae0781ae8" 810 | uuid = "ea2cea3b-5b76-57ae-a6ef-0a8af62496e1" 811 | version = "5.15.3+0" 812 | 813 | [[Quadmath]] 814 | deps = ["Printf", "Random", "Requires"] 815 | git-tree-sha1 = "5a8f74af8eae654086a1d058b4ec94ff192e3de0" 816 | uuid = "be4d8f0f-7fa4-5f49-b795-2f01399ab2dd" 817 | version = "0.5.5" 818 | 819 | [[REPL]] 820 | deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] 821 | uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" 822 | 823 | [[Random]] 824 | deps = ["Serialization"] 825 | uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" 826 | 827 | [[Ratios]] 828 | git-tree-sha1 = "37d210f612d70f3f7d57d488cb3b6eff56ad4e41" 829 | uuid = "c84ed2f1-dad5-54f0-aa8e-dbefe2724439" 830 | version = "0.4.0" 831 | 832 | [[RecipesBase]] 833 | git-tree-sha1 = "b3fb709f3c97bfc6e948be68beeecb55a0b340ae" 834 | uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" 835 | version = "1.1.1" 836 | 837 | [[RecipesPipeline]] 838 | deps = ["Dates", "NaNMath", "PlotUtils", "RecipesBase"] 839 | git-tree-sha1 = "2a7a2469ed5d94a98dea0e85c46fa653d76be0cd" 840 | uuid = "01d81517-befc-4cb6-b9ec-a95719d0359c" 841 | version = "0.3.4" 842 | 843 | [[Reexport]] 844 | git-tree-sha1 = "5f6c21241f0f655da3952fd60aa18477cf96c220" 845 | uuid = "189a3867-3050-52da-a836-e630ba90ab69" 846 | version = "1.1.0" 847 | 848 | [[Requires]] 849 | deps = ["UUIDs"] 850 | git-tree-sha1 = "4036a3bd08ac7e968e27c203d45f5fff15020621" 851 | uuid = "ae029012-a4dd-5104-9daa-d747884805df" 852 | version = "1.1.3" 853 | 854 | [[Roots]] 855 | deps = ["CommonSolve", "Printf"] 856 | git-tree-sha1 = "4d64e7c43eca16edee87219b0b11f167f09c2d84" 857 | uuid = "f2b01f46-fcfa-551c-844a-d8ac1e96c665" 858 | version = "1.0.9" 859 | 860 | [[RoundingEmulator]] 861 | git-tree-sha1 = "40b9edad2e5287e05bd413a38f61a8ff55b9557b" 862 | uuid = "5eaf0fd0-dfba-4ccb-bf02-d820a40db705" 863 | version = "0.2.1" 864 | 865 | [[SHA]] 866 | uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" 867 | 868 | [[Scratch]] 869 | deps = ["Dates"] 870 | git-tree-sha1 = "0b4b7f1393cff97c33891da2a0bf69c6ed241fda" 871 | uuid = "6c6a2e73-6563-6170-7368-637461726353" 872 | version = "1.1.0" 873 | 874 | [[Serialization]] 875 | uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" 876 | 877 | [[SetRounding]] 878 | git-tree-sha1 = "d7a25e439d07a17b7cdf97eecee504c50fedf5f6" 879 | uuid = "3cc68bcd-71a2-5612-b932-767ffbe40ab0" 880 | version = "0.2.1" 881 | 882 | [[SharedArrays]] 883 | deps = ["Distributed", "Mmap", "Random", "Serialization"] 884 | uuid = "1a1011a3-84de-559e-8e89-a11a2f7dc383" 885 | 886 | [[Showoff]] 887 | deps = ["Dates", "Grisu"] 888 | git-tree-sha1 = "91eddf657aca81df9ae6ceb20b959ae5653ad1de" 889 | uuid = "992d4aef-0814-514b-bc4d-f2e9a6c4116f" 890 | version = "1.0.3" 891 | 892 | [[Sockets]] 893 | uuid = "6462fe0b-24de-5631-8697-dd941f90decc" 894 | 895 | [[SortingAlgorithms]] 896 | deps = ["DataStructures"] 897 | git-tree-sha1 = "b3363d7460f7d098ca0912c69b082f75625d7508" 898 | uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c" 899 | version = "1.0.1" 900 | 901 | [[SparseArrays]] 902 | deps = ["LinearAlgebra", "Random"] 903 | uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" 904 | 905 | [[SpecialFunctions]] 906 | deps = ["ChainRulesCore", "LogExpFunctions", "OpenSpecFun_jll"] 907 | git-tree-sha1 = "a50550fa3164a8c46747e62063b4d774ac1bcf49" 908 | uuid = "276daf66-3868-5448-9aa4-cd146d93841b" 909 | version = "1.5.1" 910 | 911 | [[Static]] 912 | deps = ["IfElse"] 913 | git-tree-sha1 = "62701892d172a2fa41a1f829f66d2b0db94a9a63" 914 | uuid = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" 915 | version = "0.3.0" 916 | 917 | [[StaticArrays]] 918 | deps = ["LinearAlgebra", "Random", "Statistics"] 919 | git-tree-sha1 = "1b9a0f17ee0adde9e538227de093467348992397" 920 | uuid = "90137ffa-7385-5640-81b9-e52037218182" 921 | version = "1.2.7" 922 | 923 | [[Statistics]] 924 | deps = ["LinearAlgebra", "SparseArrays"] 925 | uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" 926 | 927 | [[StatsAPI]] 928 | git-tree-sha1 = "1958272568dc176a1d881acb797beb909c785510" 929 | uuid = "82ae8749-77ed-4fe6-ae5f-f523153014b0" 930 | version = "1.0.0" 931 | 932 | [[StatsBase]] 933 | deps = ["DataAPI", "DataStructures", "LinearAlgebra", "Missings", "Printf", "Random", "SortingAlgorithms", "SparseArrays", "Statistics", "StatsAPI"] 934 | git-tree-sha1 = "2f6792d523d7448bbe2fec99eca9218f06cc746d" 935 | uuid = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91" 936 | version = "0.33.8" 937 | 938 | [[StructArrays]] 939 | deps = ["Adapt", "DataAPI", "StaticArrays", "Tables"] 940 | git-tree-sha1 = "000e168f5cc9aded17b6999a560b7c11dda69095" 941 | uuid = "09ab397b-f2b6-538f-b94a-2f83cf4a842a" 942 | version = "0.6.0" 943 | 944 | [[TOML]] 945 | deps = ["Dates"] 946 | uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" 947 | 948 | [[TableTraits]] 949 | deps = ["IteratorInterfaceExtensions"] 950 | git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39" 951 | uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c" 952 | version = "1.0.1" 953 | 954 | [[Tables]] 955 | deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "TableTraits", "Test"] 956 | git-tree-sha1 = "8ed4a3ea724dac32670b062be3ef1c1de6773ae8" 957 | uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" 958 | version = "1.4.4" 959 | 960 | [[Tar]] 961 | deps = ["ArgTools", "SHA"] 962 | uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" 963 | 964 | [[Test]] 965 | deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] 966 | uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" 967 | 968 | [[TimeZones]] 969 | deps = ["Dates", "Future", "LazyArtifacts", "Mocking", "Pkg", "Printf", "RecipesBase", "Serialization", "Unicode"] 970 | git-tree-sha1 = "81753f400872e5074768c9a77d4c44e70d409ef0" 971 | uuid = "f269a46b-ccf7-5d73-abea-4c690281aa53" 972 | version = "1.5.6" 973 | 974 | [[TimerOutputs]] 975 | deps = ["ExprTools", "Printf"] 976 | git-tree-sha1 = "209a8326c4f955e2442c07b56029e88bb48299c7" 977 | uuid = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f" 978 | version = "0.5.12" 979 | 980 | [[URIs]] 981 | git-tree-sha1 = "97bbe755a53fe859669cd907f2d96aee8d2c1355" 982 | uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" 983 | version = "1.3.0" 984 | 985 | [[UUIDs]] 986 | deps = ["Random", "SHA"] 987 | uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" 988 | 989 | [[UnPack]] 990 | git-tree-sha1 = "387c1f73762231e86e0c9c5443ce3b4a0a9a0c2b" 991 | uuid = "3a884ed6-31ef-47d7-9d2a-63182c4928ed" 992 | version = "1.0.2" 993 | 994 | [[Unicode]] 995 | uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" 996 | 997 | [[Unitful]] 998 | deps = ["ConstructionBase", "Dates", "LinearAlgebra", "Random"] 999 | git-tree-sha1 = "a981a8ef8714cba2fd9780b22fd7a469e7aaf56d" 1000 | uuid = "1986cc42-f94f-5a68-af5c-568840ba703d" 1001 | version = "1.9.0" 1002 | 1003 | [[UnitfulAtomic]] 1004 | deps = ["Unitful"] 1005 | git-tree-sha1 = "903be579194534af1c4b4778d1ace676ca042238" 1006 | uuid = "a7773ee8-282e-5fa2-be4e-bd808c38a91a" 1007 | version = "1.0.0" 1008 | 1009 | [[VersionParsing]] 1010 | git-tree-sha1 = "80229be1f670524750d905f8fc8148e5a8c4537f" 1011 | uuid = "81def892-9a0e-5fdd-b105-ffc91e053289" 1012 | version = "1.2.0" 1013 | 1014 | [[Wayland_jll]] 1015 | deps = ["Artifacts", "Expat_jll", "JLLWrappers", "Libdl", "Libffi_jll", "Pkg", "XML2_jll"] 1016 | git-tree-sha1 = "3e61f0b86f90dacb0bc0e73a0c5a83f6a8636e23" 1017 | uuid = "a2964d1f-97da-50d4-b82a-358c7fce9d89" 1018 | version = "1.19.0+0" 1019 | 1020 | [[Wayland_protocols_jll]] 1021 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll"] 1022 | git-tree-sha1 = "2839f1c1296940218e35df0bbb220f2a79686670" 1023 | uuid = "2381bf8a-dfd0-557d-9999-79630e7b1b91" 1024 | version = "1.18.0+4" 1025 | 1026 | [[WoodburyMatrices]] 1027 | deps = ["LinearAlgebra", "SparseArrays"] 1028 | git-tree-sha1 = "59e2ad8fd1591ea019a5259bd012d7aee15f995c" 1029 | uuid = "efce3f68-66dc-5838-9240-27a6d6f5f9b6" 1030 | version = "0.5.3" 1031 | 1032 | [[XML2_jll]] 1033 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Pkg", "Zlib_jll"] 1034 | git-tree-sha1 = "1acf5bdf07aa0907e0a37d3718bb88d4b687b74a" 1035 | uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a" 1036 | version = "2.9.12+0" 1037 | 1038 | [[XSLT_jll]] 1039 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Libgcrypt_jll", "Libgpg_error_jll", "Libiconv_jll", "Pkg", "XML2_jll", "Zlib_jll"] 1040 | git-tree-sha1 = "91844873c4085240b95e795f692c4cec4d805f8a" 1041 | uuid = "aed1982a-8fda-507f-9586-7b0439959a61" 1042 | version = "1.1.34+0" 1043 | 1044 | [[Xorg_libX11_jll]] 1045 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll", "Xorg_xtrans_jll"] 1046 | git-tree-sha1 = "5be649d550f3f4b95308bf0183b82e2582876527" 1047 | uuid = "4f6342f7-b3d2-589e-9d20-edeb45f2b2bc" 1048 | version = "1.6.9+4" 1049 | 1050 | [[Xorg_libXau_jll]] 1051 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 1052 | git-tree-sha1 = "4e490d5c960c314f33885790ed410ff3a94ce67e" 1053 | uuid = "0c0b7dd1-d40b-584c-a123-a41640f87eec" 1054 | version = "1.0.9+4" 1055 | 1056 | [[Xorg_libXcursor_jll]] 1057 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXfixes_jll", "Xorg_libXrender_jll"] 1058 | git-tree-sha1 = "12e0eb3bc634fa2080c1c37fccf56f7c22989afd" 1059 | uuid = "935fb764-8cf2-53bf-bb30-45bb1f8bf724" 1060 | version = "1.2.0+4" 1061 | 1062 | [[Xorg_libXdmcp_jll]] 1063 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 1064 | git-tree-sha1 = "4fe47bd2247248125c428978740e18a681372dd4" 1065 | uuid = "a3789734-cfe1-5b06-b2d0-1dd0d9d62d05" 1066 | version = "1.1.3+4" 1067 | 1068 | [[Xorg_libXext_jll]] 1069 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] 1070 | git-tree-sha1 = "b7c0aa8c376b31e4852b360222848637f481f8c3" 1071 | uuid = "1082639a-0dae-5f34-9b06-72781eeb8cb3" 1072 | version = "1.3.4+4" 1073 | 1074 | [[Xorg_libXfixes_jll]] 1075 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] 1076 | git-tree-sha1 = "0e0dc7431e7a0587559f9294aeec269471c991a4" 1077 | uuid = "d091e8ba-531a-589c-9de9-94069b037ed8" 1078 | version = "5.0.3+4" 1079 | 1080 | [[Xorg_libXi_jll]] 1081 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXfixes_jll"] 1082 | git-tree-sha1 = "89b52bc2160aadc84d707093930ef0bffa641246" 1083 | uuid = "a51aa0fd-4e3c-5386-b890-e753decda492" 1084 | version = "1.7.10+4" 1085 | 1086 | [[Xorg_libXinerama_jll]] 1087 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll"] 1088 | git-tree-sha1 = "26be8b1c342929259317d8b9f7b53bf2bb73b123" 1089 | uuid = "d1454406-59df-5ea1-beac-c340f2130bc3" 1090 | version = "1.1.4+4" 1091 | 1092 | [[Xorg_libXrandr_jll]] 1093 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libXext_jll", "Xorg_libXrender_jll"] 1094 | git-tree-sha1 = "34cea83cb726fb58f325887bf0612c6b3fb17631" 1095 | uuid = "ec84b674-ba8e-5d96-8ba1-2a689ba10484" 1096 | version = "1.5.2+4" 1097 | 1098 | [[Xorg_libXrender_jll]] 1099 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] 1100 | git-tree-sha1 = "19560f30fd49f4d4efbe7002a1037f8c43d43b96" 1101 | uuid = "ea2f1a96-1ddc-540d-b46f-429655e07cfa" 1102 | version = "0.9.10+4" 1103 | 1104 | [[Xorg_libpthread_stubs_jll]] 1105 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 1106 | git-tree-sha1 = "6783737e45d3c59a4a4c4091f5f88cdcf0908cbb" 1107 | uuid = "14d82f49-176c-5ed1-bb49-ad3f5cbd8c74" 1108 | version = "0.1.0+3" 1109 | 1110 | [[Xorg_libxcb_jll]] 1111 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "XSLT_jll", "Xorg_libXau_jll", "Xorg_libXdmcp_jll", "Xorg_libpthread_stubs_jll"] 1112 | git-tree-sha1 = "daf17f441228e7a3833846cd048892861cff16d6" 1113 | uuid = "c7cfdc94-dc32-55de-ac96-5a1b8d977c5b" 1114 | version = "1.13.0+3" 1115 | 1116 | [[Xorg_libxkbfile_jll]] 1117 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libX11_jll"] 1118 | git-tree-sha1 = "926af861744212db0eb001d9e40b5d16292080b2" 1119 | uuid = "cc61e674-0454-545c-8b26-ed2c68acab7a" 1120 | version = "1.1.0+4" 1121 | 1122 | [[Xorg_xcb_util_image_jll]] 1123 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] 1124 | git-tree-sha1 = "0fab0a40349ba1cba2c1da699243396ff8e94b97" 1125 | uuid = "12413925-8142-5f55-bb0e-6d7ca50bb09b" 1126 | version = "0.4.0+1" 1127 | 1128 | [[Xorg_xcb_util_jll]] 1129 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxcb_jll"] 1130 | git-tree-sha1 = "e7fd7b2881fa2eaa72717420894d3938177862d1" 1131 | uuid = "2def613f-5ad1-5310-b15b-b15d46f528f5" 1132 | version = "0.4.0+1" 1133 | 1134 | [[Xorg_xcb_util_keysyms_jll]] 1135 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] 1136 | git-tree-sha1 = "d1151e2c45a544f32441a567d1690e701ec89b00" 1137 | uuid = "975044d2-76e6-5fbe-bf08-97ce7c6574c7" 1138 | version = "0.4.0+1" 1139 | 1140 | [[Xorg_xcb_util_renderutil_jll]] 1141 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] 1142 | git-tree-sha1 = "dfd7a8f38d4613b6a575253b3174dd991ca6183e" 1143 | uuid = "0d47668e-0667-5a69-a72c-f761630bfb7e" 1144 | version = "0.3.9+1" 1145 | 1146 | [[Xorg_xcb_util_wm_jll]] 1147 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xcb_util_jll"] 1148 | git-tree-sha1 = "e78d10aab01a4a154142c5006ed44fd9e8e31b67" 1149 | uuid = "c22f9ab0-d5fe-5066-847c-f4bb1cd4e361" 1150 | version = "0.4.1+1" 1151 | 1152 | [[Xorg_xkbcomp_jll]] 1153 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_libxkbfile_jll"] 1154 | git-tree-sha1 = "4bcbf660f6c2e714f87e960a171b119d06ee163b" 1155 | uuid = "35661453-b289-5fab-8a00-3d9160c6a3a4" 1156 | version = "1.4.2+4" 1157 | 1158 | [[Xorg_xkeyboard_config_jll]] 1159 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Xorg_xkbcomp_jll"] 1160 | git-tree-sha1 = "5c8424f8a67c3f2209646d4425f3d415fee5931d" 1161 | uuid = "33bec58e-1273-512f-9401-5d533626f822" 1162 | version = "2.27.0+4" 1163 | 1164 | [[Xorg_xtrans_jll]] 1165 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 1166 | git-tree-sha1 = "79c31e7844f6ecf779705fbc12146eb190b7d845" 1167 | uuid = "c5fb5394-a638-5e4d-96e5-b29de1b5cf10" 1168 | version = "1.4.0+3" 1169 | 1170 | [[Zlib_jll]] 1171 | deps = ["Libdl"] 1172 | uuid = "83775a58-1f1d-513f-b197-d71354ab007a" 1173 | 1174 | [[Zstd_jll]] 1175 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 1176 | git-tree-sha1 = "cc4bf3fdde8b7e3e9fa0351bdeedba1cf3b7f6e6" 1177 | uuid = "3161d3a3-bdf6-5164-811a-617609db77b4" 1178 | version = "1.5.0+0" 1179 | 1180 | [[libass_jll]] 1181 | deps = ["Artifacts", "Bzip2_jll", "FreeType2_jll", "FriBidi_jll", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] 1182 | git-tree-sha1 = "acc685bcf777b2202a904cdcb49ad34c2fa1880c" 1183 | uuid = "0ac62f75-1d6f-5e53-bd7c-93b484bb37c0" 1184 | version = "0.14.0+4" 1185 | 1186 | [[libfdk_aac_jll]] 1187 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 1188 | git-tree-sha1 = "7a5780a0d9c6864184b3a2eeeb833a0c871f00ab" 1189 | uuid = "f638f0a6-7fb0-5443-88ba-1cc74229b280" 1190 | version = "0.1.6+4" 1191 | 1192 | [[libpng_jll]] 1193 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Zlib_jll"] 1194 | git-tree-sha1 = "94d180a6d2b5e55e447e2d27a29ed04fe79eb30c" 1195 | uuid = "b53b4c65-9356-5827-b1ea-8c7a1a84506f" 1196 | version = "1.6.38+0" 1197 | 1198 | [[libvorbis_jll]] 1199 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Ogg_jll", "Pkg"] 1200 | git-tree-sha1 = "c45f4e40e7aafe9d086379e5578947ec8b95a8fb" 1201 | uuid = "f27f6e37-5d2b-51aa-960f-b287f2bc3b7a" 1202 | version = "1.3.7+0" 1203 | 1204 | [[nghttp2_jll]] 1205 | deps = ["Artifacts", "Libdl"] 1206 | uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" 1207 | 1208 | [[p7zip_jll]] 1209 | deps = ["Artifacts", "Libdl"] 1210 | uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" 1211 | 1212 | [[spglib_jll]] 1213 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 1214 | git-tree-sha1 = "6d5c2cb4619005487c21a910d168e91b85e72abd" 1215 | uuid = "ac4a9f1e-bdb2-5204-990c-47c8b2f70d4e" 1216 | version = "1.16.1+0" 1217 | 1218 | [[x264_jll]] 1219 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 1220 | git-tree-sha1 = "d713c1ce4deac133e3334ee12f4adff07f81778f" 1221 | uuid = "1270edf5-f2f9-52d2-97e9-ab00b5d0237a" 1222 | version = "2020.7.14+2" 1223 | 1224 | [[x265_jll]] 1225 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 1226 | git-tree-sha1 = "487da2f8f2f0c8ee0e83f39d13037d6bbf0a45ab" 1227 | uuid = "dfaa095f-4041-5dcd-9319-2fabd8486b76" 1228 | version = "3.0.0+3" 1229 | 1230 | [[xkbcommon_jll]] 1231 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg", "Wayland_jll", "Wayland_protocols_jll", "Xorg_libxcb_jll", "Xorg_xkeyboard_config_jll"] 1232 | git-tree-sha1 = "ece2350174195bb31de1a63bea3a41ae1aa593b6" 1233 | uuid = "d8fb68d0-12a3-5cfd-a85a-d49703b185fd" 1234 | version = "0.9.1+5" 1235 | --------------------------------------------------------------------------------