Source code for pymead.core.parametric_curve

from abc import ABC, abstractmethod
from enum import Enum

import numpy as np
import matplotlib.pyplot as plt

from pymead.core.pymead_obj import PymeadObj


LOW_RES_NT = 100
INTERMEDIATE_NT = 150
HIGH_RES_NT = 200


[docs] class PCurveData:
[docs] def __init__(self, t: np.ndarray, xy: np.ndarray, xpyp: np.ndarray, xppypp: np.ndarray, k: np.ndarray, R: np.ndarray, dxdy_start: np.ndarray = None): self.t = t self.xy = xy self.xpyp = xpyp self.xppypp = xppypp self.k = k self.R = R self.R_abs_min = np.min(np.abs(self.R)) self.dxdy_start = dxdy_start # Accounts for possibly infinite dx/dt or dy/dt value but finite dy/dx
def plot(self, ax: plt.Axes, **kwargs): ax.plot(self.xy[:, 0], self.xy[:, 1], **kwargs) def get_curvature_comb(self, max_k_normalized_scale_factor, interval: int = 1, filter_large_values: bool = True, flip_leading_edge_normal: bool = False, filter_magnitude: float = 1e5): first_deriv_mag = np.hypot(self.xpyp[:, 0], self.xpyp[:, 1]) with np.errstate(divide="ignore", invalid="ignore"): comb_heads_x = self.xy[:, 0] - np.true_divide(self.xpyp[:, 1], first_deriv_mag) * self.k * max_k_normalized_scale_factor comb_heads_y = self.xy[:, 1] + np.true_divide(self.xpyp[:, 0], first_deriv_mag) * self.k * max_k_normalized_scale_factor if self.dxdy_start is not None: normal_dir = 1 if flip_leading_edge_normal else -1 comb_head_0 = self.xy[0, :] + normal_dir * self.dxdy_start / np.hypot( self.dxdy_start[0], self.dxdy_start[1]) * self.k[0] * max_k_normalized_scale_factor comb_heads_x[0] = comb_head_0[0] comb_heads_y[0] = comb_head_0[1] # Stack the x and y columns (except for the last x and y values) horizontally and keep only the rows by the # specified interval: comb_tails = np.column_stack((self.xy[:, 0], self.xy[:, 1]))[:-1:interval, :] comb_heads = np.column_stack((comb_heads_x, comb_heads_y))[:-1:interval, :] # Add the last x and y values onto the end (to make sure they do not get skipped with input interval) comb_tails = np.row_stack((comb_tails, np.array([self.xy[-1, 0], self.xy[-1, 1]]))) comb_heads = np.row_stack((comb_heads, np.array([comb_heads_x[-1], comb_heads_y[-1]]))) if filter_large_values: filter_indices = [] for comb_idx, (comb_tail, comb_head) in enumerate(zip(comb_tails, comb_heads)): if np.hypot(comb_head[0] - comb_tail[0], comb_head[1] - comb_tail[1]) > filter_magnitude: filter_indices.append(comb_idx) for filter_index in filter_indices[::-1]: comb_tails = np.delete(comb_tails, filter_index, axis=0) comb_heads = np.delete(comb_heads, filter_index, axis=0) return comb_tails, comb_heads def approximate_arc_length(self): return np.sum(np.hypot(self.xy[1:, 0] - self.xy[:-1, 0], self.xy[1:, 1] - self.xy[:-1, 1]))
[docs] class ParametricCurveEndpoint(Enum): Start = 0 End = 1
[docs] class ParametricCurve(PymeadObj, ABC):
[docs] def __init__(self, sub_container: str, reference: bool = False): super().__init__(sub_container=sub_container) self.curve_type = self.__class__.__name__ self.reference = reference self.airfoil = None
def update(self): p_curve_data = self.evaluate() if self.canvas_item is not None: self.canvas_item.updateCanvasItem(curve_data=p_curve_data) @staticmethod def generate_t_vec(nt: int = INTERMEDIATE_NT, spacing: str = "linear", start: int = 0.0, end: int = 1.0): if spacing == "linear": return np.linspace(start, end, nt) elif spacing == "cosine": return 0.5 * (1 - np.cos(np.pi * np.linspace(start, end, nt))) else: raise ValueError("The only currently implemented spacing are 'linear' and 'cosine'.") @abstractmethod def point_removal_deletes_curve(self) -> bool: pass @abstractmethod def evaluate(self, t: np.ndarray or None = None, **kwargs): pass