26#ifndef __SPHERIC_FUNCTION_HPP__
27#define __SPHERIC_FUNCTION_HPP__
42template <function_domain_t domain_t,
typename T = std::complex<
double>>
69 : sddk::
mdarray<T, 2>(angular_domain_size__, radial_grid__.num_points())
77 : sddk::
mdarray<T, 2>(ptr__, angular_domain_size__, radial_grid__.num_points())
85 : sddk::
mdarray<T, 2>(angular_domain_size__, radial_grid__.num_points(), mp__)
93 : sddk::
mdarray<T, 2>(std::move(src__))
102 if (
this != &src__) {
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);
120 inline Spheric_function<domain_t, T>& operator+=(Spheric_function<domain_t, T>&& rhs__)
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);
131 inline Spheric_function<domain_t, T>& operator-=(Spheric_function<domain_t, T>
const& rhs__)
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);
141 inline Spheric_function<domain_t, T>& operator-=(Spheric_function<domain_t, T>&& rhs__)
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);
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__;
163 inline int angular_domain_size()
const
168 inline auto const& radial_grid()
const
174 auto component(
int lm__)
const
177 RTE_THROW(
"function is not is spectral domain");
180 Spline<T> s(radial_grid());
182 s(ir) = (*this)(lm__, ir);
188 T value(
double theta__,
double phi__,
int jr__,
double dr__)
const
198 p += ylm[
lm] * ((*this)(
lm, jr__) + deriv * dr__);
205using Flm = Spheric_function<function_domain_t::spectral, double>;
206using Ftp = Spheric_function<function_domain_t::spatial, double>;
209template <function_domain_t domain_t,
typename T = std::complex<
double>>
216 int angular_domain_size_{-1};
226 : radial_grid_(&radial_grid__)
227 , angular_domain_size_(angular_domain_size__)
229 for (
int x: {0, 1, 2}) {
230 (*this)[x] = Spheric_function<domain_t, T>(angular_domain_size__, radial_grid__);
234 inline Radial_grid<double>
const& radial_grid()
const
236 RTE_ASSERT(radial_grid_ !=
nullptr);
237 return *radial_grid_;
240 inline int angular_domain_size()
const
242 return angular_domain_size_;
252 if (a__.radial_grid().hash() != b__.radial_grid().hash()) {
253 RTE_THROW(
"wrong radial grids");
255 if (a__.angular_domain_size() != b__.angular_domain_size()) {
256 RTE_THROW(
"wrong angular domain sizes");
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);
276 if (f.radial_grid().hash() != g.radial_grid().hash()) {
277 RTE_THROW(
"wrong radial grids");
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");
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);
302template <function_domain_t domain_t,
typename T>
305 if (a__.radial_grid().hash() != b__.radial_grid().hash()) {
306 RTE_THROW(
"wrong radial grids");
308 if (a__.angular_domain_size() != b__.angular_domain_size()) {
309 RTE_THROW(
"wrong angular domain sizes");
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);
325template <function_domain_t domain_t,
typename T>
328 if (a__.radial_grid().hash() != b__.radial_grid().hash()) {
329 RTE_THROW(
"wrong radial grids");
331 if (a__.angular_domain_size() != b__.angular_domain_size()) {
332 RTE_THROW(
"wrong angular domain sizes");
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);
348template <function_domain_t domain_t,
typename T>
353 T
const* ptr_rhs = &b__(0, 0);
354 T* ptr_res = &res(0, 0);
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];
364template <function_domain_t domain_t,
typename T>
372template <function_domain_t domain_t,
typename T>
379 int lmmax = std::min(f1.angular_domain_size(), f2.angular_domain_size());
382 s(ir) +=
conj(f1(
lm, ir)) * f2(
lm, ir);
384 s(ir) *= std::pow(f1.radial_grid().x(ir), 2);
387 throw std::runtime_error(
"not implemented");
404 auto& rgrid = f__.radial_grid();
405 int lmmax = f__.angular_domain_size();
410 for (
int l = 0; l <=
lmax; l++) {
411 int ll = l * (l + 1);
412 for (
int m = -l; m <= l; m++) {
415 auto s = f__.component(
lm);
417 for (
int ir = 0; ir < s.num_points(); ir++) {
418 s1(ir) = s.deriv(1, ir);
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);
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++) {
445 tpp[
lm] = SHT::rlm_dot_ylm(l, m, m);
446 tpm[
lm] = SHT::rlm_dot_ylm(l, m, -m);
450 for (
int ir = 0; ir < f__.radial_grid().num_points(); ir++) {
452 for (
int l = 0; l <=
lmax; l++) {
453 for (
int m = -l; m <= l; m++) {
455 g__(
lm, ir) = std::real(f__(
lm, ir));
458 g__(
lm, ir) = std::real(tpp[
lm] * f__(
lm, ir) + tpm[
lm] * f__(lm1, ir));
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++) {
493 for (
int ir = 0; ir < f__.radial_grid().num_points(); ir++) {
495 for (
int l = 0; l <=
lmax; l++) {
496 for (
int m = -l; m <= l; m++) {
498 g__(
lm, ir) = f__(
lm, ir);
501 g__(
lm, ir) = tpp[
lm] * f__(
lm, ir) + tpm[
lm] * f__(lm1, ir);
520transform(SHT
const& sht__, Spheric_function<function_domain_t::spectral, T>
const& f__,
521 Spheric_function<function_domain_t::spatial, T>& g__)
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));
539transform(SHT
const& sht__, Spheric_function<function_domain_t::spatial, T>
const& f__,
540 Spheric_function<function_domain_t::spectral, T>& g__)
542 sht__.forward_transform(&f__(0, 0), f__.radial_grid().num_points(), sht__.lmmax(), sht__.lmmax(), &g__(0, 0));
560 for (
int i = 0; i < 3; i++) {
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));
570 for (
int m = -l; m <= l; m++) {
572 auto s = f.component(
lm);
574 for (
int mu = -1; mu <= 1; mu++) {
575 int j = (mu + 2) % 3;
577 if ((l + 1) <=
lmax && std::abs(m + mu) <= l + 1) {
578 int lm1 =
sf::lm(l + 1, 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;
584 if ((l - 1) >= 0 && std::abs(m + mu) <= l - 1) {
585 int lm1 =
sf::lm(l - 1, 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;
595 std::complex<double> d1(1.0 / std::sqrt(2.0), 0);
596 std::complex<double> d2(0, 1.0 / std::sqrt(2.0));
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);
615 SHT sht(sddk::device_t::CPU,
lmax);
619 for (
int x: {0, 1, 2}) {
632 for (
int x: {0, 1, 2}) {
640divergence(Spheric_vector_function<function_domain_t::spectral, double>
const& vf)
642 Spheric_function<function_domain_t::spectral, double> g(vf.angular_domain_size(), vf.radial_grid());
645 for (
int x: {0, 1, 2}) {
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.
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.
static double clebsch_gordan(int l1, int l2, int l3, int m1, int m2, int m3)
Return Clebsch-Gordan coefficient.
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.
Spline< T, U > & interpolate()
Multidimensional array with the column-major (Fortran) order.
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.
size_t size() const
Return total size (number of elements) of the array.
Memory management functions and classes.
int lmax(int lmmax__)
Get maximum orbital quantum number by the maximum lm index.
int lmmax(int lmax)
Maximum number of combinations for a given .
int lm(int l, int m)
Get composite lm index by angular index l and azimuthal index m.
void spherical_harmonics(int lmax, double theta, double phi, std::complex< double > *ylm)
Optimized implementation of complex spherical harmonics.
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.
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.
Contains declaration and particular implementation of sirius::SHT class.
Contains definition and partial implementation of sirius::Spline class.