|
| 1 | +import matplotlib |
| 2 | +matplotlib.use('Agg') |
| 3 | + |
| 4 | +import numpy as np |
| 5 | +from matplotlib import pyplot as plt |
| 6 | +from pylab import rcParams |
| 7 | + |
| 8 | +from pySDC.implementations.problem_classes.FastWaveSlowWave_0D import swfw_scalar |
| 9 | +from pySDC.implementations.datatype_classes.complex_mesh import mesh, rhs_imex_mesh |
| 10 | +from pySDC.implementations.sweeper_classes.imex_1st_order import imex_1st_order |
| 11 | +from pySDC.implementations.collocation_classes.gauss_radau_right import CollGaussRadau_Right |
| 12 | + |
| 13 | +from pySDC.core.Step import step |
| 14 | + |
| 15 | + |
| 16 | +# noinspection PyShadowingNames |
| 17 | +def main(): |
| 18 | + """ |
| 19 | + Routine to compute spectral radius and norm of the error propagation matrix E |
| 20 | +
|
| 21 | + Returns: |
| 22 | + numpy.nparray: list of number of nodes |
| 23 | + numpy.nparray: list of fast lambdas |
| 24 | + numpy.nparray: list of spectral radii |
| 25 | + numpy.nparray: list of norms |
| 26 | +
|
| 27 | + """ |
| 28 | + problem_params = dict() |
| 29 | + # SET VALUE FOR lambda_slow AND VALUES FOR lambda_fast ### |
| 30 | + problem_params['lambda_s'] = np.array([1.0 * 1j], dtype='complex') |
| 31 | + problem_params['lambda_f'] = np.array([50.0 * 1j, 100.0 * 1j], dtype='complex') |
| 32 | + problem_params['u0'] = 1.0 |
| 33 | + |
| 34 | + # initialize sweeper parameters |
| 35 | + sweeper_params = dict() |
| 36 | + # SET TYPE OF QUADRATURE NODES ### |
| 37 | + sweeper_params['collocation_class'] = CollGaussRadau_Right |
| 38 | + |
| 39 | + # initialize level parameters |
| 40 | + level_params = dict() |
| 41 | + level_params['dt'] = 1.0 |
| 42 | + t0 = 0.0 |
| 43 | + |
| 44 | + # fill description dictionary for easy step instantiation |
| 45 | + description = dict() |
| 46 | + description['problem_class'] = swfw_scalar # pass problem class |
| 47 | + description['problem_params'] = problem_params # pass problem parameters |
| 48 | + description['dtype_u'] = mesh # pass data type for u |
| 49 | + description['dtype_f'] = rhs_imex_mesh # pass data type for f |
| 50 | + description['sweeper_class'] = imex_1st_order # pass sweeper (see part B) |
| 51 | + description['level_params'] = level_params # pass level parameters |
| 52 | + description['step_params'] = dict() # pass step parameters |
| 53 | + |
| 54 | + nodes_v = np.arange(2, 10) |
| 55 | + specrad = np.zeros((3, np.size(nodes_v))) |
| 56 | + norm = np.zeros((3, np.size(nodes_v))) |
| 57 | + |
| 58 | + P = None |
| 59 | + for i in range(0, np.size(nodes_v)): |
| 60 | + |
| 61 | + sweeper_params['num_nodes'] = nodes_v[i] |
| 62 | + description['sweeper_params'] = sweeper_params # pass sweeper parameters |
| 63 | + |
| 64 | + # now the description contains more or less everything we need to create a step |
| 65 | + S = step(description=description) |
| 66 | + |
| 67 | + L = S.levels[0] |
| 68 | + P = L.prob |
| 69 | + |
| 70 | + u0 = S.levels[0].prob.u_exact(t0) |
| 71 | + S.init_step(u0) |
| 72 | + QE = L.sweep.QE[1:, 1:] |
| 73 | + QI = L.sweep.QI[1:, 1:] |
| 74 | + Q = L.sweep.coll.Qmat[1:, 1:] |
| 75 | + nnodes = L.sweep.coll.num_nodes |
| 76 | + dt = L.params.dt |
| 77 | + |
| 78 | + assert nnodes == nodes_v[i], 'Something went wrong during instantiation, nnodes is not correct, got %s' % nnodes |
| 79 | + |
| 80 | + for j in range(0, 2): |
| 81 | + LHS = np.eye(nnodes) - dt * (P.params.lambda_f[j] * QI + P.params.lambda_s[0] * QE) |
| 82 | + RHS = dt * ((P.params.lambda_f[j] + P.params.lambda_s[0]) * Q - |
| 83 | + (P.params.lambda_f[j] * QI + P.params.lambda_s[0] * QE)) |
| 84 | + evals, evecs = np.linalg.eig(np.linalg.inv(LHS).dot(RHS)) |
| 85 | + specrad[j + 1, i] = np.linalg.norm(evals, np.inf) |
| 86 | + norm[j + 1, i] = np.linalg.norm(np.linalg.inv(LHS).dot(RHS), np.inf) |
| 87 | + |
| 88 | + if L.sweep.coll.left_is_node: |
| 89 | + # For Lobatto nodes, first column and row are all zeros, since q_1 = q_0; hence remove them |
| 90 | + QI = QI[1:, 1:] |
| 91 | + Q = Q[1:, 1:] |
| 92 | + # Eigenvalue of error propagation matrix in stiff limit: E = I - inv(QI)*Q |
| 93 | + evals, evecs = np.linalg.eig(np.eye(nnodes - 1) - np.linalg.inv(QI).dot(Q)) |
| 94 | + norm[0, i] = np.linalg.norm(np.eye(nnodes - 1) - np.linalg.inv(QI).dot(Q), np.inf) |
| 95 | + else: |
| 96 | + evals, evecs = np.linalg.eig(np.eye(nnodes) - np.linalg.inv(QI).dot(Q)) |
| 97 | + norm[0, i] = np.linalg.norm(np.eye(nnodes) - np.linalg.inv(QI).dot(Q), np.inf) |
| 98 | + specrad[0, i] = np.linalg.norm(evals, np.inf) |
| 99 | + |
| 100 | + print("Spectral radius of infinitely fast wave case > 1.0 for M=%2i" % nodes_v[np.argmax(specrad[0, :] > 1.0)]) |
| 101 | + print("Spectral radius of > 1.0 for M=%2i" % nodes_v[np.argmax(specrad[1, :] > 1.0)]) |
| 102 | + |
| 103 | + return nodes_v, P.params.lambda_f, specrad, norm |
| 104 | + |
| 105 | + |
| 106 | +# noinspection PyShadowingNames |
| 107 | +def plot_results(nodes_v, lambda_f, specrad, norm): |
| 108 | + """ |
| 109 | + Plotting function for spectral radii and norms |
| 110 | +
|
| 111 | + Args: |
| 112 | + nodes_v (numpy.nparray): list of number of nodes |
| 113 | + lambda_f (numpy.nparray): list of fast lambdas |
| 114 | + specrad (numpy.nparray): list of spectral radii |
| 115 | + norm (numpy.nparray): list of norms |
| 116 | + """ |
| 117 | + fs = 8 |
| 118 | + rcParams['figure.figsize'] = 2.5, 2.5 |
| 119 | + fig = plt.figure() |
| 120 | + plt.plot(nodes_v, specrad[0, :], 'rd-', markersize=fs - 2, label=r'$\lambda_{\rm fast} = \infty$') |
| 121 | + plt.plot(nodes_v, specrad[1, :], 'bo-', markersize=fs - 2, |
| 122 | + label=r'$\lambda_{\rm fast} = %2.0f $' % lambda_f[0].imag) |
| 123 | + plt.plot(nodes_v, specrad[2, :], 'gs-', markersize=fs - 2, |
| 124 | + label=r'$\lambda_{\rm fast} = %2.0f $' % lambda_f[1].imag) |
| 125 | + plt.xlabel(r'Number of nodes $M$', fontsize=fs) |
| 126 | + plt.ylabel(r'Spectral radius $\sigma\left( \mathbf{E} \right)$', fontsize=fs, labelpad=2) |
| 127 | + plt.legend(loc='lower right', fontsize=fs, prop={'size': fs}) |
| 128 | + plt.xlim([np.min(nodes_v), np.max(nodes_v)]) |
| 129 | + plt.ylim([0, 1.0]) |
| 130 | + plt.yticks(fontsize=fs) |
| 131 | + plt.xticks(fontsize=fs) |
| 132 | + filename = 'stifflimit-specrad.png' |
| 133 | + fig.savefig(filename, bbox_inches='tight') |
| 134 | + |
| 135 | + fig = plt.figure() |
| 136 | + plt.plot(nodes_v, norm[0, :], 'rd-', markersize=fs - 2, label=r'$\lambda_{\rm fast} = \infty$') |
| 137 | + plt.plot(nodes_v, norm[1, :], 'bo-', markersize=fs - 2, |
| 138 | + label=r'$\lambda_{\rm fast} = %2.0f $' % lambda_f[0].imag) |
| 139 | + plt.plot(nodes_v, norm[2, :], 'gs-', markersize=fs - 2, |
| 140 | + label=r'$\lambda_{\rm fast} = %2.0f $' % lambda_f[1].imag) |
| 141 | + plt.xlabel(r'Number of nodes $M$', fontsize=fs) |
| 142 | + plt.ylabel(r'Norm $\left|| \mathbf{E} \right||_{\infty}$', fontsize=fs, labelpad=2) |
| 143 | + plt.legend(loc='lower right', fontsize=fs, prop={'size': fs}) |
| 144 | + plt.xlim([np.min(nodes_v), np.max(nodes_v)]) |
| 145 | + plt.ylim([0, 2.4]) |
| 146 | + plt.yticks(fontsize=fs) |
| 147 | + plt.xticks(fontsize=fs) |
| 148 | + filename = 'stifflimit-norm.png' |
| 149 | + fig.savefig(filename, bbox_inches='tight') |
| 150 | + |
| 151 | + |
| 152 | +if __name__ == "__main__": |
| 153 | + nodes_v, lambda_f, specrad, norm = main() |
| 154 | + plot_results(nodes_v, lambda_f, specrad, norm) |
0 commit comments