Source code for RCAIDE.Library.Methods.Geometry.Airfoil.convert_airfoil_to_meshgrid
# RCAIDE/Library/Methods/Geometry/Two_Dimensional/Airfoil/convert_airfoil_to_meshgrid.py
#
#
# Created: Jul 2024, M. Clarke
# ----------------------------------------------------------------------------------------------------------------------
# IMPORT
# ----------------------------------------------------------------------------------------------------------------------
import numpy as np
# ----------------------------------------------------------------------------------------------------------------------
# convert_airfoil_to_meshgrid
# ----------------------------------------------------------------------------------------------------------------------
[docs]
def convert_airfoil_to_meshgrid(airfoil_geometry, *args, **kwargs):
"""Converts a RCAIDE airfoil geometry representation to a Numpy meshgrid
array mask of boolean values.
Assumptions:
None
Source:
None
Inputs:
airfoil_geometry [RCAIDE Data Structure]
.x_lower_surface [Numpy Array, float32]
.y_lower_surface [Numpy Array, float32]
.y_upper_surface [Numpy Array, float32]
Outputs:
airfoil_meshgrid [Numpy Array, bool]
Properties Used:
N/A
"""
# Unpack Values
x_lower_surface = airfoil_geometry.x_lower_surface
y_lower_surface = airfoil_geometry.y_lower_surface
y_upper_surface = airfoil_geometry.y_upper_surface
# Determine necessary resolution of the meshgrid. We do this by dividing the
# x-length of the lower surface by the minimum separation between
# any two x-coordinates of the geometry (ceil-rounded to an int). Later
# we'll instantiate the meshgrid with this number of x-indices, so that the
# separation between any two points in the meshgrid is equal to the minimum
# separation between any two x-coordinates.
x_length = (
np.max(x_lower_surface)
)
Nx = np.ceil(
x_length / np.abs(np.min(np.diff(x_lower_surface)))
).astype(int)
# We determine the necessary number of y-coordinate points by taking the
# maximum separation between the highest point of the upper surface and the
# lowest point of the lower surface and multiplying that by the number of
# x-points in order to re-normalize to our future meshgrid coordinates,
# then ciel-rounding to an int.
Ny = np.ceil(
Nx * ( np.max(y_upper_surface) - np.min(y_lower_surface) )
).astype(int)
# Instantiate the meshgrid, using ij-indexing so that X[i,j] returns i
# for all points, and Y[i,j] returns j for all coordinates.
X, Y = np.meshgrid(np.arange(Nx), np.arange(Ny), indexing="ij")
# Create the indexing arrays for the meshgrid. These convert the airfoil
# geometry coordinates into meshgrid array indices. The X_INDICES are found
# just by multplying/stretching the x_lower_surface coordinates across the
# number of x-coodinates in the meshgrid.
X_INDICES = np.ceil(
Nx / x_length * x_lower_surface
).astype(int)
# The Y_INDICES are similarly stretched, but first are offset by the
# minimum of the lower surface to bring them to a relative zero
Y_LOWER_INDICES = np.floor(
Nx / x_length * (
y_lower_surface - np.min(y_lower_surface)
)
).astype(int)
Y_UPPER_INDICES = np.ceil(
Nx /x_length * (
y_upper_surface - np.min(y_lower_surface)
)
).astype(int)
# We then repeat the elements of the Y_INDICES by the number of gridpoints
# between each x-coordinate, essentially treating the y-surface as flat
# between those points. We trim the final point by telling it to repeat 0
# times
REPEATS = np.append(
np.diff(X_INDICES),
0
)
# Need to hand the case where the X_INDICES aren't sorted, and swap
# some elements around to allow the masks to be created
if np.any(REPEATS<0):
REPEAT_FLAG = True
NEG_REPEATS = np.where(REPEATS<0)[0]
if np.any(np.diff(NEG_REPEATS) == 1):
print("Airfoil geometry contains sequential negative x-steps. Meshing Failed.")
return None
(X_INDICES[NEG_REPEATS],
X_INDICES[NEG_REPEATS + 1]) = (X_INDICES[NEG_REPEATS + 1],
X_INDICES[NEG_REPEATS])
(Y_LOWER_INDICES[NEG_REPEATS],
Y_LOWER_INDICES[NEG_REPEATS + 1]) = (Y_LOWER_INDICES[NEG_REPEATS + 1],
Y_LOWER_INDICES[NEG_REPEATS])
(Y_UPPER_INDICES[NEG_REPEATS],
Y_UPPER_INDICES[NEG_REPEATS + 1]) = (Y_UPPER_INDICES[NEG_REPEATS + 1],
Y_UPPER_INDICES[NEG_REPEATS])
REPEATS = np.append(
np.diff(X_INDICES),
0
)
Nx = np.sum(REPEATS)
Ny = np.ceil(
Nx * (np.max(y_upper_surface) - np.min(y_lower_surface))
).astype(int)
X, Y = np.meshgrid(np.arange(Nx), np.arange(Ny), indexing="ij")
Y_LOWER_INDICES = np.repeat(Y_LOWER_INDICES, REPEATS)
Y_UPPER_INDICES = np.repeat(Y_UPPER_INDICES, REPEATS)
# We then create masks for the upper and lower surfaces by tiling the
# indices over the meshgrid (taking a transpose to comport with our earlier
# indexing style).
Y_LOWER_GRID = np.tile(Y_LOWER_INDICES, (Ny,1)).T
Y_UPPER_GRID = np.tile(Y_UPPER_INDICES, (Ny,1)).T
# We then create our airfoil meshgrid mask by comparing our Y coordinates
# from the meshgrid to our upper and lower grids, intermediately treating
# them as ints to simplify the multi-condition comparison
Y_LOWER = (Y > Y_LOWER_GRID).astype(int)
Y_UPPER = (Y < Y_UPPER_GRID).astype(int)
AIRFOIL_MASK = (Y_LOWER + Y_UPPER) > 1
return AIRFOIL_MASK