SIRIUS 7.5.0
Electronic structure library and applications
augmentation_operator.hpp
Go to the documentation of this file.
1// Copyright (c) 2013-2023 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 augmentation_operator.hpp
21 *
22 * \brief Contains implementation of sirius::Augmentation_operator class.
23 */
24
25#ifndef __AUGMENTATION_OPERATOR_HPP__
26#define __AUGMENTATION_OPERATOR_HPP__
27
29#include "core/fft/gvec.hpp"
30
31#if defined(SIRIUS_GPU)
32extern "C" {
33
34void
35aug_op_pw_coeffs_gpu(int ngvec__, int const* gvec_shell__, int const* idx__, int idxmax__,
36 std::complex<double> const* zilm__, int const* l_by_lm__, int lmmax__, double const* gc__, int ld0__,
37 int ld1__, double const* gvec_rlm__, int ld2__, double const* ri_values__, int ld3__, int ld4__,
38 double* q_pw__, int ld5__, double fourpi_omega__);
39
40void
41aug_op_pw_coeffs_deriv_gpu(int ngvec__, int const* gvec_shell__, double const* gvec_cart__, int const* idx__,
42 int idxmax__, double const* gc__, int ld0__, int ld1__, double const* rlm__, double const* rlm_dg__, int ld2__,
43 double const* ri_values__, double const* ri_dg_values__, int ld3__, int ld4__, double* q_pw__, int ld5__,
44 double fourpi__, int nu__, int lmax_q__);
45
46void
47spherical_harmonics_rlm_gpu(int lmax__, int ntp__, double const* theta__, double const* phi__, double* rlm__, int ld__);
48
49}
50#endif
51
52namespace sirius {
53
54template <typename F>
55inline void iterate_aug_atom_types(Unit_cell const& uc__, F&& f__)
56{
57 for (int iat = 0; iat < uc__.num_atom_types(); iat++) {
58 auto& atom_type = uc__.atom_type(iat);
59
60 if (!atom_type.augment() || atom_type.num_atoms() == 0) {
61 continue;
62 }
63 f__(atom_type);
64 }
65}
66
67inline auto max_l_aug(Unit_cell const& uc__)
68{
69 int l{0};
70
71 iterate_aug_atom_types(uc__,
72 [&l](Atom_type const& type__)
73 {
74 l = std::max(l, type__.indexr().lmax());
75 });
76
77 return l;
78}
79
80inline auto max_na_aug(Unit_cell const& uc__)
81{
82 int na{0};
83
84 iterate_aug_atom_types(uc__,
85 [&na](Atom_type const& type__)
86 {
87 na = std::max(na, type__.num_atoms());
88 });
89
90 return na;
91
92}
93
94inline auto max_nb_aug(Unit_cell const& uc__)
95{
96 int nb{0};
97
98 iterate_aug_atom_types(uc__,
99 [&nb](Atom_type const& type__)
100 {
101 nb = std::max(nb, type__.mt_basis_size());
102 });
103
104 return nb;
105}
106
107/// Augmentation charge operator Q(r) of the ultrasoft pseudopotential formalism.
108/** This class generates and stores the plane-wave coefficients of the augmentation charge operator for
109 a given atom type. */
111{
112 private:
113 Atom_type const& atom_type_;
114
115 fft::Gvec const& gvec_;
116
118
120
121 sddk::mdarray<double, 1> sym_weight_;
122
124
125 sddk::mdarray<double, 3> ri_values_;
126 sddk::mdarray<double, 3> ri_dq_values_;
127
129
130 sddk::mdarray<int, 1> l_by_lm_;
131
132 public:
133 /// Constructor.
134 /**\param [in] atom_type Atom type instance.
135 * \param [in] gvec G-vector instance.
136 * \param [in] radial_integrals Radial integrals of the Q(r) with spherical Bessel functions.
137 */
138 Augmentation_operator(Atom_type const& atom_type__, fft::Gvec const& gvec__,
140 : atom_type_(atom_type__)
141 , gvec_(gvec__)
142 {
143 int lmax_beta = atom_type_.indexr().lmax();
144 int lmax = 2 * lmax_beta;
145 int lmmax = sf::lmmax(lmax);
146
147 /* compute l of lm index */
148 auto l_by_lm = sf::l_by_lm(lmax);
149 l_by_lm_ = sddk::mdarray<int, 1>(lmmax);
150 std::copy(l_by_lm.begin(), l_by_lm.end(), &l_by_lm_[0]);
151
152 /* compute i^l array */
154 for (int l = 0, lm = 0; l <= lmax; l++) {
155 for (int m = -l; m <= l; m++, lm++) {
156 zilm_[lm] = std::pow(std::complex<double>(0, 1), l);
157 }
158 }
159
160 /* number of beta-projectors */
161 int nbf = atom_type_.mt_basis_size();
162 /* number of beta-projector radial functions */
163 int nbrf = atom_type__.mt_radial_basis_size();
164 /* only half of Q_{xi,xi'}(G) matrix is stored */
165 int nqlm = nbf * (nbf + 1) / 2;
166
167 /* flatten the indices */
168 idx_ = sddk::mdarray<int, 2>(3, nqlm);
169 for (int xi2 = 0; xi2 < nbf; xi2++) {
170 int lm2 = atom_type_.indexb(xi2).lm;
171 int idxrf2 = atom_type_.indexb(xi2).idxrf;
172
173 for (int xi1 = 0; xi1 <= xi2; xi1++) {
174 int lm1 = atom_type_.indexb(xi1).lm;
175 int idxrf1 = atom_type_.indexb(xi1).idxrf;
176
177 /* packed orbital index */
178 int idx12 = packed_index(xi1, xi2);
179 /* packed radial-function index */
180 int idxrf12 = packed_index(idxrf1, idxrf2);
181
182 idx_(0, idx12) = lm1;
183 idx_(1, idx12) = lm2;
184 idx_(2, idx12) = idxrf12;
185 }
186 }
187
188 ri_values_ = sddk::mdarray<double, 3>(nbrf * (nbrf + 1) / 2, lmax + 1, gvec_.num_gvec_shells_local());
189 ri_dq_values_ = sddk::mdarray<double, 3>(nbrf * (nbrf + 1) / 2, lmax + 1, gvec_.num_gvec_shells_local());
190 #pragma omp parallel for
191 for (int j = 0; j < gvec_.num_gvec_shells_local(); j++) {
192 auto ri = ri__.values(atom_type_.id(), gvec_.gvec_shell_len_local(j));
193 auto ri_dq = ri_dq__.values(atom_type__.id(), gvec_.gvec_shell_len_local(j));
194 for (int l = 0; l <= lmax; l++) {
195 for (int i = 0; i < nbrf * (nbrf + 1) / 2; i++) {
196 ri_values_(i, l, j) = ri(i, l);
197 ri_dq_values_(i, l, j) = ri_dq(i, l);
198 }
199 }
200 }
201
202 sym_weight_ = sddk::mdarray<double, 1>(nqlm);
203 for (int xi2 = 0; xi2 < nbf; xi2++) {
204 for (int xi1 = 0; xi1 <= xi2; xi1++) {
205 /* packed orbital index */
206 int idx12 = packed_index(xi1, xi2);
207 sym_weight_(idx12) = (xi1 == xi2) ? 1 : 2;
208 }
209 }
210
211 if (atom_type_.parameters().processing_unit() == sddk::device_t::GPU) {
212 auto& mpd = sddk::get_memory_pool(sddk::memory_t::device);
213 sym_weight_.allocate(mpd).copy_to(sddk::memory_t::device);
214 }
215
216 /* allocate array of plane-wave coefficients */
217 auto mt = (atom_type_.parameters().processing_unit() == sddk::device_t::CPU) ? sddk::memory_t::host :
218 sddk::memory_t::host_pinned;
219 q_pw_ = sddk::mdarray<double, 2>(nqlm, 2 * gvec_.count(), sddk::get_memory_pool(mt), "q_pw_");
220
221 }
222
223// TODO: not used at the moment, evaluate the possibility to remove in the future
224// /// Generate chunk of plane-wave coefficients on the GPU.
225// void generate_pw_coeffs_chunk_gpu(int g_begin__, int ng__, double const* gvec_rlm__, int ld__,
226// sddk::mdarray<double, 2>& qpw__) const
227// {
228//#if defined(SIRIUS_GPU)
229// double fourpi_omega = fourpi / gvec_.omega();
230//
231// /* maximum l of beta-projectors */
232// int lmax_beta = atom_type_.indexr().lmax();
233// int lmmax = sf::lmmax(2 * lmax_beta);
234// /* number of beta-projectors */
235// int nbf = atom_type_.mt_basis_size();
236// /* only half of Q_{xi,xi'}(G) matrix is stored */
237// int nqlm = nbf * (nbf + 1) / 2;
238// /* generate Q(G) */
239// aug_op_pw_coeffs_gpu(ng__, gvec_shell_.at(sddk::memory_t::device, g_begin__), idx_.at(sddk::memory_t::device),
240// nqlm, zilm_.at(sddk::memory_t::device), l_by_lm_.at(sddk::memory_t::device), lmmax,
241// gaunt_coefs_.at(sddk::memory_t::device), static_cast<int>(gaunt_coefs_.size(0)),
242// static_cast<int>(gaunt_coefs_.size(1)), gvec_rlm__, ld__,
243// ri_values_.at(sddk::memory_t::device), static_cast<int>(ri_values_.size(0)),
244// static_cast<int>(ri_values_.size(1)), qpw__.at(sddk::memory_t::device), static_cast<int>(qpw__.size(0)),
245// fourpi_omega);
246//#endif
247// }
248
249 /// Generate Q_{xi,xi'}(G) plane wave coefficients.
250 void generate_pw_coeffs();
251
252 /// Generate G-vector derivative Q_{xi,xi'}(G)/dG of the plane-wave coefficients */
253 void generate_pw_coeffs_gvec_deriv(int nu__);
254
255 auto const& q_pw() const
256 {
257 return q_pw_;
258 }
259
260 double q_pw(int i__, int ig__) const
261 {
262 return q_pw_(i__, ig__);
263 }
264
265 /// Get values of the Q-matrix.
266 inline double q_mtrx(int xi1__, int xi2__) const
267 {
268 return q_mtrx_(xi1__, xi2__);
269 }
270
271 inline auto const& sym_weight() const
272 {
273 return sym_weight_;
274 }
275
276 /// Weight of Q_{\xi,\xi'}.
277 /** 2 if off-diagonal (xi != xi'), 1 if diagonal (xi=xi') */
278 inline double sym_weight(int idx__) const
279 {
280 return sym_weight_(idx__);
281 }
282
283 Atom_type const& atom_type() const
284 {
285 return atom_type_;
286 }
287};
288
289} // namespace sirius
290
291#endif // __AUGMENTATION_OPERATOR_H__
Defines the properties of atom type.
Definition: atom_type.hpp:93
int mt_basis_size() const
Total number of muffin-tin basis functions (APW + LO).
Definition: atom_type.hpp:880
auto const & indexr() const
Return const reference to the index of radial functions.
Definition: atom_type.hpp:817
int mt_radial_basis_size() const
Total number of radial basis functions.
Definition: atom_type.hpp:886
int id() const
Return atom type id.
Definition: atom_type.hpp:675
Augmentation charge operator Q(r) of the ultrasoft pseudopotential formalism.
void generate_pw_coeffs()
Generate Q_{xi,xi'}(G) plane wave coefficients.
Augmentation_operator(Atom_type const &atom_type__, fft::Gvec const &gvec__, Radial_integrals_aug< false > const &ri__, Radial_integrals_aug< true > const &ri_dq__)
Constructor.
double sym_weight(int idx__) const
Weight of Q_{\xi,\xi'}.
double q_mtrx(int xi1__, int xi2__) const
Get values of the Q-matrix.
void generate_pw_coeffs_gvec_deriv(int nu__)
Generate G-vector derivative Q_{xi,xi'}(G)/dG of the plane-wave coefficients *‍/.
Radial integrals of the augmentation operator.
A set of G-vectors for FFTs and G+k basis functions.
Definition: gvec.hpp:130
int count() const
Number of G-vectors for a fine-grained distribution for the current MPI rank.
Definition: gvec.hpp:506
mdarray< T, N > & allocate(memory_t memory__)
Allocate memory for array.
Definition: memory.hpp:1057
Declaration and implementation of Gvec class.
void copy(T *target__, T const *source__, size_t n__)
Copy memory inside a device.
Definition: acc.hpp:320
int lmax(int lmmax__)
Get maximum orbital quantum number by the maximum lm index.
Definition: specfunc.hpp:56
int lmmax(int lmax)
Maximum number of combinations for a given .
Definition: specfunc.hpp:44
int lm(int l, int m)
Get composite lm index by angular index l and azimuthal index m.
Definition: specfunc.hpp:50
std::vector< int > l_by_lm(int lmax__)
Get array of orbital quantum numbers for each lm component.
Definition: specfunc.hpp:69
Namespace of the SIRIUS library.
Definition: sirius.f90:5
int packed_index(int i__, int j__)
Pack two indices into one for symmetric matrices.
Representation of various radial integrals.