Spaces:
Sleeping
Sleeping
import warnings | |
import numpy as np | |
import scipy.sparse as sp | |
def d_dx_upwind(x, nx): | |
""" | |
Sparse matrix representation of d/dx using first-order left/right differences with Dirichlet boundary conditions | |
""" | |
dx = x[1] - x[0] | |
Dx_minus = sp.diags([-1, 1], [0, 1], shape = (nx, nx)).tolil() / dx | |
Dx_plus = sp.diags([-1, 1], [-1, 0], shape = (nx, nx)).tolil() / dx | |
Dx_minus[-1, 0] = 1 / dx | |
Dx_plus[0, -1] = -1 / dx | |
Dx_minus = Dx_minus.tocsr() | |
Dx_plus = Dx_plus.tocsr() | |
return Dx_minus, Dx_plus | |
def d2_dx2_fourth_order(x, nx): | |
""" | |
Sparse matrix representation of d^2/dx^2 using fourth order central differences and periodic boundary conditions | |
""" | |
dx = x[1] - x[0] | |
D2x = sp.diags([-1, 16, -30, 16, -1], [-2, -1, 0, 1, 2], | |
shape = (nx, nx)).tolil() / (12 * dx**2) | |
D2x[0, -1] = 16 / (12 * dx**2) | |
D2x[0, -2] = -1 / (12 * dx**2) | |
D2x[1, -1] = -1 / (12 * dx**2) | |
D2x[-1, 0] = 16 / (12 * dx**2) | |
D2x[-1, 1] = -1 / (12 * dx**2) | |
D2x[-2, 0] = -1 / (12 * dx**2) | |
D2x = D2x.tocsr() | |
return D2x | |
def d_dx_upwind_nonuniform(x, nx): | |
""" | |
Sparse matrix representation of d/dx on a nonuniform grid, using first-order left/right differences | |
with Dirichlet boundary conditions. | |
""" | |
Dx_ = np.diff(x) | |
Dx_minus = np.diff(x[1:]) | |
Dx_minus_inv = 1 / Dx_minus | |
Dx_plus_inv = 1 / Dx_ | |
Dx_minus = sp.diags([-Dx_minus_inv, Dx_minus_inv], [0, 1], shape = (nx, nx)).tolil() | |
Dx_plus = sp.diags([-Dx_plus_inv[1:], Dx_plus_inv[:-1]], [-1, 0], shape = (nx, nx)).tolil() | |
Dx_minus = Dx_minus.tocsr() | |
Dx_plus = Dx_plus.tocsr() | |
return Dx_minus, Dx_plus | |
def get_angular_grids(nx2, nx3): | |
""" | |
x2 / x3 grids: uniform spacing and periodic boundary conditions | |
The x3 grid has an offset to ensure cos(x2 - x3) != 0. | |
""" | |
x2 = np.linspace(-np.pi, np.pi, nx2, endpoint = False) | |
x3_min, x3_max = 0 + 0.125 * (2 * np.pi / nx3), 2 * np.pi + 0.125 * (2 * np.pi / nx3) | |
x3 = np.linspace(x3_min, x3_max, nx3, endpoint = False) | |
return x2, x3 | |
def upwind_operator(Dx_minus, Dx_plus, Dx_coeff): | |
""" | |
Upwind finite difference operator. | |
Args: | |
Dx_minus (scipy.sparse matrix): backward (minus) finite difference operator. | |
Dx_plus (scipy.sparse matrix): forward (plus) finite difference operator. | |
Dx_coeff (numpy.ndarray): coefficient array | |
Returns: | |
scipy.sparse matrix: The upwind operator | |
""" | |
mask_x = Dx_coeff <= 0 | |
Dx_masked_minus = sp.diags(mask_x.ravel().astype(int)) @ Dx_minus | |
Dx_masked_plus = sp.diags((~mask_x).ravel().astype(int)) @ Dx_plus | |
Dx_upwind = Dx_masked_minus + Dx_masked_plus | |
return Dx_upwind | |
def test_ill_conditioned(Dx_coeff): | |
""" | |
Test for ill-conditioning. The thresholds are heuristic only. | |
""" | |
ill_conditioning_test = np.min(np.abs(Dx_coeff.ravel())) | |
if ill_conditioning_test < 1e-10: | |
raise ValueError(f'System is ill-conditioned; min |Dx1_coeff| = {ill_conditioning_test}') | |
elif ill_conditioning_test < 1e-6: | |
warnings.warn(f'System may be ill-conditioned; min |Dx1_coeff| = {ill_conditioning_test}') | |