Skip to content

Commit d2bc3d6

Browse files
committed
Merge pull request #66 from danielru/add/rk_imex
Add/rk imex
2 parents cb5644d + c5b6626 commit d2bc3d6

File tree

6 files changed

+261
-30
lines changed

6 files changed

+261
-30
lines changed

examples/acoustic_1d_imex/plot_dispersion.py

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from pySDC.datatype_classes.complex_mesh import mesh, rhs_imex_mesh
77
from pySDC.sweeper_classes.imex_1st_order import imex_1st_order as imex
8-
from standard_integrators import dirk
8+
from standard_integrators import dirk, rk_imex
99
# for simplicity, import the scalar problem to generate Q matrices
1010
from examples.fwsw.ProblemClass import swfw_scalar
1111
import numpy as np
@@ -41,8 +41,8 @@ def findomega(stab_fh):
4141
pparams['u0'] = 1.0
4242
swparams = {}
4343
swparams['collocation_class'] = collclass.CollGaussLegendre
44-
swparams['num_nodes'] = 2
45-
K = 2
44+
swparams['num_nodes'] = 3
45+
K = 4
4646
dirk_order = K
4747

4848
c_speed = 1.0
@@ -68,8 +68,8 @@ def findomega(stab_fh):
6868
Nsamples = 30
6969
k_vec = np.linspace(0, np.pi, Nsamples+1, endpoint=False)
7070
k_vec = k_vec[1:]
71-
phase = np.zeros((2,Nsamples))
72-
amp_factor = np.zeros((2,Nsamples))
71+
phase = np.zeros((3,Nsamples))
72+
amp_factor = np.zeros((3,Nsamples))
7373
for i in range(0,np.size(k_vec)):
7474
Cs = -1j*k_vec[i]*np.array([[0.0, c_speed],[c_speed, 0.0]], dtype='complex')
7575
Uadv = -1j*k_vec[i]*np.array([[U_speed, 0.0], [0.0, U_speed]], dtype='complex')
@@ -85,8 +85,8 @@ def findomega(stab_fh):
8585
# ---> The update formula for this case need verification!!
8686
update = step.status.dt*np.kron( level.sweep.coll.weights, Uadv+Cs )
8787

88-
y1 = np.array([1,0])
89-
y2 = np.array([0,1])
88+
y1 = np.array([1,0], dtype='complex')
89+
y2 = np.array([0,1], dtype='complex')
9090
e1 = np.kron( np.ones(nnodes), y1 )
9191
stab_fh_1 = y1 + update.dot( Mat_sweep.dot(e1) )
9292
e2 = np.kron( np.ones(nnodes), y2 )
@@ -104,21 +104,31 @@ def findomega(stab_fh):
104104
stab_fh2 = dirkts.timestep(y2, 1.0)
105105
stab_dirk = np.column_stack((stab_fh1, stab_fh2))
106106

107+
rkimex = rk_imex(M_fast = Cs, M_slow = Uadv, order = K)
108+
stab_fh1 = rkimex.timestep(y1, 1.0)
109+
stab_fh2 = rkimex.timestep(y2, 1.0)
110+
stab_rk_imex = np.column_stack((stab_fh1, stab_fh2))
111+
107112
sol_sdc = findomega(stab_sdc)
108113
sol_dirk = findomega(stab_dirk)
114+
sol_rk_imex = findomega(stab_rk_imex)
109115

110116
# Now solve for discrete phase
111117
phase[0,i] = sol_sdc.real/k_vec[i]
112118
amp_factor[0,i] = np.exp(sol_sdc.imag)
113119
phase[1,i] = sol_dirk.real/k_vec[i]
114120
amp_factor[1,i] = np.exp(sol_dirk.imag)
121+
phase[2,i] = sol_rk_imex.real/k_vec[i]
122+
amp_factor[2,i] = np.exp(sol_rk_imex.imag)
123+
115124
###
116125
rcParams['figure.figsize'] = 1.5, 1.5
117126
fs = 8
118127
fig = plt.figure()
119128
plt.plot(k_vec, (U_speed+c_speed)+np.zeros(np.size(k_vec)), '--', color='k', linewidth=1.5, label='Exact')
120-
plt.plot(k_vec, phase[0,:], '-', color='b', linewidth=1.5, label='SDC('+str(K)+')')
121129
plt.plot(k_vec, phase[1,:], '-', color='g', linewidth=1.5, label='DIRK('+str(dirkts.order)+')')
130+
plt.plot(k_vec, phase[2,:], '-', color='r', linewidth=1.5, label='RK-IMEX('+str(rkimex.order)+')')
131+
plt.plot(k_vec, phase[0,:], '-', color='b', linewidth=1.5, label='SDC('+str(K)+')')
122132
plt.xlabel('Wave number', fontsize=fs, labelpad=0.25)
123133
plt.ylabel('Phase speed', fontsize=fs, labelpad=0.5)
124134
plt.xlim([k_vec[0], k_vec[-1:]])
@@ -133,8 +143,9 @@ def findomega(stab_fh):
133143

134144
fig = plt.figure()
135145
plt.plot(k_vec, 1.0+np.zeros(np.size(k_vec)), '--', color='k', linewidth=1.5, label='Exact')
136-
plt.plot(k_vec, amp_factor[0,:], '-', color='b', linewidth=1.5, label='SDC('+str(K)+')')
137146
plt.plot(k_vec, amp_factor[1,:], '-', color='g', linewidth=1.5, label='DIRK('+str(dirkts.order)+')')
147+
plt.plot(k_vec, amp_factor[2,:], '-', color='r', linewidth=1.5, label='RK-IMEX('+str(rkimex.order)+')')
148+
plt.plot(k_vec, amp_factor[0,:], '-', color='b', linewidth=1.5, label='SDC('+str(K)+')')
138149
plt.xlabel('Wave number', fontsize=fs, labelpad=0.25)
139150
plt.ylabel('Amplification factor', fontsize=fs, labelpad=0.5)
140151
fig.gca().tick_params(axis='both', labelsize=fs)

examples/acoustic_1d_imex/runmultiscale.py

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from pySDC import Log
1313
from pySDC.Stats import grep_stats, sort_stats
1414

15-
from standard_integrators import bdf2, dirk, trapezoidal
15+
from standard_integrators import bdf2, dirk, trapezoidal, rk_imex
1616

1717
from matplotlib import pyplot as plt
1818
from pylab import rcParams
@@ -32,7 +32,7 @@
3232
lparams['restol'] = 1E-10
3333

3434
sparams = {}
35-
sparams['maxiter'] = 4
35+
sparams['maxiter'] = 2
3636

3737
# setup parameters "in time"
3838
t0 = 0.0
@@ -59,7 +59,7 @@
5959
description['dtype_f'] = rhs_imex_mesh
6060
description['collocation_class'] = collclass.CollGaussLegendre
6161
# Number of nodes
62-
description['num_nodes'] = 3
62+
description['num_nodes'] = 2
6363
description['sweeper_class'] = imex_1st_order
6464
description['level_params'] = lparams
6565
description['hook_class'] = plot_solution
@@ -77,14 +77,16 @@
7777
uend,stats = mp.run_pfasst(MS,u0=uinit,t0=t0,dt=dt,Tend=Tend)
7878

7979
# instantiate standard integrators to be run for comparison
80-
trap = trapezoidal( P.A+P.Dx, 0.5 )
80+
trap = trapezoidal( (P.A+P.Dx).astype('complex'), 0.5 )
8181
bdf2 = bdf2( P.A+P.Dx)
82-
dirk = dirk( P.A+P.Dx, sparams['maxiter'])
83-
82+
dirk = dirk( (P.A+P.Dx).astype('complex'), sparams['maxiter'])
83+
rkimex = rk_imex(P.A.astype('complex'), P.Dx.astype('complex'), sparams['maxiter'])
84+
8485
y0_tp = np.concatenate( (uinit.values[0,:], uinit.values[1,:]) )
8586
y0_bdf = y0_tp
86-
y0_dirk = y0_tp
87-
87+
y0_dirk = y0_tp.astype('complex')
88+
y0_imex = y0_tp.astype('complex')
89+
8890
# Perform 154 time steps with standard integrators
8991
for i in range(0,154):
9092

@@ -101,15 +103,20 @@
101103
# DIRK scheme
102104
ynew_dirk = dirk.timestep(y0_dirk, dt)
103105

106+
# IMEX scheme
107+
ynew_imex = rkimex.timestep(y0_imex, dt)
108+
104109
y0_tp = ynew_tp
105110
ym1_bdf = y0_bdf
106111
y0_bdf = ynew_bdf
107112
y0_dirk = ynew_dirk
108-
113+
y0_imex = ynew_imex
114+
109115
# Finished running standard integrators
110116
unew_tp, pnew_tp = np.split(ynew_tp, 2)
111117
unew_bdf, pnew_bdf = np.split(ynew_bdf, 2)
112118
unew_dirk, pnew_dirk = np.split(ynew_dirk, 2)
119+
unew_imex, pnew_imex = np.split(ynew_imex, 2)
113120

114121
rcParams['figure.figsize'] = 5, 2.5
115122
fig = plt.figure()
@@ -119,8 +126,13 @@
119126
x_0 = 0.75
120127
x_1 = 0.25
121128

122-
plt.plot(P.mesh, pnew_tp, '-', color='c', label='Trapezoidal')
123-
plt.plot(P.mesh, uend.values[1,:], '-', color='b', label='SDC('+str(sparams['maxiter'])+')')
129+
print ('Maximum pressure in SDC: %5.3e' % np.linalg.norm(uend.values[1,:], np.inf))
130+
print ('Maximum pressure in DIRK: %5.3e' % np.linalg.norm(pnew_dirk, np.inf))
131+
print ('Maximum pressure in RK-IMEX: %5.3e' % np.linalg.norm(pnew_imex, np.inf))
132+
133+
#plt.plot(P.mesh, pnew_tp, '-', color='c', label='Trapezoidal')
134+
plt.plot(P.mesh, pnew_imex, '-', color='c', label='IMEX('+str(rkimex.order)+')')
135+
plt.plot(P.mesh, uend.values[1,:], '--', color='b', label='SDC('+str(sparams['maxiter'])+')')
124136
plt.plot(P.mesh, pnew_bdf, '-', color='r', label='BDF-2')
125137
plt.plot(P.mesh, pnew_dirk, color='g', label='DIRK('+str(dirk.order)+')')
126138
#plt.plot(P.mesh, uex.values[1,:], '+', color='r', label='p (exact)')

examples/acoustic_1d_imex/standard_integrators.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,101 @@
33
import scipy.sparse.linalg as LA
44
import scipy.sparse as sp
55

6+
#
7+
# Runge-Kutta IMEX methods of order 1 to 3
8+
#
9+
class rk_imex:
10+
11+
def __init__(self, M_fast, M_slow, order):
12+
assert np.shape(M_fast)[0]==np.shape(M_fast)[1], "A_fast must be square"
13+
assert np.shape(M_slow)[0]==np.shape(M_slow)[1], "A_slow must be square"
14+
assert np.shape(M_fast)[0]==np.shape(M_slow)[0], "A_fast and A_slow must be of the same size"
15+
16+
assert order in [1,2,3,4], "Order must be 1, 2, 3 or 4"
17+
self.order = order
18+
19+
if self.order==1:
20+
self.A = np.array([[0,0],[0,1]])
21+
self.A_hat = np.array([[0,0],[1,0]])
22+
self.b = np.array([0,1])
23+
self.b_hat = np.array([1,0])
24+
self.nstages = 2
25+
26+
elif self.order==2:
27+
self.A = np.array([[0,0],[0,0.5]])
28+
self.A_hat = np.array([[0,0],[0.5,0]])
29+
self.b = np.array([0,1])
30+
self.b_hat = np.array([0,1])
31+
self.nstages = 2
32+
33+
elif self.order==3:
34+
# parameter from Pareschi and Russo, J. Sci. Comp. 2005
35+
alpha = 0.24169426078821
36+
beta = 0.06042356519705
37+
eta = 0.12915286960590
38+
self.A_hat = np.array([ [0,0,0,0], [0,0,0,0], [0,1.0,0,0], [0, 1.0/4.0, 1.0/4.0, 0] ])
39+
self.A = np.array([ [alpha, 0, 0, 0], [-alpha, alpha, 0, 0], [0, 1.0-alpha, alpha, 0], [beta, eta, 0.5-beta-eta-alpha, alpha] ])
40+
self.b_hat = np.array([0, 1.0/6.0, 1.0/6.0, 2.0/3.0])
41+
self.b = self.b_hat
42+
self.nstages = 4
43+
44+
elif self.order==4:
45+
46+
self.A_hat = np.array([ [0,0,0,0,0,0],
47+
[1./2,0,0,0,0,0],
48+
[13861./62500.,6889./62500.,0,0,0,0],
49+
[-116923316275./2393684061468.,-2731218467317./15368042101831.,9408046702089./11113171139209.,0,0,0],
50+
[-451086348788./2902428689909.,-2682348792572./7519795681897.,12662868775082./11960479115383.,3355817975965./11060851509271.,0,0],
51+
[647845179188./3216320057751.,73281519250./8382639484533.,552539513391./3454668386233.,3354512671639./8306763924573.,4040./17871.,0]])
52+
self.A = np.array([[0,0,0,0,0,0],
53+
[1./4,1./4,0,0,0,0],
54+
[8611./62500.,-1743./31250.,1./4,0,0,0],
55+
[5012029./34652500.,-654441./2922500.,174375./388108.,1./4,0,0],
56+
[15267082809./155376265600.,-71443401./120774400.,730878875./902184768.,2285395./8070912.,1./4,0],
57+
[82889./524892.,0,15625./83664.,69875./102672.,-2260./8211,1./4]])
58+
self.b = np.array([82889./524892.,0,15625./83664.,69875./102672.,-2260./8211,1./4])
59+
self.b_hat = np.array([4586570599./29645900160.,0,178811875./945068544.,814220225./1159782912.,-3700637./11593932.,61727./225920.])
60+
self.nstages = 6
61+
62+
self.M_fast = sp.csc_matrix(M_fast)
63+
self.M_slow = sp.csc_matrix(M_slow)
64+
self.ndof = np.shape(M_fast)[0]
65+
66+
self.stages = np.zeros((self.nstages, self.ndof), dtype='complex')
67+
68+
def timestep(self, u0, dt):
69+
70+
# Solve for stages
71+
for i in range(0,self.nstages):
72+
73+
# Construct RHS
74+
rhs = np.copy(u0)
75+
for j in range(0,i):
76+
rhs += dt*self.A_hat[i,j]*(self.f_slow(self.stages[j,:])) + dt*self.A[i,j]*(self.f_fast(self.stages[j,:]))
77+
78+
# Solve for stage i
79+
if self.A[i,i] == 0:
80+
# Avoid call to spsolve with identity matrix
81+
self.stages[i,:] = np.copy(rhs)
82+
else:
83+
self.stages[i,:] = self.f_fast_solve( rhs, dt*self.A[i,i] )
84+
85+
# Update
86+
for i in range(0,self.nstages):
87+
u0 += dt*self.b_hat[i]*(self.f_slow(self.stages[i,:])) + dt*self.b[i]*(self.f_fast(self.stages[i,:]))
88+
89+
return u0
90+
91+
def f_slow(self, u):
92+
return self.M_slow.dot(u)
93+
94+
def f_fast(self, u):
95+
return self.M_fast.dot(u)
96+
97+
def f_fast_solve(self, rhs, alpha):
98+
L = sp.eye(self.ndof) - alpha*self.M_fast
99+
return LA.spsolve(L, rhs)
100+
6101
#
7102
# Trapezoidal rule
8103
#

examples/boussinesq_2d_imex/plotgmrescounter.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,23 @@
99
from unflatten import unflatten
1010

1111
if __name__ == "__main__":
12-
xx = np.load('xaxis.npy')
13-
uend = np.load('sdc.npy')
12+
xx = np.load('xaxis.npy')
13+
uend = np.load('sdc.npy')
1414
udirk = np.load('dirk.npy')
15+
uimex = np.load('rkimex.npy')
1516
uref = np.load('uref.npy')
1617

1718
print "Estimated discretisation error of DIRK: %5.3e" % ( np.linalg.norm(udirk.flatten() - uref.flatten(), np.inf)/np.linalg.norm(uref.flatten(),np.inf) )
1819
print "Estimated discretisation error of SDC: %5.3e" % ( np.linalg.norm(uend.flatten() - uref.flatten(), np.inf)/np.linalg.norm(uref.flatten(),np.inf) )
20+
print "Estimated discretisation error of RK-IMEX: %5.3e" % ( np.linalg.norm(uimex.flatten() - uref.flatten(), np.inf)/np.linalg.norm(uref.flatten(),np.inf) )
1921

2022
fs = 8
2123
rcParams['figure.figsize'] = 5.0, 2.5
2224
fig = plt.figure()
2325

2426
plt.plot(xx[:,5], udirk[2,:,5], '--', color='r', markersize=fs-2, label='DIRK', dashes=(3,3))
2527
plt.plot(xx[:,5], uend[2,:,5], '-', color='b', label='SDC')
26-
#plt.plot(xx[:,5], udirk2[2,:,5], '--', color='r', markersize=fs-2, label='DIRK(2)', dashes=(3,3))
28+
plt.plot(xx[:,5], uimex[2,:,5], '--', color='g', markersize=fs-2, label='RK-IMEX', dashes=(3,3))
2729
#plt.plot(xx[:,5], utrap[2,:,5], '--', color='k', markersize=fs-2, label='Trap', dashes=(3,3))
2830
plt.legend(loc='lower left', fontsize=fs, prop={'size':fs})
2931
plt.yticks(fontsize=fs)

examples/boussinesq_2d_imex/rungmrescounter.py

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
from unflatten import unflatten
2323

24-
from standard_integrators import dirk, bdf2, trapezoidal
24+
from standard_integrators import dirk, bdf2, trapezoidal, rk_imex
2525

2626
if __name__ == "__main__":
2727

@@ -47,13 +47,13 @@
4747
# setup parameters "in time"
4848
t0 = 0
4949
Tend = 3000
50-
Nsteps = 100
50+
Nsteps = 500
5151
dt = Tend/float(Nsteps)
5252

5353
# This comes as read-in for the problem class
5454
pparams = {}
55-
pparams['nvars'] = [(4,300,20)]
56-
#pparams['nvars'] = [(4,150,10)]
55+
pparams['nvars'] = [(4,450,30)]
56+
#pparams['nvars'] = [(4,300,30)]
5757
pparams['u_adv'] = 0.02
5858
pparams['c_s'] = 0.3
5959
pparams['Nfreq'] = 0.01
@@ -63,7 +63,7 @@
6363
pparams['order_upw'] = [5]
6464
pparams['gmres_maxiter'] = [500]
6565
pparams['gmres_restart'] = [10]
66-
pparams['gmres_tol'] = [1e-6]
66+
pparams['gmres_tol'] = [1e-9]
6767

6868
# This comes as read-in for the transfer operations
6969
tparams = {}
@@ -102,27 +102,43 @@
102102
for i in range(0,Nsteps):
103103
udirk = dirkp.timestep(udirk, dt)
104104

105+
Pref = P
106+
# For reference solution, increase GMRES tolerance
107+
Pref.gmes_tol = 1e-6
105108
dirkref = dirk(P, 4)
106109
uref = u0
107110
dt_ref = dt/10.0
108111
for i in range(0,10*Nsteps):
109112
uref = dirkref.timestep(uref, dt_ref)
113+
114+
rkimex = rk_imex(P, dirk_order)
115+
uimex = u0
116+
dt_imex = dt
117+
for i in range(0,Nsteps):
118+
uimex = rkimex.timestep(uimex, dt_imex)
110119

111120
# call main function to get things done...
112121
uend,stats = mp.run_pfasst(MS,u0=uinit,t0=t0,dt=dt,Tend=Tend)
113122
udirk = unflatten(udirk, 4, P.N[0], P.N[1])
123+
uimex = unflatten(uimex, 4, P.N[0], P.N[1])
114124
uref = unflatten(uref, 4, P.N[0], P.N[1])
115125

116126
np.save('xaxis', P.xx)
117127
np.save('sdc', uend.values)
118128
np.save('dirk', udirk)
129+
np.save('rkimex', uimex)
119130
np.save('uref', uref)
120131

121-
print " #### Logging report for DIRK-%1i #### " % dirk_order
132+
print " #### Logging report for DIRK-%1i #### " % dirkp.order
122133
print "Number of calls to implicit solver: %5i" % dirkp.logger.solver_calls
123134
print "Total number of GMRES iterations: %5i" % dirkp.logger.iterations
124135
print "Average number of iterations per call: %6.3f" % (float(dirkp.logger.iterations)/float(dirkp.logger.solver_calls))
125-
136+
print " "
137+
print " #### Logging report for RK-IMEX-%1i #### " % rkimex.order
138+
print "Number of calls to implicit solver: %5i" % rkimex.logger.solver_calls
139+
print "Total number of GMRES iterations: %5i" % rkimex.logger.iterations
140+
print "Average number of iterations per call: %6.3f" % (float(rkimex.logger.iterations)/float(rkimex.logger.solver_calls))
141+
print " "
126142
print " #### Logging report for SDC-(%1i,%1i) #### " % (swparams['num_nodes'], sparams['maxiter'])
127143
print "Number of calls to implicit solver: %5i" % P.logger.solver_calls
128144
print "Total number of GMRES iterations: %5i" % P.logger.iterations

0 commit comments

Comments
 (0)