Skip to content

Commit 53da999

Browse files
committed
Refactor n_electrons out of psp correction eval
1 parent 4387f71 commit 53da999

File tree

7 files changed

+35
-34
lines changed

7 files changed

+35
-34
lines changed

src/elements.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ pseudofamily(::Element) = nothing
3535
has_core_density(::Element) = false
3636
# The preceding functions are fallback implementations that should be altered as needed.
3737

38+
eval_psp_energy_correction(T, ::Element) = zero(T)
39+
eval_psp_energy_correction(psp::Element) = eval_psp_energy_correction(Float64, psp)
40+
3841
# Fall back to the Gaussian table for Elements without pseudopotentials
3942
function valence_charge_density_fourier(el::Element, p::T)::T where {T <: Real}
4043
gaussian_valence_charge_density_fourier(el, p)
@@ -152,6 +155,7 @@ AtomsBase.mass(el::ElementPsp) = el.mass
152155
AtomsBase.species(el::ElementPsp) = el.species
153156
charge_ionic(el::ElementPsp) = charge_ionic(el.psp)
154157
has_core_density(el::ElementPsp) = has_core_density(el.psp)
158+
eval_psp_energy_correction(T, el::ElementPsp) = eval_psp_energy_correction(T, el.psp)
155159

156160
function local_potential_fourier(el::ElementPsp, p::T) where {T <: Real}
157161
p == 0 && return zero(T) # Compensating charge background
@@ -237,6 +241,7 @@ function local_potential_fourier(el::ElementCohenBergstresser, p::T) where {T <:
237241
psq_pi = Int(round(p^2 / (2π / el.lattice_constant)^2, digits=2))
238242
T(get(el.V_sym, psq_pi, 0.0))
239243
end
244+
# TODO Strictly speaking needs a eval_psp_energy_correction
240245

241246

242247
#
@@ -269,3 +274,4 @@ end
269274
function local_potential_fourier(el::ElementGaussian, p::Real)
270275
-el.α * exp(- (p * el.L)^2 / 2) # = ∫_ℝ³ V(x) exp(-ix⋅p) dx
271276
end
277+
# TODO Strictly speaking needs a eval_psp_energy_correction

src/pseudo/NormConservingPsp.jl

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ abstract type NormConservingPsp end
1818
# eval_psp_projector_fourier(psp, i, l, p::Real)
1919
# eval_psp_local_real(psp, r::Real)
2020
# eval_psp_local_fourier(psp, p::Real)
21-
# eval_psp_energy_correction(T::Type, psp, n_electrons::Integer)
21+
# eval_psp_energy_correction(T::Type, psp)
2222

2323
#### Optional methods:
2424
# eval_psp_density_valence_real(psp, r::Real)
@@ -86,15 +86,15 @@ eval_psp_local_fourier(psp::NormConservingPsp, p::AbstractVector) =
8686
eval_psp_local_fourier(psp, norm(p))
8787

8888
@doc raw"""
89-
eval_psp_energy_correction([T=Float64,] psp, n_electrons)
89+
eval_psp_energy_correction([T=Float64,] psp::NormConservingPsp)
90+
eval_psp_energy_correction([T=Float64,] element::Element)
9091
91-
Evaluate the energy correction to the Ewald electrostatic interaction energy of one unit
92-
cell, which is required compared the Ewald expression for point-like nuclei. `n_electrons`
93-
is the number of electrons per unit cell. This defines the uniform compensating background
94-
charge, which is assumed here.
95-
96-
Notice: The returned result is the *energy per unit cell* and not the energy per volume.
97-
To obtain the latter, the caller needs to divide by the unit cell volume.
92+
Evaluate the energy correction to the Ewald electrostatic interaction energy per unit
93+
of uniform negative charge. This is the correction required to account for the fact that
94+
the Ewald expression assumes point-like nuclei and not nuclei of the shape induced by
95+
the pseudopotential. The compensating background charge assumed for this expression is
96+
scaled to ``1``. Therefore multiplying by the number of electrons and dividing by the unit
97+
cell volume yields the energy correction per volume for the DFT simulation.
9898
9999
The energy correction is defined as the limit of the Fourier-transform of the local
100100
potential as ``p \to 0``, using the same correction as in the Fourier-transform of the local
@@ -103,12 +103,14 @@ potential:
103103
\lim_{p \to 0} 4π N_{\rm elec} ∫_{ℝ_+} (V(r) - C(r)) \frac{\sin(p·r)}{p·r} r^2 dr + F[C(r)]
104104
= 4π N_{\rm elec} ∫_{ℝ_+} (V(r) + Z/r) r^2 dr.
105105
```
106+
where as discussed above the implementation is expected to return the result
107+
for ``N_{\rm elec} = 1``.
106108
"""
107109
function eval_psp_energy_correction end
108110
# by default, no correction, see PspHgh implementation and tests
109111
# for details on what to implement
110-
eval_psp_energy_correction(psp::NormConservingPsp, n_electrons) =
111-
eval_psp_energy_correction(Float64, psp, n_electrons)
112+
113+
eval_psp_energy_correction(psp::NormConservingPsp) = eval_psp_energy_correction(Float64, psp)
112114

113115
"""
114116
eval_psp_density_valence_real(psp, r)

src/pseudo/PspHgh.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ function eval_psp_projector_real(psp::PspHgh, i, l, r::T) where {T <: Real}
218218
sqrt(T(2)) * r^(l + 2(i - 1)) * exp(-r^2 / 2rp^2) / rp^(l + ired) / sqrt(gamma(l + ired))
219219
end
220220

221-
function eval_psp_energy_correction(T, psp::PspHgh, n_electrons)
221+
function eval_psp_energy_correction(T, psp::PspHgh)
222222
# By construction we need to compute the DC component of the difference
223223
# of the Coulomb potential (-Z/G^2 in Fourier space) and the pseudopotential
224224
# i.e. -4πZ/(ΔG)^2 - eval_psp_local_fourier(psp, ΔG) for ΔG → 0. This is:
@@ -228,5 +228,5 @@ function eval_psp_energy_correction(T, psp::PspHgh, n_electrons)
228228

229229
# Multiply by number of electrons and 4π (spherical Hankel prefactor)
230230
# to get energy per unit cell
231-
4T(π) * n_electrons * difference_DC
231+
4T(π) * difference_DC
232232
end

src/pseudo/PspUpf.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,10 +232,10 @@ function eval_psp_density_core_fourier(psp::PspUpf, p::T) where {T<:Real}
232232
return hankel(rgrid, r2_ρcore, 0, p)
233233
end
234234

235-
function eval_psp_energy_correction(T, psp::PspUpf, n_electrons)
235+
function eval_psp_energy_correction(T, psp::PspUpf)
236236
rgrid = @view psp.rgrid[1:psp.ircut]
237237
vloc = @view psp.vloc[1:psp.ircut]
238-
4T(π) * n_electrons * simpson(rgrid) do i, r
238+
4T(π) * simpson(rgrid) do i, r
239239
r * (r * vloc[i] - -psp.Zion)
240240
end
241241
end

src/terms/psp_correction.jl

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,11 @@ Compute the correction term for properly modelling the interaction of the pseudo
2424
core with the compensating background charge induced by the `Ewald` term.
2525
"""
2626
function energy_psp_correction(lattice::AbstractMatrix{T}, atoms, atom_groups) where {T}
27-
psp_groups = [group for group in atom_groups if atoms[first(group)] isa ElementPsp]
28-
isempty(psp_groups) && return zero(T)
29-
27+
correction_per_cell_and_electron = sum(atom_groups) do group
28+
length(group) * eval_psp_energy_correction(T, atoms[first(group)])::T
29+
end
3030
n_electrons::Int = n_electrons_from_atoms(atoms)
31-
correction_per_cell = sum(
32-
length(group) * eval_psp_energy_correction(T, atoms[first(group)].psp, n_electrons)
33-
for group in psp_groups
34-
)
35-
36-
correction_per_cell / compute_unit_cell_volume(lattice)
31+
correction_per_cell_and_electron * n_electrons / compute_unit_cell_volume(lattice)
3732
end
3833
function energy_psp_correction(model::Model)
3934
energy_psp_correction(model.lattice, model.atoms, model.atom_groups)

test/PspHgh.jl

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -195,20 +195,19 @@ end
195195

196196
reg_param = 1e-6 # divergent integral, needs regularization
197197
p_small = 1e-6 # We are interested in p→0 term
198-
function integrand(psp, n_electrons, r)
198+
function integrand(psp, r)
199199
# Difference of potential of point-like atom (what is assumed in Ewald)
200200
# versus actual structure of the pseudo potential
201201
coulomb = -psp.Zion / r
202-
diff = n_electrons * (eval_psp_local_real(psp, r) - coulomb)
202+
diff = (eval_psp_local_real(psp, r) - coulomb)
203203
4π * diff * exp(-reg_param * r) * sin(p_small*r) / p_small * r
204204
end
205205

206-
n_electrons = 20
207206
family = PseudoFamily("cp2k.nc.sr.lda.v0_1.semicore.gth")
208207
for element in (:Au, :Ba)
209208
psp = load_psp(family, element)
210-
reference = quadgk(r -> integrand(psp, n_electrons, r), 0, Inf)[1]
211-
@test reference eval_psp_energy_correction(psp, n_electrons) atol=1e-2
209+
reference = quadgk(r -> integrand(psp, r), 0, Inf)[1]
210+
@test reference eval_psp_energy_correction(psp) atol=1e-3
212211
end
213212
end
214213

@@ -224,7 +223,7 @@ end
224223
psp = load_psp(family, element)
225224
coulomb = -4π * psp.Zion / p_small^2
226225
reference = eval_psp_local_fourier(psp, p_small) - coulomb
227-
@test reference eval_psp_energy_correction(psp, 1) atol=1e-3
226+
@test reference eval_psp_energy_correction(psp) atol=1e-3
228227
end
229228
end
230229

test/PspUpf.jl

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,8 @@ end
104104
for psp_pair in mPspUpf.gth_pseudos
105105
upf = psp_pair.upf
106106
gth = psp_pair.gth
107-
n_electrons = 3
108-
reference_gth = eval_psp_energy_correction(gth, n_electrons)
109-
@test reference_gth eval_psp_energy_correction(upf, n_electrons) atol=1e-3 rtol=1e-3
107+
reference_gth = eval_psp_energy_correction(gth)
108+
@test reference_gth eval_psp_energy_correction(upf) atol=1e-3 rtol=1e-3
110109
end
111110
end
112111

@@ -199,7 +198,7 @@ end
199198
for psp in values(mPspUpf.upf_pseudos)
200199
coulomb = -4π * (psp.Zion) / p_small^2
201200
reference = eval_psp_local_fourier(psp, p_small) - coulomb
202-
@test reference eval_psp_energy_correction(psp, 1) atol=1e-2
201+
@test reference eval_psp_energy_correction(psp) atol=1e-2
203202
end
204203
end
205204

0 commit comments

Comments
 (0)