import numpy as np
import pandas as pd
from numpy import linalg as LA
import math
from scipy.sparse import csr_matrix, diags
from scipy.sparse.linalg import spsolve, spsolve_triangular
from timeit import default_timer as timer
# Visualisation libraries
## plotly
from plotly.offline import init_notebook_mode, iplot
import plotly.graph_objs as go
import plotly.offline as py
from plotly.subplots import make_subplots
import plotly.express as px
## seaborn
import seaborn as sns
## matplotlib
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse, Polygon
from matplotlib.font_manager import FontProperties
import matplotlib.colors as mcolors
from matplotlib import cm
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
plt.style.use('seaborn-whitegrid')
plt.rcParams['axes.labelsize'] = 14
plt.rcParams['xtick.labelsize'] = 12
plt.rcParams['ytick.labelsize'] = 12
plt.rcParams['text.color'] = 'k'
%matplotlib inline
import warnings
warnings.filterwarnings("ignore")
The wave equation in time domain can be stated as follows, \begin{equation} \frac{\partial^2 u}{\partial t^2}=c^2 \nabla^2 u+f,\qquad x\in \Omega \subset \mathbb{R}^d,~t\in(T_1,T_2] \end{equation} where $\Delta$ is the Laplacian, $f$ is a forcing function (for example our source) and $c$ is the wave velocity at which the time and spatially varying wave $u$ propagates.
Second-Order Finite-Difference Methods for
the One Dimensional Wave Equation in Time Domain
A one-dimensional form of the wave equation presented can be found as follows, \begin{align*} \begin{cases} \dfrac{\partial^2 u}{\partial t^2} = c^2(x) \dfrac{\partial^2 u}{\partial x^2}+f(x,t),&(x,t)\in (a,b)\times(T_1,T_2],\\ u(x,T_1)=g(x),&x\in [a,b],\\ \dfrac{\partial }{\partial t}u(x,T_1) = h(x),&x\in [a,b],\\ u(a,t) = f_a(t),&t \in[T_1,T_2],\\ u(b,t) = f_b(t),&t \in[T_1,T_2]. \end{cases} \end{align*}
The following notations are introduced to generate an algorithm for the problem,
Moreover, a general form of implicit Finite-Difference scheme of the problem (1) can be written as follows, \begin{align} \frac{1}{\tau^2}\delta_t^2 u_{i}^{n}= \frac{1}{h^2}c_{i}^2\left(\alpha \delta_x^2 u_{i}^{n+1} +\beta \delta_x^2 u_{i}^{n} +\gamma \delta_x^2 u_{i}^{n-1}\right)+f_{i}^{n}, \end{align} where $\delta^2$ is the central difference operator and $\alpha,~\beta$ and $\gamma$ are constants such that $\alpha+\beta+\gamma=1$. It follows that \begin{align} u_{i}^{n+1}-2u_{i}^{n}+u_{i}^{n-1} &= \alpha c_{i}^2 \lambda^2\left( u_{i+1}^{n+1}-2u_{i}^{n+1}+u_{i-1}^{n+1}\right) +\beta c_{i}^2 \lambda^2 \left( u_{i+1}^{n} -2 u_{i}^{n}+ u_{i-1}^{n}\right) +\gamma c_{i}^2 \lambda^2 \left(u_{i+1}^{n-1}-2 u_{i}^{n-1}+u_{i-1}^{n-1}\right)+ \tau^2f_{i}^{n}. \end{align}
This also can be simplified as follows, \begin{align}\label{eq.1} -\alpha c_{i}^2 \lambda^2 \left(u_{i-1}^{n+1}+u_{i+1}^{n+1}\right)+\left(1 +2 \alpha c_{i}^2 \lambda^2 \right)u_{i}^{n+1}&=\beta c_{i}^2 \lambda^2 \left(u_{i-1}^{n}+u_{i+1}^{n} \right) +2\left(1 -\beta c_{i}^2 \lambda^2 \right)u_{i}^{n}+\gamma c_{i}^2 \lambda^2 \left(u_{i-1}^{n-1}+u_{i+1}^{n-1} \right) \notag\\ & -\left(1 +2 \gamma c_{i}^2 \lambda^2 \right)u_{i}^{n-1}+\tau^2f_{i}^{n}. \end{align}
The following matrices are introduced to write down a matrix form of the equation (2), \begin{align} A=\begin{bmatrix} 1 +2 \alpha c_{1}^2 \lambda^2 & -\alpha c_{1}^2 \lambda^2 & 0 & \dots & \dots &0 \\ -\alpha c_{2}^2 \lambda^2 &1 +2 \alpha c_{2}^2 \lambda^2 & -\alpha c_{2}^2 \lambda^2 & 0 & \vdots &\vdots \\ 0 &-\alpha c_{3}^2 \lambda^2 &1 +2 \alpha c_{3}^2 \lambda^2 & -\alpha c_{3}^2 \lambda^2 &0 &\vdots \\ 0 &0 & \ddots & \ddots &\ddots &\vdots \\ \vdots &\vdots & -\alpha c_{M-3}^2 \lambda^2 & 1 +2 \alpha c_{M-3}^2 \lambda^2 &-\alpha c_{M-3}^2 \lambda^2 & 0 \\ \vdots &\vdots & 0 & -\alpha c_{N_x-2}^2 \lambda^2 & 1 +2 \alpha c_{N_x-2}^2 \lambda^2 &-\alpha c_{N_x-2}^2 \lambda^2 \\ 0 &0 & \dots & 0 & -\alpha c_{N_x-1}^2 \lambda^2 & 1 +2 \alpha c_{N_x-1}^2 \lambda^2 \end{bmatrix}, \end{align} \begin{align} B=\begin{bmatrix} 2 -2 \beta c_{1}^2 \lambda^2 & \beta c_{1}^2 \lambda^2 & 0 & \dots & \dots &0 \\ \beta c_{2}^2 \lambda^2 &2 -2 \beta c_{2}^2 \lambda^2 & \beta c_{2}^2 \lambda^2 & 0 & \vdots &\vdots \\ 0 &\beta c_{3}^2 \lambda^2 &2 -2 \beta c_{3}^2 \lambda^2 & \beta c_{3}^2 \lambda^2 &0 &\vdots \\ 0 &0 & \ddots & \ddots &\ddots &\vdots \\ \vdots &\vdots & \beta c_{M-3}^2 \lambda^2 & 2 -2 \beta c_{M-3}^2 \lambda^2 &\beta c_{M-3}^2 \lambda^2 & 0 \\ \vdots &\vdots & 0 & \beta c_{N_x-2}^2 \lambda^2 & 2 -2 \beta c_{N_x-2}^2 \lambda^2 &\beta c_{N_x-2}^2 \lambda^2 \\ 0 &0 & \dots & 0 & \beta c_{N_x-1}^2 \lambda^2 & 2 -2 \beta c_{N_x-1}^2 \lambda^2 \end{bmatrix}, \end{align} \begin{align} C=\begin{bmatrix} -1-2 \gamma c_{1}^2 \lambda^2 & \gamma c_{1}^2 \lambda^2 & 0 & \dots & \dots &0 \\ \gamma c_{2}^2 \lambda^2 &-1-2 \gamma c_{2}^2 \lambda^2 & \gamma c_{2}^2 \lambda^2 & 0 & \vdots &\vdots \\ 0 &\gamma c_{3}^2 \lambda^2 &-1-2 \gamma c_{3}^2 \lambda^2 & \gamma c_{3}^2 \lambda^2 &0 &\vdots \\ 0 &0 & \ddots & \ddots &\ddots &\vdots \\ \vdots &\vdots & \gamma c_{M-3}^2 \lambda^2 & -1-2 \gamma c_{M-3}^2 \lambda^2 &\gamma c_{M-3}^2 \lambda^2 & 0 \\ \vdots &\vdots & 0 & \gamma c_{N_x-2}^2 \lambda^2 & -1-2 \gamma c_{N_x-2}^2 \lambda^2 &\gamma c_{N_x-2}^2 \lambda^2 \\ 0 &0 & \dots & 0 & \gamma c_{N_x-1}^2 \lambda^2 & -1-2 \gamma c_{N_x-1}^2 \lambda^2 \end{bmatrix}, \end{align} and also \begin{align} \mathbf{u}^n=\begin{bmatrix} u_{1}^{n} \\ u_{2}^{n}\\ \vdots\\ u_{N_x-2}^{n}\\ u_{N_x-1}^{n} \end{bmatrix},~ \mathbf{b}^n= \begin{bmatrix} c_{1}^2 \lambda^2 \left(\alpha u_{0}^{n+1}+\beta u_{0}^{n}+\gamma u_{0}^{n-1}\right) \\ 0\\ \vdots\\ 0\\ c_{N_x-1}^2 \lambda^2 \left(\alpha u_{N_x}^{n+1}+\beta u_{N_x}^{n}+\gamma u_{N_x}^{n-1}\right) \end{bmatrix},~ \mathbf{F}^n=\tau^2 \begin{bmatrix} f_{1}^{n}\\ f_{2}^{n}\\ \vdots\\ f_{N_x-2}^{n}\\ f_{N_x-1}^{n} \end{bmatrix}. \end{align} Therefore, the following matrix form of equation (4) can be stated based as follows, \begin{align} A \mathbf{u}^{n+1}=B \mathbf{u}^{n}+C \mathbf{u}^{n-1}+\mathbf{b}^n+\mathbf{F}^n, \end{align} which implies \begin{align} \mathbf{u}^{n+1}=A^{-1}\left(B \mathbf{u}^{n}+C \mathbf{u}^{n-1}+\mathbf{b}^n+ \mathbf{F}^n\right). \end{align}
Finite differnce method for the wave equation in time usually require computing the solution on the first two time steps. The solution on the second time step, $u(x,T_1+k)$, can be approximated as follows by means of Taylor series, \begin{align} u(x,T_1+\tau)&=u(x,T_1)+u_t(x,T_1)\tau+\frac{1}{2} u_{tt}(x,T_1)\tau^2+\frac{1}{6} u_{ttt}(x,T_1)\tau^3 +\frac{1}{24} u_{tttt}(x,T_1)\tau^4 +\mathcal{O}(\tau^5) \notag \\ & =g(x)+s(x)\tau+\frac{1}{2} u_{tt}(x,T_1)\tau^2+\frac{1}{6} u_{ttt}(x,T_1)\tau^3+\frac{1}{24} u_{tttt}(x,T_1)\tau^4+\mathcal{O}(\tau^5) \notag \\ & =g(x)+s(x)\tau+\frac{1}{2}[c^2(x) \Delta g(x)+f(x,T_1)]\tau^2 +\frac{1}{6} [c^2(x) \Delta s(x)+f_t(x,T_1)]\tau^3 \notag\\ & +\frac{1}{24}[c^2(x) \Delta [c^2(x) \Delta g(x)+f(x,T_1)] +f_{tt}(x,T_1)]\tau^4 +\mathcal{O}(\tau^5). \end{align}
First, consider $\alpha=\gamma=0$ and $\beta=1$ in the equation (2) to get the explicit method.
Similarly, consider $\alpha=\gamma=\dfrac{1}{4}$ and $\beta=\dfrac{1}{2}$ in the equation (2) to the obtain implicit method.
For Stability and convergence analyses, see this file.
Consider the following problem, \begin{align} \begin{cases} \frac{\partial^2 u}{\partial t^2} &= \mathrm{e}^{-x} \frac{\partial^2 u}{\partial x^2}+{\mathrm{e}}^{t+x}-{\mathrm{e}}^t ,&(x,t)\in (0,1)\times(0,1],\\ u(x,0)&=\mathrm{e}^{x},&x\in [0,1],\\ \frac{\partial }{\partial t}u(x,0) &= \mathrm{e}^{x},&x\in [0,1],\\ u(0,t) &= \mathrm{e}^{t} &t \in[0,1],\\ u(1,t) &= \mathrm{e}^{t+1},&t \in[0,1]. \end{cases} \end{align} The exact solution corresponding to the problem can be found as follows, $$ u(x,t)=\mathrm{e}^{x+t} $$
def Figs(U_exact, U_Comp, Scheme, data, y_range = None):
fig = go.Figure()
# [a,b] and [T1,T2]
a = 0.0
b = 1.0
T1 = 0.0
T2 = 1.0
x = np.linspace(a, b, U_exact.shape[0])
fig.add_trace(go.Scatter(x = x, y = U_Comp, mode='lines', name='Approximated'))
fig.add_trace(go.Scatter(x = x, y = U_exact, mode='lines', name='Exact'))
fig['layout']['xaxis'].update(range=[x[0], x[-1]])
if y_range != None :
fig['layout']['yaxis'].update(range=y_range)
fig.update_xaxes(showline=True, linewidth=1, linecolor='Lightgray', mirror=True,
showgrid=True, gridwidth=1, gridcolor='Lightgray',
title_text = '$x$')
fig.update_yaxes(showline=True, linewidth=1, linecolor='Lightgray', mirror=True,
showgrid=True, gridwidth=1, gridcolor='Lightgray',
title_text = '$u(x,1)$')
fig.update_xaxes(zeroline=True, zerolinewidth=1, zerolinecolor='Lightgray')
fig.update_yaxes(zeroline=True, zerolinewidth=1, zerolinecolor='Lightgray')
fig.update_layout(legend_orientation='v', plot_bgcolor= 'white', height= 600, width= 670)
fig.update_traces(marker_line_color= 'Black', marker_line_width=0.5, opacity=1)
fig.update_layout(title={'text': r'%s Approximation with Nx = %i and Nt = %i' %
(Scheme,data.Nx.values[-1], data.Nt.values[-1]),
'x':0.46, 'y':0.88, 'xanchor': 'center', 'yanchor': 'top'},
font=dict(size=10))
fig.show()
def Example01_ExSolver1D(Nx,Nt):
# N = the number of mesh points for space
# Nt = the number of mesh points for time
# [a,b] and [T1,T2]
a = 0.0
b = 1.0
T1 = 0.0
T2 = 1.0
# Functions
C2 =lambda x: np.exp(-x)
g=lambda x: np.exp(x)
h=lambda x: np.exp(x)
fa=lambda t: np.exp(t)
fb=lambda t: np.exp(t+1)
f=lambda x,t: np.exp(t + x) - np.exp(t)
Ue=lambda x,t: np.exp(x+t)
# Additional functions
gxx=lambda x: np.exp(x);
gxxxx=lambda x: np.exp(x);
hxx=lambda x: np.exp(x);
ft=lambda x,t: np.exp(t + x) - np.exp(t);
ftt=lambda x,t: np.exp(t + x) - np.exp(t);
# dx, dt and lambda^2
dx =(b-a)/Nx
dt =(T2-T1)/Nt
l2=(dt/dx)**2
# discretizing [a,b] and [T1,T2]
xx=np.linspace(a, b, Nx+1)
tt=np.linspace(T1, T2, Nt+1)
# dicretizing c^2(x)
CC=C2(xx)
# u initial time value
u0 = g(xx);
u=np.zeros(Nx+1, dtype=float)
u1=np.zeros(Nx+1, dtype=float)
# Computing the solution at the first time step
GG= g(xx)+h(xx)*dt+0.5*(C2(xx)*gxx(xx)+f(xx,T1))*(dt**2)+\
(1/6)*(C2(xx)*hxx(xx)+ft(xx,T1))*(dt**3)+(1/24)*(C2(xx)*gxxxx(xx)+ftt(xx,T1))*(dt**4)
u1[1:Nx]=GG[1:Nx]
u1[0]=fa(tt[1])
u1[Nx]=fb(tt[1])
mid=list(range(1,Nx))
midp=[i+1 for i in mid]
midm=[i-1 for i in mid]
# for loop
for n in range(1,Nt):
u=np.zeros(Nx+1, dtype=float)
u[mid]=l2*CC[mid]*(u1[midp]-2*u1[mid]+u1[midm])+2*u1[mid]-u0[mid]+(dt**2)*f(xx[mid],tt[n])
u[0]=fa(tt[n+1])
u[Nx]=fb(tt[n+1])
u0=u1
u1=u
# end of the loop
# Norm
U_Comp = u
U_exact = Ue(xx,tt[-1])
Norm=LA.norm(U_Comp - U_exact, np.inf)
return Norm, U_exact, U_Comp
it=4
Norm=np.zeros(it, dtype=float)
Nx0=10;
Nt0=200;
Nx=np.asarray([Nx0*2**n for n in range(0,it)])
Nt=np.asarray([Nt0 for n in range(0,it)])
Ratio=np.zeros(it, dtype=float)
LOG=np.zeros(it, dtype=float)
CPU_Time=np.zeros(it, dtype=float)
# iteration
for n in range(it):
if n != (it-1):
start = timer()
Norm[n],_,_ =Example01_ExSolver1D(Nx[n],Nt[n])
CPU_Time[n] = timer() - start
else:
start = timer()
Norm[n], U_exact, U_Comp =Example01_ExSolver1D(Nx[n],Nt[n])
CPU_Time[n] = timer() - start
if (n>0):
Ratio[n]=Norm[n-1]/Norm[n]
LOG[n]=math.log(Ratio[n],2)
data = pd.DataFrame({'Nx': Nx+1, 'Nt': Nt+1, 'Norm': Norm, 'Ratio': Ratio, 'Log2': LOG, 'CPU Time': CPU_Time})
del it, Norm, Nx0, Nt0, Nx, Nt, Ratio, LOG, CPU_Time, n, start
display(data.style.format({'Norm': "{:.4e}"}))
Figs(U_exact, U_Comp, Scheme = 'Explicit Scheme', data = data)
Nx | Nt | Norm | Ratio | Log2 | CPU Time | |
---|---|---|---|---|---|---|
0 | 11 | 201 | 4.7653e-04 | 0.000000 | 0.000000 | 0.010921 |
1 | 21 | 201 | 1.1857e-04 | 4.018871 | 2.006790 | 0.011487 |
2 | 41 | 201 | 2.8054e-05 | 4.226541 | 2.079477 | 0.012813 |
3 | 81 | 201 | 5.4085e-06 | 5.187090 | 2.374925 | 0.014552 |
it=4
Norm=np.zeros(it, dtype=float)
Nx0=10;
Nt0=20;
Nx=np.asarray([Nx0*2**n for n in range(0,it)])
Nt=np.asarray([Nt0*2**n for n in range(0,it)])
Ratio=np.zeros(it, dtype=float)
LOG=np.zeros(it, dtype=float)
CPU_Time=np.zeros(it, dtype=float)
# iteration
for n in range(it):
if n != (it-1):
start = timer()
Norm[n],_,_ =Example01_ExSolver1D(Nx[n],Nt[n])
CPU_Time[n] = timer() - start
else:
start = timer()
Norm[n], U_exact, U_Comp =Example01_ExSolver1D(Nx[n],Nt[n])
CPU_Time[n] = timer() - start
if (n>0):
Ratio[n]=Norm[n-1]/Norm[n]
LOG[n]=math.log(Ratio[n],2)
data = pd.DataFrame({'Nx': Nx+1, 'Nt': Nt+1, 'Norm': Norm, 'Ratio': Ratio, 'Log2': LOG, 'CPU Time': CPU_Time})
del it, Norm, Nx0, Nt0, Nx, Nt, Ratio, LOG, CPU_Time, n, start
display(data.style.format({'Norm': "{:.4e}"}))
Figs(U_exact, U_Comp, Scheme = 'Explicit Scheme', data = data)
Nx | Nt | Norm | Ratio | Log2 | CPU Time | |
---|---|---|---|---|---|---|
0 | 11 | 21 | 2.6548e-04 | 0.000000 | 0.000000 | 0.001233 |
1 | 21 | 41 | 6.6948e-05 | 3.965520 | 1.987510 | 0.002561 |
2 | 41 | 81 | 1.6789e-05 | 3.987502 | 1.995485 | 0.005250 |
3 | 81 | 161 | 4.2064e-06 | 3.991334 | 1.996871 | 0.012856 |
What stands out from the tables is that the order of the method is 2 (space and time). To test the stability condition, we can try the following experiment.
it=4
Norm=np.zeros(it, dtype=float)
Nx0=10;
Nt0=8;
Nx=np.asarray([Nx0*2**n for n in range(0,it)])
Nt=np.asarray([Nt0*2**n for n in range(0,it)])
Ratio=np.zeros(it, dtype=float)
LOG=np.zeros(it, dtype=float)
CPU_Time=np.zeros(it, dtype=float)
# iteration
for n in range(it):
start = timer()
Norm[n],_,_ =Example01_ExSolver1D(Nx[n],Nt[n])
CPU_Time[n] = timer() - start
if (n>0):
Ratio[n]=Norm[n-1]/Norm[n]
LOG[n]=math.log(Ratio[n],2)
data = pd.DataFrame({'Nx': Nx+1, 'Nt': Nt+1, 'Norm': Norm, 'Ratio': Ratio, 'Log2': LOG, 'CPU Time': CPU_Time})
del it, Norm, Nx0, Nt0, Nx, Nt, Ratio, LOG, CPU_Time, n, start
display(data.style.format({'Norm': "{:.4e}"}))
Nx | Nt | Norm | Ratio | Log2 | CPU Time | |
---|---|---|---|---|---|---|
0 | 11 | 9 | 8.4073e-04 | 0.000000 | 0.000000 | 0.000546 |
1 | 21 | 17 | 3.3127e-02 | 0.025379 | -5.300234 | 0.001109 |
2 | 41 | 33 | 1.3026e+06 | 0.000000 | -25.228801 | 0.002212 |
3 | 81 | 65 | 1.5785e+23 | 0.000000 | -56.749932 | 0.005047 |
The table highlights that the stability criteria were violated.
def Example01_ImSolver1D(Nx,Nt):
# Nx = the number of mesh points for space
# Nt = the number of mesh points for time
# alpha, beta and gamma
alpha=1/4
beta=1/2
gamma=1/4
# [a,b] and [T1,T2]
a = 0.0
b = 1.0
T1 = 0.0
T2 = 1.0
# Functions
C2 =lambda x: np.exp(-x)
g=lambda x: np.exp(x)
h=lambda x: np.exp(x)
fa=lambda t: np.exp(t)
fb=lambda t: np.exp(t+1)
f=lambda x,t: np.exp(t + x) - np.exp(t)
Ue=lambda x,t: np.exp(x+t)
# Additional functions
gxx=lambda x: np.exp(x);
gxxxx=lambda x: np.exp(x);
hxx=lambda x: np.exp(x);
ft=lambda x,t: np.exp(t + x) - np.exp(t);
ftt=lambda x,t: np.exp(t + x) - np.exp(t);
# dx, dt and lambda^2
dx =(b-a)/Nx
dt =(T2-T1)/Nt
l2=(dt/dx)**2
# discretizing [a,b] and [T1,T2]
xx=np.linspace(a, b, Nx+1)
tt=np.linspace(T1, T2, Nt+1)
# dicretizing c^2(x)
CC=C2(xx)
# u initial time value
u0 = g(xx);
u=np.zeros(Nx+1, dtype=float)
u1=np.zeros(Nx+1, dtype=float)
# Computing the solution at the first time step
GG= g(xx)+h(xx)*dt+0.5*(C2(xx)*gxx(xx)+f(xx,T1))*(dt**2)+\
(1/6)*(C2(xx)*hxx(xx)+ft(xx,T1))*(dt**3)+(1/24)*(C2(xx)*gxxxx(xx)+ftt(xx,T1))*(dt**4)
u1[1:Nx]=GG[1:Nx]
u1[0]=fa(tt[1])
u1[Nx]=fb(tt[1])
# indeces
mid=list(range(1,Nx))
sup=list(range(1,Nx-1))
sub=list(range(2,Nx))
# Matrix A
A=diags([-alpha*CC[sub]*l2,1+2*alpha*CC[mid]*l2,-alpha*CC[sup]*l2], [-1,0,1])
# Matrix B
B=diags([beta*CC[sub]*l2,2-2*beta*CC[mid]*l2,beta*CC[sup]*l2], [-1,0,1])
# Matrix C
C=diags([gamma*CC[sub]*l2,-1-2*gamma*CC[mid]*l2,gamma*CC[sup]*l2], [-1,0,1])
# Fa and Fb
FA= fa(tt)
FB= fb(tt)
for n in range(1,Nt):
u=np.zeros(Nx+1, dtype=float)
bb=np.zeros(len(mid), dtype=float)
bb[0]=CC[1]*l2*(alpha*FA[n+1]+beta*FA[n]+gamma*FA[n-1])
bb[Nx-2]=CC[Nx-1]*l2*(alpha*FB[n+1]+beta*FB[n]+gamma*FB[n-1])
u[mid]=spsolve(A,B*u1[mid]+C*u0[mid]+bb+(dt**2)*f(xx[mid],tt[n]))
u[0]=fa(tt[n+1])
u[Nx]=fb(tt[n+1])
u0=u1
u1=u
# end of the loop
# Norm
U_Comp = u
U_exact = Ue(xx,tt[-1])
Norm=LA.norm(U_Comp - U_exact, np.inf)
return Norm, U_exact, U_Comp
it=4
Norm=np.zeros(it, dtype=float)
Nx0=10;
Nt0=200;
Nx=np.asarray([Nx0*2**n for n in range(0,it)])
Nt=np.asarray([Nt0 for n in range(0,it)])
Ratio=np.zeros(it, dtype=float)
LOG=np.zeros(it, dtype=float)
CPU_Time=np.zeros(it, dtype=float)
# iteration
for n in range(it):
if n != (it-1):
start = timer()
Norm[n],_,_ =Example01_ImSolver1D(Nx[n],Nt[n])
CPU_Time[n] = timer() - start
else:
start = timer()
Norm[n], U_exact, U_Comp =Example01_ImSolver1D(Nx[n],Nt[n])
CPU_Time[n] = timer() - start
if (n>0):
Ratio[n]=Norm[n-1]/Norm[n]
LOG[n]=math.log(Ratio[n],2)
data = pd.DataFrame({'Nx': Nx+1, 'Nt': Nt+1, 'Norm': Norm, 'Ratio': Ratio, 'Log2': LOG, 'CPU Time': CPU_Time})
del it, Norm, Nx0, Nt0, Nx, Nt, Ratio, LOG, CPU_Time, n, start
display(data.style.format({'Norm': "{:.4e}"}))
Figs(U_exact, U_Comp, Scheme = 'Explicit Scheme', data = data)
Nx | Nt | Norm | Ratio | Log2 | CPU Time | |
---|---|---|---|---|---|---|
0 | 11 | 201 | 4.8011e-04 | 0.000000 | 0.000000 | 0.040941 |
1 | 21 | 201 | 1.2219e-04 | 3.929173 | 1.974226 | 0.041312 |
2 | 41 | 201 | 3.1679e-05 | 3.857149 | 1.947535 | 0.043730 |
3 | 81 | 201 | 9.0324e-06 | 3.507299 | 1.810361 | 0.047310 |
it=4
Norm=np.zeros(it, dtype=float)
Nx0=200;
Nt0=10;
Nx=np.asarray([Nx0 for n in range(0,it)])
Nt=np.asarray([Nt0*2**n for n in range(0,it)])
Ratio=np.zeros(it, dtype=float)
LOG=np.zeros(it, dtype=float)
CPU_Time=np.zeros(it, dtype=float)
# iteration
for n in range(it):
if n != (it-1):
start = timer()
Norm[n],_,_ =Example01_ImSolver1D(Nx[n],Nt[n])
CPU_Time[n] = timer() - start
else:
start = timer()
Norm[n], U_exact, U_Comp =Example01_ImSolver1D(Nx[n],Nt[n])
CPU_Time[n] = timer() - start
if (n>0):
Ratio[n]=Norm[n-1]/Norm[n]
LOG[n]=math.log(Ratio[n],2)
data = pd.DataFrame({'Nx': Nx+1, 'Nt': Nt+1, 'Norm': Norm, 'Ratio': Ratio, 'Log2': LOG, 'CPU Time': CPU_Time})
del it, Norm, Nx0, Nt0, Nx, Nt, Ratio, LOG, CPU_Time, n, start
display(data.style.format({'Norm': "{:.4e}"}))
Figs(U_exact, U_Comp, Scheme = 'Explicit Scheme', data = data)
Nx | Nt | Norm | Ratio | Log2 | CPU Time | |
---|---|---|---|---|---|---|
0 | 201 | 11 | 5.8221e-04 | 0.000000 | 0.000000 | 0.004187 |
1 | 201 | 21 | 1.4861e-04 | 3.917749 | 1.970025 | 0.006380 |
2 | 201 | 41 | 3.8270e-05 | 3.883177 | 1.957238 | 0.012306 |
3 | 201 | 81 | 1.0496e-05 | 3.646092 | 1.866351 | 0.023832 |
For a fixed $N_t$, we have
it=4
Norm=np.zeros(it, dtype=float)
Nx0=10
Nt0=200
Nx=np.asarray([Nx0*2**n for n in range(0,it)])
Nt=np.asarray([Nt0 for n in range(0,it)])
#
Exact=np.zeros((it,Nx0+1), dtype=float)
Explicit_Scheme=np.zeros((it,Nx0+1), dtype=float)
Implicit_Scheme=np.zeros((it,Nx0+1), dtype=float)
#
for n in range(it):
_,U_exact, U_Comp = Example01_ExSolver1D(Nx[n],Nt[n])
Exact[n,:] = U_exact[0:(Nx[n]+1):(2**n)]
Explicit_Scheme[n,:]=U_Comp[0:(Nx[n]+1):(2**n)]
del U_exact, U_Comp
_,_,U_Comp =Example01_ImSolver1D(Nx[n],Nt[n])
Implicit_Scheme[n,:]=U_Comp[0:(Nx[n]+1):(2**n)]
del U_Comp
fig, ax = plt.subplots(nrows=2, ncols=1, figsize=(16, 12))
for n in range(it):
tag= "$Nx = %d$" % (Nx[n])
_ = ax[0].loglog(np.linspace(0, 1, Nx0+1), np.abs(Exact[n,:]-Explicit_Scheme[n,:]),label=tag)
_ = ax[0].legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0., fontsize = 14)
_ = ax[0].set_title('Explicit Scheme', fontsize = 14)
_ = ax[1].loglog(np.linspace(0, 1, Nx0+1), np.abs(Exact[n,:]-Implicit_Scheme[n,:]),label=tag)
_ = ax[1].legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0., fontsize = 14)
_ = ax[1].set_title('Implicit Scheme', fontsize = 14)
Das, Sambit, Wenyuan Liao, and Anirudh Gupta. "An efficient fourth-order low dispersive finite difference scheme for a 2-D acoustic wave equation." Journal of computational and Applied Mathematics 258 (2014): 151-167.
Liao, Wenyuan. "On the dispersion, stability and accuracy of a compact higher-order finite difference scheme for 3D acoustic wave equation." Journal of Computational and Applied Mathematics 270 (2014): 571-583.
Liao, Wenyuan. "An implicit fourth-order compact finite difference scheme for one-dimensional Burgers’ equation." Applied Mathematics and Computation 206.2 (2008): 755-764.