|
22 | 22 | Spherical bessel function of the first kind of order `nu`, ``j_ν(x)``. This is the non-singular
|
23 | 23 | solution to the radial part of the Helmholz equation in spherical coordinates.
|
24 | 24 | """
|
25 |
| -function sphericalbesselj(nu::Real, x::T) where T |
| 25 | +sphericalbesselj(nu::Real, x::Real) = _sphericalbesselj(nu, float(x)) |
| 26 | + |
| 27 | +_sphericalbesselj(nu, x::Float16) = Float16(_sphericalbesselj(nu, Float32(x))) |
| 28 | + |
| 29 | +function _sphericalbesselj(nu::Real, x::T) where T <: Union{Float32, Float64} |
26 | 30 | isnan(nu) || isnan(x) && return NaN
|
27 | 31 | x < zero(T) && return throw(DomainError(x, "Complex result returned for real arguments. Complex arguments are currently not supported"))
|
28 | 32 |
|
29 |
| - if nu < zero(T) |
30 |
| - return SQPIO2(T) * besselj(nu + 1/2, x) / sqrt(x) |
31 |
| - else |
32 |
| - return sphericalbesselj_positive_args(nu, x) |
33 |
| - end |
| 33 | + return nu < zero(T) ? sphericalbesselj_generic(nu, x) : sphericalbesselj_positive_args(nu, x) |
34 | 34 | end
|
35 | 35 |
|
| 36 | +sphericalbesselj_generic(nu, x::T) where T = SQPIO2(T) * besselj(nu + one(T)/2, x) / sqrt(x) |
| 37 | + |
36 | 38 | #####
|
37 | 39 | ##### Positive arguments for `sphericalbesselj`
|
38 | 40 | #####
|
39 | 41 |
|
40 | 42 | function sphericalbesselj_positive_args(nu::Real, x::T) where T
|
41 |
| - if x^2 / (4*nu + 110) < eps(T) |
42 |
| - # small arguments power series expansion |
43 |
| - x2 = x^2 / 4 |
44 |
| - coef = evalpoly(x2, (1, -inv(3/2 + nu), -inv(5 + nu), -inv(21/2 + nu), -inv(18 + nu))) |
45 |
| - a = sqrt(T(pi)/2) / (gamma(T(3)/2 + nu) * 2^(nu + T(1)/2)) |
46 |
| - return x^nu * a * coef |
47 |
| - elseif isinteger(nu) |
48 |
| - if (x >= nu && nu < 250) || (x < nu && nu < 60) |
49 |
| - return sphericalbesselj_recurrence(Int(nu), x) |
50 |
| - else |
51 |
| - return SQPIO2(T) * besselj(nu + 1/2, x) / sqrt(x) |
52 |
| - end |
53 |
| - else |
54 |
| - return SQPIO2(T) * besselj(nu + 1/2, x) / sqrt(x) |
55 |
| - end |
| 43 | + isinteger(nu) && return sphericalbesselj_positive_args(Int(nu), x) |
| 44 | + return sphericalbesselj_small_args_cutoff(nu, x) ? sphericalbesselj_small_args(nu, x) : sphericalbesselj_generic(nu, x) |
| 45 | +end |
| 46 | + |
| 47 | +function sphericalbesselj_positive_args(nu::Integer, x::T) where T |
| 48 | + sphericalbesselj_small_args_cutoff(nu, x) && return sphericalbesselj_small_args(nu, x) |
| 49 | + return (x >= nu && nu < 250) || (x < nu && nu < 60) ? sphericalbesselj_recurrence(nu, x) : sphericalbesselj_generic(nu, x) |
| 50 | +end |
| 51 | + |
| 52 | +##### |
| 53 | +##### Power series expansion for small arguments |
| 54 | +##### |
| 55 | + |
| 56 | +sphericalbesselj_small_args_cutoff(nu, x::T) where T = x^2 / (4*nu + 110) < eps(T) |
| 57 | + |
| 58 | +function sphericalbesselj_small_args(nu, x::T) where T |
| 59 | + x2 = x^2 / 4 |
| 60 | + coef = evalpoly(x2, (1, -inv(T(3)/2 + nu), -inv(5 + nu), -inv(T(21)/2 + nu), -inv(18 + nu))) |
| 61 | + a = sqrt(T(pi)/2) / (gamma(T(3)/2 + nu) * 2^(nu + T(1)/2)) |
| 62 | + return x^nu * a * coef |
56 | 63 | end
|
57 | 64 |
|
58 | 65 | #####
|
|
62 | 69 | # very accurate approach however need to consider some performance issues
|
63 | 70 | # if recurrence is stable (x>=nu) can generate very fast up to orders around 250
|
64 | 71 | # for larger orders it is more efficient to use other expansions
|
65 |
| -# if (x<nu) we can use forward recurrence from sphericalbesselj_recurrence and |
| 72 | +# if (x<nu) we can use forward recurrence from sphericalbessely_recurrence and |
66 | 73 | # then use a continued fraction approach. However, for largish orders (>60) the
|
67 | 74 | # continued fraction is slower converging and more efficient to use other methods
|
68 | 75 | function sphericalbesselj_recurrence(nu::Integer, x::T) where T
|
@@ -98,30 +105,32 @@ Spherical bessel function of the second kind at order `nu`, ``y_ν(x)``. This is
|
98 | 105 | solution to the radial part of the Helmholz equation in spherical coordinates. Sometimes
|
99 | 106 | known as a spherical Neumann function.
|
100 | 107 | """
|
101 |
| -function sphericalbessely(nu::Real, x::T) where T |
| 108 | +sphericalbessely(nu::Real, x::Real) = _sphericalbessely(nu, float(x)) |
| 109 | + |
| 110 | +_sphericalbessely(nu, x::Float16) = Float16(_sphericalbessely(nu, Float32(x))) |
| 111 | + |
| 112 | +function _sphericalbessely(nu::Real, x::T) where T <: Union{Float32, Float64} |
102 | 113 | isnan(nu) || isnan(x) && return NaN
|
103 | 114 | x < zero(T) && return throw(DomainError(x, "Complex result returned for real arguments. Complex arguments are currently not supported"))
|
104 |
| - abs_nu = abs(nu) |
105 |
| - |
106 |
| - if nu < zero(T) |
107 |
| - return SQPIO2(T) * bessely(nu + 1/2, x) / sqrt(x) |
108 |
| - else |
109 |
| - return sphericalbessely_positive_args(nu, x) |
110 |
| - end |
| 115 | + return nu < zero(T) ? sphericalbessely_generic(nu, x) : sphericalbessely_positive_args(nu, x) |
111 | 116 | end
|
112 | 117 |
|
| 118 | +sphericalbessely_generic(nu, x::T) where T = SQPIO2(T) * bessely(nu + one(T)/2, x) / sqrt(x) |
| 119 | + |
113 | 120 | #####
|
114 | 121 | ##### Positive arguments for `sphericalbesselj`
|
115 | 122 | #####
|
116 | 123 |
|
117 |
| -function sphericalbessely_positive_args(nu::Real, x::T) where T |
| 124 | +sphericalbessely_positive_args(nu::Real, x) = isinteger(nu) ? sphericalbessely_positive_args(Int(nu), x) : sphericalbessely_generic(nu, x) |
| 125 | + |
| 126 | +function sphericalbessely_positive_args(nu::Integer, x::T) where T |
118 | 127 | if besseljy_debye_cutoff(nu, x)
|
119 | 128 | # for very large orders use expansion nu >> x to avoid overflow in recurrence
|
120 | 129 | return SQPIO2(T) * besseljy_debye(nu + 1/2, x)[2] / sqrt(x)
|
121 |
| - elseif isinteger(nu) && nu < 250 |
122 |
| - return sphericalbessely_forward_recurrence(Int(nu), x)[1] |
| 130 | + elseif nu < 250 |
| 131 | + return sphericalbessely_forward_recurrence(nu, x)[1] |
123 | 132 | else
|
124 |
| - return SQPIO2(T) * bessely(nu + 1/2, x) / sqrt(x) |
| 133 | + return sphericalbessely_generic(nu, x) |
125 | 134 | end
|
126 | 135 | end
|
127 | 136 |
|
|
0 commit comments