particlesΒΆ
Simple particle simulation
import numpy as np
import gr, time
from numba.core.decorators import jit
N = 300 # number of particles
M = 0.05 * np.ones(N) # masses
size = 0.04 # particle size
def step(dt, size, a):
# update positions
a[0] += dt * a[1]
n = a.shape[1]
D = np.zeros((n, n))
for i in range(n):
for j in range(n):
dx = a[0, i, 0] - a[0, j, 0]
dy = a[0, i, 1] - a[0, j, 1]
D[i, j] = np.sqrt(dx*dx + dy*dy)
# find pairs of particles undergoing a collision
for i in range(n):
for j in range(i + 1, n):
if D[i, j] < 2*size:
# relative location & velocity vectors
r_rel = a[0, i] - a[0, j]
v_rel = a[1, i] - a[1, j]
# momentum vector of the center of mass
v_cm = (M[i] * a[1, i] + M[j] * a[1, j]) / (M[i] + M[j])
# collisions of spheres reflect v_rel over r_rel
rr_rel = np.dot(r_rel, r_rel)
vr_rel = np.dot(v_rel, r_rel)
v_rel = 2 * r_rel * vr_rel / rr_rel - v_rel
# assign new velocities
a[1, i] = v_cm + v_rel * M[j] / (M[i] + M[j])
a[1, j] = v_cm - v_rel * M[i] / (M[i] + M[j])
# check for crossing boundary
for i in range(n):
if a[0, i][0] < -2 + size:
a[0, i][0] = -2 + size
a[1, i][0] *= -1
elif a[0, i][0] > 2 - size:
a[0, i][0] = 2 - size
a[1, i][0] *= -1
if a[0, i][1] < -2 + size:
a[0, i][1] = -2 + size
a[1, i][1] *= -1
elif a[0, i][1] > 2 - size:
a[0, i][1] = 2 - size
a[1, i][1] *= -1
return a
np.random.seed(0)
a = np.empty([2, N, 2], dtype=np.float)
a[0, :] = -0.5 + np.random.random((N, 2)) # positions
a[1, :] = -0.5 + np.random.random((N, 2)) # velocities
a[0, :] *= (4 - 2*size)
dt = 1. / 30
step_numba = jit('f8[:,:,:](f8, f8, f8[:,:,:])')(step)
gr.setwindow(-2, 2, -2, 2)
gr.setviewport(0, 1, 0, 1)
gr.setmarkertype(gr.MARKERTYPE_SOLID_CIRCLE)
gr.setmarkersize(1.0)
start = time.time()
t0 = start
n = 0
t = 0
worker = 'CPython'
while t < 6:
if t > 3:
if worker == 'CPython':
t0 = now
n = 0
a = step_numba(dt, size, a)
worker = 'Numba'
else:
a = step(dt, size, a)
gr.clearws()
gr.setmarkercolorind(75)
gr.polymarker(a[0, :, 0], a[0, :, 1])
if n > 0:
gr.text(0.01, 0.95, '%10s: %4d fps' % (worker, int(n / (now - t0))))
gr.updatews()
now = time.time()
n += 1
t = now - start