20#ifndef __SPECFUNC_HPP__
21#define __SPECFUNC_HPP__
29#include <gsl/gsl_sf_coupling.h>
30#include <gsl/gsl_sf_legendre.h>
31#include <gsl/gsl_sf_hermite.h>
50inline int lm(
int l,
int m)
52 return (l * l + l + m);
56inline int lmax(
int lmmax__)
58 RTE_ASSERT(lmmax__ >= 0);
59 int lmax =
static_cast<int>(std::sqrt(
static_cast<double>(lmmax__)) + 1e-8) - 1;
62 s <<
"wrong lmmax: " << lmmax__;
69inline std::vector<int>
l_by_lm(
int lmax__)
71 std::vector<int> v(
lmmax(lmax__));
72 for (
int l = 0; l <= lmax__; l++) {
73 for (
int m = -l; m <= l; m++) {
80inline double hermiteh(
int n,
double x)
84 return gsl_sf_hermite(n, x);
87inline std::vector<double> hermiteh_array(
int n,
double x)
89 std::vector<double> result(n);
90 gsl_sf_hermite_array(n, x, result.data());
94inline double hermiteh_series(
int n,
double x,
const double* a)
96 return gsl_sf_hermite_series(n, x, a);
122template <
typename T,
typename F>
142 double y = std::sqrt(1 - x__ * x__);
144 plm__[ilm__(0, 0)] = 0.28209479177387814347;
147 for (
int l = 1; l <= lmax__; l++) {
148 plm__[ilm__(l, l)] = -std::sqrt(1 + 0.5 / l) * y * plm__[ilm__(l - 1, l - 1)];
151 for (
int l = 0; l < lmax__; l++) {
152 plm__[ilm__(l + 1, l)] = std::sqrt(2.0 * l + 3) * x__ * plm__[ilm__(l, l)];
154 for (
int m = 0; m <= lmax__ - 2; m++) {
155 for (
int l = m + 2; l <= lmax__; l++) {
156 double alm = std::sqrt(
static_cast<double>((2 * l - 1) * (2 * l + 1)) / (l * l - m * m));
157 double blm = std::sqrt(
static_cast<double>((l - 1 - m) * (l - 1 + m)) / ((2 * l - 3) * (2 * l - 1)));
158 plm__[ilm__(l, m)] = alm * (x__ * plm__[ilm__(l - 1, m)] - blm * plm__[ilm__(l - 2, m)]);
210template <
typename T,
typename F>
211inline void legendre_plm_aux(
int lmax__,
double x__, F&& ilm__, T
const* plm__, T* p1lm__, T* p2lm__)
213 double y = std::sqrt(1 - x__ * x__);
215 p1lm__[ilm__(0, 0)] = 0;
216 p2lm__[ilm__(0, 0)] = 0;
218 for (
int l = 1; l <= lmax__; l++) {
219 auto a = std::sqrt(1 + 0.5 / l);
220 auto b = plm__[ilm__(l - 1, l - 1)];
222 p1lm__[ilm__(l, l)] = a * (-y * p1lm__[ilm__(l - 1, l - 1)] + x__ * b);
224 p2lm__[ilm__(l, l)] = -a * b;
226 for (
int l = 0; l < lmax__; l++) {
227 auto a = std::sqrt(2.0 * l + 3);
229 p1lm__[ilm__(l + 1, l)] = a * (x__ * p1lm__[ilm__(l, l)] + y * plm__[ilm__(l, l)]);
231 p2lm__[ilm__(l + 1, l)] = a * x__ * p2lm__[ilm__(l, l)];
233 for (
int m = 0; m <= lmax__ - 2; m++) {
234 for (
int l = m + 2; l <= lmax__; l++) {
235 double alm = std::sqrt(
static_cast<double>((2 * l - 1) * (2 * l + 1)) / (l * l - m * m));
236 double blm = std::sqrt(
static_cast<double>((l - 1 - m) * (l - 1 + m)) / ((2 * l - 3) * (2 * l - 1)));
237 p1lm__[ilm__(l, m)] = alm * (x__ * p1lm__[ilm__(l - 1, m)] + y * plm__[ilm__(l - 1, m)] -
238 blm * p1lm__[ilm__(l - 2, m)]);
239 p2lm__[ilm__(l, m)] = alm * (x__ * p2lm__[ilm__(l - 1, m)] - blm * p2lm__[ilm__(l - 2, m)]);
275 double x = std::cos(theta);
277 std::vector<double> result_array(gsl_sf_legendre_array_n(
lmax));
278 gsl_sf_legendre_array(GSL_SF_LEGENDRE_SPHARM,
lmax, x, &result_array[0]);
280 for (
int l = 0; l <=
lmax; l++) {
281 ylm[
sf::lm(l, 0)] = result_array[gsl_sf_legendre_array_index(l, 0)];
284 for (
int m = 1; m <=
lmax; m++) {
285 std::complex<double> z = std::exp(std::complex<double>(0.0, m * phi)) * std::pow(-1, m);
286 for (
int l = m; l <=
lmax; l++) {
287 ylm[
sf::lm(l, m)] = result_array[gsl_sf_legendre_array_index(l, m)] * z;
300 double x = std::cos(theta);
304 double c0 = std::cos(phi);
306 double s0 = -std::sin(phi);
312 for (
int m = 1; m <=
lmax; m++) {
313 double c = c2 * c1 - c0;
316 double s = c2 * s1 - s0;
319 for (
int l = m; l <=
lmax; l++) {
320 double p = std::real(ylm[
sf::lm(l, m)]);
321 double p1 = p * phase;
322 ylm[
sf::lm(l, m)] = std::complex<double>(p * c, p * s);
323 ylm[
sf::lm(l, -m)] = std::complex<double>(p1 * c, -p1 * s);
379 std::vector<std::complex<double>> ylm(
lmmax);
382 double const t = std::sqrt(2.0);
386 for (
int l = 1; l <=
lmax; l++) {
388 for (
int m = 1; m <= l; m++) {
398 double x = std::cos(theta);
402 double c0 = std::cos(phi);
404 double s0 = -std::sin(phi);
408 double const t = std::sqrt(2.0);
412 for (
int m = 1; m <=
lmax; m++) {
413 double c = c2 * c1 - c0;
416 double s = c2 * s1 - s0;
419 for (
int l = m; l <=
lmax; l++) {
420 double p = rlm[
sf::lm(l, m)];
421 rlm[
sf::lm(l, m)] = t * p * c;
422 rlm[
sf::lm(l, -m)] = -t * p * s * phase;
434 double c0 = std::cos(x__);
437 for (
int m = 0; m < n__; m++) {
438 data[m] = c2 * c1 - c0;
451 double s0 = -std::sin(x__);
453 double c2 = 2 * std::cos(x__);
455 for (
int m = 0; m < n__; m++) {
456 data[m] = c2 * s1 - s0;
517 if (vrs[0] < 1e-12) {
522 int lmmax = (lmax__ + 1) * (lmax__ + 1);
524 double theta = vrs[1];
527 double sint = std::sin(theta);
528 double sinp = std::sin(phi);
529 double cost = std::cos(theta);
530 double cosp = std::cos(phi);
536 std::vector<double> dRlm_dt(
lmmax);
537 std::vector<double> dRlm_dp_sin_t(
lmmax);
539 std::vector<double> plm((lmax__ + 1) * (lmax__ + 2) / 2);
540 std::vector<double> dplm((lmax__ + 1) * (lmax__ + 2) / 2);
541 std::vector<double> plm_y((lmax__ + 1) * (lmax__ + 2) / 2);
543 auto ilm = [](
int l,
int m){
return l * (l + 1) / 2 + m;};
546 dRlm_dp_sin_t[0] = 0;
559 double const t = std::sqrt(2.0);
561 for (
int l = 0; l <= lmax__; l++) {
562 dRlm_dt[
sf::lm(l, 0)] = -dplm[ilm(l, 0)];
563 dRlm_dp_sin_t[
sf::lm(l, 0)] = 0;
567 for (
int m = 1; m <= lmax__; m++) {
568 double c = c2 * c1 - c0;
571 double s = c2 * s1 - s0;
574 for (
int l = m; l <= lmax__; l++) {
575 double p = -dplm[ilm(l, m)];
576 dRlm_dt[
sf::lm(l, m)] = t * p * c;
577 dRlm_dt[
sf::lm(l, -m)] = -t * p * s * phase;
578 p = plm_y[ilm(l, m)];
579 dRlm_dp_sin_t[
sf::lm(l, m)] = -t * p * s * m;
580 dRlm_dp_sin_t[
sf::lm(l, -m)] = -t * p * c * m * phase;
586 if (!divide_by_r__) {
590 for (
int mu = 0; mu < 3; mu++) {
592 data__(
lm, mu) = (dRlm_dt[
lm] * dtheta_dr[mu] + dRlm_dp_sin_t[
lm] * dphi_dr[mu]) / vrs[0];
602 if (vrs[0] < 1e-12) {
606 double dr = 1e-5 * vrs[0];
608 int lmmax = (lmax__ + 1) * (lmax__ + 1);
610 auto pref = divide_by_r__ ? (1.0 / vrs[0]) : 1.0;
612 for (
int x = 0; x < 3; x++) {
614 r3::vector<double> v1 = r__;
617 r3::vector<double> v2 = r__;
622 std::vector<double> rlm1(
lmmax);
623 std::vector<double> rlm2(
lmmax);
629 data__(
lm, x) = pref * (rlm1[
lm] - rlm2[
lm]) / 2 / dr;
void zero(memory_t mem__, size_t idx0__, size_t n__)
Zero n elements starting from idx0.
Memory management functions and classes.
auto spherical_coordinates(vector< double > vc)
Transform Cartesian coordinates [x,y,z] to spherical coordinates [r,theta,phi].
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 .
void legendre_plm(int lmax__, double x__, F &&ilm__, T *plm__)
Generate associated Legendre polynomials.
void spherical_harmonics_ref(int lmax, double theta, double phi, std::complex< double > *ylm)
Reference implementation of complex spherical harmonics.
int lm(int l, int m)
Get composite lm index by angular index l and azimuthal index m.
std::vector< int > l_by_lm(int lmax__)
Get array of orbital quantum numbers for each lm component.
sddk::mdarray< double, 1 > sinxn(int n__, double x__)
Generate for m in [1, n] using recursion.
sddk::mdarray< double, 1 > cosxn(int n__, double x__)
Generate for m in [1, n] using recursion.
void dRlm_dr(int lmax__, r3::vector< double > &r__, sddk::mdarray< double, 2 > &data__, bool divide_by_r__=true)
Compute the derivatives of real spherical harmonics over the components of cartesian vector.
void legendre_plm_aux(int lmax__, double x__, F &&ilm__, T const *plm__, T *p1lm__, T *p2lm__)
Generate auxiliary Legendre polynomials which are necessary for spherical harmomic derivatives.
void spherical_harmonics(int lmax, double theta, double phi, std::complex< double > *ylm)
Optimized implementation of complex spherical harmonics.
Namespace of the SIRIUS library.
const double y00
First spherical harmonic .
auto conj(double x__)
Return complex conjugate of a number. For a real value this is the number itself.
Simple classes and functions to work with vectors and matrices of the R^3 space.
Eror and warning handling during run-time execution.
Contains typedefs, enums and simple descriptors.