Background I am writing a simple N-body simulation code in Python, with core physics solvers such as acceleration and position integration implemented in Cython. The code uses the leapfrog method to integrate the positions.
Conditions
- Masses: 10, 100 for 2 bodies; 1 for all bodies for number of bodies > 2.
- Position: Randomly generated
- Velocity: Randomly generated
- Timestep: 1e-3
The bug
- For number of bodies > 2: The bodies repel each other instead of attracting each other.
- For number of bodies = 2: They do not orbit each other but instead travel in straight lines.
- General bug (regardless of number of bodies): Repulsive forces
Expected behavior
- Two bodies must orbit each other
- The forces must be attractive
Efforts to resolve the bug
- Negative sign for acceleration
- Multiply acceleration by -1
- Add a new temporary expression
Code Acceleration function (Cython):
def acceleration(np.ndarray[np.float64_t, ndim=2] pos, np.ndarray[np.float64_t, ndim=1] mass):
cdef int N = pos.shape[0] # Number of bodies
# Memoryview for acceleration
cdef np.float64_t [:,:] acc = np.zeros((N,3),dtype="float64")
cdef double soft = 1e-4 # Softening length
cdef G = 6.673e-11 # Gravitational constant
# Pairwise separations
cdef double dx
cdef double dy
cdef double dz
# Total separation vectors
cdef double r
cdef double tmp
# Mass
cdef mj
# Acceleration calculation loop
for i in range(N):
for j in range(N):
# Remove gravitational self forces
if i==j:
continue
# Calculate pairwise separation vectors
dx = pos[j,0] - pos[i,0]
dy = pos[j,1] - pos[i,1]
dz = pos[j,2] - pos[i,2]
# Vector magnitude of separation vector
r = dx**2 + dy**2 + dz**2
r = np.sqrt(r)
# Mass
mj = mass[j]
tmp = G * mj * r**3
# Calculate accelerations
acc[i,0] += tmp * dx
acc[i,1] += tmp * dy
acc[i,2] += tmp * dz
return np.asarray(acc)
Position integration:
def leapfrog(np.ndarray[np.float64_t, ndim=2] pos, np.ndarray[np.float64_t, ndim=2] vel, np.ndarray[np.float64_t, ndim=2] acc, np.ndarray[np.float64_t, ndim=1] mass):
cdef double dt = 1e-3 # Timestep
# The Leapfrog integration method
# v(t+1/2) = v(t) + a(t) x dt/2
# x(t+1) = x(t) + v(t+1/2) x dt
# a(t+1) = (G * m/((dx^2 + dy^2 + dz^2)^(3/2))) * dx * x
# v(t+1) = v(t+1/2) + a(t+1) x dt/2
vel += acc * dt/2
pos += vel * dt
acc = acceleration(pos, mass)
vel += acc * dt/2
return pos, acc
Main simulation loop (Python): for _ in range(Nt): # Calculate positions and get new acceleration values pos, acc = leapfrog(pos, vel, acc, m)
Plot (Python):
plt.scatter(pos_arr[:,0], pos_arr[:,1])
Please help me solve this issue.
Refer to the images for more info regarding the bug:
Two bodies repelling each other + moving in a straight line instead of orbiting
3D View of the bug.
Edit 1: Velocity = 0 Here is the result with velocity = 0 (vel = np.zeros((N,3)), where N=2. The red point is the first element of the position array and the green point is the last point.
Edit 2: tmp * dx/2 : This is the result obtained by dividing the separation vectors by r. Updated code:
acc[i,0] += tmp * dx/r
acc[i,1] += tmp * dy/r
acc[i,2] += tmp * dz/r
Edit 3: velocity = 1e-6 This is what the result looks like for setting both velocities = 1e-6. They remain stationary.






pos = np.random.randn(N,3), vel = np.random.randn(N,3). - AstroTeenvel = np.zeros(N,3)- they should head straight through each other. But it's probably the simplest way of checking that they do attract. - DavidWacc[i,0] += tmp * dxbecomeacc[i,0] += tmp * dx/r(same for the other 2 vector) - p._phidot_