Пример #1
0
    def draw(
        self,
        scalar_to_plot:
        str = "potential",  # "potential", "streamfunction", "xvel", "yvel", "velmag", "Cp"
        x_points: np.ndarray = np.linspace(-10, 10, 400),
        y_points: np.ndarray = np.linspace(-10, 10, 300),
        percentiles_to_include=99.7,
        show=True,
    ):
        X, Y = np.meshgrid(x_points, y_points)
        X_r = np.reshape(X, -1)
        Y_r = np.reshape(Y, -1)
        points = np.vstack((X_r, Y_r)).T

        if scalar_to_plot == "potential":
            scalar_to_plot_value = sum(
                [object.get_potential_at(points) for object in self.objects])
        elif scalar_to_plot == "streamfunction":
            scalar_to_plot_value = sum([
                object.get_streamfunction_at(points) for object in self.objects
            ])
        elif scalar_to_plot == "xvel":
            scalar_to_plot_value = sum(
                [object.get_x_velocity_at(points) for object in self.objects])
        elif scalar_to_plot == "yvel":
            scalar_to_plot_value = sum(
                [object.get_y_velocity_at(points) for object in self.objects])
        elif scalar_to_plot == "velmag":
            x_vels = sum(
                [object.get_x_velocity_at(points) for object in self.objects])
            y_vels = sum(
                [object.get_y_velocity_at(points) for object in self.objects])
            scalar_to_plot_value = np.sqrt(x_vels**2 + y_vels**2)
        elif scalar_to_plot == "Cp":
            x_vels = sum(
                [object.get_x_velocity_at(points) for object in self.objects])
            y_vels = sum(
                [object.get_y_velocity_at(points) for object in self.objects])
            V = np.sqrt(x_vels**2 + y_vels**2)
            scalar_to_plot_value = 1 - V**2
        else:
            raise ValueError("Bad value of `scalar_to_plot`!")

        min = np.nanpercentile(scalar_to_plot_value,
                               50 - percentiles_to_include / 2)
        max = np.nanpercentile(scalar_to_plot_value,
                               50 + percentiles_to_include / 2)

        contour(x_points,
                y_points,
                scalar_to_plot_value.reshape(X.shape),
                levels=np.linspace(min, max, 80),
                linelabels=False,
                cmap=plt.get_cmap("rainbow"),
                contour_kwargs={
                    "linestyles": 'solid',
                    "alpha": 0.4
                })
        plt.gca().set_aspect("equal", adjustable='box')
        show_plot(f"Potential Flow: {scalar_to_plot}", "$x$", "$y$", show=show)
Пример #2
0
def stack_coordinates(x: np.ndarray, y: np.ndarray) -> np.ndarray:
    """
    Stacks a pair of x, y coordinate arrays into a Nx2 ndarray.
    Args:
        x: A 1D ndarray of x-coordinates
        y: A 1D ndarray of y-coordinates

    Returns: A Nx2 ndarray of [x, y] coordinates.

    """
    return np.vstack((x, y)).T
Пример #3
0
def get_kulfan_coordinates(
        lower_weights=-0.2 * np.ones(5),  # type: np.ndarray
        upper_weights=0.2 * np.ones(5),  # type: np.ndarray
        enforce_continuous_LE_radius=True,
        TE_thickness=0.,  # type: float
        n_points_per_side=_default_n_points_per_side,  # type: int
        N1=0.5,  # type: float
        N2=1.0,  # type: float
) -> np.ndarray:
    """
    Calculates the coordinates of a Kulfan (CST) airfoil.
    To make a Kulfan (CST) airfoil, use the following syntax:

    asb.Airfoil("My Airfoil Name", coordinates = asb.kulfan_coordinates(*args))

    More on Kulfan (CST) airfoils: http://brendakulfan.com/docs/CST2.pdf
    Notes on N1, N2 (shape factor) combinations:
        * 0.5, 1: Conventional airfoil
        * 0.5, 0.5: Elliptic airfoil
        * 1, 1: Biconvex airfoil
        * 0.75, 0.75: Sears-Haack body (radius distribution)
        * 0.75, 0.25: Low-drag projectile
        * 1, 0.001: Cone or wedge airfoil
        * 0.001, 0.001: Rectangle, circular duct, or circular rod.
    :param lower_weights:
    :param upper_weights:
    :param enforce_continuous_LE_radius: Enforces a continous leading-edge radius by throwing out the first lower weight.
    :param TE_thickness:
    :param n_points_per_side:
    :param N1: LE shape factor
    :param N2: TE shape factor
    :return:
    """

    if enforce_continuous_LE_radius:
        lower_weights[0] = -1 * upper_weights[0]

    x_lower = np.cosspace(0, 1, n_points_per_side)
    x_upper = x_lower[::-1]

    x_lower = x_lower[
        1:]  # Trim off the nose coordinate so there are no duplicates

    def shape(w, x):
        # Class function
        C = x**N1 * (1 - x)**N2

        # Shape function (Bernstein polynomials)
        n = len(w) - 1  # Order of Bernstein polynomials

        K = comb(n, np.arange(n + 1))  # Bernstein polynomial coefficients

        S_matrix = (w * K * np.expand_dims(x, 1)**np.arange(n + 1) *
                    np.expand_dims(1 - x, 1)**(n - np.arange(n + 1))
                    )  # Polynomial coefficient * weight matrix
        # S = np.sum(S_matrix, axis=1)
        S = np.array(
            [np.sum(S_matrix[i, :]) for i in range(S_matrix.shape[0])])

        # Calculate y output
        y = C * S
        return y

    y_lower = shape(lower_weights, x_lower)
    y_upper = shape(upper_weights, x_upper)

    # TE thickness
    y_lower -= x_lower * TE_thickness / 2
    y_upper += x_upper * TE_thickness / 2

    x = np.concatenate([x_upper, x_lower])
    y = np.concatenate([y_upper, y_lower])
    coordinates = np.vstack((x, y)).T

    return coordinates