# Best Solver for Bessel-like Differential Equations with Singularity; unexpected Interpolation Behavior

Hi, I’m starting a project solving equations (using the `DifferentialEquations.jl` package) that will be similar to Bessel equations: oscillatory in general, with a singularity in the function and its derivatives at `t=0`. (I will ultimately extend the work to modified types of Bessel eq’ns, entangled systems of Inhomogeneous Diff Eq’s, and possibly 4th-order Diff Eq’s via order-reduction.)

Some questions:

1. What might be the best solver(s) and parameters for me to use with `SecondOrderODE`, etc., to ensure the best possible accuracy and precision – especially letting me get high accuracy as close as possible to `t -> 0`. (I am willing to sacrifice computing speed & time.) Does anyone have specific knowledge and experience with this?

2. When doing plots of residuals (vs. theory) of the discrete values of `sol.u`, plotted along with interpolations of `sol(time)` to see how the interpolated solution fits the discrete solution values, the interpolation results are super-weird, with strange oscillatory behavior to much higher error values. (Especially when sampling the interpolations too finely.) Does anyone know why this might be happening? (I might have to rely on those interpolations at some point.)

3. Is it worth it going to BigFloat and BigInt everywhere, and possibly do setprecision() very tightly?

In my next post, I’ll include a portion of my code so you can see what I mean, and (if possible) a couple pictures of those weird interpolation plots.

Try:

`RKO65` - Olver’s 6 stage 5th order method. This method is robust on problems which have a singularity at `t=0` .

https://diffeq.sciml.ai/latest/solvers/ode_solve/

If that doesn’t work for your problem, you might want to try ApproxFun. Most of the methods in DiffEq are not safe with a singularity at `t=0`: generally that might need a discretization that’s fully implicit over time.

2 Likes

Hi again, some of my relevant code and images, to illustrate my question above:

``````BesselJInitAmount = 1.75
BesselYInitAmount = 0.37

FnOrder = [1.27]

tspanForward = (5.0, 20.0)
tspanBackward = (5.0, 0.01)

function OrdBesselDiffEqToSolve!(ddu,du,u,p,t)
OrderParam = p[1]
ddu[1] = -(du[1]/t) - (1 - ((OrderParam/t)^2))*u[1]
end

function OrdBesselInitCondCalc(BesJamt, BesYamt, Ord, tVal)
StartVal = (BesJamt*besselj(Ord,tVal)) + (BesYamt*bessely(Ord,tVal))
StartDeriv = ((BesJamt/2)*(besselj((Ord-1),tVal) - besselj((Ord+1),tVal))) +
((BesYamt/2)*(bessely((Ord-1),tVal) - bessely((Ord+1),tVal)))
return [StartVal, StartDeriv]
end

function OrdBesselTheorySoln(t, BesJamt, BesYamt, Ord)::BigFloat
return ((BesJamt*besselj(Ord,t)) + (BesYamt*bessely(Ord,t)))
end

InitialConditions = OrdBesselInitCondCalc(BesselJInitAmount, BesselYInitAmount,
FnOrder[1], tspanForward[1])

xInit = [InitialConditions[1]]
vInit = [InitialConditions[2]]

probFor = SecondOrderODEProblem(OrdBesselDiffEqToSolve!,vInit,xInit,tspanForward,FnOrder)
probBack = SecondOrderODEProblem(OrdBesselDiffEqToSolve!,vInit,xInit,tspanBackward,FnOrder)
#
#
#@time solFor = solve(probFor, dense=true, reltol=1e-12, abstol=1e-12)
#@time solBack = solve(probBack, dense=true, reltol=1e-12, abstol=1e-12)
#
#@time solFor = solve(probFor, Tsit5(), dense=true, reltol=1e-12, abstol=1e-12)
#@time solBack = solve(probBack, Tsit5(), dense=true, reltol=1e-12, abstol=1e-12)
#
@time solFor = solve(probFor, RKO65(), dense=true, reltol=1e-12, abstol=1e-12, dt=0.001)
@time solBack = solve(probBack, RKO65(), dense=true, reltol=1e-12, abstol=1e-12, dt=-0.001)

TvalsFor = getindex.(solFor.t, 1)
FprimeOfTFor = getindex.(solFor.u, 1)
FofTFor = getindex.(solFor.u, 2)
#
TvalsBack = getindex.(solBack.t, 1)
FprimeOfTBack = getindex.(solBack.u, 1)
FofTBack = getindex.(solBack.u, 2)
#

u_analyticalFor = @. OrdBesselTheorySoln(TvalsFor,
BesselJInitAmount, BesselYInitAmount, FnOrder[1])
errFor = abs.(u_analyticalFor - FofTFor)
@. errFor[errFor == 0 ] = NaN # set zeros to NaN to avoid problems caused by log(0) = -Inf
#
#
u_analyticalBack = @. OrdBesselTheorySoln(TvalsBack,
BesselJInitAmount, BesselYInitAmount, FnOrder[1])
errBack = abs.(u_analyticalBack - FofTBack)
@. errBack[errBack == 0 ] = NaN # set zeros to NaN to avoid problems caused by log(0) = -Inf
#
#
#
fineStepSize = 0.00299
fineForStepsWOends = BigInt(((tspanForward[2]-tspanForward[1]) ÷ fineStepSize)-1)
fineBackStepsWOends = BigInt(((tspanBackward[1]-tspanBackward[2]) ÷ fineStepSize)-1)
#
t_fineFor = append!(append!([tspanForward[1]],
[(tspanForward[1] + (stepN*fineStepSize)) for stepN = 1:fineForStepsWOends]),
[tspanForward[2]])
#
t_fineBack = append!(append!([tspanBackward[1]],
[(tspanForward[1] - (stepN*fineStepSize)) for stepN = 1:fineBackStepsWOends]),
[tspanBackward[2]])
#
fineForResids = [abs((solFor(time)[2] -
OrdBesselTheorySoln(time, BesselJInitAmount, BesselYInitAmount,
FnOrder[1]))) for time in t_fineFor]; @. fineForResids[fineForResids == 0] = NaN
#
fineBackResids = [abs((solBack(time)[2] -
OrdBesselTheorySoln(time, BesselJInitAmount, BesselYInitAmount,
FnOrder[1]))) for time in t_fineBack]; @. fineBackResids[fineBackResids == 0] = NaN
#
#
#
InterpDataPtResidPlots =
scatter(TvalsFor, errFor, <plot options>);
plot!(t_fineFor, fineForResids, <plot options>);
scatter!(TvalsBack, errBack, <plot options>);
plot!(t_fineBack, fineBackResids, <plot options>)
``````

Hopefully this code snippet (and the attached image) clarifies my question…

Hi Chris, thanks for the quick reply!

I did see that notation in the documentation, and in my code in my follow-up post you can see that I used that solver. But `RKO65` is a fixed-timestep method, so I was wary about it. But if you’re sure that’s the best one for `t=0` singularities, I could stick with it.

What you said about “a discretization that’s fully implicit over time” is interesting, could you explain what you mean? Also I haven’t heard of ApproxFun, so I guess I’ll have to look into that.
Thanks.

By the way, I have found that (fixed-timestep) method `RK065` works about a billion (10^9) times worse for this problem than `Tsit5` at `t = 0.001`.

I am currently also trying solvers `AutoVern9(Rodas4())`, `AutoVern9(Rodas5())`, `AutoVern9(KenCarp4())`, and `AutoTsit5(Rosenbrock23())` with `SecondOrderODE`, but this is creating error messages (as I have raised in another thread):

`DimensionMismatch("parent has 4 elements, which is incompatible with length 2")`

That’s odd. But yeah… things with singularities at `t=0` is a pretty special problem and it’s not something most of these methods are robust for, so really check out ApproxFun.jl with this.

Yeah, I’m trying out everything, looking for the best results.