Skip to content

Commit

Permalink
refactor addition
Browse files Browse the repository at this point in the history
  • Loading branch information
xquan818 committed Oct 16, 2024
1 parent b905c04 commit ad3da50
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 58 deletions.
3 changes: 1 addition & 2 deletions examples/dos.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# # Densities of states (DOS)
# In this example, we'll plot the DOS, local DOS, and projected DOS of Silicon.
# In this example, we'll plot the DOS, local DOS, and projected DOS of Silicon.
# DOS computation only supports finite temperature.
# Projected DOS only supports PspUpf.

using DFTK
using Unitful
Expand Down
3 changes: 1 addition & 2 deletions ext/DFTKPlotsExt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,7 @@ function plot_pdos(scfres; kwargs...)
# Plot DOS
p = plot_dos(scfres; scfres.εF, kwargs...)

Check warning on line 171 in ext/DFTKPlotsExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/DFTKPlotsExt.jl#L171

Added line #L171 was not covered by tests

# TODO Require symmetrization with respect to kpoints and BZ symmetry
# (now achieved by unfolding all the quantities).
# TODO do the symmetrization instead of unfolding
scfres_unfold = DFTK.unfold_bz(scfres)
basis = scfres_unfold.basis
psp_groups = [group for group in basis.model.atom_groups

Check warning on line 176 in ext/DFTKPlotsExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/DFTKPlotsExt.jl#L174-L176

Added lines #L174 - L176 were not covered by tests
Expand Down
46 changes: 23 additions & 23 deletions src/postprocess/dos.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
# LDOS (local density of states)
# LD(ε) = sum_n f_n' |ψn|^2 = sum_n δ(ε - ε_n) |ψn|^2
#
# PDOS (projected density of states)
# PD(ε) = sum_n f_n' |<ψn,ϕlmi>|^2
# ϕlmi = ∑_R ϕlmi(r-pos-R) is a periodic atomic wavefunction centered at pos
# PD(ε) = sum_n f_n' |<ψn,ϕ>|^2
# ϕ = ∑_R ϕilm(r-pos-R) is the periodized atomic wavefunction, obtained from the pseudopotential
# This is computed for a given (i,l) (eg i=2,l=2 for the 3p) and summed over all m

"""
Total density of states at energy ε
Expand Down Expand Up @@ -94,36 +94,36 @@ function compute_pdos(ε, basis, eigenvalues, ψ, i, l, psp, position;
D = mpi_sum(D, basis.comm_kpts)

Check warning on line 94 in src/postprocess/dos.jl

View check run for this annotation

Codecov / codecov/patch

src/postprocess/dos.jl#L91-L94

Added lines #L91 - L94 were not covered by tests
end

function compute_pdos(scfres::NamedTuple; ε=scfres.εF, l=0, i=1,
psp=scfres.basis.model.atoms[1].psp,
position=basis.model.positions[1], kwargs...)
# TODO Require symmetrization with respect to kpoints and BZ symmetry
# (now achieved by unfolding all the quantities).
function compute_pdos(scfres::NamedTuple, iatom, i, l; ε=scfres.εF, kwargs...)
psp = scfres.basis.model.atoms[iatom].psp
position = scfres.basis.model.positions[iatom]

Check warning on line 99 in src/postprocess/dos.jl

View check run for this annotation

Codecov / codecov/patch

src/postprocess/dos.jl#L97-L99

Added lines #L97 - L99 were not covered by tests
# TODO do the symmetrization instead of unfolding
scfres = unfold_bz(scfres)
compute_pdos(ε, scfres.basis, scfres.eigenvalues, scfres.ψ, i, l, psp, position; kwargs...)

Check warning on line 102 in src/postprocess/dos.jl

View check run for this annotation

Codecov / codecov/patch

src/postprocess/dos.jl#L101-L102

Added lines #L101 - L102 were not covered by tests
end

# Build projection vector for a single atom.
# Stored as projs[K][nk,lmi] = |<ψnk, f_m>|^2,
# where K is running over all k-points,
# m is running over -l:l for fixed l and i.
function compute_pdos_projs(basis, eigenvalues, ψ, i, l, psp::PspUpf, position)
position = vector_red_to_cart(basis.model, position)
G_plus_k_all = [to_cpu(Gplusk_vectors_cart(basis, basis.kpoints[ik]))
# Build atomic orbitals projections projs[ik][iband,m] = |<ψnk, ϕ>|^2 for a single atom.
# TODO optimization ? accept a range of positions, in case we want to compute the PDOS
# for all atoms of the same type (and reuse the computation of the atomic orbitals)
function compute_pdos_projs(basis, eigenvalues, ψ, i, l, psp::NormConservingPsp, position)

Check warning on line 108 in src/postprocess/dos.jl

View check run for this annotation

Codecov / codecov/patch

src/postprocess/dos.jl#L108

Added line #L108 was not covered by tests
# Precompute the form factors on all kpoints at once so we can better use the cache (memory-compute tradeoff).
# Revisit this (pass the cache around explicitly) if RAM becomes an issue.
G_plus_k_all = [Gplusk_vectors(basis, basis.kpoints[ik])

Check warning on line 111 in src/postprocess/dos.jl

View check run for this annotation

Codecov / codecov/patch

src/postprocess/dos.jl#L111

Added line #L111 was not covered by tests
for ik = 1:length(basis.kpoints)]
G_plus_k_all_cart = [map(recip_vector_red_to_cart(basis.model), gpk)

Check warning on line 113 in src/postprocess/dos.jl

View check run for this annotation

Codecov / codecov/patch

src/postprocess/dos.jl#L113

Added line #L113 was not covered by tests
for gpk in G_plus_k_all]

# Build Fourier transform factors of pseudo-wavefunctions centered at 0.
# Build form factors of pseudo-wavefunctions centered at 0.
fun(p) = eval_psp_pswfc_fourier(psp, i, l, p)

Check warning on line 117 in src/postprocess/dos.jl

View check run for this annotation

Codecov / codecov/patch

src/postprocess/dos.jl#L117

Added line #L117 was not covered by tests
fourier_form = atomic_centered_fun_form_factors(fun, l, G_plus_k_all)
# form_factors_all[ik][p,m]
form_factors_all = build_form_factors(fun, l, G_plus_k_all_cart)

Check warning on line 119 in src/postprocess/dos.jl

View check run for this annotation

Codecov / codecov/patch

src/postprocess/dos.jl#L119

Added line #L119 was not covered by tests

projs = Vector{Matrix}(undef, length(basis.kpoints))
for (ik, ψk) in enumerate(ψ)
fourier_form_ik = fourier_form[ik]
structure_factor_ik = exp.(-im .* [dot(position, Gik) for Gik in G_plus_k_all[ik]])

# TODO Pseudo-atomic wave functions need to be orthogonalized.
proj_vectors_ik = structure_factor_ik .* fourier_form_ik ./ sqrt(basis.model.unit_cell_volume)
projs[ik] = abs2.(ψk' * proj_vectors_ik)
structure_factor = [cis2pi(-dot(position, p)) for p in G_plus_k_all[ik]]

Check warning on line 123 in src/postprocess/dos.jl

View check run for this annotation

Codecov / codecov/patch

src/postprocess/dos.jl#L121-L123

Added lines #L121 - L123 were not covered by tests
# TODO orthogonalize pseudo-atomic wave functions?
proj_vectors = structure_factor .* form_factors_all[ik] ./ sqrt(basis.model.unit_cell_volume)
projs[ik] = abs2.(ψk' * proj_vectors) # contract on p -> projs[ik][iband,m]
end

Check warning on line 127 in src/postprocess/dos.jl

View check run for this annotation

Codecov / codecov/patch

src/postprocess/dos.jl#L125-L127

Added lines #L125 - L127 were not covered by tests

projs

Check warning on line 129 in src/postprocess/dos.jl

View check run for this annotation

Codecov / codecov/patch

src/postprocess/dos.jl#L129

Added line #L129 was not covered by tests
Expand Down
39 changes: 27 additions & 12 deletions src/pseudo/NormConservingPsp.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,24 @@ abstract type NormConservingPsp end
# description::String # Descriptive string

#### Methods:
# charge_ionic(psp::NormConservingPsp)
# has_valence_density(psp:NormConservingPsp)
# has_core_density(psp:NormConservingPsp)
# eval_psp_projector_real(psp::NormConservingPsp, i, l, r::Real)
# eval_psp_projector_fourier(psp::NormConservingPsp, i, l, p::Real)
# eval_psp_local_real(psp::NormConservingPsp, r::Real)
# eval_psp_local_fourier(psp::NormConservingPsp, p::Real)
# eval_psp_energy_correction(T::Type, psp::NormConservingPsp, n_electrons::Integer)
# charge_ionic(psp)
# has_valence_density(psp)
# has_core_density(psp)
# eval_psp_projector_real(psp, i, l, r::Real)
# eval_psp_projector_fourier(psp, i, l, p::Real)
# eval_psp_local_real(psp, r::Real)
# eval_psp_local_fourier(psp, p::Real)
# eval_psp_energy_correction(T::Type, psp, n_electrons::Integer)

#### Optional methods:
# eval_psp_density_valence_real(psp::NormConservingPsp, r::Real)
# eval_psp_density_valence_fourier(psp::NormConservingPsp, p::Real)
# eval_psp_density_core_real(psp::NormConservingPsp, r::Real)
# eval_psp_density_core_fourier(psp::NormConservingPsp, p::Real)
# eval_psp_density_valence_real(psp, r::Real)
# eval_psp_density_valence_fourier(psp, p::Real)
# eval_psp_density_core_real(psp, r::Real)
# eval_psp_density_core_fourier(psp, p::Real)
# eval_psp_pswfc_real(psp, i::Int, l::Int, p::Real)
# eval_psp_pswfc_fourier(psp, i::Int, l::Int, p::Real)
# count_n_pswfc(psp, l::Integer)
# count_n_pswfc_radial(psp, l::Integer)

"""
eval_psp_projector_real(psp, i, l, r)
Expand Down Expand Up @@ -203,3 +207,14 @@ function count_n_proj(psps, psp_positions)
sum(count_n_proj(psp) * length(positions)
for (psp, positions) in zip(psps, psp_positions))
end

count_n_pswfc_radial(psp::NormConservingPsp, l) = error("Pseudopotential $psp does not implement atomic wavefunctions.")

Check warning on line 211 in src/pseudo/NormConservingPsp.jl

View check run for this annotation

Codecov / codecov/patch

src/pseudo/NormConservingPsp.jl#L211

Added line #L211 was not covered by tests

function count_n_pswfc_radial(psp::NormConservingPsp)
sum(l -> count_n_pswfc_radial(psp, l), 0:psp.lmax; init=0)::Int

Check warning on line 214 in src/pseudo/NormConservingPsp.jl

View check run for this annotation

Codecov / codecov/patch

src/pseudo/NormConservingPsp.jl#L213-L214

Added lines #L213 - L214 were not covered by tests
end

count_n_pswfc(psp::NormConservingPsp, l) = count_n_pswfc_radial(psp, l) * (2l + 1)
function count_n_pswfc(psp::NormConservingPsp)
sum(l -> count_n_pswfc(psp, l), 0:psp.lmax; init=0)::Int

Check warning on line 219 in src/pseudo/NormConservingPsp.jl

View check run for this annotation

Codecov / codecov/patch

src/pseudo/NormConservingPsp.jl#L217-L219

Added lines #L217 - L219 were not covered by tests
end
12 changes: 2 additions & 10 deletions src/pseudo/PspUpf.jl
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ function eval_psp_projector_fourier(psp::PspUpf, i, l, p::T)::T where {T<:Real}
hankel(rgrid, r2_proj, l, p)
end

count_n_pswfc_radial(psp::PspUpf, l) = length(psp.r2_pswfcs[l+1])

Check warning on line 174 in src/pseudo/PspUpf.jl

View check run for this annotation

Codecov / codecov/patch

src/pseudo/PspUpf.jl#L174

Added line #L174 was not covered by tests

function eval_psp_pswfc_real(psp::PspUpf, i, l, r::T)::T where {T<:Real}
psp.r2_pswfcs_interp[l+1][i](r) / r^2
end
Expand Down Expand Up @@ -227,13 +229,3 @@ function eval_psp_energy_correction(T, psp::PspUpf, n_electrons)
r * (r * vloc[i] - -psp.Zion)
end
end

count_n_pswfc_radial(psp::PspUpf, l::Integer) = length(psp.r2_pswfcs[l + 1])
function count_n_pswfc_radial(psp::PspUpf)
sum(l -> count_n_pswfc_radial(psp, l), 0:psp.lmax; init=0)::Int
end

count_n_pswfc(psp::PspUpf, l::Integer) = count_n_pswfc_radial(psp, l) * (2l + 1)
function count_n_pswfc(psp::PspUpf)
sum(l -> count_n_pswfc(psp, l), 0:psp.lmax; init=0)::Int
end
19 changes: 10 additions & 9 deletions src/terms/nonlocal.jl
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ end
# We compute the forces from the irreductible BZ; they are symmetrized later.
G_plus_k = Gplusk_vectors(basis, kpt)
G_plus_k_cart = to_cpu(Gplusk_vectors_cart(basis, kpt))
form_factors = build_form_factors(element.psp, G_plus_k_cart)
form_factors = build_projector_form_factors(element.psp, G_plus_k_cart)
for idx in group
r = model.positions[idx]
structure_factors = [cis2pi(-dot(p, r)) for p in G_plus_k]
Expand Down Expand Up @@ -173,7 +173,7 @@ function build_projection_vectors(basis::PlaneWaveBasis{T}, kpt::Kpoint,
for (psp, positions) in zip(psps, psp_positions)
# Compute position-independent form factors
G_plus_k_cart = to_cpu(Gplusk_vectors_cart(basis, kpt))
form_factors = build_form_factors(psp, G_plus_k_cart)
form_factors = build_projector_form_factors(psp, G_plus_k_cart)

# Combine with structure factors
for r in positions
Expand All @@ -195,19 +195,19 @@ end
"""
Build form factors (Fourier transforms of projectors) for all orbitals of an atom centered at 0.
"""
function build_form_factors(psp::NormConservingPsp,
G_plus_k::AbstractVector{Vec3{TT}}) where {TT}
function build_projector_form_factors(psp::NormConservingPsp,
G_plus_k::AbstractVector{Vec3{TT}}) where {TT}
G_plus_ks = [G_plus_k]

n_proj = count_n_proj(psp)
form_factors = zeros(Complex{TT}, length(G_plus_k), n_proj)
for l = 0:psp.lmax,
n_proj_l = count_n_proj_radial(psp, l)
offset = sum(x -> count_n_proj(psp, x), 0:l-1; init=0) .+
n_proj_l .* (collect(1:2l+1) .- 1) # offset about m for given l and i
n_proj_l .* (collect(1:2l+1) .- 1) # offset about m for a given l
for i = 1:n_proj_l
proj_li(p) = eval_psp_projector_fourier(psp, i, l, p)
form_factors_li = atomic_centered_fun_form_factors(proj_li, l, G_plus_ks)
form_factors_li = build_form_factors(proj_li, l, G_plus_ks)
@views form_factors[:, offset.+i] = form_factors_li[1]
end
end
Expand All @@ -216,10 +216,11 @@ function build_form_factors(psp::NormConservingPsp,
end

"""
Build Fourier transform factors of a atomic function centered at 0 for a given l.
Build Fourier transform factors of an atomic function centered at 0 for a given l.
"""
function atomic_centered_fun_form_factors(fun::Function, l::Int,
G_plus_ks::AbstractVector{<:AbstractVector{Vec3{TT}}}) where {TT}
function build_form_factors(fun::Function, l::Int,
G_plus_ks::AbstractVector{<:AbstractVector{Vec3{TT}}}) where {TT}
# TODO this function can be generally useful, should refactor to a separate file eventually
T = real(TT)

# Pre-compute the radial parts of the non-local atomic functions at unique |p| to speed up
Expand Down

0 comments on commit ad3da50

Please sign in to comment.