Python 我的nbody轨道代码哪里出错了?(数学方面的东西?)
在fortran中,我的nbody代码工作得完美无缺。当我把它翻译成python时,我在某个地方搞砸了。代码仍然成功地读入了一个.txt文件中的物体,并且仍然打印出一个.txt文件,该文件记录了物体在每个时间步上的位置和速度。然而,我所有的身体似乎都被抛向了未知的世界。我知道这一点,因为当比较这些图(使用mathematica)时,我注意到我的fortran Jupiter生成的图(下面的第一幅图)是完全椭圆形的,并保持在木星预期的给定距离内,而我的python生成的图(下面的第二幅图)一直到10^15的量级,这是荒谬的。我假设这是一个简单的数学修正案,但我似乎无法理解Python 我的nbody轨道代码哪里出错了?(数学方面的东西?),python,arrays,python-3.x,numpy,Python,Arrays,Python 3.x,Numpy,在fortran中,我的nbody代码工作得完美无缺。当我把它翻译成python时,我在某个地方搞砸了。代码仍然成功地读入了一个.txt文件中的物体,并且仍然打印出一个.txt文件,该文件记录了物体在每个时间步上的位置和速度。然而,我所有的身体似乎都被抛向了未知的世界。我知道这一点,因为当比较这些图(使用mathematica)时,我注意到我的fortran Jupiter生成的图(下面的第一幅图)是完全椭圆形的,并保持在木星预期的给定距离内,而我的python生成的图(下面的第二幅图)一直到1
import numpy as np
import pandas as pd
import os
import math as mt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
nbodies = int(input("Input the number of bodies: "))
dt = int(input("Input the number of timesteps: "))
ntimesteps = int(input("Max timestep: "))
G = 6.6743E-11
def getFile():
path = os.getcwd()
global fileName
fileName = input("What file? ")
inputFile = open(path + "\\" + str(fileName),"r")
return(inputFile)
def hasNumbers(inputString):
for char in inputString:
if(char == '-'):
return True
try:
float(char)
return True
except:
return False
def readFile(inputFile):
newdata = []
data = []
while True:
line = inputFile.readline()
#if the end of the file is reached
if not line:
break;
rawdata = line.split(" ")
for i in rawdata:
if hasNumbers(i) == True:
i = i.rstrip()
newdata.append(i)
if newdata:
data.append(newdata)
newdata = []
inputFile.close()
return(data)
def emptyFile(fileName, datatype):
path = os.getcwd()
outfile = open(path + "\\" + fileName[:-4] + "_" + datatype + ".txt", "w")
return(outfile)
inputFile = getFile()
Orbital = emptyFile(fileName, "Orbital")
nData = readFile(inputFile)
m = []
x = []
y = []
z = []
vx = []
vy = []
vz = []
for i in nData:
if hasNumbers(i) == True:
m.append(float(i[0]))
x.append(float(i[1]))
y.append(float(i[2]))
z.append(float(i[3]))
vx.append(float(i[4]))
vy.append(float(i[5]))
vz.append(float(i[6]))
mass = np.array(m)
xpos = np.array(x)
ypos = np.array(y)
zpos = np.array(z)
xvel = np.array(vx)
yvel = np.array(vy)
zvel = np.array(vz)
Fx = np.zeros(nbodies)
Fy = np.zeros(nbodies)
Fz = np.zeros(nbodies)
def CalcForce(axnew, aynew, aznew):
axnew = np.zeros(nbodies)
aynew = np.zeros(nbodies)
aznew = np.zeros(nbodies)
for i in range(nbodies):
for j in range(nbodies):
if i!=j:
xdiff = x[j] - x[i]
ydiff = y[j] - y[i]
zdiff = z[j] - z[i]
r2 = (xdiff**2)+(ydiff**2)+(zdiff**2)
C = (G*m[j]*m[i])/((r2)**(1.5))
Fx[i] = Fx[i]+C*(xdiff)
Fx[j] = Fx[j]-C*(xdiff)
Fy[i] = Fy[i]+C*(ydiff)
Fy[j] = Fy[j]-C*(ydiff)
Fz[i] = Fz[i]+C*(zdiff)
Fz[j] = Fz[j]-C*(zdiff)
axnew[i] = np.divide(Fx[i],m[i])
axnew[j] = np.divide(Fx[j],m[j])
aynew[i] = np.divide(Fy[i],m[i])
aynew[j] = np.divide(Fy[j],m[j])
aznew[i] = np.divide(Fz[i],m[i])
aznew[j] = np.divide(Fz[j],m[j])
else:
continue
return axnew, aynew, aznew
axnew, aynew, aznew = CalcForce(axnew, aynew, aznew)
for k in range(ntimesteps):
xpos = xpos + xvel * dt + 0.5 * axnew * dt**2
ypos = ypos + yvel * dt + 0.5 * aynew * dt**2
zpos = zpos + zvel * dt + 0.5 * aznew * dt**2
axold = axnew
ayold = aynew
azold = aznew
xvel = xvel + 0.5 * (axold + axnew) * dt
yvel = yvel + 0.5 * (ayold + aynew) * dt
zvel = zvel + 0.5 * (azold + aznew) * dt
np.savetxt(Orbital, np.transpose([np.arange(1, nbodies+1), np.full(nbodies, k*dt), xpos, ypos, zpos]),fmt="%2i %20i %15.5E %15.5E %15.5E")
上面是我最新版本的python代码。当i没有If语句时,名为accelerations的“CalcForce.axnew”就起作用了=J现在没有了,我很天真为什么。当在定义之外调用时,删除它并返回尝试返回加速度只返回0
下面是复制到.txt文件的有用输入。它包括11个天体,从太阳到彗星(包括冥王星,我用它来比较时间)。这是在所有3个笛卡尔坐标系下完成的,基于每个物体的轨道倾角,总线性动量守恒
m x y z vx vy vz
1.988e30 -4.490e5 0.000 0.000 0.000 -1.600e1 -0.4247
3.285e23 5.790e10 0.000 0.000 0.000 4.701e4 5.772e3
4.867e24 1.080e11 0.000 0.000 0.000 3.496e4 2.077e3
5.972e24 1.494e11 0.000 0.000 0.000 2.980e4 0.000
6.390e23 2.280e11 0.000 0.000 0.000 2.399e4 0.775e3
1.898e27 7.783e11 0.000 0.000 0.000 1.306e4 0.299e3
5.683e26 1.434e12 0.000 0.000 0.000 9.671e3 0.421e3
8.681e25 2.871e12 0.000 0.000 0.000 6.799e3 0.091e3
1.024e26 4.495e12 0.000 0.000 0.000 5.427e3 0.168e3
1.309e22 7.376e12 0.000 0.000 0.000 4.532e3 1.399e3
2.200e14 5.300e12 0.000 0.000 0.000 0.951e3 0.309e3
我的fortran比较代码是
Module nbody
integer, parameter:: n = 100
integer:: nbodies, nTimesteps, i, k
double precision:: m(n), x(n), y(n), z(n), vx(n), vy(n), vz(n)
double precision:: axold(n), ayold(n), azold(n), axnew(n), aynew(n), aznew(n)
double precision:: Fx(n), Fy(n), Fz(n)
double precision:: dt, G = 6.6743D-11, r2, C, S = 1.989D30
character:: infile*40, outfile*40
character(len=20), parameter :: fmt0 = "(1X,I15)",fmt1 = "(1X,E30.10)",fmt2 = "(1X,E30.10,/)"
end module
Program Gravitas
use nbody
print*,'input the number of bodies'
read*, nbodies
print*, 'input filename'
read*, infile
print*, 'output filename'
read*, outfile
open(unit=42, file=infile, status='unknown')
open(unit=43, file=outfile, status='unknown')
read(42,*)
Do i=1, nbodies
read(42,*) m(i), x(i), y(i), z(i), vx(i), vy(i), vz(i)
end do
print*, 'input timestep(dt)'
read*, dt
print*, 'Tmax'
read*, nTimesteps
Do i=1, nbodies
WRITE(43,fmt1,advance="no")real(k)*dt
WRITE(43,fmt0,advance="no")i
WRITE(43,fmt1,advance="no")x(i)
WRITE(43,fmt1,advance="no")y(i)
WRITE(43,fmt2,advance="no")z(i)
end do
call calcforces
Do k = 1, nTimesteps
x = x + vx * dt + 0.5 * axnew * dt**2
y = y + vy * dt + 0.5 * aynew * dt**2
z = z + vz * dt + 0.5 * aznew * dt**2
axold = axnew
ayold = aynew
azold = aznew
call calcforces
vx = vx + 0.5 * (axold + axnew) * dt
vy = vy + 0.5 * (ayold + aynew) * dt
vz = vz + 0.5 * (azold + aznew) * dt
Do i = 1, nbodies
WRITE(43,fmt1,advance="no")real(k)*dt
WRITE(43,fmt0,advance="no")i
WRITE(43,fmt1,advance="no")x(i)
WRITE(43,fmt1,advance="no")y(i)
WRITE(43,fmt2,advance="no")z(i)
end do
Subroutine calcforces
use nbody
Fx=0.0
Fy=0.0
Fz=0.0
do i=1, nbodies
do j=(i+1), (nbodies)
xdiff = x(j)-x(i)
ydiff = y(j)-y(i)
zdiff = z(j)-z(i)
r2 = (xdiff**2)+(ydiff**2)+(zdiff)**2
C = (G*m(j)*m(i))/((r2)**1.5)
Fx(i)=Fx(i)+C*(xdiff)
Fx(j)=Fx(j)-C*(xdiff)
Fy(i)=Fy(i)+C*(ydiff)
Fy(j)=Fy(j)-C*(ydiff)
Fz(i)=Fz(i)+C*(zdiff)
Fz(j)=Fz(j)-C*(zdiff)
end do
end do
axnew = Fx/m
aynew = Fy/m
aznew = Fz/m
end subroutine
在嵌套的for循环中,在
CalcForce
中,循环从i+1
开始,因此每次迭代都“缺少”了i
对象的交互力。是这样吗?你能在你的fortran代码中添加一个链接或粘贴一个块吗?@Charles从i开始,我得到一个力常数的浮点除零问题:C=(G*m[j]*m[i])/((r2)**(1.5))@kendfss当然。我将把它包括在我的帖子中。CalcForce并没有像你想象的那样改变accelXN、accelYN和accelZN。您不需要在列表和nParray之间进行如此多的转换。顺便说一下,axnew=np.zeros(nbodies)
是生成零数组的一种更快的方法。