三体到底是啥?用Python跑一遍就明白了

news/2024/11/7 3:38:21/

文章目录

    • 拉格朗日方程
    • 推导方程组
    • 微分方程算法化
    • 求解+画图
    • 动图绘制

温馨提示,只想看图的画直接跳到最后一节

拉格朗日方程

此前所做的一切三体和太阳系的动画,都是基于牛顿力学的,而且直接对微分进行差分化,从而精度非常感人,用不了几年就得撞一起去。

为了给三体人提供一个更加有价值的推导,这次通过求解拉格朗日方程的数值解来实现。

首先假设三个质点的质量分别为m1,m2,m3m_1, m_2, m_3m1,m2,m3,坐标为x⃗1,x⃗2,x⃗3\vec x_1, \vec x_2, \vec x_3x1,x2,x3,质点速度可以表示为x⃗˙\dot{\vec x}x˙。假设三体在二维平面上运动,则第iii个质点的动能为

Ti=12mi(x˙i2+y˙i2)T_i=\frac{1}{2}m_i(\dot x_i^2+\dot y_i^2) Ti=21mi(x˙i2+y˙i2)

引力势能为−Gmimjrij-G\frac{m_im_j}{r_{ij}}Grijmimj,其中GGG为万有引力常量,rijr_{ij}rij为质点i,ji,ji,j之间的距离,则系统的拉格朗日量为

L=∑i12mi(x˙i2+y˙i2)−∑i≠jGmimj∥x⃗i−x⃗j∥L=\sum_i\frac{1}{2}m_i(\dot x_i^2+\dot y_i^2)-\sum_{i\not=j}G\frac{m_im_j}{\Vert\vec x_i-\vec x_j\Vert} L=i21mi(x˙i2+y˙i2)i=jGxixjmimj

有了拉格朗日量,将其带入拉格朗日方程

ddt∂L∂x˙i−∂L∂xi=0\frac{\text d}{\text dt}\frac{\partial L}{\partial\dot x_i}-\frac{\partial L}{\partial x_i}=0 dtdx˙iLxiL=0

就可以得到拉格朗日方程组。

推导方程组

对于三体系统而言,总计有3个粒子,每个粒子有x,yx,yx,y两个自由度,也就是说最后会得到6组方程。考虑到公式推导过程中可能会出现错误,所以下面采用sympy来进行公式推导。

首先定义符号变量

from sympy import symbols
from sympy.physics.mechanics import dynamicsymbols
m = symbols('m1:4')
x = dynamicsymbols('x1:4')
y = dynamicsymbols('y1:4')

接下来,需要构造系统的拉格朗日量LLL,其实质是系统的动能减去势能,对于上面构建的三体系统而言,动能和势能可分别表示为

计算每个质点的动能和势能。动能是由速度决定的,而速度是由位置对时间的导数决定的。我们可以用 sympy 的 diff 函数来求导:

from sympy import diff
# 此为速度的平方
v2 = [diff(x[i],t)**2 + diff(y[i])**2 for i in range(3)]
T = 0
for i in range(3):T += m[i]*v2[i]/2

势能是由万有引力决定的,而万有引力是由两个质点之间的距离决定的。我们可以用 sympy 的 sqrt 函数来求距离:

from sympy import sqrt,cos
G = symbols('G') # 引力常数
ijs = [(0,1), (0,2),(1,2)]
dij = [sqrt((x[i]-x[j])**2+(y[i]-y[j])**2) for i,j in ijs]
U = 0
for k in range(3):i,j = ijs[k]U -= G*m[i]*m[j]/dij[k]

有了动能和势能,就可以愉快地求拉格朗日量了,有了拉格朗日量,就可以列拉格朗日方程了

L=T−UdLdxi−ddt∂L∂x˙iL = T - U\\ \frac{\text dL}{\text dx_i}-\frac{\text d}{\text dt}\frac{\partial L}{\partial \dot x_i} L=TUdxidLdtdx˙iL

三个粒子的每一个坐标维度,都可以列出一组拉格朗日方程,所以总共有6个拉格朗日方程组

from sympy import solve
L = T - U
eqLag = lambda x : diff(L, x)-diff(diff(L, diff(x, t)), t)
# 拉格朗日方程组
eqs = [eqLag(xi) for xi in x+y]

xij=xi−xj,yij=yi−yjx_{ij}=x_i-x_j, y_{ij}=y_i-y_jxij=xixj,yij=yiyj,则

−Gm1m2x12(x122+y122)32+−Gm1m3x13(x132+y132)32−m1d2dt2x1=0Gm1m2x12(x122+y122)32+−Gm2m3x23(x232+y232)32−m2d2dt2x2=0Gm1m3x13(x132+y132)32+Gm2m3x23(x232+y232)32−m3d2dt2x3=0−Gm1m2y12(x122+y122)32+−Gm1m3y13(x132+y132)32−m1d2dt2y1=0Gm1m2y12(x122+y122)32+−Gm2m3y23(x232+y232)32−m2d2dt2y2=0Gm1m3y13(x132+y132)32+Gm2m3y23(x232+y232)32−m3d2dt2y3=0\frac{-G m_1 m_2x_{12}}{\left(x_{12}^{2} + y_{12}^{2}\right)^{\frac{3}{2}}} + \frac{-G m_1 m_{3}x_{13}}{\left(x_{13}^{2} + y_{13}^{2}\right)^{\frac{3}{2}}} - m_1 \frac{d^{2}}{d t^2} x_1=0\\ \frac{G m_1 m_2 x_{12}}{\left(x_{12}^{2} + y_{12}^{2}\right)^{\frac{3}{2}}} + \frac{-G m_2 m_{3}x_{23}}{\left(x_{23}^{2} + y_{23}^{2}\right)^{\frac{3}{2}}} - m_2 \frac{d^{2}}{d t^2} x_2=0\\ \frac{G m_1 m_{3} x_{13}}{\left(x_{13}^{2} + y_{13}^{2}\right)^{\frac{3}{2}}} + \frac{G m_2 m_{3} x_{23}}{\left(x_{23}^{2} + y_{23}^{2}\right)^{\frac{3}{2}}} - m_{3} \frac{d^{2}}{d t^2} x_{3}=0\\ \frac{-G m_1 m_2 y_{12}}{\left(x_{12}^{2} + y_{12}^{2}\right)^{\frac{3}{2}}} + \frac{-G m_1 m_{3} y_{13}}{\left(x_{13}^{2} + y_{13}^{2}\right)^{\frac{3}{2}}} - m_1 \frac{d^{2}}{d t^2} y_1=0\\ \frac{G m_1 m_2 y_{12}}{\left(x_{12}^{2} + y_{12}^{2}\right)^{\frac{3}{2}}} + \frac{-G m_2 m_{3}y_{23}}{\left(x_{23}^{2} + y_{23}^{2}\right)^{\frac{3}{2}}} - m_2 \frac{d^{2}}{d t^2} y_2=0\\ \frac{G m_1 m_{3} y_{13}}{\left(x_{13}^{2} + y_{13}^{2}\right)^{\frac{3}{2}}} + \frac{G m_2 m_{3} y_{23}}{\left(x_{23}^{2} + y_{23}^{2}\right)^{\frac{3}{2}}} - m_{3} \frac{d^{2}}{d t^2} y_{3}=0\\ (x122+y122)23Gm1m2x12+(x132+y132)23Gm1m3x13m1dt2d2x1=0(x122+y122)23Gm1m2x12+(x232+y232)23Gm2m3x23m2dt2d2x2=0(x132+y132)23Gm1m3x13+(x232+y232)23Gm2m3x23m3dt2d2x3=0(x122+y122)23Gm1m2y12+(x132+y132)23Gm1m3y13m1dt2d2y1=0(x122+y122)23Gm1m2y12+(x232+y232)23Gm2m3y23m2dt2d2y2=0(x132+y132)23Gm1m3y13+(x232+y232)23Gm2m3y23m3dt2d2y3=0

微分方程算法化

接下来就要调用Python的odeint来计算这个微分方程组的数值解,odeint的调用方法大致为odeint(func, y, t, args),其中func是一个函数,这个函数必须为func(y,t,...),且返回值为dydt\frac{\text dy}{\text dt}dtdy

为此,需要将上述方程组再行拆分,以消去其中的二次导数,以x1x_1x1为例,令u1=dx1dtu_1=\frac{\text dx_1}{\text dt}u1=dtdx1,则此方程变为方程组

x˙1(t)=u1(t)u˙1(t)=−Gm1m2x12(x122+y122)32+−Gm1m3x13(x132+y132)32\begin{aligned} \dot x_1(t)&=u_1(t)\\ \dot u_1(t)&= \frac{-G m_1 m_2x_{12}}{\left(x_{12}^{2} + y_{12}^{2}\right)^{\frac{3}{2}}} + \frac{-G m_1 m_{3}x_{13}}{\left(x_{13}^{2} + y_{13}^{2}\right)^{\frac{3}{2}}}\\ \end{aligned} x˙1(t)u˙1(t)=u1(t)=(x122+y122)23Gm1m2x12+(x132+y132)23Gm1m3x13

由于三体系统中有3个粒子,共6个独立变量,所以要列12个方程。记u(t)=textdxdt,v(t)=dydtu(t)=\frac{text dx}{\text dt}, v(t)=\frac{\text dy}{\text dt}u(t)=dttextdx,v(t)=dtdy,则odeint输入的y的形式为

[x1,x2,x3,y1,y2,y3,u1,u2,u3,v1,v2,v3][x_1, x_2, x_3, y_1, y_2, y_3, u_1, u_2, u_3, v_1, v_2, v_3] [x1,x2,x3,y1,y2,y3,u1,u2,u3,v1,v2,v3]

从而func的具体形式为

import numpy as np
dxy = lambda x,y : np.sqrt(x**2+y**2)**(3/2)
def triSys(Y, t, m, G):jk = [(1,2),(0,2),(0,1)]x,y = Y[:3], Y[3:6]u,v = Y[6:9], Y[9:]du, dv = [], []for i in range(3):j, k = jk[i]xji, xki = x[j]-x[i], x[k]-x[i]yji, yki = y[j]-y[i], y[k]-y[i]dji, dki = dxy(xji, yji), dxy(yji, yki)mji, mki = G*m[i]*m[j], G*m[i]*m[k]du.append(mji*xji/dji + mki*xki/dki)dv.append(mji*yji/dji + mki*yki/dki)dydt = [*u, *v, *du, *dv]return dydt

求解+画图

接下来就是见证奇迹的时刻,首先创建一个随机的起点,作为三体运动的初值,然后带入开整就完事儿了

from scipy.integrate import odeint
np.random.seed(42)
y0 = np.random.rand(12)
m = np.random.rand(3)
t = np.linspace(0, 20, 1001)
sol = odeint(triSys, y0, t, args=(m, 1))

然后绘制一下这三颗星的轨迹

import matplotlib.pyplot as plt
plt.plot(sol[:,0], sol[:,3])
plt.plot(sol[:,1], sol[:,4])
plt.plot(sol[:,2], sol[:,5])
plt.show()

在这里插入图片描述

光是看这个轨迹就十分惊险了有木有。

如果把其中的第一颗星作为坐标原点,那么另外两颗星的轨迹大致为

plt.plot(sol[:,1]-sol[:,0], sol[:,4]-sol[:,3])
plt.plot(sol[:,2]-sol[:,0], sol[:,5]-sol[:,3])
plt.scatter([0],[0], c='g', marker='*')
plt.show()

结果为

在这里插入图片描述

动图绘制

最后,以中间这颗星为原点,绘制一下另外两颗星运动的动态过程

import matplotlib.animation as animation fig = plt.figure(figsize=(9,4))
ax = fig.add_subplot(xlim=(-1.8,1.8),ylim=(-1.8,1.5))
ax.grid()traces = [ax.plot([],[],'-',lw=0.5)[0] for _ in range(2)]
pts = [ax.plot([],[] ,marker='*')[0] for _ in range(2)]
ax.plot([0],[0], marker="*", c='r')X1 = sol[:,1]-sol[:,0]
Y1 = sol[:,4]-sol[:,3]
X2 = sol[:,2]-sol[:,0]
Y2 = sol[:,5]-sol[:,3]def animate(n):traces[0].set_data(X1[:n], Y1[:n])traces[1].set_data(X2[:n], Y2[:n])pts[0].set_data([X1[n], Y1[n]])pts[1].set_data([X2[n], Y2[n]])return traces + ptsani = animation.FuncAnimation(fig, animate, range(1000), interval=10, blit=True)
ani.save('tri.gif')

在这里插入图片描述


http://www.ppmy.cn/news/31729.html

相关文章

TVS和稳压管的相同点和不同点

大家好,我是记得诚。 文章目录 介绍相同点不同点介绍 TVS和稳压管都是电路中很常用的电子元器件,都是二极管的一个种类。 TVS二极管全称是Transient voltage suppression diode,也叫瞬态电压抑制二极管。 稳压二极管英文名字Zener diode,又叫齐纳二极管。 关于稳压二极…

Map和Set总结

Map和Set Map和Set是专门用来进行搜索的数据结构,适合动态查找 模型 搜索的数据称为关键字(key),关键字对应的叫值(value),key-value键值对 key模型key-value模型 Map存储的就是key-value模型,Set只存储了key Map Map是接口类…

香港酒店模拟分析项目报告--使用tableau、python、matlab

转载请标记本文出处 软件:tableau、pycharm、关系型数据库:MySQL 数据大量分析考虑电脑性能的情况。 文章目录前言一、爬虫是什么?二、使用tableau数据可视化1.引入数据1.1 制作直方图-各地区酒店数量条形图1.2 各地区酒店均价1.3 价格等级堆…

Kubenates中的日志收集方案ELK(下)

1、rpm安装Logstash wget https://artifacts.elastic.co/downloads/logstash/logstash-6.8.7.rpm yum install -y logstash-6.8.7.rpm2、创建syslog配置 input {beats{port> 5044 } }output {elasticsearch {hosts > ["http://localhost:9200"]index …

【LeetCode】33. 搜索旋转排序数组、1290. 二进制链表转整数

作者:小卢 专栏:《Leetcode》 喜欢的话:世间因为少年的挺身而出,而更加瑰丽。 ——《人民日报》 目录 33. 搜索旋转排序数组 1290. 二进制链表转整数 33. 搜索旋转排序数组 33. 搜索旋转排序…

问心 | 再看token、session和cookie

什么是cookie HTTP Cookie(也叫 Web Cookie或浏览器 Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。 什么是session Session 代表着服务器和客户端一次会话…

dockerFile编写

dockerFile编写 语法参数 # DockerFile常用指令 USER # 指定运行的用户,一般不用配置 FROM # 拉取基础镜像,一切从这里开始构建 ARG # 构建参数,只能在dockerFile中使用, # eg: JAR_FILEtarget/springboot-mongo-0.0.1-SNAPSHOT.jar MAI…

C#基础之面向对象编程(二)

总目录 文章目录总目录前言一、概述1. 定义2. 面向对象的三大特性二、封装1. 定义2. 属性三、继承1. 定义2. 继承的使用3. base 和this四、多态1. 定义2. 重写和重载3. 多态性的实现1、静态多态性2、动态多态性4. 向上转型和向下转型1、定义2、语法格式3、案例结语前言 本文主…