Reference: [Toida1995PoP]
We simulate the nonlinear evolution of magnetosonic waves in a multi-ion species plasma. The governing equations are described as follows, and we consider electron, proton, and alpha particle,
\begin{align} &{\partial _t}{n_j} + \nabla \cdot \left( {{n_j}{{\bf{v}}_j}} \right) = 0;\\ &{{\partial _t}{{\bf{v}}_j} + \left( {{{\bf{v}}_j} \cdot \nabla } \right)}{\bf{v}}_j = \frac{q_j}{m_j}\left( {{\bf{E}} + \frac{{{{\bf{v}}_j}}}{c} \times {\bf{B}}} \right);\\ &\frac{1}{c}{\partial _t}{\bf{B}} = - \nabla \times {\bf{E}};\\ &\frac{1}{c}{\partial _t}{\bf{E}} = \nabla \times {\bf{B}} - \frac{{4\pi }}{c}\sum\limits_j {{q_j}{n_j}{{\bf{v}}_j}}. \end{align}Neglecting the displacement current, we obtain the dispersion relation for perpendicular propagating waves, $$ \left(\sum_j\frac{\Omega_{cj}\omega_{pj}^2}{\omega^2-\Omega_{cj}^2}\right)^2-\left(c^2k^2+\sum_j\frac{\omega_{pj}^2\omega^2}{\omega^2-\Omega_{cj}^2}\right)\left(\sum_j\frac{\omega_{pj}^2}{\omega^2-\Omega_{cj}^2}\right)=0 $$
%config InlineBackend.figure_format='retina'
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
import scipy.fftpack as sf
import scipy as sp
import math as mt
import matplotlib.animation as animation
plt.rcParams['font.size'] = 12
plt.rcParams['axes.linewidth'] = 1.5
plt.rcParams['animation.embed_limit']=60
plt.rcParams['animation.html'] = 'jshtml'
q=np.zeros(3); m=np.zeros(3)
q[0]=-1; q[1]=1 ; q[2]=2
m[0]= 1; m[1]=1000; m[2]=4*m[1]
c=1
b0=0.5
ne0=1
na0=0.84
nb0=0.08
wpe=np.sqrt(ne0*q[0]**2/m[0])
wpa=np.sqrt(na0*q[1]**2/m[1])
wpb=np.sqrt(nb0*q[2]**2/m[2])
wce=q[0]*b0/m[0]
wca=q[1]*b0/m[1]
wcb=q[2]*b0/m[2]
wpe2=wpe**2
wpa2=wpa**2
wpb2=wpb**2
wce2=wce**2
wca2=wca**2
wcb2=wcb**2
kk=np.logspace(-3,1,1000)
A2=wpe2**2*(1+c**2*kk**2/wpe2)
A1=(wpa2/wca2+wpb2/wcb2)**2*wca2*wcb2*wce2+(wpa2+wpb2)*wce2*c**2*kk**2
A0=(wpa2/wca2+wpb2/wcb2)*wca2*wcb2*wce2*c**2*kk**2
wp2=(A1+np.sqrt(A1**2-4*A2*A0))/(2*A2)
wm2=(A1-np.sqrt(A1**2-4*A2*A0))/(2*A2)
wp=np.sqrt(wp2)
wm=np.sqrt(wm2)
plt.plot(kk,wp/wca,label=r'$\omega_{+}$')
plt.plot(kk,wm/wca,label=r'$\omega_{-}$')
plt.legend()
plt.xscale('log')
plt.yscale('log')
plt.xlim(1e-3,1e1)
plt.xlabel(r'$ck/\omega_{pe}$')
plt.ylabel(r'$\omega/\Omega_a$')
plt.show()
We solve the governing equations using the pseudo-spectral method and 4th-order Runge-Kutta scheme.
We initially put a soliton solution with a large-amplitude $\delta B_0=0.2$ and impose a viscosity term for $v_{ex}$ to prevent oscillations in front of the shock.
def MIP(nx,nt,dx,dt,q,m,isav,n,vx,vy,ex,ey,bz):
global kk,kkd
xmax=nx*dx
kk =2*np.pi/xmax*np.r_[np.arange(nx/2),np.arange(-nx/2,0)]
kkd=np.zeros(nx)
kkd[np.abs(kk)<=2/3*np.max(abs(kk))]=1.0 ### 2/3-rule for dealiasing
nhst =np.zeros((3,nt//isav+1,nx))
vxhst =np.zeros((3,nt//isav+1,nx))
vyhst =np.zeros((3,nt//isav+1,nx))
exhst =np.zeros((nt//isav+1,nx))
eyhst =np.zeros((nt//isav+1,nx))
bzhst =np.zeros((nt//isav+1,nx))
nhst[0,0,:]=n[0,:]
nhst[1,0,:]=n[1,:]
nhst[2,0,:]=n[2,:]
vxhst[0,0,:]=vx[0,:]
vxhst[1,0,:]=vx[1,:]
vxhst[2,0,:]=vx[2,:]
vyhst[0,0,:]=vy[0,:]
vyhst[1,0,:]=vy[1,:]
vyhst[2,0,:]=vy[2,:]
exhst[0,:]=ex
eyhst[0,:]=ey
bzhst[0,:]=bz
nf =sf.fft(n ,axis=1)
vxf=sf.fft(vx,axis=1)
vyf=sf.fft(vy,axis=1)
exf=sf.fft(ex)
eyf=sf.fft(ey)
bzf=sf.fft(bz)
for it in range(1,nt+1):
ga1,gb1,gc1,gd1,ge1,gf1=f(nf ,vxf ,vyf ,exf ,eyf ,bzf )
ga2,gb2,gc2,gd2,ge2,gf2=f(nf+0.5*dt*ga1,vxf+0.5*dt*gb1,vyf+0.5*dt*gc1,exf+0.5*dt*gd1,eyf+0.5*dt*ge1,bzf+0.5*dt*gf1)
ga3,gb3,gc3,gd3,ge3,gf3=f(nf+0.5*dt*ga2,vxf+0.5*dt*gb2,vyf+0.5*dt*gc2,exf+0.5*dt*gd2,eyf+0.5*dt*ge2,bzf+0.5*dt*gf2)
ga4,gb4,gc4,gd4,ge4,gf4=f(nf+ dt*ga3,vxf+ dt*gb3,vyf+ dt*gc3,exf+ dt*gd3,eyf+ dt*ge3,bzf+ dt*gf3)
nf =nf +dt*(ga1+2*ga2+2*ga3+ga4)/6
vxf =vxf+dt*(gb1+2*gb2+2*gb3+gb4)/6
vyf =vyf+dt*(gc1+2*gc2+2*gc3+gc4)/6
exf =exf+dt*(gd1+2*gd2+2*gd3+gd4)/6
eyf =eyf+dt*(ge1+2*ge2+2*ge3+ge4)/6
bzf =bzf+dt*(gf1+2*gf2+2*gf3+gf4)/6
#---add viscocity and resistivity term---#
mu =1e-2*(1+(4*kk)**2)
#for i in range(3):
vxf[0,:]=np.exp(mu*(1j*kk)**2*dt)*vxf[0,:]
#exf=np.exp(nu*(1j*kk)**2*dt)*exf
if(it%isav==0):
nhst[ 0,it//isav,:]=np.real(sf.ifft(nf[ 0,:]))
nhst[ 1,it//isav,:]=np.real(sf.ifft(nf[ 1,:]))
nhst[ 2,it//isav,:]=np.real(sf.ifft(nf[ 2,:]))
vxhst[0,it//isav,:]=np.real(sf.ifft(vxf[0,:]))
vxhst[1,it//isav,:]=np.real(sf.ifft(vxf[1,:]))
vxhst[2,it//isav,:]=np.real(sf.ifft(vxf[2,:]))
vyhst[0,it//isav,:]=np.real(sf.ifft(vyf[0,:]))
vyhst[1,it//isav,:]=np.real(sf.ifft(vyf[1,:]))
vyhst[2,it//isav,:]=np.real(sf.ifft(vyf[2,:]))
exhst[ it//isav,:]=np.real(sf.ifft(exf ))
eyhst[ it//isav,:]=np.real(sf.ifft(eyf ))
bzhst[ it//isav,:]=np.real(sf.ifft(bzf ))
return locals()
def f(nf,vxf,vyf,exf,eyf,bzf):
an =np.zeros((3,nx),dtype='complex')
avx=np.zeros((3,nx),dtype='complex')
avy=np.zeros((3,nx),dtype='complex')
aex=np.zeros(nx,dtype='complex')
aey=np.zeros(nx,dtype='complex')
abz=np.zeros(nx,dtype='complex')
### linear terms ###
for i in range(3):
avx[i,:]=q[i]/m[i]*exf[:]
avy[i,:]=q[i]/m[i]*eyf[:]
abz=-1j*kk*eyf
aey=-1j*kk*bzf
### non-linear terms ###
n =np.real(sf.ifft(nf *kkd,axis=1))
vx=np.real(sf.ifft(vxf*kkd,axis=1))
vy=np.real(sf.ifft(vyf*kkd,axis=1))
ex=np.real(sf.ifft(exf*kkd))
ey=np.real(sf.ifft(eyf*kkd))
bz=np.real(sf.ifft(bzf*kkd))
vxx=np.real(sf.ifft(1j*kk*vxf*kkd,axis=1))
vyx=np.real(sf.ifft(1j*kk*vyf*kkd,axis=1))
jx=np.zeros(nx)
jy=np.zeros(nx)
for i in range(3):
an[i,:] =-1j*kk*sf.fft(n[i,:]*vx[i,:])
avx[i,:]=avx[i,:]-sf.fft(vx[i,:]*vxx[i,:])
avy[i,:]=avy[i,:]-sf.fft(vx[i,:]*vyx[i,:])
avx[i,:]=avx[i,:]+q[i]/m[i]*sf.fft(vy[i,:]*bz)
avy[i,:]=avy[i,:]-q[i]/m[i]*sf.fft(vx[i,:]*bz)
jx=jx+q[i]*n[i,:]*vx[i,:]
jy=jy+q[i]*n[i,:]*vy[i,:]
aex=sf.fft(-jx)
aey=aey+sf.fft(-jy)
return an,avx,avy,aex,aey,abz
%%time
nx=2048;nt=60000;dx=2;dt=1;isav=600
q=np.zeros(3); m=np.zeros(3)
q[0]=-1; q[1]=1 ; q[2]=2
m[0]= 1; m[1]=1000; m[2]=4*m[1]
b0=0.5
ne0=1
na0=0.84
nb0=0.08
db=0.2
wce=q[0]*b0/m[0]
wca=q[1]*b0/m[1]
wcb=q[2]*b0/m[2]
wpe=1
wpa=np.sqrt(na0*q[1]**2/m[1])
wpb=np.sqrt(nb0*q[2]**2/m[2])
wpe2=wpe**2
wpa2=wpa**2
wpb2=wpb**2
wca2=wca**2
wcb2=wcb**2
wmr=np.sqrt((wpa2*wcb2+wpb2*wca2)/(wpa2+wpb2))
wp0=(wpa2/wca2+wpb2/wcb2)*np.sqrt(wca2*wcb2)*abs(wce)
ro0=na0*m[1]+nb0*m[2]
vA =b0/np.sqrt(ro0)
kc =wmr/vA
rab =1-(wmr/wp0)**2
dl =np.sqrt(rab)/kc
vp0 =vA
lmbd=dl
alp =1
x=np.arange(nx)*dx-nx*dx/4
vp=vp0*(1+alp*db/2)
D=2*lmbd/np.sqrt(alp*db)
b1 =db/np.cosh(x/D)**2
ey1 =b1#*vA*b0
vex1=b1#*vA
vax1=b1#*vA
vbx1=b1#*vA
ne1 =b1#*ne0
na1 =b1#*na0
nb1 =b1#*nb0
jj=np.arange(nx)
jp=np.r_[jj[0:nx-1]+1,0]
jm=np.r_[nx-1,jj[1:nx]-1]
#dxb1=(b1[jp]-b1[jm])/(2*dx)*dl
xmax=dx*nx
kk =2*np.pi/xmax*np.r_[np.arange(nx/2),np.arange(-nx/2,0)]
dxb1=np.real(sf.ifft(1j*kk*sf.fft(b1)))*dl
ex1=-(vA)**2*wmr/np.sqrt(rab)*(wpe2/wce**3+wpa2/wca**3+wpb2/wcb**3)*dxb1#*vA*b0
vey1=-(wmr/wce/np.sqrt(rab)*dxb1+ex1)#*vA
vay1=-(wmr/wca/np.sqrt(rab)*dxb1+ex1)#*vA
vby1=-(wmr/wcb/np.sqrt(rab)*dxb1+ex1)#*vA
n =np.zeros((3,nx))
vx=np.zeros((3,nx))
vy=np.zeros((3,nx))
ex=np.zeros(nx)
ey=np.zeros(nx)
bz=np.zeros(nx)
n[0,:]=ne0*(1+ne1)
n[1,:]=na0*(1+na1)
n[2,:]=nb0*(1+nb1)
vx[0,:]=vex1*vA
vx[1,:]=vax1*vA
vx[2,:]=vbx1*vA
vy[0,:]=vey1*vA
vy[1,:]=vay1*vA
vy[2,:]=vby1*vA
ex=ex1*vA*b0
ey=ey1*vA*b0
bz=b0*(1+b1)
data=MIP(nx,nt,dx,dt,q,m,isav,n,vx,vy,ex,ey,bz)
locals().update(data)
def update_anim(it):
fig.clf()
ax=fig.subplots(6,1,sharex=True) #add subplots
#ax1 = fig.add_subplot(111)
#fig.tight_layout() #reduce spacing around the figure
#ax1.clear()
xx=dx*np.arange(nx)
ax[0].plot(xx,nhst[0, it,:],label=r'$n_e$')
ax[0].plot(xx,nhst[1, it,:],label=r'$n_a$')
ax[0].plot(xx,nhst[2, it,:]*8,label=r'$8\times n_b$')
ax[1].plot(xx,vxhst[0,it,:],label=r'$v_{ex}$')
ax[1].plot(xx,vxhst[1,it,:],label=r'$v_{ax}$')
ax[1].plot(xx,vxhst[2,it,:],label=r'$v_{bx}$')
ax[2].plot(xx,vyhst[0,it,:],label=r'$v_{ey}$')
ax[2].plot(xx,vyhst[1,it,:],label=r'$v_{ay}$')
ax[2].plot(xx,vyhst[2,it,:],label=r'$v_{by}$')
ax[3].plot(xx,exhst[ it,:])
ax[4].plot(xx,eyhst[ it,:])
ax[5].plot(xx,bzhst[ it,:])
ax[0].legend(loc='upper left')
ax[1].legend(loc='upper left')
ax[2].legend(loc='upper left')
ax[5].set_xlabel(r'$X/(c/\omega_{pe})$')
ax[0].set_ylabel(r'$n$')
ax[1].set_ylabel(r'$v_x$')
ax[2].set_ylabel(r'$v_y$')
ax[3].set_ylabel(r'$E_x$')
ax[4].set_ylabel(r'$E_y$')
ax[5].set_ylabel(r'$B_z$')
ax[5].set_xlim(500,2500)
ax[0].set_ylim(np.min(nhst*8),np.max(nhst))
ax[1].set_ylim(np.min(vxhst),np.max(vxhst))
ax[2].set_ylim(np.min(vyhst),np.max(vyhst))
ax[3].set_ylim(np.min(exhst),np.max(exhst))
ax[4].set_ylim(np.min(eyhst),np.max(eyhst))
ax[5].set_ylim(np.min(bzhst),np.max(bzhst))
ax[0].set_title(r'$t=$%d$\omega_{pe}^{-1}$' %(it*isav*dt))
fig=plt.figure(figsize=(18,12))
anim=animation.FuncAnimation(fig,update_anim,frames=nt//isav+1)
plt.close()
anim
!jupyter nbconvert --to html --template tmp.tpl multi-ion_fluid.ipynb