Skip to content

Commit c0b7c01

Browse files
committed
added function to produce the finite difference matrices studied in the paper by De Sterck et al., NLAA 2021
1 parent b390f5c commit c0b7c01

File tree

3 files changed

+106
-11
lines changed

3 files changed

+106
-11
lines changed

scripts/pseudo-spectrum/figure_5-8-loglog.py

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def trap(z):
4343
Tend, nslices, maxiter, nfine, ncoarse, tol, epsilon, ndof_f = par.getpar()
4444

4545
nsteps = [1, 2, 4, 8, 12, 16, 20]
46-
nsteps = [1, 10, 25, 50, 75, 100]
46+
#nsteps = [10, 100, 1000, 10000, 100000]
4747

4848
ndof_c_v = [16, 24, 30]
4949
xaxis_f = np.linspace(0.0, 1.0, ndof_f+1)[0:ndof_f]
@@ -52,6 +52,8 @@ def trap(z):
5252
if figure==5:
5353
A_f = get_upwind(ndof_f, dx_f)
5454
u0fine = solution_linear(np.zeros(ndof_f), A_f)
55+
D = A_f*A_f.H - A_f.H*A_f
56+
print("Normality number of the system matrix (this should be zero): %5.3f" % np.linalg.norm(D.todense()))
5557
elif figure==6 or figure==7:
5658
A_f = get_centered(ndof_f, dx_f)
5759
u0fine = solution_linear(np.zeros(ndof_f), A_f)
@@ -78,15 +80,15 @@ def trap(z):
7880
if figure==5:
7981
A_c = get_upwind(ndof_c, dx_c)
8082
u0coarse = solution_linear(np.zeros(ndof_c), A_c)
81-
filename = 'figure_5.pdf'
83+
filename = 'figure_5_mod.pdf'
8284
elif figure==6:
8385
A_c = get_centered(ndof_c, dx_c)
8486
u0coarse = solution_linear(np.zeros(ndof_c), A_c)
85-
filename = 'figure_6.pdf'
87+
filename = 'figure_6_mod.pdf'
8688
elif figure==7:
8789
A_c = get_centered(ndof_c, dx_c)
8890
u0coarse = solution_linear(np.zeros(ndof_c), A_c)
89-
filename = 'figure_7.pdf'
91+
filename = 'figure_7_mod.pdf'
9092
elif figure==8:
9193
u0coarse = solution_dedalus(np.zeros(ndof_c), ndof_c)
9294
filename = 'figure_8.pdf'
@@ -109,24 +111,21 @@ def trap(z):
109111
Pmat, Bmat = para.get_parareal_matrix()
110112
dt_f_v[0,mm] = para.timemesh.slices[0].int_fine.dt
111113
dt_c_v[0,mm] = para.timemesh.slices[0].int_coarse.dt
112-
113114
# Sort according to absolute values of R(z) with z = lambda*dt_f
114115
sort_index = np.argsort(np.abs(Rz(eig_val*dt_f_v[0,mm])))
115116

116117
# Store eigenvalue ndof_c+1. first "truncated" EV
117-
A_f_eig[nn,mm] = np.flip((eig_val[sort_index]))[ndof_c+1]
118-
118+
A_f_eig[nn,mm] = np.flip((eig_val[sort_index]))[ndof_c]
119119
### Parareal iteration: y^k+1 = Pmat*y^k + Bmat*b
120120
norm_l2[nn,mm] = np.linalg.norm(Pmat.todense(), 2)
121-
122121

123122
rcParams['figure.figsize'] = 2.5, 2.5
124123
fs = 8
125124
ms = 4
126125
fig = plt.figure(1)
127-
plt.loglog(dt_f_v[0,:], norm_l2[0,:]-np.abs(np.exp(np.multiply(A_f_eig[0,:],dt_f_v[0,:]))), 'bo-', label='m='+str(ndof_c_v[0]), markersize=ms)
128-
plt.loglog(dt_f_v[0,:], norm_l2[1,:]-np.abs(np.exp(np.multiply(A_f_eig[1,:],dt_f_v[0,:]))), 'rx-', label='m='+str(ndof_c_v[1]), markersize=ms)
129-
plt.loglog(dt_f_v[0,:], norm_l2[2,:]-np.abs(np.exp(np.multiply(A_f_eig[2,:],dt_f_v[0,:]))), 'cd-', label='m='+str(ndof_c_v[2]), markersize=ms)
126+
plt.loglog(dt_f_v[0,:], norm_l2[0,:]-np.abs(np.exp(np.multiply(A_f_eig[0,:],np.multiply(dt_f_v[0,:],nsteps[:])))), 'bo-', label='m='+str(ndof_c_v[0]), markersize=ms)
127+
plt.loglog(dt_f_v[0,:], norm_l2[1,:]-np.abs(np.exp(np.multiply(A_f_eig[1,:],np.multiply(dt_f_v[0,:],nsteps[:])))), 'rx-', label='m='+str(ndof_c_v[1]), markersize=ms)
128+
plt.loglog(dt_f_v[0,:], norm_l2[2,:]-np.abs(np.exp(np.multiply(A_f_eig[2,:],np.multiply(dt_f_v[0,:],nsteps[:])))), 'cd-', label='m='+str(ndof_c_v[2]), markersize=ms)
130129
plt.legend(loc='best', bbox_to_anchor=(0.5, 0.5), fontsize=fs, prop={'size':fs-2}, handlelength=3)
131130
plt.xlabel(r'$\delta t = \Delta t$', fontsize=fs)
132131
plt.ylabel(r'$|| \mathbf{E} ||_2 - | \exp(\lambda_{m+1} \delta t) |$', fontsize=fs)

src/get_matrix.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,35 @@ def get_diffusion(n,h):
2828
col[-1] = 1.0
2929
A = (1.0/h**2)*spla.circulant(col)
3030
return sp.csc_matrix(A)
31+
32+
def get_desterck(n, h, p):
33+
col = np.zeros(n)
34+
if p==2:
35+
col[0] = 3.0
36+
col[1] = -4.0
37+
col[2] = 1-0
38+
A = -1.0/(2.0*h)*spla.circulant(col)
39+
elif p==3:
40+
col[0] = 3.0
41+
col[1] = -6.0
42+
col[2] = 1.0
43+
col[-1] = 2.0
44+
A = -1.0/(6.0*h)*spla.circulant(col)
45+
elif p==4:
46+
col[0] = 10.0
47+
col[1] = -18.0
48+
col[2] = 6.0
49+
col[3] = -1.0
50+
col[-1] = 3.0
51+
A = -1.0/(12.0*h)*spla.circulant(col)
52+
elif p==5:
53+
col[0] = 20.0
54+
col[1] = -60.0
55+
col[2] = 15.0
56+
col[3] = -2.0
57+
col[-1] = 30.0
58+
col[-2] = -3.0
59+
A = -1.0/(60.0*h)*spla.circulant(col)
60+
else:
61+
sys.exit("Do not have coefficients for requested p")
62+
return sp.csc_matrix(A)

tests/test_getmatrix.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import sys
2+
sys.path.append('./src')
3+
4+
import pytest
5+
import numpy as np
6+
from get_matrix import get_upwind, get_centered, get_diffusion, get_desterck
7+
8+
class TestClass:
9+
10+
def f(x):
11+
return np.sin(2.0*np.pi*x)
12+
13+
def minus_fx(x):
14+
return -2.0*np.pi*np.cos(2.0*np.pi*x)
15+
16+
def fxx(x):
17+
return -4.0*np.pi**2*np.sin(2.0*np.pi*x)
18+
19+
def setUp(self):
20+
self.ndof = 256
21+
self.xaxis = np.linspace(0.0, 1.0, self.ndof+1)[0:self.ndof]
22+
self.dx = self.xaxis[1] - self.xaxis[0]
23+
self.u = TestClass.f(self.xaxis)
24+
self.ux = TestClass.minus_fx(self.xaxis)
25+
self.uxx = TestClass.fxx(self.xaxis)
26+
27+
'''
28+
The following tests confirm that the finite difference provide an approximation that is within
29+
some fixed tolerance to the analytic solution
30+
'''
31+
32+
def testUpwindIsAccurate(self):
33+
self.setUp()
34+
A = get_upwind(self.ndof, self.dx)
35+
ux_fd = A*self.u
36+
err = np.linalg.norm(self.ux - ux_fd, np.inf)
37+
assert err < 1e-1, "Upwind finite difference seems inaccurate"
38+
39+
def testCenteredIsAccurate(self):
40+
self.setUp()
41+
A = get_centered(self.ndof, self.dx)
42+
ux_fd = A*self.u
43+
err = np.linalg.norm(self.ux - ux_fd, np.inf)
44+
assert err < 1e-2, "Centered finite difference seems inaccurate"
45+
46+
def testDiffusionIsAccurate(self):
47+
self.setUp()
48+
A = get_diffusion(self.ndof, self.dx)
49+
uxx_fd = A*self.u
50+
err = np.linalg.norm(self.uxx - uxx_fd, np.inf)
51+
assert err < 1e-2, "Centered finite difference for diffusion seems inaccurate"
52+
53+
def testDeSterckIsAccurate(self):
54+
self.setUp()
55+
tols = [2e-2, 8e-6, 2e-7, 1e-9]
56+
for p in range(4):
57+
A = get_desterck(self.ndof, self.dx, p+2)
58+
ux_fd = A*self.u
59+
err = np.linalg.norm(self.ux - ux_fd, np.inf)
60+
assert err < tols[p], ("Order %i of De Sterck et al finite difference seems inaccurate" % (p+2))
61+
62+
63+
64+

0 commit comments

Comments
 (0)