This post shows MHD simulations including linear waves and the parametric decay instability.
We consider 1D case and assume the equation of state to be isothermal:
\begin{equation} \begin{gathered} {\partial _t}\rho + {\partial _x}\left( {\rho u} \right) = 0; \hfill \\ {\partial _t}u + u{\partial _x}u = - \frac{1}{\rho }{\partial _x}\left( {p + {{\left| {\mathbf{b}} \right|}^2}/2} \right); \hfill \\ {\partial _t}v + u{\partial _x}v = \frac{{{1}}}{\rho }{\partial _x}{b_y}; \hfill \\ {\partial _t}w + u{\partial _x}w = \frac{{{1}}}{\rho }{\partial _x}{b_z}; \hfill \\ {\partial _t}{b_y} = - {\partial _x}\left( {u{b_y} - vb_x} \right); \hfill \\ {\partial _t}{b_z} = - {\partial _x}\left( {u{b_z} - wb_x} \right); \hfill \\ p = \beta \rho . \hfill \\ \end{gathered} \end{equation}%config InlineBackend.figure_format='retina'
import numpy as np
import matplotlib.pyplot as plt
import scipy.fftpack as sf
import matplotlib.animation as animation
plt.rcParams['font.size'] = 12
plt.rcParams['axes.linewidth'] = 1.5
plt.rcParams['animation.html'] = 'jshtml'
def MHD(nx,nt,dx,dt,beta,bx,U,isav):
global kx,kd
kx =2*np.pi/(nx*dx)*np.r_[np.arange(nx/2),np.arange(-nx/2,0)]
kd=np.zeros(nx)
kd[np.abs(kx)<=2/3*np.max(abs(kx))]=1.0 ### 2/3-rule for dealiasing
hst =np.zeros((6,nt//isav,nx))
hst[:,0,:]=U[:,:]
Uf=sf.fft(U,axis=1)
for it in range(1,nt):
#---add viscocity and resistivity term---#
mu =1e-5*(1+(kx/4)**2)
eta=1e-5*(1+(kx/4)**2)
Uf[1:4,:]=np.exp(-kx**2*dt*mu )*Uf[1:4,:]
Uf[4:6,:]=np.exp(-kx**2*dt*eta)*Uf[4:6,:]
#---4th order Runge-Kutta scheme---#
LK1=flx(Uf )
LK2=flx(Uf+0.5*dt*LK1)
LK3=flx(Uf+0.5*dt*LK2)
LK4=flx(Uf+ dt*LK3)
Uf=Uf+dt*(LK1+2*LK2+2*LK3+LK4)/6
##---3rd order TVD Runge-Kutta scheme---#
#LK1=flx(Uf)
#Uf1=Uf+dt*LK1
#LK2=flx(Uf1)
#Uf2=3/4*Uf+1/4*(Uf1+dt*LK2)
#LK3=flx(Uf2)
#Uf =1/3*Uf+2/3*(Uf2+dt*LK3)
if(it%isav==0):
hst[:,it//isav,:]=np.real(sf.ifft(Uf,axis=1))
return locals()
def flx(Uf):
ff=np.zeros((6,nx),dtype='complex128')
ro =np.real(sf.ifft(Uf[0,:]*kd))
u =np.real(sf.ifft(Uf[1,:]*kd))
v =np.real(sf.ifft(Uf[2,:]*kd))
w =np.real(sf.ifft(Uf[3,:]*kd))
by =np.real(sf.ifft(Uf[4,:]*kd))
bz =np.real(sf.ifft(Uf[5,:]*kd))
ux =np.real(sf.ifft(1j*kx*Uf[1,:]*kd))
vx =np.real(sf.ifft(1j*kx*Uf[2,:]*kd))
wx =np.real(sf.ifft(1j*kx*Uf[3,:]*kd))
byx=np.real(sf.ifft(1j*kx*Uf[4,:]*kd))
bzx=np.real(sf.ifft(1j*kx*Uf[5,:]*kd))
ff[0,:]=-1j*kx*sf.fft(ro*u)
ff[1,:]=-sf.fft(u*ux+by*byx/ro+bz*bzx/ro)-1j*kx*sf.fft(np.log(ro))*beta
ff[2,:]=-sf.fft(u*vx-bx*byx/ro)
ff[3,:]=-sf.fft(u*wx-bx*bzx/ro)
ff[4,:]=-1j*kx*sf.fft(u*by-v*bx)
ff[5,:]=-1j*kx*sf.fft(u*bz-w*bx)
return ff
Linearizing and Fourier transforming, we obtain the dispersion realtion of the system.
These are Alfven ($\omega=V_A k$) and acoustic modes ($\omega=C_Sk$).
%%time
nx=2048;nt=512*40;dx=2*np.pi/nx;dt=0.1*dx;isav=40
U=np.zeros((6,nx))
x=np.arange(nx)*dx
U[0,:]=1
for ik in range(128):
ikk=ik-64
U[0,:]=U[0,:]+1e-5*np.random.randn()*np.sin(2*np.pi/(nx*dx)*x*ikk+2*np.pi*np.random.rand())
U[4,:]=U[4,:]+1e-5*np.random.randn()*np.cos(2*np.pi/(nx*dx)*x*ikk+2*np.pi*np.random.rand())
U[5,:]=U[5,:]+1e-5*np.random.randn()*np.cos(2*np.pi/(nx*dx)*x*ikk+2*np.pi*np.random.rand())
bx=1; beta=0.1
data=MHD(nx,nt,dx,dt,beta,bx,U,isav)
locals().update(data)
ddt=dt*isav
ddx=dx
nd=nt//isav
kmin=2*np.pi/(ddx*nx)*(-nx/2); kmax=2*np.pi/(ddx*nx)*(nx/2)
wmin=2*np.pi/(ddt*nd)*(-nd/2); wmax=2*np.pi/(ddt*nd)*(nd/2)
kaxis=np.linspace(kmin,kmax,nx); waxis=np.linspace(wmin,wmax,nt)
kx=np.linspace(kmin,kmax,nx)
wS1= np.sqrt(beta)*kx
wS2=-np.sqrt(beta)*kx
wR= kx
wL=-kx
fftrho=sf.fftshift(sf.fft2(hst[0,:,::-1]-1))
fftbz =sf.fftshift(sf.fft2(hst[5,:,::-1]))
plt.figure(figsize=(12,6))
plt.subplot(121)
plt.imshow(abs(fftrho),origin='lower',aspect='auto',extent=([kmin,kmax,wmin,wmax]),cmap='Blues')
plt.plot(kx,wS1,'r--')
plt.plot(kx,wS2,'r--')
plt.axis([kmin/16,kmax/16,0,wmax/2])
plt.title(r'$\rho$')
plt.xlabel(r'$k$')
plt.ylabel(r'$\omega$')
plt.clim(0,1e0)
plt.subplot(122)
plt.imshow(abs(fftbz),origin='lower',aspect='auto',extent=([kmin,kmax,wmin,wmax]),cmap='Blues')
plt.plot(kx,wR,'r--')
plt.plot(kx,wL,'r--')
plt.title(r'$b_z$')
plt.xlabel(r'$k$')
plt.ylabel(r'$\omega$')
plt.axis([kmin/16,kmax/16,0,wmax/2])
plt.clim(0,1e0)
plt.show()
We set a large amplitude left-handed circularly polarized wave and white noises in the background plasma as an initial condition. The Alfven mode experiences the parametric instability and is decayed into a backward Alfven wave and an acoustic wave matching the conditions, $k_1=k_2+k_3$ and $\omega_1=\omega_2+\omega_3$.
%%time
nx=2048;nt=512*250;dx=2*np.pi/nx;dt=0.1*dx;isav=250
U=np.zeros((6,nx))
x=np.arange(nx)*dx
U[0,:]=1
U[4,:]= 0.2*np.cos(4*x)
U[5,:]=-0.2*np.sin(4*x)
U[2,:]=-(1.0)*U[4,:]
U[3,:]=-(1.0)*U[5,:]
for ik in range(128):
ikk=ik-64
U[0,:]=U[0,:]+1e-5*np.random.randn()*np.sin(2*np.pi/(nx*dx)*x*ikk+2*np.pi*np.random.rand())
U[4,:]=U[4,:]+1e-5*np.random.randn()*np.sin(2*np.pi/(nx*dx)*x*ikk+2*np.pi*np.random.rand())
U[5,:]=U[5,:]+1e-5*np.random.randn()*np.cos(2*np.pi/(nx*dx)*x*ikk+2*np.pi*np.random.rand())
bx=1; beta=0.1
data=MHD(nx,nt,dx,dt,beta,bx,U,isav)
locals().update(data)
### Fourier decomposition (Terasawa1986JGR)
lx=nx*dx
x=np.linspace(-lx/2,lx/2,nx)
byc=np.zeros((nt//isav,nx//2))
bys=np.zeros((nt//isav,nx//2))
bzc=np.zeros((nt//isav,nx//2))
bzs=np.zeros((nt//isav,nx//2))
for it in range(nt//isav):
for ik in range(nx//2):
byc[it,ik]=2/lx*np.sum(hst[4,it,:]*np.cos(2*np.pi*(ik+1)*x/lx)*dx)
bys[it,ik]=2/lx*np.sum(hst[4,it,:]*np.sin(2*np.pi*(ik+1)*x/lx)*dx)
bzc[it,ik]=2/lx*np.sum(hst[5,it,:]*np.cos(2*np.pi*(ik+1)*x/lx)*dx)
bzs[it,ik]=2/lx*np.sum(hst[5,it,:]*np.sin(2*np.pi*(ik+1)*x/lx)*dx)
fftbr=0.5*((byc+bzs)+1j*(bzc-bys))
fftbl=0.5*((byc-bzs)+1j*(bzc+bys))
br=np.zeros((nt//isav,nx),dtype='complex')
bl=np.zeros((nt//isav,nx),dtype='complex')
for it in range(nt//isav):
for ik in range(nx//2):
br[it,:]=br[it,:]+fftbr[it,ik]*np.exp( 1j*2*np.pi*(ik+1)*x/lx)
bl[it,:]=bl[it,:]+fftbl[it,ik]*np.exp(-1j*2*np.pi*(ik+1)*x/lx)
byr=np.real(br)
bzr=np.imag(br)
byl=np.real(bl)
bzl=np.imag(bl)
def update_anim(it):
fig.clf()
ax1 = fig.add_subplot(111)
ax1.clear()
xx=dx*np.arange(nx)
im1=ax1.plot(xx,hst[0,it*4,:]-1,label=r'$\rho$')
im2=ax1.plot(xx,byr[it*4,:],label=r'$b_y\;(\leftarrow L^{-}\; \;R^{+}\rightarrow)$')
im3=ax1.plot(xx,byl[it*4,:],label=r'$b_y\;(\leftarrow R^{-}\; \;L^{+}\rightarrow)$')
ax1.legend(loc='upper right')
ax1.set_xlabel(r'$X$')
ax1.set_ylabel(r'$\Psi$')
ax1.set_xlim(0,nx*dx)
ax1.set_ylim(-1,1)
fig=plt.figure(figsize=(16,5))
anim=animation.FuncAnimation(fig,update_anim,frames=nt//isav//4)
plt.close()
anim
xx=dx*np.arange(nx)
fig, ax = plt.subplots(ncols=3, sharex=True, figsize=(16, 8))
ax[0].imshow(hst[0,:,:],cmap='jet',origin='lower',aspect='auto',extent=([0,nx*dx,0,nt*dt]))
ax[1].imshow(byl[:,:] ,cmap='bwr',origin='lower',aspect='auto',extent=([0,nx*dx,0,nt*dt]),vmin=-0.2,vmax=0.2)
ax[2].imshow(byr[:,:] ,cmap='bwr',origin='lower',aspect='auto',extent=([0,nx*dx,0,nt*dt]),vmin=-0.2,vmax=0.2)
ax[0].set_title(r'$\rho$')
ax[1].set_title(r'$b_y\;(\leftarrow R^{-}\; \;L^{+}\rightarrow)$')
ax[2].set_title(r'$b_y\;(\leftarrow L^{-}\; \;R^{+}\rightarrow)$')
for i in range(3):
ax[i].set_xlabel(r'$X$')
ax[0].set_ylabel(r'$T$')
plt.show()
ddt=dt*isav
ddx=dx
nd=nt//isav
kmin=2*np.pi/(ddx*nx)*(-nx/2); kmax=2*np.pi/(ddx*nx)*(nx/2)
wmin=2*np.pi/(ddt*nd)*(-nd/2); wmax=2*np.pi/(ddt*nd)*(nd/2)
kaxis=np.linspace(kmin,kmax,nx); waxis=np.linspace(wmin,wmax,nt)
kx=np.linspace(kmin,kmax,nx)
wS1= np.sqrt(beta)*kx
wS2=-np.sqrt(beta)*kx
wR= kx
wL=-kx
fftrho=sf.fftshift(sf.fft2(hst[0,:,::-1]-1))
fftbz =sf.fftshift(sf.fft2(hst[5,:,::-1]))
plt.figure(figsize=(12,6))
plt.imshow(abs(fftrho)+abs(fftbz),origin='lower',aspect='auto',extent=([kmin,kmax,wmin,wmax]),cmap='Blues')
plt.plot(kx,wR ,'k--',lw=1)
plt.plot(kx,wL ,'k--',lw=1)
plt.plot(kx,wS1,'k--',lw=1)
plt.plot(kx,wS2,'k--',lw=1)
plt.axis([kmin/32,kmax/32,0,wmax/4])
plt.xlabel(r'$k$')
plt.ylabel(r'$\omega$')
plt.clim(0,2e4)
plt.arrow(0,0,4,4, head_width=0.01, head_length=0.01, fc='C1', ec='C1',zorder=5)
plt.arrow(0,0,6,np.sqrt(beta)*6,head_width=0.01, head_length=0.01, fc='C1', ec='C1',zorder=5)
plt.arrow(0,0,-2,2,head_width=0.01, head_length=0.01, fc='C1', ec='C1',zorder=5)
plt.arrow(4,4,-6,-np.sqrt(beta)*6,head_width=0.01, head_length=0.01, fc='C1', ec='C1',ls='--',width=0.001)
plt.arrow(4,4,2,-2,head_width=0.01, head_length=0.01, fc='C1', ec='C1',ls='--',width=0.001)
plt.show()
Higher harmonics on the ascoutic mode branch can be understood as the result of the wave steepening.
!jupyter nbconvert --to html --template tmp.tpl MHD_parametric_instability.ipynb