|
1 |
| -# Integrations with DFTK.jl |
2 |
| - |
3 |
| -# ----------------------------------------------------------------------------- |
4 |
| -# Integration with AtomsBase |
5 |
| -# ----------------------------------------------------------------------------- |
6 |
| - |
7 |
| -# ! all functions in this section are copied directly from experimental DFTK code |
8 |
| -# ! this code will be deleted once it is live in DFTK |
9 |
| - |
10 |
| -function parse_system(system::AbstractSystem{3}) |
11 |
| - if !all(periodicity(system)) |
12 |
| - error("DFTK only supports calculations with periodic boundary conditions.") |
13 |
| - end |
14 |
| - |
15 |
| - # Parse abstract system and return data required to construct model |
16 |
| - lattice = austrip.(hcat(bounding_box(system)...)) |
17 |
| - T = eltype(lattice) |
18 |
| - |
19 |
| - # Cache for instantiated pseudopotentials |
20 |
| - # (such that the respective objects are indistinguishable) |
21 |
| - cached_pseudos = Dict{String,Any}() |
22 |
| - atoms = map(system) do atom |
23 |
| - if hasproperty(atom, :potential) |
24 |
| - potential = atom.potential |
25 |
| - elseif hasproperty(atom, :pseudopotential) |
26 |
| - pspkey = atom.pseudopotential |
27 |
| - potential = get!(cached_pseudos, pspkey) do |
28 |
| - ElementPsp(AtomsBase.atomic_symbol(atom); psp = load_psp(pspkey)) |
29 |
| - end |
30 |
| - else |
31 |
| - potential = ElementCoulomb(AtomsBase.atomic_symbol(atom)) |
32 |
| - end |
33 |
| - |
34 |
| - potential => SVector{3,T}(lattice \ T.(austrip.(position(atom)))) |
35 |
| - end |
36 |
| - |
37 |
| - oldatoms = oldatoms_from_new(atoms) |
38 |
| - |
39 |
| - (; lattice, atoms = oldatoms) |
40 |
| -end |
41 |
| -function oldatoms_from_new(atomic_potentials) |
42 |
| - potentials = first.(atomic_potentials) |
43 |
| - potential_groups = [findall(Ref(pot) .== potentials) for pot in Set(potentials)] |
44 |
| - [first(atomic_potentials[first(group)]) => last.(atomic_potentials[group]) for group in potential_groups] |
45 |
| -end |
46 |
| -function DFTK.model_LDA(system::AbstractSystem; kwargs...) |
47 |
| - parsed = parse_system(system) |
48 |
| - model_LDA(parsed.lattice, parsed.atoms; kwargs...) |
49 |
| -end |
50 |
| - |
51 | 1 | # -----------------------------------------------------------------------------
|
52 | 2 | # Integration with InteratomicPotentials
|
53 | 3 | # -----------------------------------------------------------------------------
|
54 | 4 |
|
55 | 5 | # ! This integration should ultimately move to the DFTK package itself
|
56 | 6 |
|
57 |
| -@kwdef struct DFTKPotential <: ArbitraryPotential |
| 7 | +struct DFTKPotential <: ArbitraryPotential |
58 | 8 | Ecut::Real
|
59 | 9 | kgrid::AbstractVector{<:Integer}
|
60 |
| - n_bands::Union{Integer,Nothing} = nothing |
61 |
| - tol::Union{AbstractFloat,Nothing} = nothing |
62 |
| - damping::Union{AbstractFloat,Nothing} = nothing |
63 |
| - mixing::Union{Mixing,Nothing} = nothing |
64 |
| - previous_scfres::Ref{Any} = Ref{Any}() |
65 |
| - potential_energy_cache::Dict{Float64,Float64} = Dict{Float64,Float64}() |
| 10 | + scf_args::Dict{Symbol,Any} |
| 11 | + previous_scf::Ref{Any} |
66 | 12 | end
|
67 | 13 | function DFTKPotential(Ecut::Real, kgrid::AbstractVector{<:Integer}; kwargs...)
|
68 |
| - DFTKPotential(; Ecut = Ecut, kgrid = kgrid, kwargs...) |
| 14 | + DFTKPotential(Ecut, kgrid, Dict{Symbol,Any}(kwargs...), Ref{Any}()) |
69 | 15 | end
|
70 | 16 | function DFTKPotential(Ecut::Unitful.Energy, kgrid::AbstractVector{<:Integer}; kwargs...)
|
71 |
| - DFTKPotential(; Ecut = austrip(Ecut), kgrid = kgrid, kwargs...) |
| 17 | + DFTKPotential(austrip(Ecut), kgrid, Dict{Symbol,Any}(kwargs...), Ref{Any}()) |
72 | 18 | end
|
73 | 19 |
|
74 | 20 | function InteratomicPotentials.energy_and_force(system::AbstractSystem, potential::DFTKPotential)
|
75 | 21 | model = model_LDA(system)
|
76 | 22 | basis = PlaneWaveBasis(model; Ecut = potential.Ecut, kgrid = potential.kgrid)
|
77 | 23 |
|
78 |
| - args = (f => getfield(potential, f) for f ∈ (:n_bands, :tol, :damping, :mixing) if !isnothing(getfield(potential, f))) |
79 |
| - extra_args = isassigned(potential.previous_scfres) ? (ψ = potential.previous_scfres[].ψ, ρ = potential.previous_scfres[].ρ) : (;) |
80 |
| - scfres = self_consistent_field(basis; args..., extra_args...) |
81 |
| - potential.previous_scfres[] = scfres |
82 |
| - # TODO: support multiple species |
83 |
| - (; e = scfres.energies.total, f = compute_forces_cart(scfres)[1]) |
| 24 | + extra_args = isassigned(potential.previous_scf) ? (ψ = potential.previous_scf[].ψ, ρ = potential.previous_scf[].ρ) : (;) |
| 25 | + scfres = self_consistent_field(basis; potential.scf_args..., extra_args...) |
| 26 | + potential.previous_scf[] = scfres # cache previous scf as starting point for next calculation |
| 27 | + (; e = scfres.energies.total, f = compute_forces_cart(scfres)) |
84 | 28 | end
|
0 commit comments