with pressure \(p\), acoustic velocity \(c\), and source term \(s\) contains two second derivatives that can be approximated with a difference formula such as
and equivalently for the space derivative. Injecting these approximations into the wave equation allows us to formulate the pressure p(x) for the time step \(t+dt\) (the future) as a function of the pressure at time \(t\) (now) and \(t-dt\) (the past). This is called an explicit scheme allowing the \(extrapolation\) of the space-dependent field into the future only looking at the nearest neighbourhood.
We replace the time-dependent (upper index time, lower indices space) part by
Increase the dominant frequency f0 and observe how the fit with the analytical solution gets worse. Fix the frequency and change nop to 5 (longer and more accurate space derivative). Observe how the solution improves comapared to nop = 3!
Increase dt by a factor of 2 (keeping everything else) and observe how the solution becomes unstable.
Code
# Import Libraries# ----------------------------------------------import numpy as npimport matplotlib# Show Plot in The Notebookmatplotlib.use("nbagg")import matplotlib.pyplot as plt# Sub-plot Configuration# ----------------------from matplotlib import gridspec # Ignore Warning Messages# -----------------------import warningswarnings.filterwarnings("ignore")
Code
# Parameter Configuration # -----------------------nx =10000# number of grid points in x-directionxmax =10000# physical domain (m)dx = xmax/(nx-1) # grid point distance in x-directionc0 =334.# wave speed in medium (m/s)isrc =int(nx/2) # source location in grid in x-directionir = isrc +100# receiver location in grid in x-directionnt =600# maximum number of time stepsdt =0.002# time stepop =3# Length of FD operator for 2nd space derivative (3 or 5) print(op, '- point operator')# Source time function parametersf0 =15.# dominant frequency of the source (Hz)t0 =4./ f0 # source time shift# CPL Stability Criterion# --------------------------eps = c0 * dt / dx #epsilon value (corrected May 3, 2020)print('Stability criterion =', eps)
3 - point operator
Stability criterion = 0.6679332000000001
Code
# Source time function (Gaussian)# -------------------------------src = np.zeros(nt +1)time = np.linspace(0* dt, nt * dt, nt)# 1st derivative of a Gaussian (corrected May 3, 2020)src =-8.* (time - t0) * f0 * (np.exp(-1.0* (4*f0) **2* (time - t0) **2))
Code
# Plot source time function# Plot position configuration# ---------------------------plt.ion()fig1 = plt.figure(figsize=(10, 6))gs1 = gridspec.GridSpec(1, 2, width_ratios=[1, 1], hspace=0.3, wspace=0.3)# Plot source time function# -------------------------ax1 = plt.subplot(gs1[0])ax1.plot(time, src) # plot source time functionax1.set_title('Source Time Function')ax1.set_xlim(time[0], time[-1])ax1.set_xlabel('Time (s)')ax1.set_ylabel('Amplitude')# Plot source spectrum# --------------------ax2 = plt.subplot(gs1[1])spec = np.fft.fft(src) # source time function in frequency domainfreq = np.fft.fftfreq(spec.size, d = dt ) # time domain to frequency domain (corrected May 3, 2020)ax2.plot(np.abs(freq), np.abs(spec)) # plot frequency and amplitudeax2.set_xlim(0, 250) # only display frequency from 0 to 250 Hzax2.set_title('Source Spectrum')ax2.set_xlabel('Frequency (Hz)')ax2.set_ylabel('Amplitude')ax2.yaxis.tick_right()ax2.yaxis.set_label_position("right")plt.show()
Code
# Plot Snapshot & Seismogram - Run this code after simulation # ---------------------------------------------------------------------------# Initialize empty pressure# -------------------------p = np.zeros(nx) # p at time n (now)pold = np.zeros(nx) # p at time n-1 (past)pnew = np.zeros(nx) # p at time n+1 (present)d2px = np.zeros(nx) # 2nd space derivative of p# Initialize model (assume homogeneous model)# -------------------------------------------c = np.zeros(nx)c = c + c0 # initialize wave velocity in model# Initialize coordinate# ---------------------x = np.arange(nx)x = x * dx # coordinate in x-direction# Initialize empty seismogram# ---------------------------seis = np.zeros(nt) # Analytical solution# -------------------G = time *0.for it inrange(nt): # Calculate Green's function (Heaviside function)if (time[it] - np.abs(x[ir] - x[isrc]) / c0) >=0: G[it] =1./ (2* c0)Gc = np.convolve(G, src * dt)Gc = Gc[0:nt]lim = Gc.max() # get limit value from the maximum amplitude# Plot position configuration# ---------------------------plt.ion()fig2 = plt.figure(figsize=(10, 6))gs2 = gridspec.GridSpec(1,2,width_ratios=[1, 1],hspace=0.3, wspace=0.3)# Plot 1D wave propagation# ------------------------# Note: comma is needed to update the variableax3 = plt.subplot(gs2[0])leg1,= ax3.plot(isrc, 0, 'r*', markersize=11) # plot position of the source in snapshotleg2,= ax3.plot(ir, 0, 'k^', markersize=8) # plot position of the receiver in snapshotup31,= ax3.plot(p) # plot pressure update each time stepax3.set_xlim(0, xmax)ax3.set_ylim(-np.max(p), np.max(p))ax3.set_title('Time Step (nt) = 0')ax3.set_xlabel('x (m)')ax3.set_ylabel('Pressure Amplitude')ax3.legend((leg1, leg2), ('Source', 'Receiver'), loc='upper right', fontsize=10, numpoints=1)# Plot seismogram # ---------------# Note: comma is needed to update the variableax4 = plt.subplot(gs2[1])leg3,= ax4.plot(0,0,'r--',markersize=1) # plot analytical solution markerleg4,= ax4.plot(0,0,'b-',markersize=1) # plot numerical solution markerup41,= ax4.plot(time, seis) # update recorded seismogram each time stepup42,= ax4.plot([0], [0], 'r|', markersize=15) # update time step positionax4.yaxis.tick_right()ax4.yaxis.set_label_position("right")ax4.set_xlim(time[0], time[-1])ax4.set_title('Seismogram')ax4.set_xlabel('Time (s)')ax4.set_ylabel('Amplitude')ax4.legend((leg3, leg4), ('Analytical', 'FD'), loc='upper right', fontsize=10, numpoints=1)plt.plot(time,Gc,'r--') # plot analytical solutionplt.show()