SIRIUS 7.5.0
Electronic structure library and applications
spheric_function.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 spheric_function.hpp
21 *
22 * \brief Contains declaration and implementation of sirius::Spheric_function and
23 * sirius::Spheric_function_gradient classes.
24 */
25
26#ifndef __SPHERIC_FUNCTION_HPP__
27#define __SPHERIC_FUNCTION_HPP__
28
29#include <array>
30#include <typeinfo>
31#include "radial/spline.hpp"
32#include "core/sht/sht.hpp"
33#include "core/math_tools.hpp"
34#include "SDDK/memory.hpp"
35
36namespace sirius {
37
38/// Function in spherical harmonics or spherical coordinates representation.
39/** This class works in conjugation with SHT class which provides the transformation between spherical
40 harmonics and spherical coordinates and also a conversion between real and complex spherical harmonics.
41 */
42template <function_domain_t domain_t, typename T = std::complex<double>>
44{
45 private:
46
47 /// Radial grid.
49
50 /// Size of the angular domain.
51 /** This is either a total number of spherical harmonics or a number of (theta, phi) anles covering the sphere. */
53
54 /* copy constructir is disabled */
56
57 /* copy assignment operator is disabled */
58 Spheric_function<domain_t, T>& operator=(Spheric_function<domain_t, T> const& src__) = delete;
59
60 public:
61
62 /// Constructor of the empty function.
64 {
65 }
66
67 /// Constructor.
68 Spheric_function(int angular_domain_size__, Radial_grid<double> const& radial_grid__)
69 : sddk::mdarray<T, 2>(angular_domain_size__, radial_grid__.num_points())
70 , radial_grid_(&radial_grid__)
71 , angular_domain_size_(angular_domain_size__)
72 {
73 }
74
75 /// Constructor.
76 Spheric_function(T* ptr__, int angular_domain_size__, Radial_grid<double> const& radial_grid__)
77 : sddk::mdarray<T, 2>(ptr__, angular_domain_size__, radial_grid__.num_points())
78 , radial_grid_(&radial_grid__)
79 , angular_domain_size_(angular_domain_size__)
80 {
81 }
82
83 /// Constructor.
84 Spheric_function(sddk::memory_pool& mp__, int angular_domain_size__, Radial_grid<double> const& radial_grid__)
85 : sddk::mdarray<T, 2>(angular_domain_size__, radial_grid__.num_points(), mp__)
86 , radial_grid_(&radial_grid__)
87 , angular_domain_size_(angular_domain_size__)
88 {
89 }
90
91 /// Move constructor.
93 : sddk::mdarray<T, 2>(std::move(src__))
94 {
95 radial_grid_ = src__.radial_grid_;
96 angular_domain_size_ = src__.angular_domain_size_;
97 }
98
99 /// Move asigment operator.
101 {
102 if (this != &src__) {
103 sddk::mdarray<T, 2>::operator=(std::move(src__));
104 radial_grid_ = src__.radial_grid_;
105 angular_domain_size_ = src__.angular_domain_size_;
106 }
107 return *this;
108 }
109
110 inline Spheric_function<domain_t, T>& operator+=(Spheric_function<domain_t, T> const& rhs__)
111 {
112 for (int i1 = 0; i1 < (int)this->size(1); i1++) {
113 for (int i0 = 0; i0 < (int)this->size(0); i0++) {
114 (*this)(i0, i1) += rhs__(i0, i1);
115 }
116 }
117 return *this;
118 }
119
120 inline Spheric_function<domain_t, T>& operator+=(Spheric_function<domain_t, T>&& rhs__)
121 {
122 for (int i1 = 0; i1 < (int)this->size(1); i1++) {
123 for (int i0 = 0; i0 < (int)this->size(0); i0++) {
124 (*this)(i0, i1) += rhs__(i0, i1);
125 }
126 }
127
128 return *this;
129 }
130
131 inline Spheric_function<domain_t, T>& operator-=(Spheric_function<domain_t, T> const& rhs__)
132 {
133 for (int i1 = 0; i1 < (int)this->size(1); i1++) {
134 for (int i0 = 0; i0 < (int)this->size(0); i0++) {
135 (*this)(i0, i1) -= rhs__(i0, i1);
136 }
137 }
138 return *this;
139 }
140
141 inline Spheric_function<domain_t, T>& operator-=(Spheric_function<domain_t, T>&& rhs__)
142 {
143 for (int i1 = 0; i1 < (int)this->size(1); i1++) {
144 for (int i0 = 0; i0 < (int)this->size(0); i0++) {
145 (*this)(i0, i1) -= rhs__(i0, i1);
146 }
147 }
148
149 return *this;
150 }
151 /// Multiply by a constant.
153 {
154 for (int i1 = 0; i1 < (int)this->size(1); i1++) {
155 for (int i0 = 0; i0 < (int)this->size(0); i0++) {
156 (*this)(i0, i1) *= alpha__;
157 }
158 }
159
160 return *this;
161 }
162
163 inline int angular_domain_size() const
164 {
166 }
167
168 inline auto const& radial_grid() const
169 {
170 RTE_ASSERT(radial_grid_ != nullptr);
171 return *radial_grid_;
172 }
173
174 auto component(int lm__) const
175 {
176 if (domain_t != function_domain_t::spectral) {
177 RTE_THROW("function is not is spectral domain");
178 }
179
180 Spline<T> s(radial_grid());
181 for (int ir = 0; ir < radial_grid_->num_points(); ir++) {
182 s(ir) = (*this)(lm__, ir);
183 }
184 s.interpolate();
185 return s;
186 }
187
188 T value(double theta__, double phi__, int jr__, double dr__) const
189 {
190 RTE_ASSERT(domain_t == function_domain_t::spectral);
191
193 std::vector<T> ylm(angular_domain_size_);
194 sf::spherical_harmonics(lmax, theta__, phi__, &ylm[0]);
195 T p = 0.0;
196 for (int lm = 0; lm < angular_domain_size_; lm++) {
197 double deriv = ((*this)(lm, jr__ + 1) - (*this)(lm, jr__)) / radial_grid_->dx(jr__);
198 p += ylm[lm] * ((*this)(lm, jr__) + deriv * dr__);
199 }
200 return p;
201 }
202
203};
204
205using Flm = Spheric_function<function_domain_t::spectral, double>;
206using Ftp = Spheric_function<function_domain_t::spatial, double>;
207
208/// 3D vector function.
209template <function_domain_t domain_t, typename T = std::complex<double>>
210class Spheric_vector_function : public std::array<Spheric_function<domain_t, T>, 3>
211{
212 private:
213
214 Radial_grid<double> const* radial_grid_{nullptr};
215
216 int angular_domain_size_{-1};
217
218 public:
219
220 /// Default constructor does nothing
222 {
223 }
224
225 Spheric_vector_function(int angular_domain_size__, Radial_grid<double> const& radial_grid__)
226 : radial_grid_(&radial_grid__)
227 , angular_domain_size_(angular_domain_size__)
228 {
229 for (int x: {0, 1, 2}) {
230 (*this)[x] = Spheric_function<domain_t, T>(angular_domain_size__, radial_grid__);
231 }
232 }
233
234 inline Radial_grid<double> const& radial_grid() const
235 {
236 RTE_ASSERT(radial_grid_ != nullptr);
237 return *radial_grid_;
238 }
239
240 inline int angular_domain_size() const
241 {
242 return angular_domain_size_;
243 }
244};
245
246/// Multiplication of two functions in spatial domain.
247/** The result of the operation is a scalar function in spatial domain */
248template <typename T>
251{
252 if (a__.radial_grid().hash() != b__.radial_grid().hash()) {
253 RTE_THROW("wrong radial grids");
254 }
255 if (a__.angular_domain_size() != b__.angular_domain_size()) {
256 RTE_THROW("wrong angular domain sizes");
257 }
258
259 Spheric_function<function_domain_t::spatial, T> res(a__.angular_domain_size(), a__.radial_grid());
260
261 #pragma omp parallel for schedule(static)
262 for (int ir = 0; ir < res.radial_grid().num_points(); ir++) {
263 for (int tp = 0; tp < res.angular_domain_size(); tp++) {
264 res(tp, ir) = a__(tp, ir) * b__(tp, ir);
265 }
266 }
267
268 return res;
269}
270
271/// Dot product of two gradiensts of real functions in spatial domain.
272/** The result of the operation is the real scalar function in spatial domain */
275{
276 if (f.radial_grid().hash() != g.radial_grid().hash()) {
277 RTE_THROW("wrong radial grids");
278 }
279
280 for (int x: {0, 1, 2}) {
281 if (f[x].angular_domain_size() != g[x].angular_domain_size()) {
282 RTE_THROW("wrong number of angular points");
283 }
284 }
285
286 Spheric_function<function_domain_t::spatial, double> result(f.angular_domain_size(), f.radial_grid());
287 result.zero();
288
289 for (int x: {0, 1, 2}) {
290 #pragma omp parallel for schedule(static)
291 for (int ir = 0; ir < f.radial_grid().num_points(); ir++) {
292 for (int tp = 0; tp < f.angular_domain_size(); tp++) {
293 result(tp, ir) += f[x](tp, ir) * g[x](tp, ir);
294 }
295 }
296 }
297
298 return result;
299}
300
301/// Summation of two functions.
302template <function_domain_t domain_t, typename T>
304{
305 if (a__.radial_grid().hash() != b__.radial_grid().hash()) {
306 RTE_THROW("wrong radial grids");
307 }
308 if (a__.angular_domain_size() != b__.angular_domain_size()) {
309 RTE_THROW("wrong angular domain sizes");
310 }
311
312 Spheric_function<domain_t, T> result(a__.angular_domain_size(), a__.radial_grid());
313
314 #pragma omp parallel for schedule(static)
315 for (int ir = 0; ir < a__.radial_grid().num_points(); ir++) {
316 for (int i = 0; i < a__.angular_domain_size(); i++) {
317 result(i, ir) = a__(i, ir) + b__(i, ir);
318 }
319 }
320
321 return result;
322}
323
324/// Subtraction of functions.
325template <function_domain_t domain_t, typename T>
327{
328 if (a__.radial_grid().hash() != b__.radial_grid().hash()) {
329 RTE_THROW("wrong radial grids");
330 }
331 if (a__.angular_domain_size() != b__.angular_domain_size()) {
332 RTE_THROW("wrong angular domain sizes");
333 }
334
335 Spheric_function<domain_t, T> res(a__.angular_domain_size(), a__.radial_grid());
336
337 #pragma omp parallel for schedule(static)
338 for (int ir = 0; ir < a__.radial_grid().num_points(); ir++) {
339 for (int i = 0; i < a__.angular_domain_size(); i++) {
340 res(i, ir) = a__(i, ir) - b__(i, ir);
341 }
342 }
343
344 return res;
345}
346
347/// Multiply function by a scalar.
348template <function_domain_t domain_t, typename T>
350{
351 Spheric_function<domain_t, T> res(b__.angular_domain_size(), b__.radial_grid());
352
353 T const* ptr_rhs = &b__(0, 0);
354 T* ptr_res = &res(0, 0);
355
356 #pragma omp parallel for schedule(static)
357 for (size_t i = 0; i < b__.size(); i++) {
358 ptr_res[i] = a__ * ptr_rhs[i];
359 }
360
361 return res;
362}
363/// Multiply function by a scalar (inverse order).
364template <function_domain_t domain_t, typename T>
366{
367 return (a__ * b__);
368}
369
370/// Inner product of two spherical functions.
371/** The result of the operation is a scalar value. */
372template <function_domain_t domain_t, typename T>
373inline auto
375{
376 Spline<T> s(f1.radial_grid());
377
378 if (domain_t == function_domain_t::spectral) {
379 int lmmax = std::min(f1.angular_domain_size(), f2.angular_domain_size());
380 for (int ir = 0; ir < s.num_points(); ir++) {
381 for (int lm = 0; lm < lmmax; lm++) {
382 s(ir) += conj(f1(lm, ir)) * f2(lm, ir);
383 }
384 s(ir) *= std::pow(f1.radial_grid().x(ir), 2);
385 }
386 } else {
387 throw std::runtime_error("not implemented");
388 }
389 return s.interpolate().integrate(0);
390}
391
392/// Compute Laplacian of the spheric function.
393/** Laplacian in spherical coordinates has the following expression:
394 \f[
395 \Delta = \frac{1}{r^2}\frac{\partial}{\partial r}\Big( r^2 \frac{\partial}{\partial r} \Big) +
396 \frac{1}{r^2}\Delta_{\theta, \phi}
397 \f]
398 */
399template <typename T>
400inline auto
402{
404 auto& rgrid = f__.radial_grid();
405 int lmmax = f__.angular_domain_size();
406 int lmax = sf::lmax(lmmax);
408
409 Spline<T> s1(rgrid);
410 for (int l = 0; l <= lmax; l++) {
411 int ll = l * (l + 1);
412 for (int m = -l; m <= l; m++) {
413 int lm = sf::lm(l, m);
414 /* get lm component */
415 auto s = f__.component(lm);
416 /* compute 1st derivative */
417 for (int ir = 0; ir < s.num_points(); ir++) {
418 s1(ir) = s.deriv(1, ir);
419 }
420 s1.interpolate();
421
422 for (int ir = 0; ir < s.num_points(); ir++) {
423 g(lm, ir) = 2.0 * s1(ir) * rgrid.x_inv(ir) + s1.deriv(1, ir) -
424 s(ir) * static_cast<double>(ll) / std::pow(rgrid[ir], 2);
425 }
426 }
427 }
428
429 return g;
430}
431
432/// Convert from Ylm to Rlm representation.
433inline void
434convert(Spheric_function<function_domain_t::spectral, std::complex<double>> const& f__,
436{
437 int lmax = sf::lmax(f__.angular_domain_size());
438
439 /* cache transformation arrays */
440 std::vector<std::complex<double>> tpp(f__.angular_domain_size());
441 std::vector<std::complex<double>> tpm(f__.angular_domain_size());
442 for (int l = 0; l <= lmax; l++) {
443 for (int m = -l; m <= l; m++) {
444 int lm = sf::lm(l, m);
445 tpp[lm] = SHT::rlm_dot_ylm(l, m, m);
446 tpm[lm] = SHT::rlm_dot_ylm(l, m, -m);
447 }
448 }
449
450 for (int ir = 0; ir < f__.radial_grid().num_points(); ir++) {
451 int lm = 0;
452 for (int l = 0; l <= lmax; l++) {
453 for (int m = -l; m <= l; m++) {
454 if (m == 0) {
455 g__(lm, ir) = std::real(f__(lm, ir));
456 } else {
457 int lm1 = sf::lm(l, -m);
458 g__(lm, ir) = std::real(tpp[lm] * f__(lm, ir) + tpm[lm] * f__(lm1, ir));
459 }
460 lm++;
461 }
462 }
463 }
464}
465
466/// Convert from Ylm to Rlm representation.
467inline auto
468convert(Spheric_function<function_domain_t::spectral, std::complex<double>> const& f__)
469{
470 Spheric_function<function_domain_t::spectral, double> g(f__.angular_domain_size(), f__.radial_grid());
471 convert(f__, g);
472 return g;
473}
474
475/// Convert from Rlm to Ylm representation.
476inline void
478 Spheric_function<function_domain_t::spectral, std::complex<double>>& g__)
479{
480 int lmax = sf::lmax(f__.angular_domain_size());
481
482 /* cache transformation arrays */
483 std::vector<std::complex<double>> tpp(f__.angular_domain_size());
484 std::vector<std::complex<double>> tpm(f__.angular_domain_size());
485 for (int l = 0; l <= lmax; l++) {
486 for (int m = -l; m <= l; m++) {
487 int lm = sf::lm(l, m);
488 tpp[lm] = SHT::ylm_dot_rlm(l, m, m);
489 tpm[lm] = SHT::ylm_dot_rlm(l, m, -m);
490 }
491 }
492
493 for (int ir = 0; ir < f__.radial_grid().num_points(); ir++) {
494 int lm = 0;
495 for (int l = 0; l <= lmax; l++) {
496 for (int m = -l; m <= l; m++) {
497 if (m == 0) {
498 g__(lm, ir) = f__(lm, ir);
499 } else {
500 int lm1 = sf::lm(l, -m);
501 g__(lm, ir) = tpp[lm] * f__(lm, ir) + tpm[lm] * f__(lm1, ir);
502 }
503 lm++;
504 }
505 }
506 }
507}
508
509/// Convert from Rlm to Ylm representation.
510inline auto
512{
513 Spheric_function<function_domain_t::spectral, std::complex<double>> g(f__.angular_domain_size(), f__.radial_grid());
514 convert(f__, g);
515 return g;
516}
517
518template <typename T>
519inline void
520transform(SHT const& sht__, Spheric_function<function_domain_t::spectral, T> const& f__,
521 Spheric_function<function_domain_t::spatial, T>& g__)
522{
523 sht__.backward_transform(f__.angular_domain_size(), &f__(0, 0), f__.radial_grid().num_points(),
524 std::min(sht__.lmmax(), f__.angular_domain_size()), &g__(0, 0));
525}
526
527/// Transform to spatial domain (to r, \theta, \phi coordinates).
528template <typename T>
529inline auto
531{
532 Spheric_function<function_domain_t::spatial, T> g(sht__.num_points(), f__.radial_grid());
533 transform(sht__, f__, g);
534 return g;
535}
536
537template <typename T>
538inline void
539transform(SHT const& sht__, Spheric_function<function_domain_t::spatial, T> const& f__,
540 Spheric_function<function_domain_t::spectral, T>& g__)
541{
542 sht__.forward_transform(&f__(0, 0), f__.radial_grid().num_points(), sht__.lmmax(), sht__.lmmax(), &g__(0, 0));
543}
544
545/// Transform to spectral domain.
546template <typename T>
547inline auto
549{
550 Spheric_function<function_domain_t::spectral, T> g(sht__.lmmax(), f__.radial_grid());
551 transform(sht__, f__, g);
552 return g;
553}
554
555/// Gradient of the function in complex spherical harmonics.
556inline auto
558{
559 Spheric_vector_function<function_domain_t::spectral, std::complex<double>> g(f.angular_domain_size(), f.radial_grid());
560 for (int i = 0; i < 3; i++) {
561 g[i].zero();
562 }
563
564 int lmax = sf::lmax(f.angular_domain_size());
565
566 for (int l = 0; l <= lmax; l++) {
567 double d1 = std::sqrt(double(l + 1) / double(2 * l + 3));
568 double d2 = std::sqrt(double(l) / double(2 * l - 1));
569
570 for (int m = -l; m <= l; m++) {
571 int lm = sf::lm(l, m);
572 auto s = f.component(lm);
573
574 for (int mu = -1; mu <= 1; mu++) {
575 int j = (mu + 2) % 3; // map -1,0,1 to 1,2,0 (to y,z,x)
576
577 if ((l + 1) <= lmax && std::abs(m + mu) <= l + 1) {
578 int lm1 = sf::lm(l + 1, m + mu);
579 double d = d1 * SHT::clebsch_gordan(l, 1, l + 1, m, mu, m + mu);
580 for (int ir = 0; ir < f.radial_grid().num_points(); ir++) {
581 g[j](lm1, ir) += (s.deriv(1, ir) - f(lm, ir) * f.radial_grid().x_inv(ir) * double(l)) * d;
582 }
583 }
584 if ((l - 1) >= 0 && std::abs(m + mu) <= l - 1) {
585 int lm1 = sf::lm(l - 1, m + mu);
586 double d = d2 * SHT::clebsch_gordan(l, 1, l - 1, m, mu, m + mu);
587 for (int ir = 0; ir < f.radial_grid().num_points(); ir++) {
588 g[j](lm1, ir) -= (s.deriv(1, ir) + f(lm, ir) * f.radial_grid().x_inv(ir) * double(l + 1)) * d;
589 }
590 }
591 }
592 }
593 }
594
595 std::complex<double> d1(1.0 / std::sqrt(2.0), 0);
596 std::complex<double> d2(0, 1.0 / std::sqrt(2.0));
597
598 for (int ir = 0; ir < f.radial_grid().num_points(); ir++) {
599 for (int lm = 0; lm < f.angular_domain_size(); lm++) {
600 std::complex<double> g_p = g[0](lm, ir);
601 std::complex<double> g_m = g[1](lm, ir);
602 g[0](lm, ir) = d1 * (g_m - g_p);
603 g[1](lm, ir) = d2 * (g_m + g_p);
604 }
605 }
606
607 return g;
608}
609
610/// Gradient of the function in real spherical harmonics.
611inline auto
613{
614 int lmax = sf::lmax(f__.angular_domain_size());
615 SHT sht(sddk::device_t::CPU, lmax);
616 auto zf = convert(f__);
617 auto zg = gradient(zf);
618 Spheric_vector_function<function_domain_t::spectral, double> g(f__.angular_domain_size(), f__.radial_grid());
619 for (int x: {0, 1, 2}) {
620 g[x] = convert(zg[x]);
621 }
622 return g;
623}
624
625/// Divergence of the vector function in complex spherical harmonics.
626inline auto
628{
629 Spheric_function<function_domain_t::spectral, std::complex<double>> g(vf__.angular_domain_size(), vf__.radial_grid());
630 g.zero();
631
632 for (int x: {0, 1, 2}) {
633 auto f = gradient(vf__[x]);
634 g += f[x];
635 }
636 return g;
637}
638
639inline auto
640divergence(Spheric_vector_function<function_domain_t::spectral, double> const& vf)
641{
642 Spheric_function<function_domain_t::spectral, double> g(vf.angular_domain_size(), vf.radial_grid());
643 g.zero();
644
645 for (int x: {0, 1, 2}) {
646 auto zf = convert(vf[x]);
647 auto zf1 = gradient(zf);
648 auto f2 = convert(zf1[x]);
649 g += f2;
650 }
651 return g;
652}
653
654} // namespace
655
656#endif // __SPHERIC_FUNCTION_HPP__
T dx(const int i) const
Return .
T x_inv(const int i) const
Return .
int num_points() const
Number of grid points.
Spherical harmonics transformations and related oprtations.
Definition: sht.hpp:81
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
static double clebsch_gordan(int l1, int l2, int l3, int m1, int m2, int m3)
Return Clebsch-Gordan coefficient.
Definition: sht.hpp:515
Function in spherical harmonics or spherical coordinates representation.
Spheric_function()
Constructor of the empty function.
Spheric_function< domain_t, T > & operator=(Spheric_function< domain_t, T > &&src__)
Move asigment operator.
int angular_domain_size_
Size of the angular domain.
Radial_grid< double > const * radial_grid_
Radial grid.
Spheric_function(sddk::memory_pool &mp__, int angular_domain_size__, Radial_grid< double > const &radial_grid__)
Constructor.
Spheric_function(T *ptr__, int angular_domain_size__, Radial_grid< double > const &radial_grid__)
Constructor.
Spheric_function(Spheric_function< domain_t, T > &&src__)
Move constructor.
Spheric_function(int angular_domain_size__, Radial_grid< double > const &radial_grid__)
Constructor.
Spheric_function< domain_t, T > & operator*=(double alpha__)
Multiply by a constant.
Spheric_vector_function()
Default constructor does nothing.
Cubic spline with a not-a-knot boundary conditions.
Definition: spline.hpp:76
Spline< T, U > & interpolate()
Definition: spline.hpp:275
Multidimensional array with the column-major (Fortran) order.
Definition: memory.hpp:660
mdarray< T, N > & operator=(mdarray< T, N > const &src)=delete
Assignment operator is forbidden.
void zero(memory_t mem__, size_t idx0__, size_t n__)
Zero n elements starting from idx0.
Definition: memory.hpp:1316
size_t size() const
Return total size (number of elements) of the array.
Definition: memory.hpp:1207
Math helper functions.
Memory management functions and classes.
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
void spherical_harmonics(int lmax, double theta, double phi, std::complex< double > *ylm)
Optimized implementation of complex spherical harmonics.
Definition: specfunc.hpp:298
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.
std::enable_if_t< std::is_same< T, real_type< F > >::value, void > transform(::spla::Context &spla_ctx__, sddk::memory_t mem__, la::dmatrix< F > const &M__, int irow0__, int jcol0__, real_type< F > alpha__, Wave_functions< T > const &wf_in__, spin_index s_in__, band_range br_in__, real_type< F > beta__, Wave_functions< T > &wf_out__, spin_index s_out__, band_range br_out__)
Apply linear transformation to the wave-functions.
Namespace of the SIRIUS library.
Definition: sirius.f90:5
void convert(Spheric_function< function_domain_t::spectral, std::complex< double > > const &f__, Spheric_function< function_domain_t::spectral, double > &g__)
Convert from Ylm to Rlm representation.
auto operator+(Spheric_function< domain_t, T > const &a__, Spheric_function< domain_t, T > const &b__)
Summation of two functions.
Smooth_periodic_vector_function< T > gradient(Smooth_periodic_function< T > &f__)
Gradient of the function in the plane-wave domain.
auto operator*(Spheric_function< function_domain_t::spatial, T > const &a__, Spheric_function< function_domain_t::spatial, T > const &b__)
Multiplication of two functions in spatial domain.
@ spectral
Spectral domain.
Smooth_periodic_function< T > laplacian(Smooth_periodic_function< T > &f__)
Laplacian of the function in the plane-wave domain.
Smooth_periodic_function< T > divergence(Smooth_periodic_vector_function< T > &g__)
Divergence of the vecor function.
auto operator-(Spheric_function< domain_t, T > const &a__, Spheric_function< domain_t, T > const &b__)
Subtraction of functions.
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 particular implementation of sirius::SHT class.
Contains definition and partial implementation of sirius::Spline class.