This notebook covers the following aspects: * Initialize the Chebyshev derivative matrix \(D_{ij}\) and display the Chebyshev derivative matrix * Define and initialize space, material and source parameters * Extrapolate time using the previously defined Chebyshev derivative matrix
Basic Equations
This notebook presents the numerical solution for the 1D elastic wave equation using the Chebyshev Pseudospectral Method. We depart from the equation
An alternative way of performing space derivatives of a function defined on the Chebyshev collocation points is to define a derivative matrix \(D_{ij}\)
where \(N+1\) is the number of Chebyshev collocation points $ x_i = cos(i/ N)$, $ i=0,…,N$ and the \(c_i\) are given as
\[ c_i = 2 \hspace{1.5cm} \text{for i = 0 or N} \]\[ c_i = 1 \hspace{1.5cm} \text{otherwise} \]
This differentiation matrix allows us to write the derivative of the function \(f_i = f(x_i)\) (possibly depending on time) simply as
\[\partial_x u_i = D_{ij} \ u_j\]
where the right-hand side is a matrix-vector product, and the Einstein summation convention applies.
Code
# This is a configuration step for the exercise. Please run it before calculating the derivative!import numpy as npimport matplotlib# Show Plot in The Notebook# -----------------------matplotlib.use("nbagg")import matplotlib.pyplot as plt# Import python function from the file "ricker.py"# -----------------------from ricker import ricker # Ignore Warning Messages# -----------------------import warningswarnings.filterwarnings("ignore")
1. Chebyshev derivative method
Code
# Define Function that initializes the Chebyshev derivative matrix D_{ij} def get_cheby_matrix(nx): cx = np.zeros(nx+1) x = np.zeros(nx+1)for ix inrange(0,nx+1): x[ix] = np.cos(np.pi * ix / nx) cx[0] =2. cx[nx] =2. cx[1:nx] =1. D = np.zeros((nx+1,nx+1))for i inrange(0, nx+1):for j inrange(0, nx+1):if i==j and i!=0and i!=nx: D[i,i]=-x[i]/(2.0*(1.0-x[i]*x[i]))else: D[i,j]=(cx[i]*(-1)**(i+j))/(cx[j]*(x[i]-x[j])) D[0,0] = (2.*nx**2+1.)/6. D[nx,nx] =-D[0,0]return D # Call the chebyshev differentiation matrix# ---------------------------------------------------------------D_ij = get_cheby_matrix(50)# ---------------------------------------------------------------# Display Differentiation Matrix# ---------------------------------------------------------------plt.imshow(D_ij, interpolation="bicubic", cmap="gray")plt.title('Differentiation Matrix $D_{ij}$')plt.axis("off")plt.tight_layout()plt.show()
2. Initialization of setup
Code
# Basic parameters# ---------------------------------------------------------------#nt = 5000 # number of time stepstmax =0.0006eps =1.4# stability limitisx =100lw =0.7ft =10f0 =100000# dominant frequencyiplot =20# Snapshot frequency# material parametersrho =2500.c =3000.mu = rho*c**2# space domainnx =100# number of grid points in x 199xs = np.floor(nx/2) # source locationxr = np.floor(nx*0.8)x = np.zeros(nx+1) # initialization of pressure fieldsp = np.zeros(nx+1) pnew = np.zeros(nx+1)pold = np.zeros(nx+1)d2p = np.zeros(nx+1) for ix inrange(0,nx+1): x[ix] = np.cos(ix * np.pi / nx) dxmin =min(abs(np.diff(x)))dxmax =max(abs(np.diff(x)))dt = eps*dxmin/c # calculate time step from stability criterionnt =int(round(tmax/dt))
Now we time extrapolate using the previously defined get_cheby_matrix(nx) method to call the differentiation matrix. The discrete values of the numerical simulation are indicated by dots in the animation, they represent the Chebyshev collocation points. Observe how the wavefield near the domain center is less dense than towards the boundaries.
Code
# Initialize animated plot# ---------------------------------------------------------------plt.figure(figsize=(10,6))line = plt.plot(x, p, 'k.', lw=2)plt.title('Chebyshev Method - 1D Elastic wave', size=16)plt.xlabel(' x(m)', size=14)plt.ylabel(' Amplitude ', size=14)plt.ion() # set interective modeplt.show()# ---------------------------------------------------------------# Time extrapolation# ---------------------------------------------------------------# Differentiation matrixD = get_cheby_matrix(nx)for it inrange(nt):# Space derivatives dp = np.dot(D, p.T) dp = mu/rho * dp dp = D @ dp# Time extrapolation pnew =2*p - pold + np.transpose(dp) * dt**2# Source injection pnew = pnew + sg*src[it]*dt**2/rho# Remapping pold, p = p, pnew p[0] =0; p[nx] =0# set boundaries pressure free # -------------------------------------- # Animation plot. Display solutionifnot it % iplot: for l in line: l.remove()del l # -------------------------------------- # Display lines line = plt.plot(x, p, 'k.', lw=1.5) plt.gcf().canvas.draw()