Skip to content

Commit 23539a7

Browse files
committed
sphericalbessel branch
1 parent 6dfcf3d commit 23539a7

File tree

2 files changed

+165
-0
lines changed

2 files changed

+165
-0
lines changed

src/Bessels.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ include("besselj.jl")
3131
include("besselk.jl")
3232
include("bessely.jl")
3333
include("hankel.jl")
34+
include("sphericalbessel.jl")
3435

3536
include("Float128/besseli.jl")
3637
include("Float128/besselj.jl")

src/sphericalbessel.jl

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
function sphericalbesselj(nu::Real, x::T) where T
2+
isinteger(nu) && return sphericalbesselj(Int(nu), x)
3+
abs_nu = abs(nu)
4+
abs_x = abs(x)
5+
6+
Jnu = sphericalbesselj_positive_args(abs_nu, abs_x)
7+
if nu >= zero(T)
8+
if x >= zero(T)
9+
return Jnu
10+
else
11+
return throw(DomainError(x, "Complex result returned for real arguments. Complex arguments are currently not supported"))
12+
#return Jnu * cispi(abs_nu)
13+
end
14+
else
15+
Ynu = sphericalbessely_positive_args(abs_nu, abs_x)
16+
spi, cpi = sincospi(abs_nu)
17+
out = Jnu * cpi - Ynu * spi
18+
if x >= zero(T)
19+
return out
20+
else
21+
return throw(DomainError(x, "Complex result returned for real arguments. Complex arguments are currently not supported"))
22+
#return out * cispi(nu)
23+
end
24+
end
25+
end
26+
27+
function sphericalbesselj(nu::Integer, x::T) where T
28+
abs_nu = abs(nu)
29+
abs_x = abs(x)
30+
sg = iseven(abs_nu) ? 1 : -1
31+
32+
Jnu = sphericalbesselj_positive_args(abs_nu, abs_x)
33+
if nu >= zero(T)
34+
return x >= zero(T) ? Jnu : Jnu * sg
35+
else
36+
if x >= zero(T)
37+
return Jnu * sg
38+
else
39+
Ynu = sphericalbessely_positive_args(abs_nu, abs_x)
40+
spi, cpi = sincospi(abs_nu)
41+
return (cpi*Jnu - spi*Ynu) * sg
42+
end
43+
end
44+
end
45+
46+
function sphericalbesselj_positive_args(nu::Real, x::T) where T
47+
if x^2 / (4*nu + 110) < eps(T)
48+
# small arguments power series expansion
49+
x2 = x^2 / 4
50+
coef = evalpoly(x2, (1, -inv(3/2 + nu), -inv(5 + nu), -inv(21/2 + nu), -inv(18 + nu)))
51+
a = sqrt(T(pi)/2) / (gamma(T(3)/2 + nu) * 2^(nu + T(1)/2))
52+
return x^nu * a * coef
53+
elseif isinteger(nu)
54+
if (x >= nu && nu < 250) || (x < nu && nu < 60)
55+
return sphericalbesselj_recurrence(nu, x)
56+
else
57+
return SQPIO2(T) * besselj(nu + 1/2, x) / sqrt(x)
58+
end
59+
else
60+
return SQPIO2(T) * besselj(nu + 1/2, x) / sqrt(x)
61+
end
62+
end
63+
64+
# very accurate approach however need to consider some performance issues
65+
# if recurrence is stable (x>=nu) can generate very fast up to orders around 250
66+
# for larger orders it is more efficient to use other expansions
67+
# if (x<nu) we can use forward recurrence from sphericalbesselj_recurrence and
68+
# then use a continued fraction approach. However, for largish orders (>60) the
69+
# continued fraction is slower converging and more efficient to use other methods
70+
function sphericalbesselj_recurrence(nu::Integer, x)
71+
if x >= nu
72+
# forward recurrence if stable
73+
xinv = inv(x)
74+
s, c = sincos(x)
75+
sJ0 = s * xinv
76+
sJ1 = (sJ0 - c) * xinv
77+
78+
nu_start = one(T)
79+
while nu_start < nu + 0.5
80+
sJ0, sJ1 = sJ1, muladd((2*nu_start + 1)*xinv, sJ1, -sJ0)
81+
nu_start += 1
82+
end
83+
return sJ0
84+
elseif x < nu
85+
# compute sphericalbessely with forward recurrence and use continued fraction
86+
sYnm1, sYn = sphericalbessely_forward_recurrence(nu, x)
87+
H = besselj_ratio_jnu_jnum1(nu + 3/2, x)
88+
return inv(x^2 * (H*sYnm1 - sYn))
89+
end
90+
end
91+
92+
93+
94+
function sphericalbessely(nu::Real, x::T) where T
95+
isinteger(nu) && return sphericalbessely(Int(nu), x)
96+
abs_nu = abs(nu)
97+
abs_x = abs(x)
98+
99+
Ynu = sphericalbessely_positive_args(abs_nu, abs_x)
100+
if nu >= zero(T)
101+
if x >= zero(T)
102+
return Ynu
103+
else
104+
return throw(DomainError(x, "Complex result returned for real arguments. Complex arguments are currently not supported"))
105+
#return Ynu * cispi(-nu) + 2im * besselj_positive_args(abs_nu, abs_x) * cospi(abs_nu)
106+
end
107+
else
108+
Jnu = sphericalbesselj_positive_args(abs_nu, abs_x)
109+
spi, cpi = sincospi(abs_nu)
110+
if x >= zero(T)
111+
return Ynu * cpi + Jnu * spi
112+
else
113+
return throw(DomainError(x, "Complex result returned for real arguments. Complex arguments are currently not supported"))
114+
#return cpi * (Ynu * cispi(nu) + 2im * Jnu * cpi) + Jnu * spi * cispi(abs_nu)
115+
end
116+
end
117+
end
118+
function sphericalbessely(nu::Integer, x::T) where T
119+
abs_nu = abs(nu)
120+
abs_x = abs(x)
121+
sg = iseven(abs_nu) ? 1 : -1
122+
123+
Ynu = sphericalbessely_positive_args(abs_nu, abs_x)
124+
if nu >= zero(T)
125+
if x >= zero(T)
126+
return Ynu
127+
else
128+
return throw(DomainError(x, "Complex result returned for real arguments. Complex arguments are currently not supported"))
129+
#return Ynu * sg + 2im * sg * besselj_positive_args(abs_nu, abs_x)
130+
end
131+
else
132+
if x >= zero(T)
133+
return Ynu * sg
134+
else
135+
return throw(DomainError(x, "Complex result returned for real arguments. Complex arguments are currently not supported"))
136+
#return Ynu + 2im * besselj_positive_args(abs_nu, abs_x)
137+
end
138+
end
139+
end
140+
141+
function sphericalbessely_positive_args(nu::Real, x::T) where T
142+
if besseljy_debye_cutoff(nu, x)
143+
# for very large orders use expansion nu >> x to avoid overflow in recurrence
144+
return SQPIO2(T) * besseljy_debye(nu + 1/2, x)[2] / sqrt(x)
145+
elseif isinteger(nu) && nu < 250
146+
return sphericalbessely_forward_recurrence(Int(nu), x)[1]
147+
else
148+
return SQPIO2(T) * bessely(nu + 1/2, x) / sqrt(x)
149+
end
150+
end
151+
152+
function sphericalbessely_forward_recurrence(nu::Integer, x::T) where T
153+
xinv = inv(x)
154+
s, c = sincos(x)
155+
sY0 = -c * xinv
156+
sY1 = xinv * (sY0 - s)
157+
158+
nu_start = one(T)
159+
while nu_start < nu + 0.5
160+
sY0, sY1 = sY1, muladd((2*nu_start + 1)*xinv, sY1, -sY0)
161+
nu_start += 1
162+
end
163+
return sY0, sY1
164+
end

0 commit comments

Comments
 (0)