溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

基于Python如何實(shí)現(xiàn)模擬三體運(yùn)動(dòng)

發(fā)布時(shí)間:2023-03-10 10:18:35 來源:億速云 閱讀:128 作者:iii 欄目:開發(fā)技術(shù)

本文小編為大家詳細(xì)介紹“基于Python如何實(shí)現(xiàn)模擬三體運(yùn)動(dòng)”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“基于Python如何實(shí)現(xiàn)模擬三體運(yùn)動(dòng)”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學(xué)習(xí)新知識(shí)吧。

拉格朗日方程

此前所做的一切三體和太陽系的動(dòng)畫,都是基于牛頓力學(xué)的,而且直接對微分進(jìn)行差分化,從而精度非常感人,用不了幾年就得撞一起去。

為了給三體人提供一個(gè)更加有價(jià)值的推導(dǎo),這次通過求解拉格朗日方程的數(shù)值解來實(shí)現(xiàn)。

首先假設(shè)三個(gè)質(zhì)點(diǎn)的質(zhì)量分別為m1, m2,m3,坐標(biāo)為x→1,x→2,x→3,質(zhì)點(diǎn)速度可以表示為x → ˙.假設(shè)三體在二維平面上運(yùn)動(dòng),則第i個(gè)質(zhì)點(diǎn)的動(dòng)能為

基于Python如何實(shí)現(xiàn)模擬三體運(yùn)動(dòng)

引力勢能為

基于Python如何實(shí)現(xiàn)模擬三體運(yùn)動(dòng)

其中G為萬有引力常量,rij為質(zhì)點(diǎn)i,j之間的距離,則系統(tǒng)的拉格朗日量為

基于Python如何實(shí)現(xiàn)模擬三體運(yùn)動(dòng)

有了拉格朗日量,將其帶入拉格朗日方程

基于Python如何實(shí)現(xiàn)模擬三體運(yùn)動(dòng)

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

推導(dǎo)方程組

對于三體系統(tǒng)而言,總計(jì)有3個(gè)粒子,每個(gè)粒子有x,y兩個(gè)自由度,也就是說最后會(huì)得到6組方程。考慮到公式推導(dǎo)過程中可能會(huì)出現(xiàn)錯(cuò)誤,所以下面采用sympy來進(jìn)行公式推導(dǎo)。

首先定義符號變量

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

接下來,需要構(gòu)造系統(tǒng)的拉格朗日量L,其實(shí)質(zhì)是系統(tǒng)的動(dòng)能減去勢能,對于上面構(gòu)建的三體系統(tǒng)而言,動(dòng)能和勢能可分別表示為

計(jì)算每個(gè)質(zhì)點(diǎn)的動(dòng)能和勢能。動(dòng)能是由速度決定的,而速度是由位置對時(shí)間的導(dǎo)數(shù)決定的。我們可以用 sympy 的 diff 函數(shù)來求導(dǎo):

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

勢能是由萬有引力決定的,而萬有引力是由兩個(gè)質(zhì)點(diǎn)之間的距離決定的。我們可以用 sympy 的 sqrt 函數(shù)來求距離:

from sympy import sqrt,cos
G = symbols('G') # 引力常數(shù)
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]

有了動(dòng)能和勢能,就可以愉快地求拉格朗日量了,有了拉格朗日量,就可以列拉格朗日方程了

基于Python如何實(shí)現(xiàn)模擬三體運(yùn)動(dòng)

三個(gè)粒子的每一個(gè)坐標(biāo)維度,都可以列出一組拉格朗日方程,所以總共有6個(gè)拉格朗日方程組

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−yj ,則

基于Python如何實(shí)現(xiàn)模擬三體運(yùn)動(dòng)

微分方程算法化

接下來就要調(diào)用Python的odeint來計(jì)算這個(gè)微分方程組的數(shù)值解,odeint的調(diào)用方法大致為odeint(func, y, t, args),其中func是一個(gè)函數(shù),這個(gè)函數(shù)必須為func(y,t,...),且返回值為dy/dt.

為此,需要將上述方程組再行拆分,以消去其中的二次導(dǎo)數(shù),以x1為例,令u1=dx1/dt ,則此方程變?yōu)榉匠探M

基于Python如何實(shí)現(xiàn)模擬三體運(yùn)動(dòng)

由于三體系統(tǒng)中有3個(gè)粒子,共6個(gè)獨(dú)立變量,所以要列12個(gè)方程。記

基于Python如何實(shí)現(xiàn)模擬三體運(yùn)動(dòng)

odeint輸入的y的形式為

基于Python如何實(shí)現(xiàn)模擬三體運(yùn)動(dòng)

從而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

求解+畫圖

接下來就是見證奇跡的時(shí)刻,首先創(chuàng)建一個(gè)隨機(jī)的起點(diǎn),作為三體運(yùn)動(dòng)的初值,然后帶入開整就完事兒了

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()

基于Python如何實(shí)現(xiàn)模擬三體運(yùn)動(dòng)

光是看這個(gè)軌跡就十分驚險(xiǎn)了有木有。

如果把其中的第一顆星作為坐標(biāo)原點(diǎn),那么另外兩顆星的軌跡大致為

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()

結(jié)果為

基于Python如何實(shí)現(xiàn)模擬三體運(yùn)動(dòng)

動(dòng)圖繪制

最后,以中間這顆星為原點(diǎn),繪制一下另外兩顆星運(yùn)動(dòng)的動(dòng)態(tài)過程

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 + pts

ani = animation.FuncAnimation(fig, animate, 
    range(1000), interval=10, blit=True)
ani.save('tri.gif')

基于Python如何實(shí)現(xiàn)模擬三體運(yùn)動(dòng)

讀到這里,這篇“基于Python如何實(shí)現(xiàn)模擬三體運(yùn)動(dòng)”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識(shí)點(diǎn)還需要大家自己動(dòng)手實(shí)踐使用過才能領(lǐng)會(huì),如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI