|
| 1 | +#!/usr/bin/env python3 |
| 2 | +# -*- coding: utf-8 -*- |
| 3 | +""" |
| 4 | +Script investigating IMEX stability for SDC methods |
| 5 | +""" |
| 6 | +import numpy as np |
| 7 | +import scipy.optimize as sco |
| 8 | +import matplotlib.pyplot as plt |
| 9 | + |
| 10 | +from qmat.qcoeff.collocation import Collocation |
| 11 | +from qmat.qdelta import QDELTA_GENERATORS |
| 12 | + |
| 13 | +from qmat.solvers.dahlquist import DahlquistIMEX |
| 14 | + |
| 15 | + |
| 16 | +# Script parameters |
| 17 | +nNodes = 4 |
| 18 | +nSweeps = 4 |
| 19 | +stepUpdate = False |
| 20 | +implSweep = "MIN-SR-FLEX" |
| 21 | +explSweep = "PIC" |
| 22 | + |
| 23 | + |
| 24 | +# Script execution |
| 25 | +lamE = np.linspace(0, 6, num=501) |
| 26 | +ratio = np.logspace(-3, 2, num=301) |
| 27 | +zI = -ratio[None, :]*lamE[:, None] |
| 28 | +zE = 1j*lamE[:, None] |
| 29 | + |
| 30 | +problem = DahlquistIMEX(zI, zE) |
| 31 | + |
| 32 | +coll = Collocation(nNodes=nNodes, nodeType="LEGENDRE", quadType="RADAU-RIGHT") |
| 33 | + |
| 34 | +genI = QDELTA_GENERATORS[implSweep](qGen=coll) |
| 35 | +genE = QDELTA_GENERATORS[explSweep](qGen=coll) |
| 36 | + |
| 37 | +sweeps = [k+1 for k in range(nSweeps)] |
| 38 | + |
| 39 | +uNum = problem.solveSDC( |
| 40 | + coll.Q, coll.weights if stepUpdate else None, |
| 41 | + genI.genCoeffs(k=sweeps), genE.genCoeffs(k=sweeps), |
| 42 | + nSweeps=nSweeps) |
| 43 | + |
| 44 | +u1 = uNum[-1] |
| 45 | +stab = np.abs(u1) |
| 46 | +stab = np.clip(stab, 0, 1.2) # clip to ignore unstable area |
| 47 | +error = np.abs(u1 - np.exp(zI+zE)) |
| 48 | + |
| 49 | + |
| 50 | +plt.figure("imex stability") |
| 51 | +plt.clf() |
| 52 | + |
| 53 | +coords = (ratio, lamE) |
| 54 | +plt.contourf(*coords, stab, levels = [0, 0.2, 0.4, 0.6, 0.8, 1, 1.2]) |
| 55 | +plt.colorbar() |
| 56 | +plt.contour(*coords, stab, levels=[1], colors="black") |
| 57 | +plt.contour(*coords, error, levels=[1], colors="red", linestyles=":") |
| 58 | +plt.contour(*coords, error, levels=[1e-1], colors="orange", linestyles="-.") |
| 59 | +plt.contour(*coords, error, levels=[1e-2], colors="gray", linestyles="--") |
| 60 | +plt.grid(True) |
| 61 | +plt.xscale('log') |
| 62 | +plt.ylabel(r"$\lambda_E \Delta t$") |
| 63 | +plt.xlabel(r"advection $\quad\leftarrow\quad\frac{-\lambda_I}{\lambda_E}\quad\rightarrow\quad$ diffusion", fontsize=20) |
| 64 | +plt.tight_layout() |
| 65 | + |
| 66 | + |
| 67 | +def imStab(x): |
| 68 | + uSDC = DahlquistIMEX([0], [x*1j]).solveSDC( |
| 69 | + coll.Q, coll.weights if stepUpdate else None, |
| 70 | + genI.genCoeffs(k=sweeps), genE.genCoeffs(k=sweeps), |
| 71 | + nSweeps=nSweeps) |
| 72 | + return np.abs(uSDC[-1]) - 1 |
| 73 | + |
| 74 | +try: |
| 75 | + sol = sco.bisect(imStab, 1e-1, 1e2, xtol=1e-16) |
| 76 | + print(f"CFL max [SDC] : {sol}") |
| 77 | +except: |
| 78 | + pass |
| 79 | + |
| 80 | +plt.figure("stability on imaginary axis") |
| 81 | +plt.clf() |
| 82 | +plt.grid(True) |
| 83 | +x = np.linspace(0, 6, num=501) |
| 84 | +plt.plot(x, [imStab(s)[0] for s in x], label="RK") |
| 85 | +plt.ylim(-1, 0.5) |
| 86 | +plt.ylabel("over-amplification") |
| 87 | +plt.xlabel(r"$\lambda_E \Delta t$") |
| 88 | +plt.legend() |
| 89 | +plt.tight_layout() |
| 90 | + |
| 91 | +plt.show() |
0 commit comments