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