-
Notifications
You must be signed in to change notification settings - Fork 0
/
n-bodies-seq.py
110 lines (89 loc) · 3.56 KB
/
n-bodies-seq.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# Sequential version
# python3 n-bodies-base.py 12 1000
import sys
import math
import random
import matplotlib.pyplot as plt
import time
import numpy as np
ID, POSX, POSY, SPEEDX, SPEEDY, WEIGHT = range(6)
solarmass=1.98892e30
def circlev(rx, ry):
r2=math.sqrt(rx*rx+ry*ry)
numerator=(6.67e-11)*1e6*solarmass
return math.sqrt(numerator/r2)
# from http://physics.princeton.edu/~fpretori/Nbody/code.htm
def create_item(id, positionx, positiony, speedx, speedy, weight):
if positionx == 0 and positiony == 0: # the center of the world, very heavy one...
speedx = 0
speedy = 0
else:
if speedx==0 and speedy==0: # initial values
magv=circlev(positionx, positiony)
absangle = math.atan(math.fabs(positiony/positionx))
thetav= math.pi/2-absangle
phiv = random.uniform(0,1)*math.pi
speedx = -1*math.copysign(1, positiony)*math.cos(thetav)*magv
speedy = math.copysign(1, positionx)*math.sin(thetav)*magv
#Orient a random 2D circular orbit
if (random.uniform(0,1) <=.5):
speedx=-speedx
speedy=-speedy
return np.array([id, positionx, positiony, speedx, speedy, weight], dtype='f')
def str_item(item):
return "ID="+str(item[ID])+" POS=("+str(item[POSX])+","+str(item[POSY])+") SPEED=("+str(item[SPEEDX])+","+str(item[SPEEDY])+") WEIGHT="+str(item[WEIGHT])
def display(m, l):
for i in range(len(l)):
print("PROC"+str(rank)+":"+m+"-"+str_item(l[i]))
def displayPlot(d):
plt.gcf().clear() # to remove to see the traces of the particules...
plt.axis((-1e17,1e17,-1e17,1e17))
xx = [ d[i][POSX] for i in range(len(d)) ]
yy = [ d[i][POSY] for i in range(len(d)) ]
plt.plot(xx, yy, 'ro')
plt.draw()
plt.pause(0.00001) # in order to see something otherwise too fast...
def interaction(i, j):
dist = math.sqrt( (j[POSX]-i[POSX])*(j[POSX]-i[POSX]) + (j[POSY]-i[POSY])*(j[POSY]-i[POSY]) )
if dist == 0:
return np.zeros(2)
g = 6.673e-11
factor = g * i[WEIGHT] * j[WEIGHT] / (dist*dist+3e4*3e4)
return np.array([factor*(j[POSX]-i[POSX])/dist, factor*(j[POSY]-i[POSY])/dist])
def update(d, f):
dt = 1e11
vx = d[SPEEDX] + dt * f[0]/d[WEIGHT]
vy = d[SPEEDY] + dt * f[1]/d[WEIGHT]
px = d[POSX] + dt * vx
py = d[POSY] + dt * vy
return create_item(d[ID], positionx=px, positiony=py, speedx=vx, speedy=vy, weight=d[WEIGHT])
def signature(world):
s = 0
for d in world:
s+=d[POSX]+d[POSY]
return s
def init_world(n):
data = [ create_item(id=i, positionx=1e18*math.exp(-1.8)*(.5-random.uniform(0,1)), positiony=1e18*math.exp(-1.8)*(.5-random.uniform(0,1)), speedx=0, speedy=0, weight=(random.uniform(0,1)*solarmass*10+1e20)) for i in range(n-1)]
data.append( create_item(id=nbbodies-1, positionx=0, positiony=0, speedx=0, speedy=0, weight=1e6*solarmass))
return np.array(data)
nbbodies = int(sys.argv[1])
NBSTEPS = int(sys.argv[2])
DISPLAY = len(sys.argv) != 4
# Modify only starting here (and in the imports)
random.seed(0)
data = init_world(nbbodies)
start_time = time.time()
if DISPLAY:
displayPlot(data)
for t in range(NBSTEPS):
force = np.zeros((nbbodies , 2))
for i in range(nbbodies):
for j in range(nbbodies):
force[i] = force[i] + interaction(data[i], data[j])
for i in range(nbbodies):
data[i] = update(data[i], force[i])
if DISPLAY:
displayPlot(data)
print("Duration : ", time.time()-start_time)
print("Signature of the world :")
print(signature(data))