我是一名物理系学生,但他是编程方面的新手。 几年前我已经学会了如何为引力场中的粒子编写一个跨越式积分器的C代码,但是内存很模糊,而我现在所做的就是用Python编写代码来实现蛙跳在某个磁场中的粒子积分器。有人告诉我Boris算法对于这种模拟更好,但我先决定先尝试一下我之前学到的东西,跳过积分器。但是C语言和Python语法的差异太大了(至少对我而言)所以我不能只将C中的代码翻译成Python,我不得不写一个新的。所以我不确定算法是否正确。
我的代码是这样的,
# -*- coding: utf-8 -*-
"""
Created on Thu Feb 15 19:00:55 2018
@author: Heptacle
"""
import numpy as np
import matplotlib.pyplot as plt
q=1.6e-19 # unit charge
m=1.67e-27 # proton mass
xs=1 # x_star
B0=1 # maximum magnetic field
b=B0/xs
initial_position = np.array((0.1, 0,0)) # Initial position vector of Particle
initial_velocity = np.array((0, 0,0.1)) # Initial velocity vector of Particle
num_steps = 4000
time_values = np.linspace(0, 1000, num_steps)
dt = time_values[1] - time_values[0]
positions = np.zeros((num_steps, 3))
positions[0] = initial_position
velocities = np.zeros((num_steps, 3))
velocities[0] = initial_velocity
def acc(x,v):
if np.abs(x[0])<=1:
B=(0,b*x[0],0)
elif x[0]>=1:
B=(0,B0,0)
else:
B=(0,-B0,0)
a=q*np.cross(v,B)/m
return a
vh=np.zeros((num_steps, 3))
vh[0]=velocities[0]+acc(positions[0],velocities[0])*dt/2
accs = np.zeros((num_steps, 3))
accs[0] = acc(positions[0],velocities[0])
for i in range(num_steps - 1):
positions[i+1]=positions[i]+dt*vh[i]
vh[i+1]=vh[i]+dt*acc(positions[i+1],vh[i])
velocities[i+1]=vh[i+1]-dt/2*acc(positions[i+1],velocities[i])
####################
##### PLOTTING #####
####################
x_vals = positions[:,0]
y_vals = positions[:,1]
z_vals = positions[:,2]
plt.figure()
plt.plot(x_vals, z_vals, color = "blue", label = "Particle trajectory")
plt.legend(loc = "upper right")
plt.title("Orbit Plots")
plt.xlim((min(x_vals), max(x_vals)))
plt.ylim((min(z_vals), max(z_vals)))
plt.xlabel("x position ")
plt.ylabel("z position ")
plt.show()
但它没有正常运作。 result plot
z值无情地增加。这似乎是一些计算问题,但我找不到确切的问题。 有人可以帮帮我吗?
答案 0 :(得分:1)
我不习惯您正在使用的跳跃式算法的版本。但是,我测试了你的代码,我认为罪魁祸首是q和m变量。他们所采取的极小值极有可能导致数字问题。实际上,我的python解释器甚至警告过这个:
A
这种问题在数值模拟中非常常见,可以通过使用所谓的简化单位(参见例如here)来解决。在您的示例中,设置q = 1和m = 1似乎产生逼真的results。
编辑:我想补充一点,使用简化单位并不像将所有常数设置为1一样简单,因为无法单独选择物理测量单位。例如,在分子模拟(我的领域)中,通常将粒径,能量标度和质量设定为1。然后以这些单位表示所有其他数量。在您的情况下,设置RuntimeWarning: overflow encountered in divide
a=q*np.cross(v,B)/m
和q = 1
会更改m = 1
和B0
的值。