Search code examples
juliadifferential-equationscalculation

Julia program on ephemerides shows inadequate answers


While solving a differential equation on satellite motion encountered this error:

dt <= dtmin. Aborting. If you would like to force continuation with dt=dtmin, set force_dtmin=true

Here is my code:

    using JPLEphemeris
    spk = SPK("some-path/de430.bsp")
    jd = Dates.datetime2julian(DateTime(some-date))#date of the calculatinons 
    yyyy/mm/dd hh/mm/ss
    jd2 = Dates.datetime2julian(DateTime(some-date))#date of the calculatinons 
    yyyy/mm/dd hh/mm/ss

   println(jd)
println(jd2)

st_bar_sun = state(spk, 0, 10, jd)
st_bar_moon_earth = state(spk, 0, 3, jd)
st_bar_me_earth = state(spk, 3, 399, jd)
st_bar_me_moon = state(spk, 3, 301, jd)

moon_cord = st_bar_me_moon - st_bar_me_earth

a = st_bar_moon_earth + st_bar_me_earth
sun_cord = st_bar_sun - a


println(sputnik_cord)
sputnik_cord = [8.0,8.0,8.0,8.0,8.0,8.0,8.0]
moon_sputnik = sputnik_cord - moon_cord
sun_sputnic = sputnik_cord - sun_cord

Req = 6378137
J2 = 1.08262668E-3

GMe = 398600.4418E+9
GMm = 4.903E+12
GMs = 1.32712440018E+20

function f(dy,y,p,t)

  re2=(y[1]^2 + y[2]^2 + y[3]^2)
  re3=re2^(3/2)

  rs3 = ((y[1]-sun_cord[1])^2 + (y[2]-sun_cord[2])^2 + (y[3]-sun_cord[3])^2)^(3/2)
  rm3 = ((y[1]-moon_cord[1])^2 + (y[2]-moon_cord[2])^2 + (y[3]-moon_cord[3])^2)^(3/2)

  w = 1 + 1.5J2*(Req*Req/re2)*(1 - 5y[3]*y[3]/re2)
  w2 = 1 + 1.5J2*(Req*Req/re2)*(3 - 5y[3]*y[3]/re2)

  dy[1] = y[4]
  dy[2] = y[5]
  dy[3] = y[6]
  dy[4] = -GMe*y[1]*w/re3 
  dy[5] = -GMe*y[2]*w/re3 
  dy[6] = -GMe*y[3]*w2/re3
end

function f2(dy,y,p,t)

  re2=(y[1]^2 + y[2]^2 + y[3]^2)
  re3=re2^(3/2)

  rs3 = ((y[1]-sun_cord[1])^2 + (y[2]-sun_cord[2])^2 + (y[3]-sun_cord[3])^2)^(3/2)
  rm3 = ((y[1]-moon_cord[1])^2 + (y[2]-moon_cord[2])^2 + (y[3]-moon_cord[3])^2)^(3/2)

  w = 1 + 1.5J2*(Req*Req/re2)*(1 - 5y[3]*y[3]/re2)
  w2 = 1 + 1.5J2*(Req*Req/re2)*(3 - 5y[3]*y[3]/re2)

  dy[1] = y[4]
  dy[2] = y[5]
  dy[3] = y[6]
  dy[4] = -GMe*y[1]*w/re3 - GMm*y[1]/rm3 - GMs*y[1]/rs3
  dy[5] = -GMe*y[2]*w/re3 - GMm*y[2]/rm3 - GMs*y[2]/rs3
  dy[6] = -GMe*y[3]*w2/re3- GMm*y[3]/rm3 - GMs*y[3]/rs3
end



y0 = sputnik_cord

jd=jd*86400
jd2=jd2*86400
using DifferentialEquations
prob = ODEProblem(f,y0,(jd,jd2))
sol = solve(prob,DP5(),abstol=1e-13,reltol=1e-13)


prob2 = ODEProblem(f2,y0,(jd,jd2))
sol2 = solve(prob2,DP5(),abstol=1e-13,reltol=1e-13)
println("Without SUN and MOON")
println(sol[end])
for i = (1:6)
 println(sputnik_cord[i]-sol[end][i])
end
println("With SUN and MOON")
println(sol2[end])

What(except the values) can be a reason of this? It worked well before I added the terms with sun_coords and moon_coords in definition of dy[4], dy[5], dy[6] in function f2(As I suppose the function f1 works correctly).


Solution

  • There are two reasons this could be happening. For one, you could see this error because the model is unstable due to implementation issues. If you accidentally put something in wrong, the solution may be diverging to infinity and as it diverges the time steps shorten and it exists with this error.

    Another thing that can happen is that your model might be stiff. This can happen if you have large time scale differences between different components. In that case, DP5(), an explicit Runge-Kutta method, is not an appropriate algorithm for this problem. Instead, you will want to look at something for stiff equations. I would recommend giving Rosenbrock23() a try: it's not the fastest but it's super stable and if the problem is integrable it'll handle it.

    That's a very good way to diagnose these issues: try other integrators. Try Rosenbrock23(), CVODE_BDF(), radau(), dopri5(), Vern9(), etc. If none of these are working, then you will have just tested your algorithm with a mixture of the most well-tested algorithms (some of them Julia implementations, but others are just wrappers to standard classic C++ and Fortran methods) and this suggests that the issue is in your model formulation and not a peculiarity of a specific solver on this problem. Since I cannot run your example (you should make your example runnable, i.e. no extra files required, if you want me to test things out), I cannot be sure that your model implementation is correct and this would be a good way to find out.

    My guess is that the model you have written down is not a good implementation because of floating point issues.

    GMe = 398600.4418E+9
    GMm = 4.903E+12
    GMs = 1.32712440018E+20
    

    these values have only precision 16 digits less than their prescribed value:

    > eps(1.32712440018E+20)
    16384.0
    > 1.32712440018E+20 + 16383
    1.3271244001800002e20
    
    > 1.32712440018E+20 + 16380
    1.3271244001800002e20
    
    > 1.32712440018E+20 + 16000
    1.3271244001800002e20
    

    Notice the lack of precision below the machine epsilon for this value. Well, you're asking for

    sol = solve(prob,DP5(),abstol=1e-13,reltol=1e-13)
    

    precision to 1e-13 when it's difficult to be precise to 1e5 given the size of your constants. You need to adjust your units or utilize BigFloat numbers if you want this kind of precision on this problem. So what's likely going on is that the differential equation solvers are realizing that they are not hitting 1e-13 precision, shrinking the stepsize, and repeating this indefinitely (because they can never hit 1e-13 precision due to the size of the floating point numbers) until the stepsize is too small and it exits. If you change the units so that way the constants are more reasonable in size then you can fix this problem.