Spaces:
Sleeping
Sleeping
File size: 4,669 Bytes
d68c650 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
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
|