提交 35ac68f7 编写于 作者: M march3

三体运行模拟器

上级 cf5948b7
...@@ -32,14 +32,19 @@ class Body: ...@@ -32,14 +32,19 @@ class Body:
:param size_scale: 尺寸缩放 :param size_scale: 尺寸缩放
:param distance_scale: 距离缩放 :param distance_scale: 距离缩放
""" """
self.__his_pos = []
self.__his_vel = []
self.__his_acc = []
self.__his_reserved_num = 20
self.name = name self.name = name
self.__mass = mass self.__mass = mass
self.init_position = np.array(init_position, dtype='float32') self.init_position = np.array(init_position, dtype='float32')
self.init_velocity = np.array(init_velocity, dtype='float32') self.init_velocity = np.array(init_velocity, dtype='float32')
self.position = self.init_position self.__position = self.init_position
self.velocity = self.init_velocity self.__velocity = self.init_velocity
self.__density = density self.__density = density
...@@ -50,14 +55,40 @@ class Body: ...@@ -50,14 +55,40 @@ class Body:
self.distance_scale = distance_scale self.distance_scale = distance_scale
# 初始化后,加速度为0,只有多个天体的引力才会影响到加速度 # 初始化后,加速度为0,只有多个天体的引力才会影响到加速度
self.acceleration = np.array([0, 0, 0], dtype='float32') # m/s²
self.__acceleration = np.array([0, 0, 0], dtype='float32')
self.__record_history()
self.__his_pos = []
self.__his_vel = []
self.__his_acc = []
self.__his_reserved_num = 10
def append_history(self, his_list, data): @property
def position(self):
return self.__position
@position.setter
def position(self, value):
self.__position = value
self.__record_history()
@property
def acceleration(self):
return self.__acceleration
@acceleration.setter
def acceleration(self, value):
self.__acceleration = value
self.__record_history()
@property
def velocity(self):
return self.__velocity
@velocity.setter
def velocity(self, value):
self.__velocity = value
self.__record_history()
def __append_history(self, his_list, data):
""" """
:param his_list: :param his_list:
...@@ -69,23 +100,22 @@ class Body: ...@@ -69,23 +100,22 @@ class Body:
np.sum(data == his_list[-1]) < len(data): np.sum(data == his_list[-1]) < len(data):
his_list.append(data.copy()) his_list.append(data.copy())
def record_history(self): def __record_history(self):
""" """
记录历史 记录历史
:return: :return:
""" """
# 如果历史记录数超过了保留数量,则截断,只保留 __his_reserved_num 数量的历史 # 如果历史记录数超过了保留数量,则截断,只保留 __his_reserved_num 数量的历史
if len(self.__his_pos) > self.__his_reserved_num: if len(self.__his_pos) > self.__his_reserved_num:
self.__his_pos = self.__his_pos[len(self.__his_pos)-self.__his_reserved_num:] self.__his_pos = self.__his_pos[len(self.__his_pos) - self.__his_reserved_num:]
self.__his_vel = self.__his_vel[len(self.__his_vel)-self.__his_reserved_num:] self.__his_vel = self.__his_vel[len(self.__his_vel) - self.__his_reserved_num:]
self.__his_acc = self.__his_acc[len(self.__his_acc)-self.__his_reserved_num:] self.__his_acc = self.__his_acc[len(self.__his_acc) - self.__his_reserved_num:]
# 追加历史记录(位置、速度、加速度) # 追加历史记录(位置、速度、加速度)
self.append_history(self.__his_pos, self.position) self.__append_history(self.__his_pos, self.position)
self.append_history(self.__his_vel, self.velocity) self.__append_history(self.__his_vel, self.velocity)
self.append_history(self.__his_acc, self.acceleration) self.__append_history(self.__his_acc, self.acceleration)
# print(self.name, "his pos->", self.__his_pos)
print(self.name, "his pos->", self.__his_pos)
def his_position(self): def his_position(self):
""" """
......
...@@ -23,7 +23,7 @@ class Earth(Body): ...@@ -23,7 +23,7 @@ class Earth(Body):
def __init__(self, name="earth", mass=5.97237e24, def __init__(self, name="earth", mass=5.97237e24,
init_position=[149597870.700, 0, 0], init_position=[149597870.700, 0, 0],
init_velocity=[29.79, 0, 0], init_velocity=[0, 29.79, 0],
texture="", size_scale=1.0, distance_scale=1.0): texture="", size_scale=1.0, distance_scale=1.0):
params = { params = {
"name": name, "name": name,
......
...@@ -10,7 +10,9 @@ from bodies.body import Body ...@@ -10,7 +10,9 @@ from bodies.body import Body
class Sun(Body): class Sun(Body):
def __init__(self, name="sun", mass=1.9891e30, init_position=[0, 0, 0], init_velocity=[0, 0, 0], def __init__(self, name="sun", mass=1.9891e30,
init_position=[0, 0, 0],
init_velocity=[0, 0, 0],
texture="", size_scale=1.0, distance_scale=1.0): texture="", size_scale=1.0, distance_scale=1.0):
params = { params = {
"name": name, "name": name,
......
...@@ -17,27 +17,47 @@ X_MIN, X_MAX = -2e+14, 2e+14 # the x range of the bounding box (m) ...@@ -17,27 +17,47 @@ X_MIN, X_MAX = -2e+14, 2e+14 # the x range of the bounding box (m)
Y_MIN, Y_MAX = -2e+14, 2e+14 # the y range of the bounding box (m) Y_MIN, Y_MAX = -2e+14, 2e+14 # the y range of the bounding box (m)
Z_MIN, Z_MAX = -2e+14, 2e+14 # the z range of the bounding box (m) Z_MIN, Z_MAX = -2e+14, 2e+14 # the z range of the bounding box (m)
X_MIN, X_MAX = -2e+12, 2e+12 # the x range of the bounding box (m)
Y_MIN, Y_MAX = -2e+12, 2e+12 # the y range of the bounding box (m)
Z_MIN, Z_MAX = -2e+12, 2e+12 # the z range of the bounding box (m)
X_MIN, X_MAX = -1e+9, 1e+9 # the x range of the bounding box (m)
Y_MIN, Y_MAX = -1e+9, 1e+9 # the y range of the bounding box (m)
Z_MIN, Z_MAX = -1e+9, 1e+9 # the z range of the bounding box (m)
# X_MIN, X_MAX = -8e+8, 8e+8 # the x range of the bounding box (m)
# Y_MIN, Y_MAX = -8e+8, 8e+8 # the y range of the bounding box (m)
# Z_MIN, Z_MAX = -8e+8, 8e+8 # the z range of the bounding box (m)
def show(bodies, idx=0): def show(bodies, idx=0):
# from scipy.interpolate import make_interp_spline
# Creating figures for the plot # Creating figures for the plot
fig = plt.figure(figsize=(16, 12)) fig = plt.figure(figsize=(16, 12))
ax = plt.axes(projection="3d") ax = plt.axes(projection="3d")
ax.set_xlim(X_MIN, X_MAX) ax.set_xlim(X_MIN, X_MAX)
ax.set_ylim(Y_MIN, Y_MAX) ax.set_ylim(Y_MIN, Y_MAX)
ax.set_zlim(Z_MIN, Z_MAX) ax.set_zlim(Z_MIN, Z_MAX)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
# Creating a plot using the random datasets # Creating a plot using the random datasets
colors = ['red', 'blue'] colors = ['red', 'blue', 'red', 'red']
sizes = [800, 500] sizes = [800, 500, 800, 800]
for idx, body in enumerate(bodies): for idx, body in enumerate(bodies):
color = 'red' if str(body.name).startswith("sun") else 'blue'
size = 800 if str(body.name).startswith("sun") else 500
pos = body.position pos = body.position
ax.scatter(pos[0], pos[1], pos[2], color=colors[idx], s=sizes[idx]) ax.text(pos[0], pos[1], pos[2] + 1e8, body.name, color=color, fontsize=20)
for _his_pos in body.his_position(): ax.scatter(pos[0], pos[1], pos[2], color=color, s=size)
ax.scatter3D(_his_pos[0], _his_pos[1], _his_pos[2], color=colors[idx], alpha=0.5) # for _his_pos in body.his_position():
# ax.scatter(his_pos[0], his_pos[1], his_pos[2], color=colors[idx], s=10) # ax.scatter3D(_his_pos[0], _his_pos[1], _his_pos[2], color=color, alpha=0.5)
# ax.scatter(his_pos[0], his_pos[1], his_pos[2], color=colors[idx], s=10)
his_pos = body.his_position() his_pos = body.his_position()
if len(his_pos) > 2: if len(his_pos) > 1:
_his_pos = list(zip(*his_pos)) _his_pos = list(zip(*his_pos))
ax.plot3D(_his_pos[0], _his_pos[1], _his_pos[2], color=colors[idx], alpha=0.5) ax.plot3D(_his_pos[0], _his_pos[1], _his_pos[2], color=color, alpha=0.8)
plt.title("3D scatter plot %s" % idx) plt.title("3D scatter plot %s" % idx)
# display the plot # display the plot
plt.show() plt.show()
...@@ -52,6 +72,7 @@ class Simulator: ...@@ -52,6 +72,7 @@ class Simulator:
self.dt = dt self.dt = dt
def evolve(self, dt): def evolve(self, dt):
show(self.system.bodies)
self.system.update_acceleration() self.system.update_acceleration()
# next_p = p + dt * v + 0.5 * a * (dt ** 2) # next_p = p + dt * v + 0.5 * a * (dt ** 2)
...@@ -68,30 +89,42 @@ class Simulator: ...@@ -68,30 +89,42 @@ class Simulator:
# body1.update_source_data() # body1.update_source_data()
for body in self.system.bodies: for body in self.system.bodies:
body.position += body.velocity * dt + 0.5 * body.acceleration * (dt ** 2) # body.vx = body.vx + ax * dt
# body.x = body.x + body.vx * dt
# acceleration 加速度 # acceleration 加速度
body.velocity += body.acceleration * dt body.velocity += body.acceleration * dt
# body.position += body.velocity * dt # - 0.5 * body.acceleration * (dt ** 2)
print(body.name, body.position) body.position += body.velocity * dt
body.record_history() print(body)
# print(body.name, body.position)
show(self.system.bodies)
def run(self, t): def run(self, t):
n = int(t / self.dt) n = int(t / self.dt)
for i in range(n): for i in range(n):
time.sleep(1)
self.evolve(self.dt) self.evolve(self.dt)
time.sleep(1)
def run_always(self): def run_always(self):
dt = 1 # 时间变化1秒 dt = 1 # 时间变化1秒
while True: while True:
time.sleep(1) # time.sleep(1)
self.evolve(dt) self.evolve(dt)
if __name__ == '__main__': if __name__ == '__main__':
t = 60 * 60 * 24 t = 60 * 60 * 24 * 100
_sys = System([Sun(), Earth()])
# _sys = System([Sun(init_position=[0, 0, 149597870.700]), Earth()])
# _sys = System([Sun(init_position=[849597870.700, 0, 0], init_velocity=[0, 9.79, 0]),
# Sun(init_position=[0, 0, 0], init_velocity=[0, -9.79, 0])])
# _sys = System([Sun(), Earth()])
_sys = System([Sun(name="sun1", init_position=[849597870.700, 0, 0], init_velocity=[0, 7.0, 0]),
Sun(name="sun2", init_position=[0, 0, 0], init_velocity=[0, -8.0, 0]),
Sun(name="sun3", init_position=[0, -849597870.700, 0], init_velocity=[18.0, 0, 0]),
Earth(init_position=[0, -349597870.700, 0], init_velocity=[15.50, 0, 0])])
_sim = Simulator(_sys, t) _sim = Simulator(_sys, t)
_sim.run(t * 100) _sim.run(t * 100)
...@@ -139,12 +139,30 @@ class System(object): ...@@ -139,12 +139,30 @@ class System(object):
# body1.position = body1.position + (body1.momentum / body1.mass) * dt # body1.position = body1.position + (body1.momentum / body1.mass) * dt
# body1.update_source_data() # body1.update_source_data()
def acceleration(self, body1, body2, G=6.67e-11):
"""
计算两个天体之间的加速度
:param body1: 天体1
:param body2: 天体2
:param G: 引力常数
:return: 加速度
"""
import math
dx = body2.position[0] - body1.position[0]
dy = body2.position[1] - body1.position[1]
dz = body2.position[2] - body1.position[2]
distance = math.sqrt(dx ** 2 + dy ** 2 + dz ** 2)
mag = G * body2.mass / (distance ** 2)
acc = [dx / distance * mag, dy / distance * mag, dz / distance * mag]
return np.array(acc)/1000/1000/1000
def update_acceleration(self): def update_acceleration(self):
for body in self.bodies: # for body in self.bodies:
body.acceleration = np.zeros(3) # body.acceleration = np.zeros(3)
for body1 in self.bodies: for body1 in self.bodies:
body1.record_history() acceleration = np.zeros(3)
for body2 in self.bodies: for body2 in self.bodies:
if body1 is body2: if body1 is body2:
continue continue
...@@ -154,7 +172,9 @@ class System(object): ...@@ -154,7 +172,9 @@ class System(object):
# body.acceleration1 += aij * dir # body.acceleration1 += aij * dir
r = body2.position - body1.position r = body2.position - body1.position
body.acceleration += -6.67e-11 * body2.mass * r / np.linalg.norm(r) ** 3 # m/s²
# body1.acceleration += self.acceleration(body1,body2)
acceleration += (6.67e-11 * body2.mass * r / np.linalg.norm(r) ** 3) / 1e9
# body1.acceleration = body.acceleration2 # body1.acceleration = body.acceleration2
# r = body2.position - body1.position # r = body2.position - body1.position
...@@ -168,6 +188,7 @@ class System(object): ...@@ -168,6 +188,7 @@ class System(object):
# r = 1 # 两个天体之间的距离 # r = 1 # 两个天体之间的距离
# #
# a = G * m2 / math.pow(r, 2) # a = G * m2 / math.pow(r, 2)
body1.acceleration = acceleration
""" """
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册