caleb2's picture
initial commit
d68c650
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}')