35template <
bool add_pseudo_core__>
38 PROFILE(
"sirius::Potential::xc_rg_nonmagnetic");
40 bool const use_2nd_deriv{
false};
44 bool is_gga = is_gradient_correction();
46 int num_points = ctx_.spfft<
double>().local_slice_size();
57 for (
int ir = 0; ir < num_points; ir++) {
60 double d = density__.
rho().rg().value(ir);
61 if (add_pseudo_core__) {
62 d += density__.rho_pseudo_core().value(ir);
66 rhomin = std::min(rhomin, d);
67 rho.value(ir) = std::max(d, 0.0);
71 if (rhomin < 0.0 && ctx_.
comm().
rank() == 0) {
73 s <<
"Interstitial charge density has negative values" << std::endl
74 <<
"most negatve value : " << rhomin;
78 if (env::print_hash()) {
79 auto h = rho.hash_f_rg();
80 print_hash(
"rho", h, ctx_.
out());
83 if (env::print_checksum()) {
84 auto cs = density__.
rho().rg().checksum_rg();
85 print_checksum(
"rho_rg", cs, ctx_.
out());
96 rho.fft_transform(-1);
104 lapl_rho.fft_transform(1);
108 for (
int x: {0, 1, 2}) {
109 grad_rho[x].fft_transform(1);
113 grad_rho_grad_rho = dot(grad_rho, grad_rho);
115 if (env::print_hash()) {
117 auto h2 = grad_rho_grad_rho.hash_f_rg();
119 print_hash(
"grad_rho_grad_rho", h2, ctx_.
out());
133 for (
auto& ixc: xc_func_) {
134 PROFILE_START(
"sirius::Potential::xc_rg_nonmagnetic|libxc");
136#if defined(SIRIUS_USE_VDWXC)
140 ixc.get_vdw(&rho.value(0), &grad_rho_grad_rho.value(0), vxc.at(sddk::memory_t::host), &vsigma.value(0),
141 exc.at(sddk::memory_t::host));
143 ixc.get_vdw(
nullptr,
nullptr,
nullptr,
nullptr,
nullptr);
146 RTE_THROW(
"You should not be there since SIRIUS is not compiled with libVDWXC support\n");
156 ixc.get_lda(spl_t.
local_size(), &rho.value(spl_t.global_offset()),
157 vxc.at(sddk::memory_t::host, spl_t.global_offset()),
158 exc.at(sddk::memory_t::host, spl_t.global_offset()));
162 ixc.get_gga(spl_t.
local_size(), &rho.value(spl_t.global_offset()),
163 &grad_rho_grad_rho.value(spl_t.global_offset()),
164 vxc.at(sddk::memory_t::host, spl_t.global_offset()),
165 &vsigma.value(spl_t.global_offset()),
166 exc.at(sddk::memory_t::host, spl_t.global_offset()));
187 PROFILE_STOP(
"sirius::Potential::xc_rg_nonmagnetic|libxc");
189 #pragma omp parallel for
190 for (
int ir = 0; ir < num_points; ir++) {
192 vsigma_[0]->value(ir) += vsigma.value(ir);
197 vsigma.fft_transform(-1);
200 auto grad_vsigma =
gradient(vsigma);
203 for (
int x: {0, 1, 2}) {
204 grad_vsigma[x].fft_transform(1);
208 auto grad_vsigma_grad_rho = dot(grad_vsigma, grad_rho);
211 #pragma omp parallel for
212 for (
int ir = 0; ir < num_points; ir++) {
213 vxc(ir) -= 2 * (vsigma.value(ir) * lapl_rho.value(ir) + grad_vsigma_grad_rho.value(ir));
218 for (
int x: {0, 1, 2}) {
219 for (
int ir = 0; ir < num_points; ir++) {
220 vsigma_grad_rho[x].value(ir) = grad_rho[x].value(ir) * vsigma.value(ir);
223 vsigma_grad_rho[x].fft_transform(-1);
225 div_vsigma_grad_rho =
divergence(vsigma_grad_rho);
227 div_vsigma_grad_rho.fft_transform(1);
228 for (
int ir = 0; ir < num_points; ir++) {
229 vxc(ir) -= 2 * div_vsigma_grad_rho.value(ir);
233 #pragma omp parallel for
234 for (
int ir = 0; ir < num_points; ir++) {
240 if (env::print_checksum()) {
242 print_checksum(
"exc", cs, ctx_.
out());
246template <
bool add_pseudo_core__>
249 PROFILE(
"sirius::Potential::xc_rg_magnetic");
251 bool is_gga = is_gradient_correction();
253 int num_points = ctx_.spfft<
double>().local_slice_size();
257 auto& rho_up = *result[0];
258 auto& rho_dn = *result[1];
260 if (env::print_hash()) {
261 auto h1 = rho_up.hash_f_rg();
262 auto h2 = rho_dn.hash_f_rg();
263 print_hash(
"rho_up", h1, ctx_.
out());
264 print_hash(
"rho_dn", h2, ctx_.
out());
274 PROFILE(
"sirius::Potential::xc_rg_magnetic|grad1");
276 rho_up.fft_transform(-1);
277 rho_dn.fft_transform(-1);
284 for (
int x: {0, 1, 2}) {
285 grad_rho_up[x].fft_transform(1);
286 grad_rho_dn[x].fft_transform(1);
290 grad_rho_up_grad_rho_up = dot(grad_rho_up, grad_rho_up);
291 grad_rho_up_grad_rho_dn = dot(grad_rho_up, grad_rho_dn);
292 grad_rho_dn_grad_rho_dn = dot(grad_rho_dn, grad_rho_dn);
294 if (env::print_hash()) {
295 auto h3 = grad_rho_up_grad_rho_up.hash_f_rg();
296 auto h4 = grad_rho_up_grad_rho_dn.hash_f_rg();
297 auto h5 = grad_rho_dn_grad_rho_dn.hash_f_rg();
299 print_hash(
"grad_rho_up_grad_rho_up", h3, ctx_.
out());
300 print_hash(
"grad_rho_up_grad_rho_dn", h4, ctx_.
out());
301 print_hash(
"grad_rho_dn_grad_rho_dn", h5, ctx_.
out());
316 for (
int i = 0; i < 3; i++) {
326 for (
auto& ixc: xc_func_) {
327 PROFILE_START(
"sirius::Potential::xc_rg_magnetic|libxc");
329#if defined(SIRIUS_USE_VDWXC)
332 ixc.get_vdw(&rho_up.value(0), &rho_dn.value(0), &grad_rho_up_grad_rho_up.value(0),
333 &grad_rho_dn_grad_rho_dn.value(0), vxc_up.at(sddk::memory_t::host), vxc_dn.at(sddk::memory_t::host),
334 &vsigma_uu.value(0), &vsigma_dd.value(0), exc.at(sddk::memory_t::host));
336 ixc.get_vdw(
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr);
339 RTE_THROW(
"You should not be there since sirius is not compiled with libVDWXC\n");
349 ixc.get_lda(spl_t.
local_size(), &rho_up.value(spl_t.global_offset()),
350 &rho_dn.value(spl_t.global_offset()),
351 vxc_up.at(sddk::memory_t::host, spl_t.global_offset()),
352 vxc_dn.at(sddk::memory_t::host, spl_t.global_offset()),
353 exc.at(sddk::memory_t::host, spl_t.global_offset()));
357 ixc.get_gga(spl_t.
local_size(), &rho_up.value(spl_t.global_offset()),
358 &rho_dn.value(spl_t.global_offset()),
359 &grad_rho_up_grad_rho_up.value(spl_t.global_offset()),
360 &grad_rho_up_grad_rho_dn.value(spl_t.global_offset()),
361 &grad_rho_dn_grad_rho_dn.value(spl_t.global_offset()),
362 vxc_up.at(sddk::memory_t::host, spl_t.global_offset()),
363 vxc_dn.at(sddk::memory_t::host, spl_t.global_offset()),
364 &vsigma_uu.value(spl_t.global_offset()),
365 &vsigma_ud.value(spl_t.global_offset()),
366 &vsigma_dd.value(spl_t.global_offset()),
367 exc.at(sddk::memory_t::host, spl_t.global_offset()));
372 PROFILE_STOP(
"sirius::Potential::xc_rg_magnetic|libxc");
374 #pragma omp parallel for
375 for (
int ir = 0; ir < num_points; ir++) {
377 vsigma_[0]->value(ir) += vsigma_uu.value(ir);
378 vsigma_[1]->value(ir) += vsigma_ud.value(ir);
379 vsigma_[2]->value(ir) += vsigma_dd.value(ir);
384 for (
int x: {0, 1, 2}) {
385 for(
int ir = 0; ir < num_points; ir++) {
386 up_gradrho_vsigma[x].value(ir) = 2 * grad_rho_up[x].value(ir) * vsigma_uu.value(ir) + grad_rho_dn[x].value(ir) * vsigma_ud.value(ir);
387 dn_gradrho_vsigma[x].value(ir) = 2 * grad_rho_dn[x].value(ir) * vsigma_dd.value(ir) + grad_rho_up[x].value(ir) * vsigma_ud.value(ir);
390 up_gradrho_vsigma[x].fft_transform(-1);
391 dn_gradrho_vsigma[x].fft_transform(-1);
394 auto div_up_gradrho_vsigma =
divergence(up_gradrho_vsigma);
395 div_up_gradrho_vsigma.fft_transform(1);
396 auto div_dn_gradrho_vsigma =
divergence(dn_gradrho_vsigma);
397 div_dn_gradrho_vsigma.fft_transform(1);
400 #pragma omp parallel for
401 for (
int ir = 0; ir < num_points; ir++) {
402 vxc_up(ir) -= div_up_gradrho_vsigma.value(ir);
403 vxc_dn(ir) -= div_dn_gradrho_vsigma.value(ir);
407 #pragma omp parallel for
408 for (
int irloc = 0; irloc < num_points; irloc++) {
412 xc_potential_->rg().value(irloc) += 0.5 * (vxc_up(irloc) + vxc_dn(irloc));
414 double bxc = 0.5 * (vxc_up(irloc) - vxc_dn(irloc));
417 auto s =
sign((rho_up.value(irloc) - rho_dn.value(irloc)) * bxc);
421 m[j] = density__.mag(j).rg().value(irloc);
427 effective_magnetic_field(j).rg().value(irloc) += std::abs(bxc) * s * m[j] / m_len;
434template <
bool add_pseudo_core__>
437 PROFILE(
"sirius::Potential::xc");
443 effective_magnetic_field(i).zero();
446 if (xc_func_.size() == 0) {
450 if (ctx_.full_potential()) {
455 xc_rg_nonmagnetic<add_pseudo_core__>(density__);
457 xc_rg_magnetic<add_pseudo_core__>(density__);
460 if (env::print_hash()) {
462 print_hash(
"Exc", h, ctx_.
out());
467template void Potential::xc_rg_nonmagnetic<true>(
Density const&);
468template void Potential::xc_rg_nonmagnetic<false>(
Density const&);
469template void Potential::xc_rg_magnetic<true>(
Density const&);
470template void Potential::xc_rg_magnetic<false>(
Density const&);
471template void Potential::xc<true>(
Density const&);
472template void Potential::xc<false>(
Density const&);
Generate charge density and magnetization from occupied spinor wave-functions.
auto const & rho() const
Return const reference to charge density (scalar functions).
void xc_rg_magnetic(Density const &density__)
Generate magnetic XC potential on the regular real-space grid.
std::unique_ptr< Periodic_function< double > > xc_energy_density_
XC energy per unit particle.
double add_delta_mag_xc_
Add extra charge to the density.
void xc_mt(Density const &density__)
Generate XC potential in the muffin-tins.
void xc(Density const &rho__)
Generate XC potential and energy density.
std::unique_ptr< Periodic_function< double > > xc_potential_
XC potential.
std::array< std::unique_ptr< Smooth_periodic_function< double > >, 3 > vsigma_
Derivative .
void xc_rg_nonmagnetic(Density const &density__)
Generate non-magnetic XC potential on the regular real-space grid.
double add_delta_rho_xc_
Add extra charge to the density.
auto gvec_fft_sptr() const
Return shared pointer to Gvec_fft object.
std::ostream & out() const
Return output stream.
mpi::Communicator const & comm() const
Total communicator of the simulation.
int num_spins() const
Number of spin components.
int num_mag_dims() const
Number of dimensions in the magnetization vector.
Representation of a smooth (Fourier-transformable) periodic function.
Vector of the smooth periodic functions.
MPI communicator wrapper.
void allreduce(T *buffer__, int count__) const
Perform the in-place (the output buffer is used as the input buffer) all-to-all reduction.
int rank() const
Rank of MPI process inside communicator.
double length() const
Return vector length (L2 norm).
value_type local_size(block_id block_id__) const
Return local size of the split index for a given block.
Namespace of the SIRIUS library.
Smooth_periodic_vector_function< T > gradient(Smooth_periodic_function< T > &f__)
Gradient of the function in the plane-wave domain.
strong_type< int, struct __block_id_tag > block_id
ID of the block.
Smooth_periodic_function< T > laplacian(Smooth_periodic_function< T > &f__)
Laplacian of the function in the plane-wave domain.
Smooth_periodic_function< T > divergence(Smooth_periodic_vector_function< T > &g__)
Divergence of the vecor function.
int sign(T val)
Sign of the variable.
strong_type< int, struct __n_blocks_tag > n_blocks
Number of blocks to which the global index is split.
Add or substitute OMP functions.
Contains declaration and partial implementation of sirius::Potential class.
Contains typedefs, enums and simple descriptors.
Contains implementation of sirius::XC_functional class.