SIRIUS 7.5.0
Electronic structure library and applications
non_local_functor.hpp
Go to the documentation of this file.
1// Copyright (c) 2013-2018 Anton Kozhevnikov, Ilia Sivkov, Mathieu Taillefumier, Thomas Schulthess
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without modification, are permitted provided that
5// the following conditions are met:
6//
7// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
8// following disclaimer.
9// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions
10// and the following disclaimer in the documentation and/or other materials provided with the distribution.
11//
12// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
13// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
14// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
15// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
16// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
17// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
18// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
19
20/** \file non_local_functor.hpp
21 *
22 * \brief Common operation for forces and stress tensor.
23 */
24
25#ifndef __NON_LOCAL_FUNCTOR_HPP__
26#define __NON_LOCAL_FUNCTOR_HPP__
27
29#include "k_point/k_point.hpp"
32#include "SDDK/memory.hpp"
33
34namespace sirius {
35
36/** \tparam T Precision type of the wave-functions */
37template<typename T, typename F>
39 K_point<T>& kp__, sddk::mdarray<real_type<F>, 2>& collect_res__)
40{
41 PROFILE("sirius::add_k_point_contribution_nonlocal");
42
43 auto& uc = ctx__.unit_cell();
44
45 if (uc.max_mt_basis_size() == 0) {
46 return;
47 }
48
49 auto& bp = kp__.beta_projectors();
50
51 double main_two_factor{-2};
52
53 auto mt = ctx__.processing_unit_memory_t();
54 auto bp_gen = bp.make_generator(mt);
55 auto beta_coeffs = bp_gen.prepare();
56
57 auto bp_base_gen = bp_base__.make_generator(mt);
58 auto beta_coeffs_base = bp_base_gen.prepare();
59
60 for (int icnk = 0; icnk < bp_base__.num_chunks(); icnk++) {
61
62 /* generate chunk for inner product of beta */
63 bp_gen.generate(beta_coeffs, icnk);
64
65 /* store <beta|psi> for spin up and down */
66 sddk::matrix<F> beta_phi_chunks[2];
67
68 for (int ispn = 0; ispn < ctx__.num_spins(); ispn++) {
69 int nbnd = kp__.num_occupied_bands(ispn);
70 // beta_phi_chunks[ispn] = bp.template inner<F>(ctx__.processing_unit_memory_t(), icnk,
71 // kp__.spinor_wave_functions(), wf::spin_index(ispn), wf::band_range(0, nbnd));
72 beta_phi_chunks[ispn] = inner_prod_beta<F>(ctx__.spla_context(), mt, ctx__.host_memory_t(), sddk::is_device_memory(mt),
73 beta_coeffs, kp__.spinor_wave_functions(), wf::spin_index(ispn), wf::band_range(0, nbnd));
74 }
75 // bp.dismiss();
76
77 // bp_base__.prepare();
78 for (int x = 0; x < bp_base__.num_comp(); x++) {
79 /* generate chunk for inner product of beta gradient */
80 bp_base_gen.generate(beta_coeffs_base, icnk, x);
81
82 for (int ispn = 0; ispn < ctx__.num_spins(); ispn++) {
83 int spin_factor = (ispn == 0 ? 1 : -1);
84
85 int nbnd = kp__.num_occupied_bands(ispn);
86
87 /* inner product of beta gradient and WF */
88 auto bp_base_phi_chunk = inner_prod_beta<F>(
89 ctx__.spla_context(), mt, ctx__.host_memory_t(), sddk::is_device_memory(mt), beta_coeffs_base,
90 kp__.spinor_wave_functions(), wf::spin_index(ispn), wf::band_range(0, nbnd));
91
92 splindex_block<> spl_nbnd(nbnd, n_blocks(kp__.comm().size()), block_id(kp__.comm().rank()));
93
94 int nbnd_loc = spl_nbnd.local_size();
95
96 #pragma omp parallel for
97 for (int ia_chunk = 0; ia_chunk < beta_coeffs_base.beta_chunk_.num_atoms_; ia_chunk++) {
98 int ia = beta_coeffs_base.beta_chunk_.desc_(beta_desc_idx::ia, ia_chunk);
99 int offs = beta_coeffs_base.beta_chunk_.desc_(beta_desc_idx::offset, ia_chunk);
100 int nbf = beta_coeffs_base.beta_chunk_.desc_(beta_desc_idx::nbf, ia_chunk);
101 int iat = uc.atom(ia).type_id();
102
103 if (uc.atom(ia).type().spin_orbit_coupling()) {
104 RTE_THROW("stress and forces with SO coupling are not upported");
105 }
106
107 /* helper lambda to calculate for sum loop over bands for different beta_phi and dij combinations*/
108 auto for_bnd = [&](int ibf, int jbf, std::complex<real_type<F>> dij, real_type<F> qij,
109 sddk::matrix<F>& beta_phi_chunk) {
110 /* gather everything = - 2 Re[ occ(k,n) weight(k) beta_phi*(i,n) [Dij - E(n)Qij] beta_base_phi(j,n) ]*/
111 for (int ibnd_loc = 0; ibnd_loc < nbnd_loc; ibnd_loc++) {
112 int ibnd = spl_nbnd.global_index(ibnd_loc);
113
114 auto d1 = main_two_factor * kp__.band_occupancy(ibnd, ispn) * kp__.weight();
115 auto z2 = dij - static_cast<real_type<F>>(kp__.band_energy(ibnd, ispn) * qij);
116 auto z1 = z2 * std::conj(beta_phi_chunk(offs + jbf, ibnd)) * bp_base_phi_chunk(offs + ibf, ibnd);
117
118 auto scalar_part = static_cast<real_type<F>>(d1) * z1;
119
120 /* get real part and add to the result array*/
121 collect_res__(x, ia) += scalar_part.real();
122 }
123 };
124
125 for (int ibf = 0; ibf < nbf; ibf++) {
126 int lm2 = uc.atom(ia).type().indexb(ibf).lm;
127 int idxrf2 = uc.atom(ia).type().indexb(ibf).idxrf;
128 for (int jbf = 0; jbf < nbf; jbf++) {
129 int lm1 = uc.atom(ia).type().indexb(jbf).lm;
130 int idxrf1 = uc.atom(ia).type().indexb(jbf).idxrf;
131
132 /* Qij exists only in the case of ultrasoft/PAW */
133 real_type<F> qij{0};
134 if (uc.atom(ia).type().augment()) {
135 qij = ctx__.augmentation_op(iat).q_mtrx(ibf, jbf);
136 }
137 std::complex<real_type<F>> dij{0};
138
139 /* get non-magnetic or collinear spin parts of dij*/
140 switch (ctx__.num_spins()) {
141 case 1: {
142 dij = uc.atom(ia).d_mtrx(ibf, jbf, 0);
143 if (lm1 == lm2) {
144 dij += uc.atom(ia).type().d_mtrx_ion()(idxrf1, idxrf2);
145 }
146 break;
147 }
148
149 case 2: {
150 /* Dij(00) = dij + dij_Z ; Dij(11) = dij - dij_Z*/
151 dij = (uc.atom(ia).d_mtrx(ibf, jbf, 0) +
152 spin_factor * uc.atom(ia).d_mtrx(ibf, jbf, 1));
153 if (lm1 == lm2) {
154 dij += uc.atom(ia).type().d_mtrx_ion()(idxrf1, idxrf2);
155 }
156 break;
157 }
158
159 default: {
160 RTE_THROW("Error in non_local_functor, D_aug_mtrx. ");
161 break;
162 }
163 }
164
165 /* add non-magnetic or diagonal spin components (or collinear part) */
166 for_bnd(ibf, jbf, dij, qij, beta_phi_chunks[ispn]);
167
168 /* for non-collinear case*/
169 if (ctx__.num_mag_dims() == 3) {
170 /* Dij(10) = dij_X + i dij_Y ; Dij(01) = dij_X - i dij_Y */
171 dij = std::complex<real_type<F>>(uc.atom(ia).d_mtrx(ibf, jbf, 2),
172 spin_factor * uc.atom(ia).d_mtrx(ibf, jbf, 3));
173 /* add non-diagonal spin components*/
174 for_bnd(ibf, jbf, dij, 0.0, beta_phi_chunks[ispn + spin_factor]);
175 }
176 } // jbf
177 } // ibf
178 } // ia_chunk
179 } // ispn
180 } // x
181 }
182
183 // bp_base__.dismiss();
184}
185
186}
187
188#endif /* __NON_LOCAL_FUNCTOR_HPP__ */
Contains implementation of sirius::Augmentation_operator class.
Contains declaration and implementation of sirius::Beta_projectors_base class.
Base class for beta-projectors, gradient of beta-projectors and strain derivatives of beta-projectors...
K-point related variables and methods.
Definition: k_point.hpp:44
double band_occupancy(int j__, int ispn__) const
Get band occupancy.
Definition: k_point.hpp:434
double band_energy(int j__, int ispn__) const
Get band energy.
Definition: k_point.hpp:413
double weight() const
Return weight of k-point.
Definition: k_point.hpp:456
int num_occupied_bands(int ispn__=-1) const
Get the number of occupied bands for each spin channel.
Definition: k_point.hpp:399
Simulation context is a set of parameters and objects describing a single simulation.
auto const & augmentation_op(int iat__) const
Returns a constant pointer to the augmentation operator of a given atom type.
auto processing_unit_memory_t() const
Return the memory type for processing unit.
auto host_memory_t() const
Type of the host memory for arrays used in linear algebra operations.
int num_spins() const
Number of spin components.
int num_mag_dims() const
Number of dimensions in the magnetization vector.
Multidimensional array with the column-major (Fortran) order.
Definition: memory.hpp:660
value_type local_size(block_id block_id__) const
Return local size of the split index for a given block.
Definition: splindex.hpp:302
Index_t::global global_index(typename Index_t::local idxloc__, block_id block_id__) const
Return global index of an element by local index and block id.
Definition: splindex.hpp:332
Describe a range of bands.
Contains definition of sirius::K_point class.
Memory management functions and classes.
Namespace of the SIRIUS library.
Definition: sirius.f90:5
void add_k_point_contribution_nonlocal(Simulation_context &ctx__, Beta_projectors_base< T > &bp_base__, K_point< T > &kp__, sddk::mdarray< real_type< F >, 2 > &collect_res__)
strong_type< int, struct __n_blocks_tag > n_blocks
Number of blocks to which the global index is split.
Definition: splindex.hpp:105
auto conj(double x__)
Return complex conjugate of a number. For a real value this is the number itself.
Definition: math_tools.hpp:165
Contains declaration and partial implementation of sirius::Periodic_function class.
static const int ia
Global index of atom.
static const int nbf
Number of beta-projector functions for this atom.
static const int offset
Offset of beta-projectors in this chunk.