python中自适应步长模拟电子运动微分方程
我试图模拟强激光的振荡电场如何推动一个靠近a+1离子库仑势的电子。激光场是 E=y方向上的Eo sin(wt) 库仑势是 F=ke q1*q2/r^2,在r方向 强电场导致电子移动,因此电子的初始条件是在y方向上从原子移动。然后,电子被激光场来回推动,有机会与库仑势相互作用。我想模拟库仑势如何影响电子的飞行。模拟需要是三维的,因为我最终想要包括更复杂的激光场,它们推动电子在x和y方向,而电子可以从z方向的动量开始 起初,我认为这很容易。下面是我用来以非常小的步骤(1e-18秒)逐步完成时间的代码。当电子不在离子附近时,这种方法很有效。然而,对于靠近离子的电子,结果强烈依赖于模拟中使用的时间步长。如果我把时间步长变小,计算会花很长时间python中自适应步长模拟电子运动微分方程,python,scipy,physics,ode,differential-equations,Python,Scipy,Physics,Ode,Differential Equations,我试图模拟强激光的振荡电场如何推动一个靠近a+1离子库仑势的电子。激光场是 E=y方向上的Eo sin(wt) 库仑势是 F=ke q1*q2/r^2,在r方向 强电场导致电子移动,因此电子的初始条件是在y方向上从原子移动。然后,电子被激光场来回推动,有机会与库仑势相互作用。我想模拟库仑势如何影响电子的飞行。模拟需要是三维的,因为我最终想要包括更复杂的激光场,它们推动电子在x和y方向,而电子可以从z方向的动量开始 起初,我认为这很容易。下面是我用来以非常小的步骤(1e-18秒)逐步完成时间的代码
所以,我认为在这种情况下,我应该使用一个自适应的时间步长。此外,从我所读到的,龙格-库塔方法应该比我使用的简单方法优越。但是,我不认为scipy.odeint适用于三维。关于如何提高这些模拟的准确性和速度,有什么想法吗 下图显示了时间步长对结果的巨大影响(一件坏事): 这是我的代码:
import numpy as np
import matplotlib.pyplot as plt
q = 1.602e-19 #Coulombs Charge of electron
h_bar = 1.054e-34 #J*s Plank's Constant div by 2Pi
c = 3.0e8 #m/s Speed of light
eo = 8.8541e-12 #C^2/(Nm^2) Permittivity of vacuum
me = 9.109e-31 #kg Mass of electron
ke = 8.985551e9 #N m^2 C-2 Coulomb's constant
def fly_trajectory(wavelength,intensity,tb=0,pulseFWHM=40.e-15,
final_time=100e-15,time_step=.001e-15,Ip=15.13,v0=(2e4,0,0)):
#Intensity is in w/cm2. Ip is in eV. Otherwise it's SI units throughout.
#The electric field of the later is in the y-direction
Ip = 15.13 * q #Calculate the ionization potential of the atom in Joules
Eo = np.sqrt(2*intensity*10**4/(c*8.85e-12)) # Electric field in V/m
w = c/wavelength * 2. * np.pi #Angular frequency of the laser
times = np.arange(tb,final_time,time_step)
Ey = Eo*np.sin(w*times) * np.exp(-times**2/(2*(pulseFWHM / 2.35482)**2))
Eb = Ey[0] #E-field at time of birth (time of tunneling)
if Eb == 0: return 0,0 #No field --> no electrons
tunnel_position = -Ip / (Eb*q)
x,y,z = 0,tunnel_position,0
vx,vy,vz = v0
y_list = np.zeros(len(times)) #store the y-values for later
for index in range(0,len(times)):
r = np.sqrt(x**2+y**2+z**2)
rx = x/r; ry = y/r; rz=z/r
Fcy = -q**2 * ke/(r**2) * ry
ay = Ey[index]*(-q)/me + Fcy/me #only y includes the laser
vy = vy + ay*time_step
y = y + vy * time_step
Fcx = -q**2 * ke/(r**2) * rx
ax = (-q)/me + Fcx/me
vx = vx + ax*time_step
x = x + vx * time_step
Fcz = -q**2 * ke/(r**2) * rz
az = (-q)/me + Fcz/me
vz = vz + az*time_step
z = z + vz * time_step
y_list[index] = y
return times,y_list
for tb in np.linspace(0.25*2.66e-15,0.5*2.66e-15,5):
print tb
times,ys = fly_trajectory(800e-9,2e14,tb=tb,time_step=.01e-15)
plt.plot(times,ys,color='r')
times,ys = fly_trajectory(800e-9,2e14,tb=tb,time_step=.001e-15)
plt.plot(times,ys,color='b')
#plot legend and labels:
plt.plot(0,0,color='r',label='10e-18 sec step')
plt.plot(0,0,color='b',label='1e-18 sec step')
plt.xlim(0,10e-15); plt.ylim(-1e-8,1e-8)
leg = plt.legend(); leg.draw_frame(False)
plt.xlabel('Time (sec)')
plt.ylabel('Y-distance (meters)')
plt.show()
正如Warren Weckesser所建议的那样,我可以简单地遵循Scipy关于耦合质量-弹簧系统的食谱。首先,我需要将我的“右侧”方程写成:
x' = vx
y' = vy
z' = vz
vx' = Ac*x/r
vy' = Ac*y/r + q*E/m
vz' = Ac*z/r
式中,Ac=keq^2/(mr^2)是库仑势引起的加速度大小,E是激光器随时间变化的电场。然后,我可以用它来找到解决方案。这比我以前使用的方法更快、更可靠
这是odeint的电子轨迹。现在他们都没有疯狂地飞走:
代码如下:
import numpy as np
import matplotlib.pyplot as plt
import scipy.integrate
q = 1.602e-19 #Coulombs Charge of electron
c = 3.0e8 #m/s Speed of light
eo = 8.8541e-12 #C^2/(Nm^2) Permittivity of vacuum
me = 9.109e-31 #kg Mass of electron
ke = 8.985551e9 #N m^2 C-2 Coulomb's constant
def tunnel_position(tb,intensity,wavelength,pulseFWHM,Ip):
Ip = 15.13 * q
Eb = E_laser(tb,intensity,wavelength,pulseFWHM)
return -Ip / (Eb*q)
def E_laser(t,intensity,wavelength,pulseFWHM):
w = c/wavelength * 2. * np.pi #Angular frequency of the laser
Eo = np.sqrt(2*intensity*10**4/(c*8.85e-12)) # Electric field in V/m
return Eo*np.sin(w*t) * np.exp(-t**2/(2*(pulseFWHM / 2.35482)**2))
def vectorfield(variables,t,params):
x,y,z,vx,vy,vz = variables
intensity,wavelength,pulseFWHM,tb = params
r = np.sqrt(x**2+y**2+z**2)
Ac = -ke*q**2/(r**2*me)
return [vx,vy,vz,
Ac*x/r,
Ac*y/r + q/me * E_laser((t-tb),intensity,wavelength,pulseFWHM),
Ac*z/r]
Ip = 15.13 # Ionization potential of Argon eV
intensity = 2e14
wavelength = 800e-9
pulseFWHM = 40e-15
period = wavelength/c
t = np.linspace(0,20*period,10000)
birth_times = np.linspace(0.01*period,0.999*period,50)
max_field = np.max(np.abs(E_laser(birth_times,intensity,wavelength,pulseFWHM)))
for tb in birth_times:
x0 = 0
y0 = tunnel_position(tb,intensity,wavelength,pulseFWHM,Ip)
z0 = 0
vx0 = 2e4
vy0 = 0
vz0 = 0
p = [intensity,wavelength,pulseFWHM,tb]
w0 = [x0,y0,z0,vx0,vy0,vz0]
solution,info = scipy.integrate.odeint(vectorfield,w0,t, args=(p,),full_output=True)
print 'Tb: %.2f fs - smallest step : %.05f attosec'%((tb*1e15),np.min(info['hu'])*1e18)
y = solution[:,1]
importance = (np.abs(E_laser(tb,intensity,wavelength,pulseFWHM))/max_field)
plt.plot(t,y,alpha=importance*0.8,lw=1)
plt.xlabel('Time (sec)')
plt.ylabel('Y-distance (meters)')
plt.show()
有趣的问题;但这几乎不是一个编程问题……问题基本上是我如何在python中实现adaptive timestep runge kutta。可能已经有一个python包可以为我完成这项工作,所以这是一个编程问题。我只是提供了太多的背景信息。“然而,我不认为scipy.odeint适用于三维。”这不是真的
scipy.odeint
设计用于求解n维系统。例如,请参见或使用scipy.odeint
,您的第一个任务是将微分方程作为一阶系统编写(就像我之前的评论中链接的scipy Cookbook中的耦合弹簧质量示例一样)。在这种情况下,您的系统有六个维度;变量为x、y、z、vx、vy和vz。一旦将系统的“右侧”作为函数实现,就可以使用scipy.odeint
。