SIRIUS 7.5.0
Electronic structure library and applications
radial_integrals.hpp
Go to the documentation of this file.
1// Copyright (c) 2013-2017 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 radial_integrals.hpp
21 *
22 * \brief Representation of various radial integrals.
23 */
24
25#ifndef __RADIAL_INTEGRALS_HPP__
26#define __RADIAL_INTEGRALS_HPP__
27
29#include "core/sf/sbessel.hpp"
30#include "core/rte/rte.hpp"
31#include "core/env/env.hpp"
33
34namespace sirius {
35
36/// Base class for all kinds of radial integrals.
37template <int N>
39{
40 protected:
41 /// Unit cell.
43
44 /// Linear grid of q-points on which the interpolation of radial integrals is done.
46
47 /// Split index of q-points.
49
50 /// Array with integrals.
52
53 /// Maximum length of the reciprocal wave-vector.
54 double qmax_{0};
55
56 public:
57 /// Constructor.
58 Radial_integrals_base(Unit_cell const& unit_cell__, double const qmax__, int const np__)
59 : unit_cell_(unit_cell__)
60 {
61 /* Add extra length to the cutoffs in order to interpolate radial integrals for q > cutoff.
62 This is needed for the variable cell relaxation when lattice changes and the G-vectors in
63 Cartiesin coordinates exceed the initial cutoff length. Do not remove this extra delta! */
64
65 /* add extra length in [a.u.^-1] */
66 qmax_ = qmax__ + std::max(10.0, qmax__ * 0.1);
67
68 grid_q_ = Radial_grid_lin<double>(static_cast<int>(np__ * qmax_), 0, qmax_);
70 block_id(unit_cell_.comm().rank()));
71 }
72
73 /// Get starting index iq and delta dq for the q-point on the linear grid.
74 /** The following condition is satisfied: q = grid_q[iq] + dq */
75 inline std::pair<int, double> iqdq(double q__) const
76 {
77 if (q__ > grid_q_.last()) {
78 std::stringstream s;
79 s << "q-point is out of range" << std::endl
80 << " q : " << q__ << std::endl
81 << " last point of the q-grid : " << grid_q_.last() << std::endl;
82 auto uc = unit_cell_.serialize();
83 s << "unit cell: " << uc;
84 RTE_THROW(s);
85 }
86 std::pair<int, double> result;
87 /* find index of q-point */
88 result.first = static_cast<int>((grid_q_.num_points() - 1) * q__ / grid_q_.last());
89 /* delta q = q - q_i */
90 result.second = q__ - grid_q_[result.first];
91 return result;
92 }
93
94 /// Return value of the radial integral with specific indices.
95 template <typename... Args>
96 inline double value(Args... args, double q__) const
97 {
98 auto idx = iqdq(q__);
99 return values_(args...)(idx.first, idx.second);
100 }
101
102 inline int nq() const
103 {
104 return grid_q_.num_points();
105 }
106
107 inline double qmax() const
108 {
109 return qmax_;
110 }
111};
112
113/// Radial integrals of the atomic centered orbitals.
114/** Used in initialize_subspace and in the hubbard correction. */
115template <bool jl_deriv>
117{
118 private:
119 /// Callback function to compute radial integrals using the host code.
120 std::function<void(int, double, double*, int)> atomic_wfc_callback_{nullptr};
121 /// Return radial basis index for a given atom type.
122 std::function<radial_functions_index const&(int)> indexr_;
123 /// Generate radial integrals.
124 void generate(std::function<Spline<double> const&(int, int)> fl__);
125
126 public:
127 /// Constructor.
128 Radial_integrals_atomic_wf(Unit_cell const& unit_cell__, double qmax__, int np__,
129 std::function<radial_functions_index const&(int)> indexr__,
130 std::function<Spline<double> const&(int, int)> fl__,
131 std::function<void(int, double, double*, int)> atomic_wfc_callback__)
132 : Radial_integrals_base<2>(unit_cell__, qmax__, np__)
133 , atomic_wfc_callback_(atomic_wfc_callback__)
134 , indexr_(indexr__)
135 {
136 if (atomic_wfc_callback_ == nullptr) {
137 int nrf_max{0};
138 for (int iat = 0; iat < unit_cell__.num_atom_types(); iat++) {
139 nrf_max = std::max(nrf_max, static_cast<int>(indexr_(iat).size()));
140 }
141
143
144 generate(fl__);
145 }
146 }
147
148 /// Retrieve a value for a given orbital of an atom type.
149 inline Spline<double> const& values(int iwf__, int iat__) const
150 {
151 return values_(iwf__, iat__);
152 }
153
154 /// Get all values for a given atom type and q-point.
155 inline sddk::mdarray<double, 1> values(int iat__, double q__) const
156 {
157 auto idx = iqdq(q__);
158 auto& atom_type = unit_cell_.atom_type(iat__);
159 int nrf = indexr_(atom_type.id()).size();
160
162
163 if (atomic_wfc_callback_ == nullptr) {
164 for (int i = 0; i < nrf; i++) {
165 val(i) = values_(i, iat__)(idx.first, idx.second);
166 }
167 } else {
168 atomic_wfc_callback_(iat__ + 1, q__, &val[0], nrf);
169 }
170 return val;
171 }
172};
173
174/// Radial integrals of the augmentation operator.
175template <bool jl_deriv>
177{
178 private:
179 std::function<void(int, double, double*, int, int)> ri_callback_{nullptr};
180
181 void generate();
182
183 public:
184 Radial_integrals_aug(Unit_cell const& unit_cell__, double qmax__, int np__,
185 std::function<void(int, double, double*, int, int)> ri_callback__)
186 : Radial_integrals_base<3>(unit_cell__, qmax__, np__)
187 , ri_callback_(ri_callback__)
188 {
189 if (ri_callback_ == nullptr) {
191 int lmax = unit_cell_.lmax();
192
193 values_ =
194 sddk::mdarray<Spline<double>, 3>(nmax * (nmax + 1) / 2, 2 * lmax + 1, unit_cell_.num_atom_types());
195
196 generate();
197 }
198 }
199
200 inline sddk::mdarray<double, 2> values(int iat__, double q__) const
201 {
202 auto& atom_type = unit_cell_.atom_type(iat__);
203 int lmax = atom_type.indexr().lmax();
204 int nbrf = atom_type.mt_radial_basis_size();
205
206 sddk::mdarray<double, 2> val(nbrf * (nbrf + 1) / 2, 2 * lmax + 1);
207
208 if (ri_callback_ == nullptr) {
209 auto idx = iqdq(q__);
210
211 for (int l = 0; l <= 2 * lmax; l++) {
212 for (int i = 0; i < nbrf * (nbrf + 1) / 2; i++) {
213 val(i, l) = values_(i, l, iat__)(idx.first, idx.second);
214 }
215 }
216 } else {
217 ri_callback_(iat__ + 1, q__, &val[0], nbrf * (nbrf + 1) / 2, 2 * lmax + 1);
218 }
219 return val;
220 }
221};
222
224{
225 private:
226 std::function<void(int, int, double*, double*)> ri_callback_{nullptr};
227 void generate();
228
229 public:
230 Radial_integrals_rho_pseudo(Unit_cell const& unit_cell__, double qmax__, int np__,
231 std::function<void(int, int, double*, double*)> ri_callback__)
232 : Radial_integrals_base<1>(unit_cell__, qmax__, np__)
233 , ri_callback_(ri_callback__)
234 {
235 if (ri_callback__ == nullptr) {
237 generate();
238
239 auto pcs = env::print_checksum();
240
241 if (pcs && unit_cell_.comm().rank() == 0) {
242 double cs{0};
243 for (int iat = 0; iat < unit_cell_.num_atom_types(); iat++) {
244 for (int iq = 0; iq < grid_q_.num_points(); iq++) {
245 cs += values_(iat)(iq);
246 }
247 }
248 print_checksum("Radial_integrals_rho_pseudo", cs, std::cout);
249 }
250 }
251 }
252
253 /// Compute all values of the raial integrals.
254 inline auto values(std::vector<double>& q__, mpi::Communicator const& comm__) const
255 {
256 int nq = static_cast<int>(q__.size());
257 splindex_block<> splq(nq, n_blocks(comm__.size()), block_id(comm__.rank()));
259 result.zero();
260 for (int iat = 0; iat < unit_cell_.num_atom_types(); iat++) {
261 if (!unit_cell_.atom_type(iat).ps_total_charge_density().empty()) {
262 #pragma omp parallel for
263 for (int iqloc = 0; iqloc < splq.local_size(); iqloc++) {
264 auto iq = splq.global_index(iqloc);
265 if (ri_callback_) {
266 ri_callback_(iat + 1, 1, &q__[iq], &result(iq, iat));
267 } else {
268 result(iq, iat) = this->value<int>(iat, q__[iq]);
269 }
270 }
271 comm__.allgather(&result(0, iat), splq.local_size(), splq.global_offset());
272 }
273 }
274 return result;
275 }
276};
277
278template <bool jl_deriv>
280{
281 private:
282 std::function<void(int, int, double*, double*)> ri_callback_{nullptr};
283 void generate();
284
285 public:
286 Radial_integrals_rho_core_pseudo(Unit_cell const& unit_cell__, double qmax__, int np__,
287 std::function<void(int, int, double*, double*)> ri_callback__)
288 : Radial_integrals_base<1>(unit_cell__, qmax__, np__)
289 , ri_callback_(ri_callback__)
290 {
291 if (ri_callback_ == nullptr) {
293 generate();
294 }
295 }
296
297 /// Compute all values of the raial integrals.
298 inline auto values(std::vector<double>& q__, mpi::Communicator const& comm__) const
299 {
300 int nq = static_cast<int>(q__.size());
301 splindex_block<> splq(nq, n_blocks(comm__.size()), block_id(comm__.rank()));
303 result.zero();
304 for (int iat = 0; iat < unit_cell_.num_atom_types(); iat++) {
305 if (!unit_cell_.atom_type(iat).ps_core_charge_density().empty()) {
306 #pragma omp parallel for
307 for (int iqloc = 0; iqloc < splq.local_size(); iqloc++) {
308 auto iq = splq.global_index(iqloc);
309 if (ri_callback_) {
310 ri_callback_(iat + 1, 1, &q__[iq], &result(iq, iat));
311 } else {
312 result(iq, iat) = this->value<int>(iat, q__[iq]);
313 }
314 }
315 comm__.allgather(&result(0, iat), splq.local_size(), splq.global_offset());
316 }
317 }
318 return result;
319 }
320};
321
322/// Radial integrals of beta projectors.
323template <bool jl_deriv>
325{
326 private:
327 /// Callback function to compute radial integrals using the host code.
328 std::function<void(int, double, double*, int)> ri_callback_{nullptr};
329
330 /// Generate radial integrals on the q-grid.
331 void generate();
332
333 public:
334 Radial_integrals_beta(Unit_cell const& unit_cell__, double qmax__, int np__,
335 std::function<void(int, double, double*, int)> ri_callback__)
336 : Radial_integrals_base<2>(unit_cell__, qmax__, np__)
337 , ri_callback_(ri_callback__)
338 {
339 if (ri_callback_ == nullptr) {
340 /* create space for <j_l(qr)|beta> or <d j_l(qr) / dq|beta> radial integrals */
342 generate();
343 }
344 }
345
346 /// Get all values for a given atom type and q-point.
347 inline sddk::mdarray<double, 1> values(int iat__, double q__) const
348 {
349 auto& atom_type = unit_cell_.atom_type(iat__);
350 sddk::mdarray<double, 1> val(atom_type.mt_radial_basis_size());
351 if (ri_callback_ == nullptr) {
352 auto idx = iqdq(q__);
353 for (int i = 0; i < atom_type.mt_radial_basis_size(); i++) {
354 val(i) = values_(i, iat__)(idx.first, idx.second);
355 }
356 } else {
357 ri_callback_(iat__ + 1, q__, &val[0], atom_type.mt_radial_basis_size());
358 }
359 return val;
360 }
361};
362
363template <bool jl_deriv>
365{
366 private:
367 std::function<void(int, int, double*, double*)> ri_callback_{nullptr};
368 void generate();
369
370 public:
371 Radial_integrals_vloc(Unit_cell const& unit_cell__, double qmax__, int np__,
372 std::function<void(int, int, double*, double*)> ri_callback__)
373 : Radial_integrals_base<1>(unit_cell__, qmax__, np__)
374 , ri_callback_(ri_callback__)
375 {
376 if (ri_callback_ == nullptr) {
378 generate();
379 }
380 }
381
382 /// Special implementation to recover the true radial integral value.
383 inline double value(int iat__, double q__) const
384 {
385 if (unit_cell_.atom_type(iat__).local_potential().empty()) {
386 return 0;
387 }
388 auto idx = iqdq(q__);
389 if (std::abs(q__) < 1e-12) {
390 if (jl_deriv) {
391 return 0;
392 } else {
393 return values_(iat__)(0);
394 }
395 } else {
396 auto& atom_type = unit_cell_.atom_type(iat__);
397
398 auto q2 = std::pow(q__, 2);
399 if (jl_deriv) {
400 return values_(iat__)(idx.first, idx.second) / q2 / q__ -
401 atom_type.zn() * std::exp(-q2 / 4) * (4 + q2) / 2 / q2 / q2;
402 } else {
403 return values_(iat__)(idx.first, idx.second) / q__ - atom_type.zn() * std::exp(-q2 / 4) / q2;
404 }
405 }
406 }
407
408 /// Compute all values of the raial integrals.
409 inline auto values(std::vector<double>& q__, mpi::Communicator const& comm__) const
410 {
411 int nq = static_cast<int>(q__.size());
412 splindex_block<> splq(nq, n_blocks(comm__.size()), block_id(comm__.rank()));
414 result.zero();
415 for (int iat = 0; iat < unit_cell_.num_atom_types(); iat++) {
416 if (!unit_cell_.atom_type(iat).local_potential().empty()) {
417 #pragma omp parallel for
418 for (int iqloc = 0; iqloc < splq.local_size(); iqloc++) {
419 auto iq = splq.global_index(iqloc);
420 if (ri_callback_) {
421 ri_callback_(iat + 1, 1, &q__[iq], &result(iq, iat));
422 } else {
423 result(iq, iat) = this->value(iat, q__[iq]);
424 }
425 }
426 comm__.allgather(&result(0, iat), splq.local_size(), splq.global_offset());
427 }
428 }
429 return result;
430 }
431};
432
434{
435 private:
436 void generate();
437
438 public:
439 Radial_integrals_rho_free_atom(Unit_cell const& unit_cell__, double qmax__, int np__)
440 : Radial_integrals_base<1>(unit_cell__, qmax__, np__)
441 {
443 generate();
444 }
445
446 /// Special implementation to recover the true radial integral value.
447 inline double value(int iat__, double q__) const
448 {
449 auto idx = iqdq(q__);
450 if (std::abs(q__) < 1e-12) {
451 return values_(iat__)(0);
452 } else {
453 return values_(iat__)(idx.first, idx.second) / q__;
454 }
455 }
456};
457
458} // namespace sirius
459
460#endif // __RADIAL_INTEGRALS_H__
std::vector< double > & local_potential(std::vector< double > vloc__)
Set the radial function of the local potential.
Definition: atom_type.hpp:575
T last() const
Last point of the grid.
int num_points() const
Number of grid points.
Radial integrals of the atomic centered orbitals.
Radial_integrals_atomic_wf(Unit_cell const &unit_cell__, double qmax__, int np__, std::function< radial_functions_index const &(int)> indexr__, std::function< Spline< double > const &(int, int)> fl__, std::function< void(int, double, double *, int)> atomic_wfc_callback__)
Constructor.
sddk::mdarray< double, 1 > values(int iat__, double q__) const
Get all values for a given atom type and q-point.
std::function< radial_functions_index const &(int)> indexr_
Return radial basis index for a given atom type.
void generate(std::function< Spline< double > const &(int, int)> fl__)
Generate radial integrals.
Spline< double > const & values(int iwf__, int iat__) const
Retrieve a value for a given orbital of an atom type.
std::function< void(int, double, double *, int)> atomic_wfc_callback_
Callback function to compute radial integrals using the host code.
Radial integrals of the augmentation operator.
Base class for all kinds of radial integrals.
double value(Args... args, double q__) const
Return value of the radial integral with specific indices.
Radial_integrals_base(Unit_cell const &unit_cell__, double const qmax__, int const np__)
Constructor.
sddk::mdarray< Spline< double >, N > values_
Array with integrals.
Unit_cell const & unit_cell_
Unit cell.
double qmax_
Maximum length of the reciprocal wave-vector.
std::pair< int, double > iqdq(double q__) const
Get starting index iq and delta dq for the q-point on the linear grid.
splindex_block spl_q_
Split index of q-points.
Radial_grid< double > grid_q_
Linear grid of q-points on which the interpolation of radial integrals is done.
Radial integrals of beta projectors.
sddk::mdarray< double, 1 > values(int iat__, double q__) const
Get all values for a given atom type and q-point.
void generate()
Generate radial integrals on the q-grid.
std::function< void(int, double, double *, int)> ri_callback_
Callback function to compute radial integrals using the host code.
auto values(std::vector< double > &q__, mpi::Communicator const &comm__) const
Compute all values of the raial integrals.
double value(int iat__, double q__) const
Special implementation to recover the true radial integral value.
auto values(std::vector< double > &q__, mpi::Communicator const &comm__) const
Compute all values of the raial integrals.
double value(int iat__, double q__) const
Special implementation to recover the true radial integral value.
auto values(std::vector< double > &q__, mpi::Communicator const &comm__) const
Compute all values of the raial integrals.
Representation of a unit cell.
Definition: unit_cell.hpp:43
int lmax() const
Maximum orbital quantum number of radial functions between all atom types.
Definition: unit_cell.hpp:526
int num_atom_types() const
Number of atom types.
Definition: unit_cell.hpp:281
json serialize(bool cart_pos__=false) const
Write structure to JSON file.
Definition: unit_cell.cpp:374
Atom_type & atom_type(int id__)
Return atom type instance by id.
Definition: unit_cell.hpp:288
int max_mt_radial_basis_size() const
Maximum number of radial functions among all atom types.
Definition: unit_cell.hpp:440
MPI communicator wrapper.
void allgather(T *buffer__, int const *recvcounts__, int const *displs__) const
In-place MPI_Allgatherv.
int size() const
Size of the communicator (number of ranks).
int rank() const
Rank of MPI process inside communicator.
Radial basis function index.
Multidimensional array with the column-major (Fortran) order.
Definition: memory.hpp:660
void zero(memory_t mem__, size_t idx0__, size_t n__)
Zero n elements starting from idx0.
Definition: memory.hpp:1316
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
Get the environment variables.
int lmax(int lmmax__)
Get maximum orbital quantum number by the maximum lm index.
Definition: specfunc.hpp:56
Namespace of the SIRIUS library.
Definition: sirius.f90:5
strong_type< int, struct __n_blocks_tag > n_blocks
Number of blocks to which the global index is split.
Definition: splindex.hpp:105
Output stream tools.
Eror and warning handling during run-time execution.
Contains implementation of sirius::Spherical_Bessel_functions class.
Contains definition and partial implementation of sirius::Unit_cell class.