@@ -163,9 +163,9 @@ function atomic_density_superposition(basis::PlaneWaveBasis{T},
163163
164164 # Pre-allocation of large arrays for GPU efficiency
165165 Gs = G_vectors (basis)
166- ρ = to_device (basis. architecture, zeros (Complex{T}, length (Gs)))
167- ρ_tmp = similar (ρ)
168166 indices = to_device (basis. architecture, collect (1 : length (Gs)))
167+ ρ = zeros_like (indices, Complex{T})
168+ ρ_tmp = similar (ρ)
169169
170170 for (igroup, group) in enumerate (basis. model. atom_groups)
171171 for iatom in group
184184Returns the form factors at unique values of |G + q| (in Cartesian coordinates).
185185Additionally, returns a mapping from any G index to the corresponding entry in the form_factors array.
186186"""
187- function atomic_density_form_factors (basis:: PlaneWaveBasis{T} ,
188- method:: AtomicDensity ) where {T<: Real }
187+ function atomic_density_form_factors (basis:: PlaneWaveBasis{T} , method:: AtomicDensity ) where {T<: Real }
189188 G_cart = to_cpu (G_vectors_cart (basis))
190189
191190 iG2ifnorm_cpu = zeros (Int, length (G_cart))
@@ -194,49 +193,94 @@ function atomic_density_form_factors(basis::PlaneWaveBasis{T},
194193 p = norm (G)
195194 iG2ifnorm_cpu[iG] = get! (norm_indices, p, length (norm_indices) + 1 )
196195 end
196+ iG2ifnorm = to_device (basis. architecture, iG2ifnorm_cpu)
197197
198- form_factors_cpu = zeros (T, length (norm_indices), length (basis. model. atom_groups))
199- for (p, ifnorm) in norm_indices
200- for (igroup, group) in enumerate (basis. model. atom_groups)
201- element = basis. model. atoms[first (group)]
202- form_factors_cpu[ifnorm, igroup] = atomic_density (element, p, method)
203- end
198+ ni_pairs = collect (pairs (norm_indices))
199+ ps = to_device (basis. architecture, first .(ni_pairs))
200+ indices = to_device (basis. architecture, last .(ni_pairs))
201+
202+ form_factors = similar (ps, length (norm_indices), length (basis. model. atom_groups))
203+ for (igroup, group) in enumerate (basis. model. atom_groups)
204+ element = basis. model. atoms[first (group)]
205+ @inbounds form_factors[indices, igroup] .= atomic_density (element, ps, method)
204206 end
205207
206- form_factors = to_device (basis. architecture, form_factors_cpu)
207- iG2ifnorm = to_device (basis. architecture, iG2ifnorm_cpu)
208208 (; form_factors, iG2ifnorm)
209209end
210210
211- function atomic_density (element:: Element , Gnorm:: T ,
212- :: ValenceDensityGaussian ):: T where {T <: Real }
213- gaussian_valence_charge_density_fourier (element, Gnorm)
214- end
211+ #
212+ # Check for presence of certain densities in elements
213+ #
214+
215+ """ Check presence of model valence density (as an initial guess)."""
216+ has_valence_density (:: Element ) = false
217+
218+ """ Check presence of model core charge density (non-linear core correction)."""
219+ has_core_density (:: Element ) = false
220+
221+ """ Check presence of model core kinetic energy density (non-linear core correction for τ)."""
222+ has_core_kinetic_energy_density (:: Element ) = false
223+
224+ has_core_density (el:: ElementPsp ) = has_core_density (el. psp)
225+ has_core_kinetic_energy_density (el:: ElementPsp ) = has_core_kinetic_energy_density (el. psp)
226+ has_valence_density (el:: ElementPsp ) = has_valence_density (el. psp)
215227
216- function atomic_density (element:: Element , Gnorm:: T ,
217- :: ValenceDensityPseudo ):: T where {T <: Real }
218- eval_psp_valence_density_fourier (element. psp, Gnorm)
228+ #
229+ # Atomic density dispatches
230+ #
231+
232+ function atomic_density (element:: Union{Element,<:ElementPsp} , Gnorm:: Real , dens:: AtomicDensity )
233+ first (atomic_density (element, [Gnorm], dens)) # Dispatch to vector version
219234end
220235
221- function atomic_density (element:: Element , Gnorm:: T ,
222- :: ValenceDensityAuto ):: T where {T <: Real }
223- valence_charge_density_fourier (element, Gnorm)
236+ """ Gaussian valence charge density using Abinit's coefficient table, in Fourier space."""
237+ function atomic_density (element:: Element , Gnorms:: AbstractVector , :: ValenceDensityGaussian )
238+ charge = charge_ionic (element)
239+ decay_length = atom_decay_length (element)
240+ map (Gnorms) do Gnorm
241+ # Note: cannot pass element to GPU kernel, because not isbit
242+ charge * exp (- (Gnorm * decay_length)^ 2 )
243+ end
244+ end
245+ function atomic_density (element:: Element , Gnorms:: AbstractVector , :: ValenceDensityAuto )
246+ if has_valence_density (element)
247+ atomic_density (element, Gnorms, ValenceDensityPseudo ())
248+ else
249+ atomic_density (element, Gnorms, ValenceDensityGaussian ())
250+ end
224251end
225252
226- function atomic_density (element:: Element , Gnorm:: T ,
227- :: CoreDensity ):: T where {T <: Real }
228- has_core_density (element) ? core_charge_density_fourier (element, Gnorm) : zero (T)
253+ function atomic_density (element:: Element , Gnorms:: AbstractVector , :: CoreDensity )
254+ @assert ! has_core_density (element)
255+ zeros_like (Gnorms)
256+ end
257+ function atomic_density (element:: Element , Gnorms:: AbstractVector , :: CoreKineticEnergyDensity )
258+ @assert ! has_core_kinetic_energy_density (element)
259+ zeros_like (Gnorms)
229260end
230261
231- function atomic_density (element:: Element , Gnorm:: T ,
232- :: CoreKineticEnergyDensity ):: T where {T <: Real }
262+ function atomic_density (element:: ElementPsp , Gnorms:: AbstractVector , :: ValenceDensityPseudo )
263+ eval_psp_valence_density_fourier (element. psp, Gnorms)
264+ end
265+ function atomic_density (element:: ElementPsp , Gnorms:: AbstractVector , :: CoreDensity )
266+ if has_core_density (element)
267+ eval_psp_core_density_fourier (element. psp, Gnorms)
268+ else
269+ zeros_like (Gnorms)
270+ end
271+ end
272+ function atomic_density (element:: ElementPsp , Gnorms:: AbstractVector , :: CoreKineticEnergyDensity )
233273 if has_core_kinetic_energy_density (element)
234- eval_psp_core_kinetic_energy_density_fourier (element. psp, Gnorm )
274+ eval_psp_core_kinetic_energy_density_fourier (element. psp, Gnorms )
235275 else
236- zero (T )
276+ zeros_like (Gnorms )
237277 end
238278end
239279
280+ #
281+ # Some data we need for the Gaussian densities
282+ #
283+
240284# Get the lengthscale of the valence density for an atom with `n_elec_core` core
241285# and `n_elec_valence` valence electrons.
242286function atom_decay_length (n_elec_core, n_elec_valence)
0 commit comments