-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnbody.py
115 lines (90 loc) · 2.83 KB
/
nbody.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
110
111
112
113
114
115
from __future__ import division
import sys
import numpy as np
import matplotlib.pyplot as plt
COLORS = ['b', 'g', 'r', 'y', 'm', 'k', 'c']
G = 6.67259e-11 # gravitational constant
class Particle(object):
def __init__(self, name, mass, r0, v0):
self.name = name
self.mass = mass
self.r0 = r0
self.v0 = v0
def read_particles_data(file_name):
global NAMES, MASSES, POS_0, VEL_O, PLANETS
def _format_vector(vec):
"""
Utility function that formats an input string
in the format: '%f;%f' into a tuple (x, y)
::vec:: input string
::return:: vector as tuple
"""
xy = vec.split(';')
return (float(xy[0].strip()), float(xy[1].strip()))
data = []
with open(file_name, 'r') as file:
content = file.read()
particles = content.split('\n\n')
for part in particles:
p = part.split('\n')
name = p[0].strip()
mass = float(p[1].strip())
r0 = _format_vector(p[2].strip())
v0 = _format_vector(p[3].strip())
data.append(Particle(name, mass, r0, v0))
return data
def draw(data, STEPS, T_MAX):
PARTICLES = len(data)
h = T_MAX / STEPS # step size
m = np.zeros(PARTICLES) # masses
# time planet x,y
r = np.zeros((STEPS, PARTICLES, 2)) # positions
# planet v_x,v_y
v_s = np.zeros((PARTICLES, 2)) # velocities at step s
# apply initial conditions
for p in xrange(PARTICLES):
m[p] = data[p].mass
for i in xrange(2):
r[0][p][i] = data[p].r0[i]
v_s[p][i] = data[p].v0[i]
def mod3(v):
""" returns the lenght of a 2d-vector to the third power """
return np.power(v[0]*v[0] + v[1]*v[1], 1.5)
def g(p, rs):
"""
return the intensity of the gravitational force in particle p due to the others
given by Newton's law of universal gravitation:
g_p = - G * sum_k [m_k * (r_p - r_k) / |r_p - r_k|^2 where k != p]
"""
v = [0, 0]
for k in xrange(PARTICLES):
if k == p:
continue
v += m[k] * (rs[p] - rs[k]) / mod3(rs[p] - rs[k])
return - G * v
alpha = [0, 0, 0.5, 0.5, 1] # first index for simplicity
rk4 = np.zeros((5, PARTICLES, 2))
for s in xrange(1, STEPS):
for j in xrange(1, 5):
for p in xrange(PARTICLES):
rk4[j][p] = g(p, r[s - 1] + alpha[j] * h * rk4[j - 1])
v_s += (h / 6) * (rk4[1] + 2 * (rk4[2] + rk4[3]) + rk4[4])
r[s] = r[s - 1] + h * v_s
# plot the trajectory
for p in xrange(PARTICLES):
plt.plot(r[:,p,0], r[:,p,1], label=data[p].name, lw=2, color=COLORS[p % len(COLORS)])
plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3,
ncol=3, mode="expand", borderaxespad=0.) # legend location at top
# set x, y plot limits for convenience
#plt.xlim(-1.6e11, 1.6e11)
#plt.ylim(-1.6e11, 1.6e11)
plt.savefig("nbody.pdf")
plt.show()
if __name__ == '__main__':
file_name = None
if len(sys.argv) > 1:
file_name = sys.argv[1]
else:
file_name = 'ss_data.txt'
data = read_particles_data(file_name)
draw(data, 4000, 365 * 24 * 3600.0)