-1
$\begingroup$

I've professional experience with physics simulations and C++ programming, although I don't have specific experience with astrophysics simulations.

I'm trying to build a two-body evolving system myself, but I'm struggling with obtaining even the simplest stable orbit (more than just a few revolutions).

Therefore I'm looking for some advice or ideally some source code project as reference.

I'm starting from random parameters, as I do not want to force anything in place. I've used Runge-Kutta from boost as it was suggested to me, but now I doubt that's enough. Planets tends to crash into each other or separate immediately. I've tried also to limit the initial parameters in some sensible range.

Best result I've obtained was a few revolutions, not stable at all (also in terms of trajectories).

Thanks in advance.

$\endgroup$
19
  • 3
    $\begingroup$ To me, this sounds like an issue in the implementation of the right-hand side of ODE or a bad selection of initial conditions. While a symplectic method is a good choice, its benefits will likely only be apparent for long-term integration. Over just a few orbits, the difference between a symplectic and non-symplectic integrator should be negligible. $\endgroup$ Aug 8, 2021 at 22:05
  • $\begingroup$ Did you tried with a simpler ODE first? A pendulum, for example. $\endgroup$
    – nicoguaro
    Aug 9, 2021 at 0:02
  • $\begingroup$ One also needs to avoid singular situations, as for close encounters of two planets the relative velocity can get so high that the sampling frequency of the fixed-step integration is too low, radically increasing the error in the energy. One could use adaptive-step methods until such a situation is resolved and then continue with the symplectic method. $\endgroup$ Aug 9, 2021 at 7:59
  • $\begingroup$ See stackoverflow.com/questions/66893929/velocity-verlet-algorithm, and other topics from the tag "orbital-mechanics", and also math.stackexchange.com/questions/1392051/…, but math.SE has less on the Verlet method under the tag "celestial-mechanics" $\endgroup$ Aug 9, 2021 at 8:26
  • 2
    $\begingroup$ The program that generates the array to search in is a 3-body simulation, the initial data is easy to find. The previous question of that OP has plots of a similar 3-body problem. /// (Your problem description is not very reproducible, you could add code or an algorithm description along with a selection of initial configurations that illustrate your observations.) $\endgroup$ Aug 9, 2021 at 21:21

1 Answer 1

1
$\begingroup$

I cannot claim very deep computational expertise, so in case it might help you, I can just post some code that contains two versions of a fixed-step straight-forward symplectic algorithms (leap-frog / Verlet's type). I however am not so proficient in C++, so I can offer a python version, so maybe you can translate it into C++. On the bright side, the python is more transparent in terms of methodological ideas and organization, so that could be beneficial. The code also does not feature the realistic constants, but scaled versions.

Also, the code is set up to two mass-points in a plane, because you specified that you want to start with a two-body simulation. I hope that's ok to get you started.

'''
Two body leap-forg algorithm simulation
'''

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

'''
Calculation of the gravitational acceleration
r is a 2 x 2 matrix, each row is the position of one of the two mass-points
'''     

def g_accel(r, mass1, mass2):
    r_12 = r[1,:] - r[0,:]
    g_force = mass1 * mass2 * r_12 / np.linalg.norm( r_12 )**3 
    return np.array([g_force / mass1, - g_force / mass2]) 


'''
propagation/numerical integration using leap-from / verlet's type time-reversible symplectic algorithm of convergence rate dt**2 
'''

def propagate_system(r1_in, r2_in, v1_in, v2_in, mass1, mass2, n_steps, dt):
    r = np.empty((n_steps, 2, 2),dtype=float)
    v = np.empty((n_steps, 2, 2),dtype=float)
    r[0,0,:] = r1_in
    r[0,1,:] = r2_in
    v[0,0,:] = v1_in
    v[0,1,:] = v2_in
    for n in range(n_steps-1):
        r[n+1,:,:] = r[n,:,:]  +  dt * v[n,:,:] / 2
        v[n+1,:,:] = v[n,:,:]  +  dt * g_accel(r[n+1,:], mass1, mass2)
        r[n+1,:,:] = r[n+1,:,:] + dt * v[n+1,:,:] / 2
    return r, v

'''
another propagation/numerical integration using leap-from / verlet's type time-reversible symplectic algorithm of convergence rate dt**4 
'''
def propagate_system_1(r1_in, r2_in, v1_in, v2_in, mass1, mass2, n_steps, dt):
    w0 = pow(2, 1/3)
    w1 = 1 / (2 - w0)
    w0 = - w0*w1
    c = np.array([w1, w0+w1 , w0+w1, w1]) / 2
    d = np.array([w1, w0, w1])
    r = np.empty((n_steps, 2, 2),dtype=float)
    v = np.empty((n_steps, 2, 2),dtype=float)
    r[0,0,:] = r1_in
    r[0,1,:] = r2_in
    v[0,0,:] = v1_in
    v[0,1,:] = v2_in
    for n in range(n_steps-1):
        r[n+1,:,:] = r[n,:,:]
        v[n+1,:,:] = v[n,:,:]
        for i in range(3):
            r[n+1,:,:] = r[n+1,:,:] +  c[i]*dt * v[n+1,:,:]
            v[n+1,:,:] = v[n+1,:,:] +  d[i]*dt * g_accel(r[n+1,:,:], mass1, mass2)
        r[n+1,:,:] = r[n+1,:,:] +  c[3]*dt * v[n+1,:,:]
    return r, v


'''
Test simulation:
Initial conditions:
'''
mass1 = 2 
mass2 = 1
initial_position1 = np.array([-1,0]) 
initial_position2 = np.array([1.3,0])
initial_velocity1 = np.array([0, 0.5])

initial_velocity2 = - mass1 * initial_velocity1 / mass2 

'''
Integration parameters:
'''
t_step = 0.05
N = 20000

'''
System time-propagation (numerical integration):
'''
r, v = propagate_system_1(initial_position1, 
                        initial_position2, 
                        initial_velocity1,
                        initial_velocity2, 
                        mass1, mass2, 
                        N, t_step)


'''
reducing the frequency of time-measurements for faster simulation speed 
'''
r = r[np.arange(1, N, 10), :, :]

'''
animation plot of time-evolution:
'''
plt.style.use('seaborn-whitegrid')

fig = plt.figure()
ax = plt.axes()
ax.set_aspect('equal')

ax.set_xlim(-12, 12)
ax.set_ylim(-12, 12)
line = np.empty(2, dtype=type(ax.plot(r[0, 0, 0], r[0, 0, 1])))
for point in range(2):
    line[point], = ax.plot( r[0, point, 0],  r[0, point, 1] )

def animate(i):
    '''
    update plot
    '''
    for p in range(2):
        line[p].set_xdata(r[0:i, p, 0])
        line[p].set_ydata(r[0:i, p, 1])
    return line

intervals = 50
frames = N
frames = int(frames)

anim = FuncAnimation(fig, animate, frames=frames, interval=intervals)
plt.show()
```   
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.