PlanetOrbits.jl icon indicating copy to clipboard operation
PlanetOrbits.jl copied to clipboard

Implement unbound parabolic and hyperbolic orbits

Open astrojuanlu opened this issue 2 years ago • 13 comments

I'm trying the library for the first time and noticed a couple of strange things. It's my very first time running Julia, so bear with me.

I'm using the following semimajor axis and attractor mass (which I understand it's expressed in solar masses):

a = 10000e3
M = 3e-6

And the following code for the orbit definition and plotting:

using PlanetOrbits
using Plots

elems = KeplerianElementsDeg(
       a = a,
       M = M,
       i = 0,
       e = e,
       ω = 0,
       Ω = 0,
       plx = 100,
       τ = 0
       )

plot(elems)

(what's the parallax for, by the way? I typed 100 because I didn't know what to write but also it didn't seem to affect the results)

For near-parabolic orbits e = 0.99999, I noticed that the representation rounding is a bit too agressive, appearing as 1.0. In any case, the correct value is stored:

julia> elems = KeplerianElementsDeg(
       a = a,
       M = M,
       i = 0,
       e = 0.99999,
       ω = 0,
       Ω = 0,
       plx = 100,
       τ = 0
       )
KeplerianElements{Float64}
─────────────────────────
a   [au ] = 1.0e7
e         = 1.0
i   [°  ] = 0.0
ω   [°  ] = 0.0
Ω   [°  ] = 0.0
τ         = 0.0
M   [M⊙ ] = 3.0e-6 
plx [mas] = 100.0 
──────────────────────────
period      [yrs ] : 1.82468092739242e13 
distance    [pc  ] : 10.0 
mean motion [°/yr] : 1.97e-11 
──────────────────────────


julia> elems.e
0.99999

In this case, a straight line is produced as a plot, probably because the x range is not properly computed:

near-parabolic

In the hyperbolic case, the eccentricity is set to 1.0 silently:

julia> elems = KeplerianElementsDeg(
       a = a,
       M = M,
       i = 0,
       e = 1.2,
       ω = 0,
       Ω = 0,
       plx = 100,
       τ = 0
       )
KeplerianElements{Float64}
─────────────────────────
a   [au ] = 1.0e7
e         = 1.0
i   [°  ] = 0.0
ω   [°  ] = 0.0
Ω   [°  ] = 0.0
τ         = 0.0
M   [M⊙ ] = 3.0e-6 
plx [mas] = 100.0 
──────────────────────────
period      [yrs ] : 1.82468092739242e13 
distance    [pc  ] : 10.0 
mean motion [°/yr] : 1.97e-11 
──────────────────────────


julia> elems.e
1.0

And a seemingly empty plot is produced:

parabolic-plot

astrojuanlu avatar Jun 06 '22 08:06 astrojuanlu

Just noticed that I was setting an absurd SMA since the units are au and not m, but it's only a scale effect. Double checked that with a = 10000e3 / 150e9 the results are the same.

astrojuanlu avatar Jun 06 '22 08:06 astrojuanlu

Hi @astrojuanlu thanks for the bug report and for trying the package out (and Julia)!

There's a few things going on.

First, the parameter plx is the parallax distance to the system in milliarcseconds. The main type KeplerianElements represents the visual orbit of a secondary in the plane of the sky. We should probably rename this and create another type to represent a general orbit in 3D space.

Next, the plot recipe for the orbital elements has aspectratio=1 by default, but we can turn that off

plot(elems, aspectratio=:auto)

Next, I see that the heuristic for distributing points along the orbit is not working well for this case:

scatter(elems, aspectratio=:auto, title="e=0.995")

image I used scatter instead of plot to see the points instead of a line. Right now the plot recipe solves the orbit at a set of points that are equidistant in true anomaly.

I think a good solution would be to plot points that are equidistant in edit:~mean~eccentric anomaly instead: image

Here's solutions for a wide range of eccentricities:

elems = [
    KeplerianElementsDeg(
              a = 10000e3/150e9,
              M = 3e-6,
              i = 65,
              e = e,
              ω = 0,
              Ω = 0,
              plx = 100,
              τ = 0
      )
     for e in 1 .- 10.0 .^(-9:0)
]
plot(elems, aspectratio=:auto)

image

I'll go ahead and tag a new version with that fix.

Finally, hyperbolic orbits are not yet supported by the kepler solver we are using, but I would welcome either a pull request implementing it or a pointer towards a good algorithm for hyperbolic cases.

sefffal avatar Jun 06 '22 14:06 sefffal

Version 0.1.1 has the plotting fix. Once merged in the registry you can update by entering package mode and running update (type ] update).

sefffal avatar Jun 06 '22 14:06 sefffal

I think a good solution would be to plot points that are equidistant in mean anomaly instead:

You might want to check https://apps.dtic.mil/dtic/tr/fulltext/u2/a605040.pdf out:

image

In poliastro we are doing uniform sampling of the eccentric anomaly for closed orbits:

https://github.com/poliastro/poliastro/blob/321ca443f47e64eac40b462c31ca72a80cefa3b5/src/poliastro/twobody/sampling.py#L8-L41

astrojuanlu avatar Jun 06 '22 16:06 astrojuanlu

Ok, PlanetOrbits.jl now does the same uniform sampling of eccentric anomaly. Thanks for your help @astrojuanlu!

sefffal avatar Jun 06 '22 16:06 sefffal

Thanks for the swift response by the way! Answering one last thing:

Finally, hyperbolic orbits are not yet supported by the kepler solver we are using, but I would welcome either a pull request implementing it or a pointer towards a good algorithm for hyperbolic cases.

I see you implemented Markley's algorithm. In poliastro we are using a method by Farnocchia et al http://dx.doi.org/10.1007/s10569-013-9476-9 that has the property of also converging in the near-parabolic region (both elliptic and hyperbolic), you can read the source code here:

https://github.com/poliastro/poliastro/blob/0.16.x/src/poliastro/core/propagation/farnocchia.py

It's MIT licensed, so the only thing we ask is that the attribution is retained. And you can also cite our upcoming paper :)

astrojuanlu avatar Jun 06 '22 16:06 astrojuanlu

(Our own implementation of Markley is to be found here https://github.com/poliastro/poliastro/blob/3c504db/src/poliastro/core/propagation/markley.py)

astrojuanlu avatar Jun 06 '22 16:06 astrojuanlu

Okay nice, I'll take a look. One thing I really liked about the Markley algorithm is that it's non iterative. This lets it work on the GPU and works nicely with some kinds of auto-diff backends like Enzyme.jl. Which means we can write a model or cost function that computes orbits and automatically get gradients to accelerate optimization etc.

I think the best solution would be to support multiple algorithms by passing them through to orbitsolve, e.g. orbitsolve(elem, Markley()) or orbitsolve(elem, Farnocchia()).

sefffal avatar Jun 06 '22 16:06 sefffal

I addded support for choosing different kepler solver algorithms including options with arbitrary precision: https://sefffal.github.io/PlanetOrbits.jl/dev/kepler/

Everything is now in place to allow solving unbound orbits, except that some assumptions in the code will have to be relaxed. For example, we pre-calculate some factors like √((1 + e)/(1 - e)) which are no longer valid for e > 1.

sefffal avatar Aug 23 '22 21:08 sefffal

@astrojuanlu I'm working to add support for hyperbolic orbits here.

Do you happen to have a reference for determining a hyperbolic orbit from an (x,y,z,vx,vy,vz) point?

I haven't been able to find anything in the literature.

sefffal avatar Jan 05 '24 01:01 sefffal

I don't, and I'm not actively working on poliastro or Astrodynamics anymore 😢

astrojuanlu avatar Jan 05 '24 10:01 astrojuanlu

Oh, sorry for the notification spam then!

sefffal avatar Jan 05 '24 13:01 sefffal

No worries! Best luck ✨

astrojuanlu avatar Jan 06 '24 20:01 astrojuanlu