Skip to content

Commit 1c320ba

Browse files
author
Daniel Ruprecht
committed
adds function get_scalar_problems_manysweep_mat to imex_sweeper which generates a matrix representing K many sweeps of IMEX-SDC; modified test_imexsweeper to test that this formulation is equivalent to K sweeps using update_nodes
1 parent 9a4a9ee commit 1c320ba

File tree

3 files changed

+24
-27
lines changed

3 files changed

+24
-27
lines changed

examples/fwsw/plot_stability.py

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
N_s = 100
1919
N_f = 400
2020

21-
lam_s_max = 12.0
22-
lam_f_max = 24.0
21+
lam_s_max = 3.0
22+
lam_f_max = 12.0
2323
lambda_s = 1j*np.linspace(0.0, lam_s_max, N_s)
2424
lambda_f = 1j*np.linspace(0.0, lam_f_max, N_f)
2525

@@ -31,7 +31,7 @@
3131
swparams = {}
3232
swparams['collocation_class'] = collclass.CollGaussLegendre
3333
swparams['num_nodes'] = 3
34-
K = 0
34+
K = 3
3535
do_coll_update = True
3636

3737
#
@@ -47,10 +47,6 @@
4747
nnodes = step.levels[0].sweep.coll.num_nodes
4848
level = step.levels[0]
4949
problem = level.prob
50-
51-
QE = level.sweep.QE[1:,1:]
52-
QI = level.sweep.QI[1:,1:]
53-
Q = level.sweep.coll.Qmat[1:,1:]
5450

5551
stab = np.zeros((N_f, N_s), dtype='complex')
5652

@@ -59,15 +55,9 @@
5955
lambda_fast = lambda_f[j]
6056
lambda_slow = lambda_s[i]
6157
if K is not 0:
62-
63-
LHS = np.eye(nnodes) - step.status.dt*( lambda_fast*QI + lambda_slow*QE )
64-
RHS = step.status.dt*( (lambda_fast+lambda_slow)*Q - (lambda_fast*QI + lambda_slow*QE) )
65-
66-
Pinv = np.linalg.inv(LHS)
67-
Mat_sweep = np.linalg.matrix_power(Pinv.dot(RHS), K)
68-
for k in range(0,K):
69-
Mat_sweep = Mat_sweep + np.linalg.matrix_power(Pinv.dot(RHS),k).dot(Pinv)
70-
58+
lambdas = [ lambda_fast, lambda_slow ]
59+
LHS, RHS = level.sweep.get_scalar_problems_sweeper_mats( lambdas = lambdas )
60+
Mat_sweep = level.sweep.get_scalar_problems_manysweep_mat( nsweeps = K, lambdas = lambdas )
7161
else:
7262
# Compute stability function of collocation solution
7363
Mat_sweep = np.linalg.inv(np.eye(nnodes)-step.status.dt*(lambda_fast + lambda_slow)*Q)

pySDC/sweeper_classes/imex_1st_order.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ def get_scalar_problems_sweeper_mats(self, lambdas=[None, None]):
169169
"""
170170
For a scalar problem, an IMEX-SDC sweep can be written in matrix formulation. This function returns the corresponding matrices.
171171
See Ruprecht & Speck, ``Spectral deferred corrections with fast-wave slow-wave splitting'', 2016 for the derivation.
172+
173+
The first entry in lambdas is lambda_fast, the second is lambda_slow.
172174
"""
173175
QE, QI, Q = self.get_sweeper_mats()
174176
if lambdas==[None,None]:
@@ -178,9 +180,19 @@ def get_scalar_problems_sweeper_mats(self, lambdas=[None, None]):
178180
else:
179181
lambda_fast = lambdas[0]
180182
lambda_slow = lambdas[1]
181-
assert abs(lambda_slow)<=abs(lambda_fast), "First entry in parameter lambdas (lambda_fast) has to be greater than second entry (lambda_slow)"
182183
nnodes = self.coll.num_nodes
183184
dt = self.level.dt
184185
LHS = np.eye(nnodes) - dt*( lambda_fast*QI + lambda_slow*QE )
185186
RHS = dt*( (lambda_fast+lambda_slow)*Q - (lambda_fast*QI + lambda_slow*QE) )
186187
return LHS, RHS
188+
189+
def get_scalar_problems_manysweep_mat(self, nsweeps, lambdas=[None,None]):
190+
"""
191+
For a scalar problem, K sweeps of IMEX-SDC can be written in matrix form.
192+
"""
193+
LHS, RHS = self.get_scalar_problems_sweeper_mats(lambdas = lambdas)
194+
Pinv = np.linalg.inv(LHS)
195+
Mat_sweep = np.linalg.matrix_power(Pinv.dot(RHS), nsweeps)
196+
for k in range(0,nsweeps):
197+
Mat_sweep += np.linalg.matrix_power(Pinv.dot(RHS), k).dot(Pinv)
198+
return Mat_sweep

tests/test_imexsweeper.py

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -116,21 +116,22 @@ def test_sweepequalmatrix(self):
116116
def test_updateformula(self):
117117
for type in classes:
118118
self.swparams['collocation_class'] = getattr(pySDC.CollocationClasses, type)
119+
119120
step, level, problem, nnodes = self.setupLevelStepProblem()
120121
level.sweep.predict()
121122
u0full = np.array([ level.u[l].values.flatten() for l in range(1,nnodes+1) ])
122123

123124
# Perform update step in sweeper
124125
level.sweep.update_nodes()
125126
ustages = np.array([ level.u[l].values.flatten() for l in range(1,nnodes+1) ])
126-
127127
# Compute end value through provided function
128128
level.sweep.compute_end_point()
129129
uend_sweep = level.uend.values
130130
# Compute end value from matrix formulation
131131
uend_mat = self.pparams['u0'] + step.status.dt*level.sweep.coll.weights.dot(ustages*(problem.lambda_s[0] + problem.lambda_f[0]))
132132
assert np.linalg.norm(uend_sweep - uend_mat, np.infty)<1e-14, "Update formula in sweeper gives different result than matrix update formula"
133133

134+
134135
#
135136
# Compute the exact collocation solution by matrix inversion and make sure it is a fixed point
136137
#
@@ -193,11 +194,7 @@ def test_manysweepsequalmatrix(self):
193194

194195
assert np.linalg.norm(unew - usweep, np.infty)<1e-14, "Doing multiple node-to-node sweeps yields different result than same number of matrix-form sweeps"
195196

196-
# Build single matrix representing K sweeps
197-
Pinv = np.linalg.inv(LHS)
198-
Mat_sweep = np.linalg.matrix_power(Pinv.dot(RHS), K)
199-
for i in range(0,K):
200-
Mat_sweep = Mat_sweep + np.linalg.matrix_power(Pinv.dot(RHS),i).dot(Pinv)
197+
Mat_sweep = level.sweep.get_scalar_problems_manysweep_mat( nsweeps = K, lambdas = lambdas )
201198
usweep_onematrix = Mat_sweep.dot(u0full)
202199
assert np.linalg.norm( usweep_onematrix - usweep, np.infty )<1e-14, "Single-matrix multiple sweep formulation yields different result than multiple sweeps in node-to-node or matrix form form"
203200

@@ -208,6 +205,7 @@ def test_manysweepsequalmatrix(self):
208205
def test_manysweepupdate(self):
209206
for type in classes:
210207
self.swparams['collocation_class'] = getattr(pySDC.CollocationClasses, type)
208+
211209
step, level, problem, nnodes = self.setupLevelStepProblem()
212210
step.levels[0].sweep.predict()
213211
u0full = np.array([ level.u[l].values.flatten() for l in range(1,nnodes+1) ])
@@ -224,10 +222,7 @@ def test_manysweepupdate(self):
224222
LHS, RHS = level.sweep.get_scalar_problems_sweeper_mats( lambdas = lambdas )
225223

226224
# Build single matrix representing K sweeps
227-
Pinv = np.linalg.inv(LHS)
228-
Mat_sweep = np.linalg.matrix_power(Pinv.dot(RHS), K)
229-
for i in range(0,K):
230-
Mat_sweep = Mat_sweep + np.linalg.matrix_power(Pinv.dot(RHS),i).dot(Pinv)
225+
Mat_sweep = level.sweep.get_scalar_problems_manysweep_mat( nsweeps = K, lambdas = lambdas )
231226
# Now build update function
232227
update = 1.0 + (problem.lambda_s[0] + problem.lambda_f[0])*level.sweep.coll.weights.dot(Mat_sweep.dot(np.ones(nnodes)))
233228
# Multiply u0 by value of update function to get end value directly

0 commit comments

Comments
 (0)