pythonsimulationphysicsleapfrog-integration

Does this leapfrog method work for the 3 body problem?


I have been trying to make a leapfrog integration to document the variation of the hamiltonian over time for the 3BP, but I never really grasped how to implement it using the normal half-step method so I tried using a variation but I'm not sure if it's correct.

This is the functions I'm using where the variables p, v, m

p = [array([x,y]), array([x,y]), array([x,y])]
v = [array([x,y]), array([x,y]), array([x,y])]
m = [1, 1, 1]

are numpy arrays:

from numpy import sum
from numpy.linalg import norm
from copy import deepcopy

def H(p, v, m): #hamiltonian function
    #sum of kinetic energy for all bodies
    T = sum([m[i]*norm(v[i])**2/2 for i in range(3)])
    #sum of potential energy between all bodies 
    V = -sum([m[0-i]*m[1-i]/norm(p[0-i]-p[1-i]) for i in range(3)])
    return T + V

def a(p, n, m): #sum of the acceleration arrays for body n and the two other bodies
    return m[n-1]*(p[n-1]-p[n])/(norm(p[n-1]-p[n])**3) + m[n-2]*(p[n-2]-p[n])/(norm(p[n-2]-p[n])**3)

def collision(p): #checks for collisions
    for i in range(3):
        if norm(p[0-i] - p[1-i]) < 0.1:
            return True

#leapfrog
def Leapfrog(P, V, dt, steps, m):
    p,v=deepcopy(P),deepcopy(V)
    H_L = [H(p, v, m)]

    for t in range(steps):
        atemp = [a(p, i, m) for i in range(3)] #acceleration at time step i

        #calc new values
        for i in range(3):
            p[i] = p[i] + v[i]*dt + 0.5*atemp[i]*dt**2

        for i in range(3):
            v[i] = v[i] + 0.5*(atemp[i] + a(p, i, m))*dt #acceleration at timestep i+1


        if collision(p):
            return H_L
        H_L.append(H(p, v, m))
    return H_L

Solution

  • Corrected implementation

    import numpy as np
    from numpy.linalg import norm
    from copy import deepcopy
    
    def H(p, v, m):  # hamiltonian function
        # sum of kinetic energy for all bodies
        T = sum([m[i] * norm(v[i])**2 / 2 for i in range(3)])
        # sum of potential energy between all unique pairs
        V = -sum([m[i] * m[j] / norm(p[i] - p[j]) 
                  for i in range(3) for j in range(i+1, 3)])
        return T + V
    
    def acceleration(p, m):
        """Compute acceleration for all bodies"""
        a = [np.zeros(2) for _ in range(3)]
        for i in range(3):
            for j in range(3):
                if i != j:
                    r = p[i] - p[j]
                    a[i] -= m[j] * r / (norm(r)**3)
        return a
    
    def collision(p):
        for i in range(3):
            for j in range(i+1, 3):
                if norm(p[i] - p[j]) < 0.1:
                    return True
        return False
    
    def Leapfrog(P, V, dt, steps, m):
        p, v = deepcopy(P), deepcopy(V)
        H_L = [H(p, v, m)]
        
        # Initial acceleration
        a_prev = acceleration(p, m)
        
        for _ in range(steps):
            # Half-step velocity update
            v_half = [v[i] + 0.5 * a_prev[i] * dt for i in range(3)]
            
            # Full-step position update
            p = [p[i] + v_half[i] * dt for i in range(3)]
            
            # Compute new acceleration
            a_new = acceleration(p, m)
            
            # Second half-step velocity update
            v = [v_half[i] + 0.5 * a_new[i] * dt for i in range(3)]
            
            if collision(p):
                return H_L
            H_L.append(H(p, v, m))
            a_prev = a_new
        
        return H_L