Spaces:
Sleeping
Sleeping
from .common import * | |
def u_dot_thetavec(r, theta, w): | |
""" | |
Dot product of u = (cos(w), sin(w)) with the coordinate vector for theta. | |
Args: | |
r (float or array-like): the radial coordinate(s) | |
theta (float or array-like): The angular coordinate(s). | |
w (float or array-like): The w coordinate(s). | |
Returns: | |
numpy.ndarray: The calculated dot product for each point. | |
""" | |
return r * np.sin(w - theta) | |
def u_dot_thetahat(theta, w): | |
""" | |
Dot product of u = (cos(w), sin(w)) with the unit vector for theta. | |
Args: | |
theta (float or array-like): The angular (theta) coordinate(s). | |
w (float or array-like): The w coordinate(s). | |
Returns: | |
numpy.ndarray: The calculated dot product for each point. | |
""" | |
return np.sin(w - theta) | |
def u_dot_rvec(theta, w): | |
""" | |
Dot product of u = (cos(w), sin(w)) with the coordinate vector for r. | |
Args: | |
theta (float or array-like): The radial (r) coordinate(s). | |
w (float or array-like): The w coordinate(s). | |
Returns: | |
numpy.ndarray: The calculated dot product for each point. | |
""" | |
return np.cos(w - theta) | |
def get_system_circle(config): | |
""" | |
For a circular geometry, constructs the matrices, grids, and other quantities corresponding to the PDE system | |
specified by "config"". | |
Args: | |
config (dict): Configuration dictionary containing the system parameters. | |
Returns: | |
tuple: A tuple containing matrices, grids, etc. for the PDE system | |
""" | |
required_keys = ['nx1', 'nx2', 'nx3', 'ell', 'a2'] | |
optional_keys = [] | |
missing_keys = [key for key in required_keys if key not in config] | |
if missing_keys: | |
raise KeyError(f"Missing keys in config: {', '.join(missing_keys)}") | |
unused_keys = [key for key in config if key not in required_keys + optional_keys] | |
if unused_keys: | |
warnings.warn(f"Unused keys in config: {', '.join(unused_keys)}") | |
for key in ['nx1', 'nx2', 'nx3']: | |
if not isinstance(config[key], int): | |
raise TypeError(f"{key} must be an integer.") | |
for key in ['nx1', 'nx2', 'nx3', 'ell', 'a2']: | |
if config[key] <= 0: | |
raise ValueError(f"{key} must be positive.") | |
if config['a2'] < 1.0: | |
raise ValueError('a2 must be greater than 1.') | |
nr, ntheta, nw = config['nx1'], config['nx2'], config['nx3'] | |
R1 = 1.0 | |
R2 = config['a2'] | |
ell = config['ell'] | |
# 1D grids | |
theta, w = get_angular_grids(ntheta, nw) | |
# r grid: non-uniform spacing and Dirichlet boundary conditions | |
y = np.linspace(-np.pi / 2, np.pi / 2, nr + 2) | |
r_ = (R2 - R1) * (np.sin(y) / 2 + 0.5) + R1 | |
dr1 = r_[1] - r_[0] | |
dr2 = r_[-1] - r_[-2] | |
r = r_[1:-1] | |
# 1D finite-difference operators | |
Dtheta_minus, Dtheta_plus = d_dx_upwind(theta, ntheta) | |
D2w = d2_dx2_fourth_order(w, nw) | |
Dr_minus, Dr_plus = d_dx_upwind_nonuniform(r_, nr) | |
# 3D quantities. Kronecker products are used to build the 3D difference operators | |
r_3D, theta_3D, w_3D = np.meshgrid(r, theta, w, indexing = 'ij') | |
I_r = sp.eye(nr) | |
I_theta = sp.eye(ntheta) | |
I_w = sp.eye(nw) | |
Dtheta_3D_minus = sp.kron(sp.kron(I_r, Dtheta_minus), I_w) | |
Dtheta_3D_plus = sp.kron(sp.kron(I_r, Dtheta_plus), I_w) | |
D2w_3D = sp.kron(sp.kron(I_r, I_theta), D2w) | |
Dr_3D_minus = sp.kron(sp.kron(Dr_minus, I_theta), I_w) | |
Dr_3D_plus = sp.kron(sp.kron(Dr_plus, I_theta), I_w) | |
# Metric tensor. Note that g_12 = g_21 = 0. | |
g_11 = np.ones_like(r_3D) | |
g_22_over_r = r_3D # divide out factor of r | |
# Dot products | |
dp_r = u_dot_rvec(theta_3D, w_3D) | |
dp_thetahat = u_dot_thetahat(theta_3D, w_3D) | |
# Coefficient of d / dr | |
Dr_3D_coeff_meshgrid = dp_r / g_11 | |
test_ill_conditioned(Dr_3D_coeff_meshgrid) | |
Dr_3D_coeff = sp.diags(Dr_3D_coeff_meshgrid.ravel()) | |
# Coefficient of d / dtheta | |
Dtheta_3D_coeff_meshgrid = dp_thetahat / g_22_over_r | |
Dtheta_3D_coeff = sp.diags(Dtheta_3D_coeff_meshgrid.ravel()) | |
# Upwind differencing | |
Dr_3D_upwind = upwind_operator(Dr_3D_minus, Dr_3D_plus, Dr_3D_coeff_meshgrid) | |
Dtheta_3D_upwind = upwind_operator(Dtheta_3D_minus, Dtheta_3D_plus, Dtheta_3D_coeff_meshgrid) | |
# Full operator | |
L = Dr_3D_coeff @ Dr_3D_upwind + Dtheta_3D_coeff @ Dtheta_3D_upwind - (1 / ell) * D2w_3D | |
return L, r_3D, theta_3D, w_3D, dr1, dr2, Dr_3D_coeff_meshgrid | |
def get_boundary_quantities_circle(theta_3D, w_3D): | |
""" | |
Gets grid coordinates on the boundaries, as well as slice arrays | |
for positive/negative angles with respect to the boundary angle. | |
Args: | |
theta_3D (numpy.ndarray): 3D array of theta values on the grid. | |
w_3D (numpy.ndarray): 3D array of w values on the grid. | |
Returns: | |
tuple: Tuple of the grid coordinates and slice arrays | |
""" | |
th1 = theta_3D[0, :, :] | |
wb1 = w_3D[0, :, :] | |
th2 = theta_3D[-1, :, :] | |
wb2 = w_3D[-1, :, :] | |
ib_slice = np.cos(th1 - wb1) > 0 | |
ob_slice = np.cos(th2 - wb2) < 0 | |
return th1, th2, wb1, wb2, ib_slice, ob_slice | |