SIRIUS 7.5.0
Electronic structure library and applications
sht.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 sht.hpp
21 *
22 * \brief Contains declaration and particular implementation of sirius::SHT class.
23 */
24
25#ifndef __SHT_HPP__
26#define __SHT_HPP__
27
28#include <math.h>
29#include <stddef.h>
30#include <gsl/gsl_sf_coupling.h>
31#include <gsl/gsl_sf_legendre.h>
32#include <string.h>
33#include <vector>
34#include <algorithm>
35
36#include "core/constants.hpp"
37#include "core/typedefs.hpp"
38#include "core/r3/r3.hpp"
39#include "core/sf/specfunc.hpp"
40#include "core/la/linalg.hpp"
41#include "lebedev_grids.hpp"
42
43namespace sirius {
44
45namespace sht {
46
47sddk::mdarray<double, 2>
48wigner_d_matrix(int l, double beta);
49
50template <typename T>
51sddk::mdarray<T, 2>
52rotation_matrix_l(int l, r3::vector<double> euler_angles, int proper_rotation);
53
54template <typename T>
55void
56rotation_matrix(int lmax, r3::vector<double> euler_angles, int proper_rotation, sddk::mdarray<T, 2>& rotm);
57
58template <typename T>
59std::vector<sddk::mdarray<T, 2>>
60rotation_matrix(int lmax, r3::vector<double> euler_angles, int proper_rotation);
61
62double
63ClebschGordan(const int l, const double j, const double mj, const int spin);
64
65// this function computes the U^sigma_{ljm mj} coefficient that
66// rotates the complex spherical harmonics to the real one for the
67// spin orbit case
68
69// mj is normally half integer from -j to j but to avoid computation
70// error it is considered as integer so mj = 2 mj
71std::complex<double>
72calculate_U_sigma_m(const int l, const double j, const int mj, const int mp, const int sigma);
73
74}
75
76/// Spherical harmonics transformations and related oprtations.
77/** This class is responsible for the generation of complex and real spherical harmonics, generation of transformation
78 * matrices, transformation between spectral and real-space representations, generation of Gaunt and Clebsch-Gordan
79 * coefficients and calculation of spherical harmonic derivatives */
80class SHT // TODO: better name
81{
82 private:
83 /// Type of processing unit.
85
86 /// Maximum \f$ \ell \f$ of spherical harmonics.
87 int lmax_;
88
89 /// Maximum number of \f$ \ell, m \f$ components.
90 int lmmax_;
91
92 /// Number of real-space \f$ (\theta, \phi) \f$ points on the sphere.
94
95 /// Cartesian coordinates of points (normalized to 1).
97
98 /// \f$ (\theta, \phi) \f$ angles of points.
100
101 /// Point weights.
102 std::vector<double> w_;
103
104 /// Backward transformation from Ylm to spherical coordinates.
106
107 /// Forward transformation from spherical coordinates to Ylm.
109
110 /// Backward transformation from Rlm to spherical coordinates.
112
113 /// Forward transformation from spherical coordinates to Rlm.
115
116 /// Type of spherical grid (0: Lebedev-Laikov, 1: uniform).
118
119 public:
120 /// Default constructor.
121 SHT(sddk::device_t pu__, int lmax__, int mesh_type__ = 0)
122 : pu_(pu__)
123 , lmax_(lmax__)
124 , mesh_type_(mesh_type__)
125 {
126 lmmax_ = (lmax_ + 1) * (lmax_ + 1);
127
128 switch (mesh_type_) {
129 case 0: {
130 num_points_ = Lebedev_Laikov_npoint(2 * lmax_);
131 break;
132 }
133 case 1: {
135 break;
136 }
137 default: {
138 std::stringstream s;
139 s << "[SHT] wrong spherical coverage parameter : " << mesh_type_;
140 throw std::runtime_error(s.str());
141 }
142 }
143
144 std::vector<double> x(num_points_);
145 std::vector<double> y(num_points_);
146 std::vector<double> z(num_points_);
147
149
151
152 w_.resize(num_points_);
153
154 switch (mesh_type_) {
155 case 0: {
156 Lebedev_Laikov_sphere(num_points_, &x[0], &y[0], &z[0], &w_[0]);
157 break;
158 }
159 case 1: {
160 uniform_coverage();
161 break;
162 }
163 }
164
166
168
170
172
173 for (int itp = 0; itp < num_points_; itp++) {
174 switch (mesh_type_) {
175 case 0: {
176 coord_(0, itp) = x[itp];
177 coord_(1, itp) = y[itp];
178 coord_(2, itp) = z[itp];
179
180 auto vs = spherical_coordinates(r3::vector<double>(x[itp], y[itp], z[itp]));
181
182 tp_(0, itp) = vs[1];
183 tp_(1, itp) = vs[2];
184 sf::spherical_harmonics(lmax_, vs[1], vs[2], &ylm_backward_(0, itp));
185 sf::spherical_harmonics(lmax_, vs[1], vs[2], &rlm_backward_(0, itp));
186 for (int lm = 0; lm < lmmax_; lm++) {
187 ylm_forward_(itp, lm) = std::conj(ylm_backward_(lm, itp)) * w_[itp] * fourpi;
188 rlm_forward_(itp, lm) = rlm_backward_(lm, itp) * w_[itp] * fourpi;
189 }
190 break;
191 }
192 case 1: {
193 double t = tp_(0, itp);
194 double p = tp_(1, itp);
195
196 coord_(0, itp) = std::sin(t) * std::cos(p);
197 coord_(1, itp) = std::sin(t) * std::sin(p);
198 coord_(2, itp) = std::cos(t);
199
202
203 for (int lm = 0; lm < lmmax_; lm++) {
204 ylm_forward_(lm, itp) = ylm_backward_(lm, itp);
205 rlm_forward_(lm, itp) = rlm_backward_(lm, itp);
206 }
207 break;
208 }
209 }
210 }
211
212 if (mesh_type_ == 1) {
215 }
216
217 switch (pu_) {
218 case sddk::device_t::GPU: {
219 ylm_forward_.allocate(sddk::memory_t::device).copy_to(sddk::memory_t::device);
220 rlm_forward_.allocate(sddk::memory_t::device).copy_to(sddk::memory_t::device);
221 ylm_backward_.allocate(sddk::memory_t::device).copy_to(sddk::memory_t::device);
222 rlm_backward_.allocate(sddk::memory_t::device).copy_to(sddk::memory_t::device);
223 break;
224 }
225 case sddk::device_t::CPU: {
226 break;
227 }
228 }
229 }
230
231 /// Check the transformations.
232 void check() const;
233
234 /// Perform a backward transformation from spherical harmonics to spherical coordinates.
235 /** \f[
236 * f(\theta, \phi, r) = \sum_{\ell m} f_{\ell m}(r) Y_{\ell m}(\theta, \phi)
237 * \f]
238 *
239 * \param [in] ld Size of leading dimension of flm.
240 * \param [in] flm Raw pointer to \f$ f_{\ell m}(r) \f$.
241 * \param [in] nr Number of radial points.
242 * \param [in] lmmax Maximum number of lm- harmonics to take into sum.
243 * \param [out] ftp Raw pointer to \f$ f(\theta, \phi, r) \f$.
244 */
245 template <typename T>
246 void backward_transform(int ld, T const* flm, int nr, int lmmax, T* ftp) const;
247
248 /// Perform a forward transformation from spherical coordinates to spherical harmonics.
249 /** \f[
250 * f_{\ell m}(r) = \iint f(\theta, \phi, r) Y_{\ell m}^{*}(\theta, \phi) \sin \theta d\phi d\theta =
251 * \sum_{i} f(\theta_i, \phi_i, r) Y_{\ell m}^{*}(\theta_i, \phi_i) w_i
252 * \f]
253 *
254 * \param [in] ftp Raw pointer to \f$ f(\theta, \phi, r) \f$.
255 * \param [in] nr Number of radial points.
256 * \param [in] lmmax Maximum number of lm- coefficients to generate.
257 * \param [in] ld Size of leading dimension of flm.
258 * \param [out] flm Raw pointer to \f$ f_{\ell m}(r) \f$.
259 */
260 template <typename T>
261 void forward_transform(T const* ftp, int nr, int lmmax, int ld, T* flm) const;
262
263 /// Convert form Rlm to Ylm representation.
264 static void convert(int lmax__, double const* f_rlm__, std::complex<double>* f_ylm__)
265 {
266 int lm = 0;
267 for (int l = 0; l <= lmax__; l++) {
268 for (int m = -l; m <= l; m++) {
269 if (m == 0) {
270 f_ylm__[lm] = f_rlm__[lm];
271 } else {
272 int lm1 = sf::lm(l, -m);
273 f_ylm__[lm] = ylm_dot_rlm(l, m, m) * f_rlm__[lm] + ylm_dot_rlm(l, m, -m) * f_rlm__[lm1];
274 }
275 lm++;
276 }
277 }
278 }
279
280 /// Convert from Ylm to Rlm representation.
281 static void convert(int lmax__, std::complex<double> const* f_ylm__, double* f_rlm__)
282 {
283 int lm = 0;
284 for (int l = 0; l <= lmax__; l++) {
285 for (int m = -l; m <= l; m++) {
286 if (m == 0) {
287 f_rlm__[lm] = std::real(f_ylm__[lm]);
288 } else {
289 int lm1 = sf::lm(l, -m);
290 f_rlm__[lm] = std::real(rlm_dot_ylm(l, m, m) * f_ylm__[lm] + rlm_dot_ylm(l, m, -m) * f_ylm__[lm1]);
291 }
292 lm++;
293 }
294 }
295 }
296
297 //void rlm_forward_iterative_transform(double *ftp__, int lmmax, int ncol, double* flm)
298 //{
299 // Timer t("sirius::SHT::rlm_forward_iterative_transform");
300 //
301 // RTE_ASSERT(lmmax <= lmmax_);
302
303 // mdarray<double, 2> ftp(ftp__, num_points_, ncol);
304 // mdarray<double, 2> ftp1(num_points_, ncol);
305 //
306 // blas<cpu>::gemm(1, 0, lmmax, ncol, num_points_, 1.0, &rlm_forward_(0, 0), num_points_, &ftp(0, 0), num_points_, 0.0,
307 // flm, lmmax);
308 //
309 // for (int i = 0; i < 2; i++)
310 // {
311 // rlm_backward_transform(flm, lmmax, ncol, &ftp1(0, 0));
312 // double tdiff = 0.0;
313 // for (int ir = 0; ir < ncol; ir++)
314 // {
315 // for (int itp = 0; itp < num_points_; itp++)
316 // {
317 // ftp1(itp, ir) = ftp(itp, ir) - ftp1(itp, ir);
318 // //tdiff += fabs(ftp1(itp, ir));
319 // }
320 // }
321 //
322 // for (int itp = 0; itp < num_points_; itp++)
323 // {
324 // tdiff += fabs(ftp1(itp, ncol - 1));
325 // }
326 // std::cout << "iter : " << i << " avg. MT diff = " << tdiff / num_points_ << std::endl;
327 // blas<cpu>::gemm(1, 0, lmmax, ncol, num_points_, 1.0, &rlm_forward_(0, 0), num_points_, &ftp1(0, 0), num_points_, 1.0,
328 // flm, lmmax);
329 // }
330 //}
331
332 /// Compute element of the transformation matrix from complex to real spherical harmonics.
333 /** Real spherical harmonic can be written as a linear combination of complex harmonics:
334 \f[
335 R_{\ell m}(\theta, \phi) = \sum_{m'} a^{\ell}_{m' m}Y_{\ell m'}(\theta, \phi)
336 \f]
337 where
338 \f[
339 a^{\ell}_{m' m} = \langle Y_{\ell m'} | R_{\ell m} \rangle
340 \f]
341 which gives the name to this function.
342
343 Transformation from real to complex spherical harmonics is conjugate transpose:
344
345 \f[
346 Y_{\ell m}(\theta, \phi) = \sum_{m'} a^{\ell*}_{m m'}R_{\ell m'}(\theta, \phi)
347 \f]
348
349 Mathematica code:
350 \verbatim
351 b[m1_, m2_] :=
352 If[m1 == 0, 1,
353 If[m1 < 0 && m2 < 0, -I/Sqrt[2],
354 If[m1 > 0 && m2 < 0, (-1)^m1*I/Sqrt[2],
355 If[m1 < 0 && m2 > 0, (-1)^m2/Sqrt[2],
356 If[m1 > 0 && m2 > 0, 1/Sqrt[2]]]]]]
357
358 a[m1_, m2_] := If[Abs[m1] == Abs[m2], b[m1, m2], 0]
359
360 Rlm[l_, m_, t_, p_] := Sum[a[m1, m]*SphericalHarmonicY[l, m1, t, p], {m1, -l, l}]
361 \endverbatim
362 */
363 static inline std::complex<double> ylm_dot_rlm(int l, int m1, int m2)
364 {
365 double const isqrt2 = 1.0 / std::sqrt(2);
366
367 RTE_ASSERT(l >= 0 && std::abs(m1) <= l && std::abs(m2) <= l);
368
369 if (!((m1 == m2) || (m1 == -m2))) {
370 return std::complex<double>(0, 0);
371 }
372
373 if (m1 == 0) {
374 return std::complex<double>(1, 0);
375 }
376
377 if (m1 < 0) {
378 if (m2 < 0) {
379 return -std::complex<double>(0, isqrt2);
380 } else {
381 return std::pow(-1.0, m2) * std::complex<double>(isqrt2, 0);
382 }
383 } else {
384 if (m2 < 0) {
385 return std::pow(-1.0, m1) * std::complex<double>(0, isqrt2);
386 } else {
387 return std::complex<double>(isqrt2, 0);
388 }
389 }
390 }
391
392 static inline std::complex<double> rlm_dot_ylm(int l, int m1, int m2)
393 {
394 return std::conj(ylm_dot_rlm(l, m2, m1));
395 }
396
397 /// Gaunt coefficent of three complex spherical harmonics.
398 /**
399 * \f[
400 * \langle Y_{\ell_1 m_1} | Y_{\ell_2 m_2} | Y_{\ell_3 m_3} \rangle
401 * \f]
402 */
403 static double gaunt_yyy(int l1, int l2, int l3, int m1, int m2, int m3)
404 {
405 RTE_ASSERT(l1 >= 0);
406 RTE_ASSERT(l2 >= 0);
407 RTE_ASSERT(l3 >= 0);
408 RTE_ASSERT(m1 >= -l1 && m1 <= l1);
409 RTE_ASSERT(m2 >= -l2 && m2 <= l2);
410 RTE_ASSERT(m3 >= -l3 && m3 <= l3);
411
412 return std::pow(-1.0, std::abs(m1)) * std::sqrt(double(2 * l1 + 1) * double(2 * l2 + 1) * double(2 * l3 + 1) / fourpi) *
413 gsl_sf_coupling_3j(2 * l1, 2 * l2, 2 * l3, 0, 0, 0) *
414 gsl_sf_coupling_3j(2 * l1, 2 * l2, 2 * l3, -2 * m1, 2 * m2, 2 * m3);
415 }
416
417 /// Gaunt coefficent of three real spherical harmonics.
418 /**
419 * \f[
420 * \langle R_{\ell_1 m_1} | R_{\ell_2 m_2} | R_{\ell_3 m_3} \rangle
421 * \f]
422 */
423 static double gaunt_rrr(int l1, int l2, int l3, int m1, int m2, int m3)
424 {
425 RTE_ASSERT(l1 >= 0);
426 RTE_ASSERT(l2 >= 0);
427 RTE_ASSERT(l3 >= 0);
428 RTE_ASSERT(m1 >= -l1 && m1 <= l1);
429 RTE_ASSERT(m2 >= -l2 && m2 <= l2);
430 RTE_ASSERT(m3 >= -l3 && m3 <= l3);
431
432 double d = 0;
433 for (int k1 = -l1; k1 <= l1; k1++) {
434 for (int k2 = -l2; k2 <= l2; k2++) {
435 for (int k3 = -l3; k3 <= l3; k3++) {
436 d += std::real(std::conj(SHT::ylm_dot_rlm(l1, k1, m1)) *
437 SHT::ylm_dot_rlm(l2, k2, m2) *
438 SHT::ylm_dot_rlm(l3, k3, m3)) *
439 SHT::gaunt_yyy(l1, l2, l3, k1, k2, k3);
440 }
441 }
442 }
443 return d;
444 }
445
446 /// Gaunt coefficent of two real spherical harmonics with a complex one.
447 /**
448 * \f[
449 * \langle R_{\ell_1 m_1} | Y_{\ell_2 m_2} | R_{\ell_3 m_3} \rangle
450 * \f]
451 */
452 static double gaunt_rlm_ylm_rlm(int l1, int l2, int l3, int m1, int m2, int m3)
453 {
454 RTE_ASSERT(l1 >= 0);
455 RTE_ASSERT(l2 >= 0);
456 RTE_ASSERT(l3 >= 0);
457 RTE_ASSERT(m1 >= -l1 && m1 <= l1);
458 RTE_ASSERT(m2 >= -l2 && m2 <= l2);
459 RTE_ASSERT(m3 >= -l3 && m3 <= l3);
460
461 double d = 0;
462 for (int k1 = -l1; k1 <= l1; k1++) {
463 for (int k3 = -l3; k3 <= l3; k3++) {
464 d += std::real(std::conj(SHT::ylm_dot_rlm(l1, k1, m1)) *
465 SHT::ylm_dot_rlm(l3, k3, m3)) *
466 SHT::gaunt_yyy(l1, l2, l3, k1, m2, k3);
467 }
468 }
469 return d;
470 }
471
472 /// Gaunt coefficent of two complex and one real spherical harmonics.
473 /**
474 * \f[
475 * \langle Y_{\ell_1 m_1} | R_{\ell_2 m_2} | Y_{\ell_3 m_3} \rangle
476 * \f]
477 */
478 static std::complex<double> gaunt_hybrid(int l1, int l2, int l3, int m1, int m2, int m3)
479 {
480 RTE_ASSERT(l1 >= 0);
481 RTE_ASSERT(l2 >= 0);
482 RTE_ASSERT(l3 >= 0);
483 RTE_ASSERT(m1 >= -l1 && m1 <= l1);
484 RTE_ASSERT(m2 >= -l2 && m2 <= l2);
485 RTE_ASSERT(m3 >= -l3 && m3 <= l3);
486
487 if (m2 == 0) {
488 return std::complex<double>(gaunt_yyy(l1, l2, l3, m1, m2, m3), 0.0);
489 } else {
490 return (ylm_dot_rlm(l2, m2, m2) * gaunt_yyy(l1, l2, l3, m1, m2, m3) +
491 ylm_dot_rlm(l2, -m2, m2) * gaunt_yyy(l1, l2, l3, m1, -m2, m3));
492 }
493 }
494
495 void uniform_coverage()
496 {
497 tp_(0, 0) = pi;
498 tp_(1, 0) = 0;
499
500 for (int k = 1; k < num_points_ - 1; k++) {
501 double hk = -1.0 + double(2 * k) / double(num_points_ - 1);
502 tp_(0, k) = std::acos(hk);
503 double t = tp_(1, k - 1) + 3.80925122745582 / std::sqrt(double(num_points_)) / std::sqrt(1 - hk * hk);
504 tp_(1, k) = std::fmod(t, twopi);
505 }
506
507 tp_(0, num_points_ - 1) = 0;
508 tp_(1, num_points_ - 1) = 0;
509 }
510
511 /// Return Clebsch-Gordan coefficient.
512 /** Clebsch-Gordan coefficients arise when two angular momenta are combined into a
513 * total angular momentum.
514 */
515 static inline double clebsch_gordan(int l1, int l2, int l3, int m1, int m2, int m3)
516 {
517 RTE_ASSERT(l1 >= 0);
518 RTE_ASSERT(l2 >= 0);
519 RTE_ASSERT(l3 >= 0);
520 RTE_ASSERT(m1 >= -l1 && m1 <= l1);
521 RTE_ASSERT(m2 >= -l2 && m2 <= l2);
522 RTE_ASSERT(m3 >= -l3 && m3 <= l3);
523
524 return std::pow(-1, l1 - l2 + m3) * std::sqrt(double(2 * l3 + 1)) *
525 gsl_sf_coupling_3j(2 * l1, 2 * l2, 2 * l3, 2 * m1, 2 * m2, -2 * m3);
526 }
527
528 inline auto ylm_backward(int lm, int itp) const
529 {
530 return ylm_backward_(lm, itp);
531 }
532
533 inline auto rlm_backward(int lm, int itp) const
534 {
535 return rlm_backward_(lm, itp);
536 }
537
538 inline auto coord(int x, int itp) const
539 {
540 return coord_(x, itp);
541 }
542
543 inline auto coord(int idx__) const
544 {
545 return r3::vector<double>(coord_(0, idx__), coord_(1, idx__), coord(2, idx__));
546 }
547
548 inline auto theta(int idx__) const
549 {
550 return tp_(0, idx__);
551 }
552
553 inline auto phi(int idx__) const
554 {
555 return tp_(1, idx__);
556 }
557
558 inline auto weight(int idx__) const
559 {
560 return w_[idx__];
561 }
562
563 inline auto num_points() const
564 {
565 return num_points_;
566 }
567
568 inline auto lmax() const
569 {
570 return lmax_;
571 }
572
573 inline auto lmmax() const
574 {
575 return lmmax_;
576 }
577};
578
579} // namespace sirius
580
581#endif // __SHT_HPP__
Spherical harmonics transformations and related oprtations.
Definition: sht.hpp:81
void check() const
Check the transformations.
Definition: sht.cpp:283
static double gaunt_rlm_ylm_rlm(int l1, int l2, int l3, int m1, int m2, int m3)
Gaunt coefficent of two real spherical harmonics with a complex one.
Definition: sht.hpp:452
int mesh_type_
Type of spherical grid (0: Lebedev-Laikov, 1: uniform).
Definition: sht.hpp:117
static std::complex< double > gaunt_hybrid(int l1, int l2, int l3, int m1, int m2, int m3)
Gaunt coefficent of two complex and one real spherical harmonics.
Definition: sht.hpp:478
SHT(sddk::device_t pu__, int lmax__, int mesh_type__=0)
Default constructor.
Definition: sht.hpp:121
sddk::mdarray< std::complex< double >, 2 > ylm_forward_
Forward transformation from spherical coordinates to Ylm.
Definition: sht.hpp:108
int lmmax_
Maximum number of components.
Definition: sht.hpp:90
void backward_transform(int ld, T const *flm, int nr, int lmmax, T *ftp) const
Perform a backward transformation from spherical harmonics to spherical coordinates.
sddk::mdarray< double, 2 > rlm_forward_
Forward transformation from spherical coordinates to Rlm.
Definition: sht.hpp:114
static void convert(int lmax__, double const *f_rlm__, std::complex< double > *f_ylm__)
Convert form Rlm to Ylm representation.
Definition: sht.hpp:264
static double gaunt_rrr(int l1, int l2, int l3, int m1, int m2, int m3)
Gaunt coefficent of three real spherical harmonics.
Definition: sht.hpp:423
std::vector< double > w_
Point weights.
Definition: sht.hpp:102
static double gaunt_yyy(int l1, int l2, int l3, int m1, int m2, int m3)
Gaunt coefficent of three complex spherical harmonics.
Definition: sht.hpp:403
static void convert(int lmax__, std::complex< double > const *f_ylm__, double *f_rlm__)
Convert from Ylm to Rlm representation.
Definition: sht.hpp:281
void forward_transform(T const *ftp, int nr, int lmmax, int ld, T *flm) const
Perform a forward transformation from spherical coordinates to spherical harmonics.
sddk::mdarray< std::complex< double >, 2 > ylm_backward_
Backward transformation from Ylm to spherical coordinates.
Definition: sht.hpp:105
int num_points_
Number of real-space points on the sphere.
Definition: sht.hpp:93
sddk::mdarray< double, 2 > rlm_backward_
Backward transformation from Rlm to spherical coordinates.
Definition: sht.hpp:111
sddk::mdarray< double, 2 > coord_
Cartesian coordinates of points (normalized to 1).
Definition: sht.hpp:96
sddk::device_t pu_
Type of processing unit.
Definition: sht.hpp:84
static std::complex< double > ylm_dot_rlm(int l, int m1, int m2)
Compute element of the transformation matrix from complex to real spherical harmonics.
Definition: sht.hpp:363
int lmax_
Maximum of spherical harmonics.
Definition: sht.hpp:87
static double clebsch_gordan(int l1, int l2, int l3, int m1, int m2, int m3)
Return Clebsch-Gordan coefficient.
Definition: sht.hpp:515
sddk::mdarray< double, 2 > tp_
angles of points.
Definition: sht.hpp:99
void geinv(ftn_int n, sddk::matrix< T > &A) const
Invert a general matrix.
Definition: linalg.hpp:163
mdarray< T, N > & allocate(memory_t memory__)
Allocate memory for array.
Definition: memory.hpp:1057
Various constants.
Generate Lebedev-Laikov grids on the sphere.
Linear algebra interface.
device_t
Type of the main processing unit.
Definition: memory.hpp:120
@ lapack
CPU LAPACK.
auto spherical_coordinates(vector< double > vc)
Transform Cartesian coordinates [x,y,z] to spherical coordinates [r,theta,phi].
Definition: r3.hpp:590
int lmax(int lmmax__)
Get maximum orbital quantum number by the maximum lm index.
Definition: specfunc.hpp:56
int lm(int l, int m)
Get composite lm index by angular index l and azimuthal index m.
Definition: specfunc.hpp:50
void spherical_harmonics(int lmax, double theta, double phi, std::complex< double > *ylm)
Optimized implementation of complex spherical harmonics.
Definition: specfunc.hpp:298
Namespace of the SIRIUS library.
Definition: sirius.f90:5
auto euler_angles(r3::matrix< double > const &rot__, double tolerance__)
Compute Euler angles corresponding to the proper rotation matrix.
Definition: rotation.hpp:196
const double twopi
Definition: constants.hpp:45
const double pi
Definition: constants.hpp:42
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
Simple classes and functions to work with vectors and matrices of the R^3 space.
Special functions.
Contains typedefs, enums and simple descriptors.