SIRIUS 7.5.0
Electronic structure library and applications
mixer_functions.cpp
Go to the documentation of this file.
1// Copyright (c) 2013-2019 Simon Frasch, Anton Kozhevnikov, 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 mixer_functions.cpp
21 *
22 * \brief Contains implemenations of functions required for mixing.
23 */
24
25#include <cassert>
26
28
29namespace sirius {
30
31namespace mixer {
32
33FunctionProperties<Periodic_function<double>> periodic_function_property()
34{
35 auto global_size_func = [](const Periodic_function<double>& x) -> double
36 {
37 return x.ctx().unit_cell().omega();
38 };
39
40 auto inner_prod_func = [](const Periodic_function<double>& x, const Periodic_function<double>& y) -> double {
41 return sirius::inner(x, y);
42 };
43
44 auto scal_function = [](double alpha, Periodic_function<double>& x) -> void {
45 scale(alpha, x.rg());
46 if (x.ctx().full_potential()) {
47 scale(alpha, x.mt());
48 }
49 };
50
51 auto copy_function = [](const Periodic_function<double>& x, Periodic_function<double>& y) -> void {
52 copy(x.rg(), y.rg());
53 if (x.ctx().full_potential()) {
54 copy(x.mt(), y.mt());
55 }
56 };
57
58 auto axpy_function = [](double alpha, const Periodic_function<double>& x, Periodic_function<double>& y) -> void {
59 axpy(alpha, x.rg(), y.rg());
60 if (x.ctx().full_potential()) {
61 axpy(alpha, x.mt(), y.mt());
62 }
63 };
64
65 auto rotate_function = [](double c, double s, Periodic_function<double>& x, Periodic_function<double>& y) -> void {
66 #pragma omp parallel
67 {
68 #pragma omp for schedule(static) nowait
69 for (std::size_t i = 0; i < x.rg().values().size(); ++i) {
70 auto xi = x.rg().value(i);
71 auto yi = y.rg().value(i);
72 x.rg().value(i) = xi * c + yi * s;
73 y.rg().value(i) = xi * -s + yi * c;
74 }
75 if (x.ctx().full_potential()) {
76 for (auto it : x.ctx().unit_cell().spl_num_atoms()) {
77 int ia = it.i;
78 auto& x_f_mt = x.mt()[ia];
79 auto& y_f_mt = y.mt()[ia];
80 #pragma omp for schedule(static) nowait
81 for (int i = 0; i < static_cast<int>(x.mt()[ia].size()); i++) {
82 auto xi = x_f_mt[i];
83 auto yi = y_f_mt[i];
84 x_f_mt[i] = xi * c + yi * s;
85 y_f_mt[i] = xi * -s + yi * c;
86 }
87 }
88 }
89 }
90 };
91
92 return FunctionProperties<Periodic_function<double>>(global_size_func, inner_prod_func, scal_function, copy_function,
93 axpy_function, rotate_function);
94}
95
96/// Only for the PP-PW case.
98{
99 auto global_size_func = [](Periodic_function<double> const& x) -> double
100 {
101 return 1.0 / x.ctx().unit_cell().omega();
102 };
103
104 auto inner_prod_func = [use_coarse_gvec__](Periodic_function<double> const& x,
105 Periodic_function<double> const& y) -> double
106 {
107 double result{0};
108 if (use_coarse_gvec__) {
109 for (int igloc = x.ctx().gvec_coarse().skip_g0(); igloc < x.ctx().gvec_coarse().count(); igloc++) {
110 /* local index in fine G-vector list */
111 int ig1 = x.ctx().gvec().gvec_base_mapping(igloc);
112
113 result += std::real(std::conj(x.rg().f_pw_local(ig1)) * y.rg().f_pw_local(ig1)) /
114 std::pow(x.ctx().gvec().gvec_len<index_domain_t::local>(ig1), 2);
115 }
116 } else {
117 for (int igloc = x.ctx().gvec().skip_g0(); igloc < x.ctx().gvec().count(); igloc++) {
118 result += std::real(std::conj(x.rg().f_pw_local(igloc)) * y.rg().f_pw_local(igloc)) /
119 std::pow(x.ctx().gvec().gvec_len<index_domain_t::local>(igloc), 2);
120 }
121 }
122 if (x.ctx().gvec().reduced()) {
123 result *= 2;
124 }
125 result *= fourpi;
126 x.ctx().comm().allreduce(&result, 1);
127 return result;
128 };
129
130 auto scal_function = [](double alpha, Periodic_function<double>& x) -> void
131 {
132 scale(alpha, x.rg());
133 };
134
135 auto copy_function = [](Periodic_function<double> const& x, Periodic_function<double>& y) -> void {
136 copy(x.rg(), y.rg());
137 };
138
139 auto axpy_function = [](double alpha, const Periodic_function<double>& x, Periodic_function<double>& y) -> void
140 {
141 axpy(alpha, x.rg(), y.rg());
142 };
143
144 auto rotate_function = [](double c, double s, Periodic_function<double>& x, Periodic_function<double>& y) -> void
145 {
146 #pragma omp parallel for schedule(static)
147 for (std::size_t i = 0; i < x.rg().values().size(); ++i) {
148 auto xi = x.rg().value(i);
149 auto yi = y.rg().value(i);
150 x.rg().value(i) = xi * c + yi * s;
151 y.rg().value(i) = xi * -s + yi * c;
152 }
153 };
154
155 return FunctionProperties<Periodic_function<double>>(global_size_func, inner_prod_func, scal_function, copy_function,
156 axpy_function, rotate_function);
157}
158
159FunctionProperties<density_matrix_t> density_function_property()
160{
161 auto global_size_func = [](density_matrix_t const& x) -> double {
162 size_t result{0};
163 for (auto& e : x) {
164 result += e.size();
165 }
166 return result;
167 };
168
169 auto inner_prod_func = [](density_matrix_t const& x, density_matrix_t const& y) -> double {
170 // do not contribute to mixing
171 return 0.0;
172 };
173
174 auto scal_function = [](double alpha, density_matrix_t& x) -> void {
175 for (std::size_t i = 0; i < x.size(); i++) {
176 for (std::size_t j = 0; j < x[i].size(); j++) {
177 x[i][j] *= alpha;
178 }
179 }
180 };
181
182 auto copy_function = [](density_matrix_t const& x, density_matrix_t& y) -> void {
183 assert(x.size() == y.size());
184 for (std::size_t i = 0; i < x.size(); i++) {
185 copy(x[i], y[i]);
186 }
187 };
188
189 auto axpy_function = [](double alpha, density_matrix_t const& x, density_matrix_t& y) -> void {
190 assert(x.size() == y.size());
191 for (std::size_t i = 0; i < x.size(); i++) {
192 for (std::size_t j = 0; j < x[i].size(); j++) {
193 y[i][j] += alpha * x[i][j];
194 }
195 }
196 };
197
198 auto rotate_function = [](double c, double s, density_matrix_t& x, density_matrix_t& y) -> void {
199 assert(x.size() == y.size());
200 for (std::size_t i = 0; i < x.size(); i++) {
201 for (std::size_t j = 0; j < x[i].size(); j++) {
202 auto xi = x[i][j];
203 auto yi = y[i][j];
204 x[i][j] = xi * c + yi * s;
205 y[i][j] = xi * -s + yi * c;
206 }
207 }
208 };
209
210 return FunctionProperties<density_matrix_t>(global_size_func, inner_prod_func, scal_function,
211 copy_function, axpy_function, rotate_function);
212}
213
214FunctionProperties<PAW_density<double>> paw_density_function_property()
215{
216 auto global_size_func = [](PAW_density<double> const& x) -> double
217 {
218 return x.unit_cell().num_paw_atoms();
219 };
220
221 auto inner_prod_func = [](PAW_density<double> const& x, PAW_density<double> const& y) -> double
222 {
223 return inner(x, y);
224 };
225
226 auto scale_func = [](double alpha, PAW_density<double>& x) -> void
227 {
228 for (auto it : x.unit_cell().spl_num_paw_atoms()) {
229 int ia = x.unit_cell().paw_atom_index(it.i);
230 for (int j = 0; j < x.unit_cell().parameters().num_mag_dims() + 1; j++) {
231 x.ae_density(j, ia) *= alpha;
232 x.ps_density(j, ia) *= alpha;
233 }
234 }
235 };
236
237 auto copy_function = [](PAW_density<double> const& x, PAW_density<double>& y) -> void
238 {
239 for (auto it : x.unit_cell().spl_num_paw_atoms()) {
240 int ia = x.unit_cell().paw_atom_index(it.i);
241 for (int j = 0; j < x.unit_cell().parameters().num_mag_dims() + 1; j++) {
242 sddk::copy(x.ae_density(j, ia), y.ae_density(j, ia));
243 sddk::copy(x.ps_density(j, ia), y.ps_density(j, ia));
244 }
245 }
246 };
247
248 auto axpy_function = [](double alpha, PAW_density<double> const& x, PAW_density<double>& y) -> void
249 {
250 for (auto it : x.unit_cell().spl_num_paw_atoms()) {
251 int ia = x.unit_cell().paw_atom_index(it.i);
252 for (int j = 0; j < x.unit_cell().parameters().num_mag_dims() + 1; j++) {
253 y.ae_density(j, ia) = x.ae_density(j, ia) * alpha + y.ae_density(j, ia);
254 y.ps_density(j, ia) = x.ps_density(j, ia) * alpha + y.ps_density(j, ia);
255 }
256 }
257 };
258
259 auto rotate_function = [](double c, double s, PAW_density<double>& x, PAW_density<double>& y) -> void
260 {
261 for (auto it : x.unit_cell().spl_num_paw_atoms()) {
262 int ia = x.unit_cell().paw_atom_index(it.i);
263 for (int j = 0; j < x.unit_cell().parameters().num_mag_dims() + 1; j++) {
264 x.ae_density(j, ia) = x.ae_density(j, ia) * c + s * y.ae_density(j, ia);
265 y.ae_density(j, ia) = y.ae_density(j, ia) * c - s * x.ae_density(j, ia);
266
267 x.ps_density(j, ia) = x.ps_density(j, ia) * c + s * y.ps_density(j, ia);
268 y.ps_density(j, ia) = y.ps_density(j, ia) * c - s * x.ps_density(j, ia);
269 }
270 }
271 };
272
273 return FunctionProperties<PAW_density<double>>(global_size_func, inner_prod_func, scale_func, copy_function,
274 axpy_function, rotate_function);
275}
276
277FunctionProperties<Hubbard_matrix> hubbard_matrix_function_property()
278{
279 auto global_size_func = [](Hubbard_matrix const& x) -> double
280 {
281 return 1.0;
282 };
283
284 auto inner_prod_func = [](Hubbard_matrix const& x, Hubbard_matrix const& y) -> double
285 {
286 /* do not contribute to mixing */
287 return 0;
288 };
289
290 auto scale_func = [](double alpha, Hubbard_matrix& x) -> void
291 {
292 for (size_t at_lvl = 0; at_lvl < x.local().size(); at_lvl++) {
293 for (size_t i = 0; i < x.local(at_lvl).size(); i++) {
294 x.local(at_lvl)[i] *= alpha;
295 }
296 }
297
298 for (size_t at_lvl = 0; at_lvl < x.nonlocal().size(); at_lvl++) {
299 for (size_t i = 0; i < x.nonlocal(at_lvl).size(); i++) {
300 x.nonlocal(at_lvl)[i] *= alpha;
301 }
302 }
303 };
304
305 auto copy_func = [](Hubbard_matrix const& x, Hubbard_matrix& y) -> void
306 {
307 for (size_t at_lvl = 0; at_lvl < x.local().size(); at_lvl++) {
308 sddk::copy(x.local(at_lvl), y.local(at_lvl));
309 }
310
311 for (size_t at_lvl = 0; at_lvl < x.nonlocal().size(); at_lvl++) {
312 sddk::copy(x.nonlocal(at_lvl), y.nonlocal(at_lvl));
313 }
314 };
315
316 auto axpy_func = [](double alpha, Hubbard_matrix const& x, Hubbard_matrix& y) -> void
317 {
318 for (size_t at_lvl = 0; at_lvl < x.local().size(); at_lvl++) {
319 for (size_t i = 0; i < x.local(at_lvl).size(); i++) {
320 y.local(at_lvl)[i] = alpha * x.local(at_lvl)[i] + y.local(at_lvl)[i];
321 }
322 }
323 for (size_t at_lvl = 0; at_lvl < x.nonlocal().size(); at_lvl++) {
324 for (size_t i = 0; i < x.nonlocal(at_lvl).size(); i++) {
325 y.nonlocal(at_lvl)[i] = alpha * x.nonlocal(at_lvl)[i] + y.nonlocal(at_lvl)[i];
326 }
327 }
328 };
329
330 auto rotate_func = [](double c, double s, Hubbard_matrix& x, Hubbard_matrix& y) -> void
331 {
332 for (size_t at_lvl = 0; at_lvl < x.local().size(); at_lvl++) {
333 for (size_t i = 0; i < x.local(at_lvl).size(); i++) {
334 auto xi = x.local(at_lvl)[i];
335 auto yi = y.local(at_lvl)[i];
336 x.local(at_lvl)[i] = xi * c + yi * s;
337 y.local(at_lvl)[i] = yi * c - xi * s;
338 }
339 }
340
341 for (size_t at_lvl = 0; at_lvl < x.nonlocal().size(); at_lvl++) {
342 for (size_t i = 0; i < x.nonlocal(at_lvl).size(); i++) {
343 auto xi = x.nonlocal(at_lvl)[i];
344 auto yi = y.nonlocal(at_lvl)[i];
345 x.nonlocal(at_lvl)[i] = xi * c + yi * s;
346 y.nonlocal(at_lvl)[i] = yi * c - xi * s;
347 }
348 }
349 };
350
351 return FunctionProperties<Hubbard_matrix>(global_size_func, inner_prod_func, scale_func, copy_func, axpy_func,
352 rotate_func);
353}
354} // namespace mixer
355
356} // namespace sirius
Representation of the periodical function on the muffin-tin geometry.
auto & rg()
Return reference to regular space grid component.
Contains declarations of functions required for mixing.
void copy(T *target__, T const *source__, size_t n__)
Copy memory inside a device.
Definition: acc.hpp:320
FunctionProperties< Periodic_function< double > > periodic_function_property_modified(bool use_coarse_gvec__)
Only for the PP-PW case.
std::enable_if_t< std::is_same< T, real_type< F > >::value, void > inner(::spla::Context &spla_ctx__, sddk::memory_t mem__, spin_range spins__, W const &wf_i__, band_range br_i__, Wave_functions< T > const &wf_j__, band_range br_j__, la::dmatrix< F > &result__, int irow0__, int jcol0__)
Compute inner product between the two sets of wave-functions.
Namespace of the SIRIUS library.
Definition: sirius.f90:5
const double fourpi
Definition: constants.hpp:48
auto conj(double x__)
Return complex conjugate of a number. For a real value this is the number itself.
Definition: math_tools.hpp:165
Describes operations on a function type used for mixing.
Definition: mixer.hpp:50