Coverage for pySDC/implementations/problem_classes/boussinesq_helpers/standard_integrators.py: 0%
394 statements
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-20 14:51 +0000
« prev ^ index » next coverage.py v7.6.9, created at 2024-12-20 14:51 +0000
1import math
2from decimal import Decimal, getcontext
4import numpy as np
5import scipy.sparse as sp
6from scipy.sparse.linalg import gmres
8from pySDC.implementations.problem_classes.Boussinesq_2D_FD_imex import boussinesq_2d_imex
9from pySDC.implementations.problem_classes.boussinesq_helpers.helper_classes import logging, Callback
12#
13# Runge-Kutta IMEX methods of order 1 to 3
14#
15class rk_imex:
16 def __init__(self, problem, order):
17 assert order in [1, 2, 3, 4, 5], "Order must be between 1 and 5"
18 self.order = order
20 if self.order == 1:
21 self.A = np.array([[0, 0], [0, 1]])
22 self.A_hat = np.array([[0, 0], [1, 0]])
23 self.b = np.array([0, 1])
24 self.b_hat = np.array([1, 0])
25 self.nstages = 2
27 elif self.order == 2:
28 self.A = np.array([[0, 0], [0, 0.5]])
29 self.A_hat = np.array([[0, 0], [0.5, 0]])
30 self.b = np.array([0, 1])
31 self.b_hat = np.array([0, 1])
32 self.nstages = 2
34 elif self.order == 3:
35 # parameter from Pareschi and Russo, J. Sci. Comp. 2005
36 alpha = 0.24169426078821
37 beta = 0.06042356519705
38 eta = 0.12915286960590
39 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]])
40 self.A = np.array(
41 [
42 [alpha, 0, 0, 0],
43 [-alpha, alpha, 0, 0],
44 [0, 1.0 - alpha, alpha, 0],
45 [beta, eta, 0.5 - beta - eta - alpha, alpha],
46 ]
47 )
48 self.b_hat = np.array([0, 1.0 / 6.0, 1.0 / 6.0, 2.0 / 3.0])
49 self.b = self.b_hat
50 self.nstages = 4
52 elif self.order == 4:
53 self.A_hat = np.array(
54 [
55 [0, 0, 0, 0, 0, 0],
56 [1.0 / 2, 0, 0, 0, 0, 0],
57 [13861.0 / 62500.0, 6889.0 / 62500.0, 0, 0, 0, 0],
58 [
59 -116923316275.0 / 2393684061468.0,
60 -2731218467317.0 / 15368042101831.0,
61 9408046702089.0 / 11113171139209.0,
62 0,
63 0,
64 0,
65 ],
66 [
67 -451086348788.0 / 2902428689909.0,
68 -2682348792572.0 / 7519795681897.0,
69 12662868775082.0 / 11960479115383.0,
70 3355817975965.0 / 11060851509271.0,
71 0,
72 0,
73 ],
74 [
75 647845179188.0 / 3216320057751.0,
76 73281519250.0 / 8382639484533.0,
77 552539513391.0 / 3454668386233.0,
78 3354512671639.0 / 8306763924573.0,
79 4040.0 / 17871.0,
80 0,
81 ],
82 ]
83 )
84 self.A = np.array(
85 [
86 [0, 0, 0, 0, 0, 0],
87 [1.0 / 4, 1.0 / 4, 0, 0, 0, 0],
88 [8611.0 / 62500.0, -1743.0 / 31250.0, 1.0 / 4, 0, 0, 0],
89 [5012029.0 / 34652500.0, -654441.0 / 2922500.0, 174375.0 / 388108.0, 1.0 / 4, 0, 0],
90 [
91 15267082809.0 / 155376265600.0,
92 -71443401.0 / 120774400.0,
93 730878875.0 / 902184768.0,
94 2285395.0 / 8070912.0,
95 1.0 / 4,
96 0,
97 ],
98 [82889.0 / 524892.0, 0, 15625.0 / 83664.0, 69875.0 / 102672.0, -2260.0 / 8211, 1.0 / 4],
99 ]
100 )
101 self.b = np.array([82889.0 / 524892.0, 0, 15625.0 / 83664.0, 69875.0 / 102672.0, -2260.0 / 8211, 1.0 / 4])
102 self.b_hat = np.array(
103 [
104 4586570599.0 / 29645900160.0,
105 0,
106 178811875.0 / 945068544.0,
107 814220225.0 / 1159782912.0,
108 -3700637.0 / 11593932.0,
109 61727.0 / 225920.0,
110 ]
111 )
112 self.nstages = 6
114 elif self.order == 5:
115 # from Kennedy and Carpenter
116 # copied from http://www.mcs.anl.gov/petsc/petsc-3.2/src/ts/impls/arkimex/arkimex.c
117 self.A_hat = np.zeros((8, 8))
118 getcontext().prec = 56
119 self.A_hat[1, 0] = Decimal(41.0) / Decimal(100.0)
120 self.A_hat[2, 0] = Decimal(367902744464.0) / Decimal(2072280473677.0)
121 self.A_hat[2, 1] = Decimal(677623207551.0) / Decimal(8224143866563.0)
122 self.A_hat[3, 0] = Decimal(1268023523408.0) / Decimal(10340822734521.0)
123 self.A_hat[3, 1] = 0.0
124 self.A_hat[3, 2] = Decimal(1029933939417.0) / Decimal(13636558850479.0)
125 self.A_hat[4, 0] = Decimal(14463281900351.0) / Decimal(6315353703477.0)
126 self.A_hat[4, 1] = 0.0
127 self.A_hat[4, 2] = Decimal(66114435211212.0) / Decimal(5879490589093.0)
128 self.A_hat[4, 3] = Decimal(-54053170152839.0) / Decimal(4284798021562.0)
129 self.A_hat[5, 0] = Decimal(14090043504691.0) / Decimal(34967701212078.0)
130 self.A_hat[5, 1] = 0.0
131 self.A_hat[5, 2] = Decimal(15191511035443.0) / Decimal(11219624916014.0)
132 self.A_hat[5, 3] = Decimal(-18461159152457.0) / Decimal(12425892160975.0)
133 self.A_hat[5, 4] = Decimal(-281667163811.0) / Decimal(9011619295870.0)
134 self.A_hat[6, 0] = Decimal(19230459214898.0) / Decimal(13134317526959.0)
135 self.A_hat[6, 1] = 0.0
136 self.A_hat[6, 2] = Decimal(21275331358303.0) / Decimal(2942455364971.0)
137 self.A_hat[6, 3] = Decimal(-38145345988419.0) / Decimal(4862620318723.0)
138 self.A_hat[6, 4] = Decimal(-1.0) / Decimal(8.0)
139 self.A_hat[6, 5] = Decimal(-1.0) / Decimal(8.0)
140 self.A_hat[7, 0] = Decimal(-19977161125411.0) / Decimal(11928030595625.0)
141 self.A_hat[7, 1] = 0.0
142 self.A_hat[7, 2] = Decimal(-40795976796054.0) / Decimal(6384907823539.0)
143 self.A_hat[7, 3] = Decimal(177454434618887.0) / Decimal(12078138498510.0)
144 self.A_hat[7, 4] = Decimal(782672205425.0) / Decimal(8267701900261.0)
145 self.A_hat[7, 5] = Decimal(-69563011059811.0) / Decimal(9646580694205.0)
146 self.A_hat[7, 6] = Decimal(7356628210526.0) / Decimal(4942186776405.0)
148 self.b_hat = np.zeros(8)
149 self.b_hat[0] = Decimal(-872700587467.0) / Decimal(9133579230613.0)
150 self.b_hat[1] = 0.0
151 self.b_hat[2] = 0.0
152 self.b_hat[3] = Decimal(22348218063261.0) / Decimal(9555858737531.0)
153 self.b_hat[4] = Decimal(-1143369518992.0) / Decimal(8141816002931.0)
154 self.b_hat[5] = Decimal(-39379526789629.0) / Decimal(19018526304540.0)
155 self.b_hat[6] = Decimal(32727382324388.0) / Decimal(42900044865799.0)
156 self.b_hat[7] = Decimal(41.0) / Decimal(200.0)
158 self.A = np.zeros((8, 8))
159 self.A[1, 0] = Decimal(41.0) / Decimal(200.0)
160 self.A[1, 1] = Decimal(41.0) / Decimal(200.0)
161 self.A[2, 0] = Decimal(41.0) / Decimal(400.0)
162 self.A[2, 1] = Decimal(-567603406766.0) / Decimal(11931857230679.0)
163 self.A[2, 2] = Decimal(41.0) / Decimal(200.0)
164 self.A[3, 0] = Decimal(683785636431.0) / Decimal(9252920307686.0)
165 self.A[3, 1] = 0.0
166 self.A[3, 2] = Decimal(-110385047103.0) / Decimal(1367015193373.0)
167 self.A[3, 3] = Decimal(41.0) / Decimal(200.0)
168 self.A[4, 0] = Decimal(3016520224154.0) / Decimal(10081342136671.0)
169 self.A[4, 1] = 0.0
170 self.A[4, 2] = Decimal(30586259806659.0) / Decimal(12414158314087.0)
171 self.A[4, 3] = Decimal(-22760509404356.0) / Decimal(11113319521817.0)
172 self.A[4, 4] = Decimal(41.0) / Decimal(200.0)
173 self.A[5, 0] = Decimal(218866479029.0) / Decimal(1489978393911.0)
174 self.A[5, 1] = 0.0
175 self.A[5, 2] = Decimal(638256894668.0) / Decimal(5436446318841.0)
176 self.A[5, 3] = Decimal(-1179710474555.0) / Decimal(5321154724896.0)
177 self.A[5, 4] = Decimal(-60928119172.0) / Decimal(8023461067671.0)
178 self.A[5, 5] = Decimal(41.0) / Decimal(200.0)
179 self.A[6, 0] = Decimal(1020004230633.0) / Decimal(5715676835656.0)
180 self.A[6, 1] = 0.0
181 self.A[6, 2] = Decimal(25762820946817.0) / Decimal(25263940353407.0)
182 self.A[6, 3] = Decimal(-2161375909145.0) / Decimal(9755907335909.0)
183 self.A[6, 4] = Decimal(-211217309593.0) / Decimal(5846859502534.0)
184 self.A[6, 5] = Decimal(-4269925059573.0) / Decimal(7827059040749.0)
185 self.A[6, 6] = Decimal(41.0) / Decimal(200.0)
186 self.A[7, 0] = Decimal(-872700587467.0) / Decimal(9133579230613.0)
187 self.A[7, 1] = 0.0
188 self.A[7, 2] = 0.0
189 self.A[7, 3] = Decimal(22348218063261.0) / Decimal(9555858737531.0)
190 self.A[7, 4] = Decimal(-1143369518992.0) / Decimal(8141816002931.0)
191 self.A[7, 5] = Decimal(-39379526789629.0) / Decimal(19018526304540.0)
192 self.A[7, 6] = Decimal(32727382324388.0) / Decimal(42900044865799.0)
193 self.A[7, 7] = Decimal(41.0) / Decimal(200.0)
195 self.b = np.zeros(8)
197 self.b[0] = Decimal(-975461918565.0) / Decimal(9796059967033.0)
198 self.b[1] = 0.0
199 self.b[2] = 0.0
200 self.b[3] = Decimal(78070527104295.0) / Decimal(32432590147079.0)
201 self.b[4] = Decimal(-548382580838.0) / Decimal(3424219808633.0)
202 self.b[5] = Decimal(-33438840321285.0) / Decimal(15594753105479.0)
203 self.b[6] = Decimal(3629800801594.0) / Decimal(4656183773603.0)
204 self.b[7] = Decimal(4035322873751.0) / Decimal(18575991585200.0)
206 self.nstages = 8
208 self.problem = problem
209 self.ndof = np.shape(problem.M)[0]
210 self.logger = logging()
211 self.stages = np.zeros((self.nstages, self.ndof))
213 def timestep(self, u0, dt):
214 # Solve for stages
215 for i in range(0, self.nstages):
216 # Construct RHS
217 rhs = np.copy(u0)
218 for j in range(0, i):
219 rhs += dt * self.A_hat[i, j] * (self.f_slow(self.stages[j, :])) + dt * self.A[i, j] * (
220 self.f_fast(self.stages[j, :])
221 )
223 # Solve for stage i
224 if self.A[i, i] == 0:
225 # Avoid call to spsolve with identity matrix
226 self.stages[i, :] = np.copy(rhs)
227 else:
228 self.stages[i, :] = self.f_fast_solve(rhs, dt * self.A[i, i], u0)
230 # Update
231 for i in range(0, self.nstages):
232 u0 += dt * self.b_hat[i] * (self.f_slow(self.stages[i, :])) + dt * self.b[i] * (
233 self.f_fast(self.stages[i, :])
234 )
236 return u0
238 def f_slow(self, u):
239 return self.problem.D_upwind.dot(u)
241 def f_fast(self, u):
242 return self.problem.M.dot(u)
244 def f_fast_solve(self, rhs, alpha, u0):
245 cb = Callback()
246 sol, info = gmres(
247 self.problem.Id - alpha * self.problem.M,
248 rhs,
249 x0=u0,
250 rtol=self.problem.params.gmres_tol_limit,
251 restart=self.problem.params.gmres_restart,
252 maxiter=self.problem.params.gmres_maxiter,
253 atol=0,
254 callback=cb,
255 )
256 if alpha != 0.0:
257 self.logger.add(cb.getcounter())
258 return sol
261#
262# Trapezoidal rule
263#
264class trapezoidal:
265 def __init__(self, problem, alpha=0.5):
266 assert isinstance(problem, boussinesq_2d_imex), "problem is wrong type of object"
267 self.Ndof = np.shape(problem.M)[0]
268 self.order = 2
269 self.logger = logging()
270 self.problem = problem
271 self.alpha = alpha
273 def timestep(self, u0, dt):
274 B_trap = sp.eye(self.Ndof) + self.alpha * dt * (self.problem.D_upwind + self.problem.M)
275 b = B_trap.dot(u0)
276 return self.f_solve(b, alpha=(1.0 - self.alpha) * dt, u0=u0)
278 #
279 # Returns f(u) = c*u
280 #
281 def f(self, u):
282 return self.problem.D_upwind.dot(u) + self.problem.M.dot(u)
284 #
285 # Solves (Id - alpha*c)*u = b for u
286 #
287 def f_solve(self, b, alpha, u0):
288 cb = Callback()
289 sol, info = gmres(
290 self.problem.Id - alpha * (self.problem.D_upwind + self.problem.M),
291 b,
292 x0=u0,
293 rtol=self.problem.params.gmres_tol_limit,
294 restart=self.problem.params.gmres_restart,
295 maxiter=self.problem.params.gmres_maxiter,
296 atol=0,
297 callback=cb,
298 )
299 if alpha != 0.0:
300 self.logger.add(cb.getcounter())
301 return sol
304#
305# A BDF-2 implicit two-step method
306#
307class bdf2:
308 def __init__(self, problem):
309 assert isinstance(problem, boussinesq_2d_imex), "problem is wrong type of object"
310 self.Ndof = np.shape(problem.M)[0]
311 self.order = 2
312 self.logger = logging()
313 self.problem = problem
315 def firsttimestep(self, u0, dt):
316 return self.f_solve(b=u0, alpha=dt, u0=u0)
318 def timestep(self, u0, um1, dt):
319 b = (4.0 / 3.0) * u0 - (1.0 / 3.0) * um1
320 return self.f_solve(b=b, alpha=(2.0 / 3.0) * dt, u0=u0)
322 #
323 # Returns f(u) = c*u
324 #
325 def f(self, u):
326 return self.problem.D_upwind.dot(u) + self.problem.M.dot(u)
328 #
329 # Solves (Id - alpha*c)*u = b for u
330 #
331 def f_solve(self, b, alpha, u0):
332 cb = Callback()
333 sol, info = gmres(
334 self.problem.Id - alpha * (self.problem.D_upwind + self.problem.M),
335 b,
336 x0=u0,
337 rtol=self.problem.params.gmres_tol_limit,
338 restart=self.problem.params.gmres_restart,
339 maxiter=self.problem.params.gmres_maxiter,
340 atol=0,
341 callback=cb,
342 )
343 if alpha != 0.0:
344 self.logger.add(cb.getcounter())
345 return sol
348#
349# Split-Explicit method
350#
353class SplitExplicit:
354 def __init__(self, problem, method, pparams):
355 assert isinstance(problem, boussinesq_2d_imex), "problem is wrong type of object"
356 self.Ndof = np.shape(problem.M)[0]
357 self.method = method
358 self.logger = logging()
359 self.problem = problem
360 self.pparams = pparams
361 self.NdofTher = 2 * problem.N[0] * problem.N[1]
362 self.NdofMom = 2 * problem.N[0] * problem.N[1]
364 self.ns = None
366 # print("dx ",problem.h[0])
367 # print("dz ",problem.h[1])
369 assert self.method in ["MIS4_4", "RK3"], 'Method must be MIS4_4'
371 if self.method == 'RK3':
372 self.nstages = 3
373 self.aRunge = np.zeros((4, 4))
374 self.aRunge[0, 0] = 1.0 / 3.0
375 self.aRunge[1, 1] = 1.0 / 2.0
376 self.aRunge[2, 2] = 1.0
377 self.dRunge = np.zeros((4, 4))
378 self.gRunge = np.zeros((4, 4))
379 if self.method == 'MIS4_4':
380 self.nstages = 4
381 self.aRunge = np.zeros((4, 4))
382 self.aRunge[0, 0] = 0.38758444641450318
383 self.aRunge[1, 0] = -2.5318448354142823e-002
384 self.aRunge[1, 1] = 0.38668943087310403
385 self.aRunge[2, 0] = 0.20899983523553325
386 self.aRunge[2, 1] = -0.45856648476371231
387 self.aRunge[2, 2] = 0.43423187573425748
388 self.aRunge[3, 0] = -0.10048822195663100
389 self.aRunge[3, 1] = -0.46186171956333327
390 self.aRunge[3, 2] = 0.83045062122462809
391 self.aRunge[3, 3] = 0.27014914900250392
392 self.dRunge = np.zeros((4, 4))
393 self.dRunge[1, 1] = 0.52349249922385610
394 self.dRunge[2, 1] = 1.1683374366893629
395 self.dRunge[2, 2] = -0.75762080241712637
396 self.dRunge[3, 1] = -3.6477233846797109e-002
397 self.dRunge[3, 2] = 0.56936148730740477
398 self.dRunge[3, 3] = 0.47746263002599681
399 self.gRunge = np.zeros((4, 4))
400 self.gRunge[1, 1] = 0.13145089796226542
401 self.gRunge[2, 1] = -0.36855857648747881
402 self.gRunge[2, 2] = 0.33159232636600550
403 self.gRunge[3, 1] = -6.5767130537473045e-002
404 self.gRunge[3, 2] = 4.0591093109036858e-002
405 self.gRunge[3, 3] = 6.4902111640806712e-002
406 self.dtRunge = np.zeros(self.nstages)
407 for i in range(0, self.nstages):
408 self.dtRunge[i] = 0
409 temp = 1.0
410 for j in range(0, i + 1):
411 self.dtRunge[i] = self.dtRunge[i] + self.aRunge[i, j]
412 temp = temp - self.dRunge[i, j]
413 self.dRunge[i, 0] = temp
414 for j in range(0, i + 1):
415 self.aRunge[i, j] = self.aRunge[i, j] / self.dtRunge[i]
416 self.gRunge[i, j] = self.gRunge[i, j] / self.dtRunge[i]
418 self.U = np.zeros((self.Ndof, self.nstages + 1))
419 self.F = np.zeros((self.Ndof, self.nstages))
420 self.FSlow = np.zeros(self.Ndof)
421 self.nsMin = 8
422 self.logger.nsmall = 0
424 def NumSmallTimeSteps(self, dx, dz, dt):
425 cs = self.pparams['c_s']
426 ns = dt / (0.9 / np.sqrt(1 / (dx * dx) + 1 / (dz * dz)) / cs)
427 ns = max(np.int(np.ceil(ns)), self.nsMin)
428 return ns
430 def timestep(self, u0, dt):
431 self.U[:, 0] = u0
433 self.ns = self.NumSmallTimeSteps(self.problem.h[0], self.problem.h[1], dt)
435 for i in range(0, self.nstages):
436 self.F[:, i] = self.f_slow(self.U[:, i])
437 self.FSlow[:] = 0.0
438 for j in range(0, i + 1):
439 self.FSlow += self.aRunge[i, j] * self.F[:, j] + self.gRunge[i, j] / dt * (self.U[:, j] - u0)
440 self.U[:, i + 1] = 0
441 for j in range(0, i + 1):
442 self.U[:, i + 1] += self.dRunge[i, j] * self.U[:, j]
443 nsLoc = np.int(np.ceil(self.ns * self.dtRunge[i]))
444 self.logger.nsmall += nsLoc
445 dtLoc = dt * self.dtRunge[i]
446 dTau = dtLoc / nsLoc
447 self.U[:, i + 1] = self.VerletLin(self.U[:, i + 1], self.FSlow, nsLoc, dTau)
448 u0 = self.U[:, self.nstages]
449 return u0
451 def VerletLin(self, u0, FSlow, ns, dTau):
452 for _ in range(0, ns):
453 u0[0 : self.NdofMom] += dTau * (self.f_fastMom(u0) + FSlow[0 : self.NdofMom])
454 u0[self.NdofMom : self.Ndof] += dTau * (self.f_fastTher(u0) + FSlow[self.NdofMom : self.Ndof])
456 return u0
458 def RK3Lin(self, u0, FSlow, ns, dTau):
459 u = u0
460 for _ in range(0, ns):
461 u = u0 + dTau / 3.0 * (self.f_fast(u) + FSlow)
462 u = u0 + dTau / 2.0 * (self.f_fast(u) + FSlow)
463 u = u0 + dTau * (self.f_fast(u) + FSlow)
464 u0 = u
466 return u0
468 def f_slow(self, u):
469 return self.problem.D_upwind.dot(u)
471 def f_fast(self, u):
472 return self.problem.M.dot(u)
474 def f_fastMom(self, u):
475 return self.problem.M[0 : self.NdofMom, self.NdofMom : self.Ndof].dot(u[self.NdofMom : self.Ndof])
477 def f_fastTher(self, u):
478 return self.problem.M[self.NdofMom : self.Ndof, 0 : self.NdofMom].dot(u[0 : self.NdofMom])
481class dirk:
482 def __init__(self, problem, order):
483 assert isinstance(problem, boussinesq_2d_imex), "problem is wrong type of object"
484 self.Ndof = np.shape(problem.M)[0]
485 self.order = order
486 self.logger = logging()
487 self.problem = problem
489 assert self.order in [2, 22, 3, 4, 5], 'Order must be 2,22,3,4'
491 if self.order == 2:
492 self.nstages = 1
493 self.A = np.zeros((1, 1))
494 self.A[0, 0] = 0.5
495 self.tau = [0.5]
496 self.b = [1.0]
498 if self.order == 22:
499 self.nstages = 2
500 self.A = np.zeros((2, 2))
501 self.A[0, 0] = 1.0 / 3.0
502 self.A[1, 0] = 1.0 / 2.0
503 self.A[1, 1] = 1.0 / 2.0
505 self.tau = np.zeros(2)
506 self.tau[0] = 1.0 / 3.0
507 self.tau[1] = 1.0
509 self.b = np.zeros(2)
510 self.b[0] = 3.0 / 4.0
511 self.b[1] = 1.0 / 4.0
513 if self.order == 3:
514 self.nstages = 2
515 self.A = np.zeros((2, 2))
516 self.A[0, 0] = 0.5 + 1.0 / (2.0 * math.sqrt(3.0))
517 self.A[1, 0] = -1.0 / math.sqrt(3.0)
518 self.A[1, 1] = self.A[0, 0]
520 self.tau = np.zeros(2)
521 self.tau[0] = 0.5 + 1.0 / (2.0 * math.sqrt(3.0))
522 self.tau[1] = 0.5 - 1.0 / (2.0 * math.sqrt(3.0))
524 self.b = np.zeros(2)
525 self.b[0] = 0.5
526 self.b[1] = 0.5
528 if self.order == 4:
529 self.nstages = 3
530 alpha = 2.0 * math.cos(math.pi / 18.0) / math.sqrt(3.0)
532 self.A = np.zeros((3, 3))
533 self.A[0, 0] = (1.0 + alpha) / 2.0
534 self.A[1, 0] = -alpha / 2.0
535 self.A[1, 1] = self.A[0, 0]
536 self.A[2, 0] = 1.0 + alpha
537 self.A[2, 1] = -(1.0 + 2.0 * alpha)
538 self.A[2, 2] = self.A[0, 0]
540 self.tau = np.zeros(3)
541 self.tau[0] = (1.0 + alpha) / 2.0
542 self.tau[1] = 1.0 / 2.0
543 self.tau[2] = (1.0 - alpha) / 2.0
545 self.b = np.zeros(3)
546 self.b[0] = 1.0 / (6.0 * alpha * alpha)
547 self.b[1] = 1.0 - 1.0 / (3.0 * alpha * alpha)
548 self.b[2] = 1.0 / (6.0 * alpha * alpha)
550 if self.order == 5:
551 self.nstages = 5
552 # From Kennedy, Carpenter "Diagonally Implicit Runge-Kutta Methods for Ordinary Differential Equations.
553 # A Review"
554 self.A = np.zeros((5, 5))
555 self.A[0, 0] = 4024571134387.0 / 14474071345096.0
557 self.A[1, 0] = 9365021263232.0 / 12572342979331.0
558 self.A[1, 1] = self.A[0, 0]
560 self.A[2, 0] = 2144716224527.0 / 9320917548702.0
561 self.A[2, 1] = -397905335951.0 / 4008788611757.0
562 self.A[2, 2] = self.A[0, 0]
564 self.A[3, 0] = -291541413000.0 / 6267936762551.0
565 self.A[3, 1] = 226761949132.0 / 4473940808273.0
566 self.A[3, 2] = -1282248297070.0 / 9697416712681.0
567 self.A[3, 3] = self.A[0, 0]
569 self.A[4, 0] = -2481679516057.0 / 4626464057815.0
570 self.A[4, 1] = -197112422687.0 / 6604378783090.0
571 self.A[4, 2] = 3952887910906.0 / 9713059315593.0
572 self.A[4, 3] = 4906835613583.0 / 8134926921134.0
573 self.A[4, 4] = self.A[0, 0]
575 self.b = np.zeros(5)
576 self.b[0] = -2522702558582.0 / 12162329469185.0
577 self.b[1] = 1018267903655.0 / 12907234417901.0
578 self.b[2] = 4542392826351.0 / 13702606430957.0
579 self.b[3] = 5001116467727.0 / 12224457745473.0
580 self.b[4] = 1509636094297.0 / 3891594770934.0
582 self.stages = np.zeros((self.nstages, self.Ndof))
584 def timestep(self, u0, dt):
585 uend = u0
586 for i in range(0, self.nstages):
587 b = u0
589 # Compute right hand side for this stage's implicit step
590 for j in range(0, i):
591 b = b + self.A[i, j] * dt * self.f(self.stages[j, :])
593 # Implicit solve for current stage
594 # if i==0:
595 self.stages[i, :] = self.f_solve(b, dt * self.A[i, i], u0)
596 # else:
597 # self.stages[i,:] = self.f_solve( b, dt*self.A[i,i] , self.stages[i-1,:] )
599 # Add contribution of current stage to final value
600 uend = uend + self.b[i] * dt * self.f(self.stages[i, :])
602 return uend
604 #
605 # Returns f(u) = c*u
606 #
607 def f(self, u):
608 return self.problem.D_upwind.dot(u) + self.problem.M.dot(u)
610 #
611 # Solves (Id - alpha*c)*u = b for u
612 #
613 def f_solve(self, b, alpha, u0):
614 cb = Callback()
615 sol, info = gmres(
616 self.problem.Id - alpha * (self.problem.D_upwind + self.problem.M),
617 b,
618 x0=u0,
619 rtol=self.problem.params.gmres_tol_limit,
620 restart=self.problem.params.gmres_restart,
621 maxiter=self.problem.params.gmres_maxiter,
622 atol=0,
623 callback=cb,
624 )
625 if alpha != 0.0:
626 self.logger.add(cb.getcounter())
627 return sol