SIRIUS 7.5.0
Electronic structure library and applications
sbessel.cpp
1#include <gsl/gsl_sf_bessel.h>
2#include <cmath>
3#include <cassert>
4
5#include "sbessel.hpp"
6
7namespace sirius {
8
9namespace sf {
10
11// compute the spherical bessel functions.
12// This implementation is faster than the one provided by GSL, but not necessarily as accurate. For small input, GSL is
13// used as a fallback.
14static void custom_bessel(int lmax, double x, double* result) {
15 if (x == 0.0) {
16 result[0] = 1.0;
17 for (int l = 1; l <= lmax; ++l) {
18 result[l] = 0.0;
19 }
20 } else if (x < 0.1) {
21 /* gsl is more accurate for small inputs */
22 gsl_sf_bessel_jl_array(lmax, x, result);
23 } else {
24 const double x_inv = 1.0 / x;
25 const double sin_x = std::sin(x);
26 result[0] = sin_x * x_inv;
27
28 if (lmax > 0) {
29 result[1] = sin_x * x_inv * x_inv - std::cos(x) * x_inv;
30 }
31
32 for (int l = 2; l <= lmax; ++l) {
33 result[l] = (2 * (l - 1) + 1) / x * result[l - 1] - result[l - 2];
34 }
35 }
36
37 /* compare result with gsl in debug mode */
38#ifndef NDEBUG
39 std::vector<double> ref_result(lmax + 1);
40 gsl_sf_bessel_jl_array(lmax, x, ref_result.data());
41 for(int l = 0; l <= lmax; ++l) {
42 assert(std::abs(result[l] - ref_result[l]) < 1e-6);
43 }
44#endif
45}
46
47Spherical_Bessel_functions::Spherical_Bessel_functions(int lmax__,
48 Radial_grid<double> const& rgrid__,
49 double q__)
50 : q_(q__)
51 , rgrid_(&rgrid__)
52{
53 assert(q_ >= 0);
54
55 sbessel_ = std::vector<Spline<double>>(lmax__ + 2);
56 for (int l = 0; l <= lmax__ + 1; l++) {
57 sbessel_[l] = Spline<double>(rgrid__);
58 }
59
60 std::vector<double> jl(lmax__ + 2);
61 for (int ir = 0; ir < rgrid__.num_points(); ir++) {
62 double t = rgrid__[ir] * q__;
63 custom_bessel(lmax__ + 1, t, &jl[0]);
64 for (int l = 0; l <= lmax__ + 1; l++) {
65 sbessel_[l](ir) = jl[l];
66 }
67 }
68
69 for (int l = 0; l <= lmax__ + 1; l++) {
70 sbessel_[l].interpolate();
71 }
72}
73
74void
75Spherical_Bessel_functions::sbessel(int lmax__, double t__, double* jl__)
76{
77 gsl_sf_bessel_jl_array(lmax__, t__, jl__);
78}
79
80void
81Spherical_Bessel_functions::sbessel_deriv_q(int lmax__, double q__, double x__, double* jl_dq__)
82{
83 std::vector<double> jl(lmax__ + 2);
84 /* compute Bessel functions */
85 sbessel(lmax__ + 1, x__ * q__, &jl[0]);
86
87 for (int l = 0; l <= lmax__; l++) {
88 if (q__ != 0) {
89 jl_dq__[l] = (l / q__) * jl[l] - x__ * jl[l + 1];
90 } else {
91 if (l == 1) {
92 jl_dq__[l] = x__ / 3;
93 } else {
94 jl_dq__[l] = 0;
95 }
96 }
97 }
98}
99
100Spline<double> const&
101Spherical_Bessel_functions::operator[](int l__) const
102{
103 return sbessel_[l__];
104}
105
108{
109 assert(q_ >= 0);
110 Spline<double> s(*rgrid_);
111 if (q_ != 0) {
112 for (int ir = 0; ir < rgrid_->num_points(); ir++) {
113 s(ir) = (l__ / q_) * sbessel_[l__](ir) - (*rgrid_)[ir] * sbessel_[l__ + 1](ir);
114 }
115 } else {
116 if (l__ == 1) {
117 for (int ir = 0; ir < rgrid_->num_points(); ir++) {
118 s(ir) = (*rgrid_)[ir] / 3;
119 }
120 }
121 }
122 s.interpolate();
123 return s;
124}
125
126} // namespace sf
127
128} // sirius
int num_points() const
Number of grid points.
Spline< T, U > & interpolate()
Definition: spline.hpp:275
Spline< double > deriv_q(int l__)
Derivative of Bessel function with respect to q.
Definition: sbessel.cpp:107
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
Contains implementation of sirius::Spherical_Bessel_functions class.