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
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