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 | |