This notebook covers the following aspects: * Present a Fourier Pseudospectral code for solving the 2D acoustic wave equation * Compute the same using using finite difference scheme * Analyze the disperion behaviour in each case
Basic Equations
This notebook presents a Fourier Pseudospectral code for solving the 2D acoustic wave equation. Additionally, a solution using finite difference scheme is given for comparison.
The problem of solving the wave equation
\[\begin{equation}
\partial_t^2 p = c^2 (\partial_{x}^{2}p + \partial_{z}^{2}p) + s
\end{equation}\]
can be achieved using finite differeces in combination with spectral methods. Here, spatial partial derivatives with respect to \(x\) and \(z\) are computed via the Fourier method, i.e.
where \(\mathscr{F}\) represents the Fourier transform operator.
As it was the case in previous numerical solutions, we use a standard 3-point finite-difference operator to approximate the time derivatives. Then, the pressure field is extrapolated as
# Import all necessary libraries, this is a configuration step for the exercise.# Please run it before the simulation code!import numpy as npimport matplotlib# Show Plot in The Notebookmatplotlib.use("nbagg")import matplotlib.pyplot as pltfrom ricker import ricker
1. Fourier derivative method
Code
def fourier_derivative_2nd(f, dx):# Length of vector f nx = np.size(f)# Initialize k vector up to Nyquist wavenumber kmax = np.pi / dx dk = kmax / (nx /2) k = np.arange(float(nx)) k[: int(nx/2)] = k[: int(nx/2)] * dk k[int(nx/2) :] = k[: int(nx/2)] - kmax# Fourier derivative ff = np.fft.fft(f) ff = (1j*k)**2* ff df_num = np.real(np.fft.ifft(ff))return df_num
2. Initialization of setup
Code
# Basic parameters# ---------------------------------------------------------------nt =600# number of time stepsnx =256# number of grid points in x nz = nx # number of grid points in zc =343.# acoustic velocityeps =.2# stability limitisnap =600# snapshot frequencyisx =int(nx/2) # source locationisz =int(nz/2)f0 =200.# Frequency (div by 5)xmax =200iplot =20# initialization of pressure fieldsap = np.zeros((nx, nz), dtype=float)apnew = np.zeros((nx, nz), dtype=float)apold = np.zeros((nx, nz), dtype=float)ad2px = np.zeros((nx, nz), dtype=float)ad2pz = np.zeros((nx, nz), dtype=float) sp = np.zeros((nx, nz), dtype=float)spnew = np.zeros((nx, nz), dtype=float)spold = np.zeros((nx, nz), dtype=float)sd2px = np.zeros((nx, nz), dtype=float)sd2pz = np.zeros((nx, nz), dtype=float);sp_sec =-np.abs(sp[1:int(nx/2), 1:int(nz/2)])ap_sec =-np.abs(ap[int(nx/2):nx, 1:int(nz/2)].T)dx = xmax/(nx-1) # calculate space incrementx = np.arange(0, nx)*dx # initialize space coordinatesz = np.arange(0, nx)*dx # initialize space coordinatesdt = eps*dx/c # calculate tim step from stability criterion
temporal derivative is done with a 3-point finite difference operator.
Numerical dispersion and anysotropy
One of the most significant characteristics of the fourier method is the low numerical dispersion in comparison with the finite difference method. The snapshots displayed below for both solutions allow us to brifly comment two significant observations:
There is strong anisotropic dispersion behaviour visible for the finite-difference solution. The most accurate direction occur at \(\theta = \pi/4\)
The Fourier solution do not exhibit significant dispersion, but the most importantly, it does not seem to be directionally dependent. In other words the error is isotropic.