pymead.core.airfoil.Airfoil#
- class Airfoil(leading_edge: Point, trailing_edge: Point, upper_surf_end: Point | None = None, lower_surf_end: Point | None = None, name: str | None = None)[source]#
Bases:
PymeadObjThis is a primary class in pymead, which defines an airfoil by a leading edge, a trailing edge, and optionally an upper-surface endpoint and a lower-surface endpoint in the case of a blunt airfoil. For the purposes of single-airfoil evaluation method (such as XFOIL or the built-in panel code), instances of this class are sufficient. For multi-element airfoil evaluation (such as MSES), instances of this class are stored in the container class,
pymead.core.mea.MEA, which adds some additional and necessary functionality. Coordinates are stored in thecoordsattribute and can be updated using theupdate_coordsmethod.- __init__(leading_edge: Point, trailing_edge: Point, upper_surf_end: Point | None = None, lower_surf_end: Point | None = None, name: str | None = None)[source]#
- Parameters:
leading_edge (Point) – The airfoil’s leading edge point (usually at \((0,0)\) for a typical single airfoil configuration)
trailing_edge (Point) – The airfoil’s trailing edge point (usually at \((1,0)\) for a typical single airfoil configuration)
upper_surf_end (Point) – Optional specification of the upper surface endpoint (the first point in the Selig file format). If this point is not specified, the trailing edge point is used instead. Default:
Nonelower_surf_end (Point) – Optional specification of the lower surface endpoint (the last point in the Selig file format). If this point is not specified, the trailing edge point is used instead. Default:
Nonename (str) – Optional name for the airfoil. If
None, a default name is used. Default:None
Methods
add_relative_points(points)Marks a list of control points tied to an airfoil as airfoil-relative
This method checks if the airfoil is composed of a closed set of curves.
Determines whether the airfoil intersects itself using the is_simple() function of the shapely library.
compute_area([airfoil_frame_relative])compute_camber_at_points(x_over_c[, ...])Calculates the thickness (t/c) at a set of x-locations (x/c)
compute_min_radius([chord_relative])Computes the minimum radius of curvature for the airfoil.
compute_thickness([airfoil_frame_relative, ...])Calculates the thickness distribution and maximum thickness of the airfoil.
compute_thickness_at_points(x_arr[, ...])Calculates the thickness (t/c) at a set of x-locations (x/c)
contains_line_string(points[, ...])Whether a connected string of points is contained inside the airfoil.
contains_point(point[, airfoil_frame_relative])Determines whether a point is contained inside the airfoil
downsample(max_airfoil_points[, curvature_exp])Downsamples the airfoil coordinates based on a curvature exponent.
get_chord_relative_coords([coords, ...])Gets the chord-relative values of the airfoil coordinates.
get_coords_selig_format([...])Gets the coordinates of the airfoil in the Selig file format (coordinate array of size \(N \times 2\), where \(N\) is the number of airfoil coordinates, and the columns represent \(x\) and \(y\)).
Gets a dictionary representation of the pymead object.
get_scaled_coords([coords, ...])Gets the chord-relative values of the airfoil coordinates.
Measures the angle of attack in radians
Measures the chord length
plot([ax, show, save_file])Plots the airfoil to a
matplotlibfigure.remove_relative_points(points)Removes the relative assignment of a list of points in an airfoil.
save_coords_selig_format(file_name)Saves this airfoil's coords in Selig file format: \(x\)- and \(y\)-columns in counter-clockwise order, starting at the upper surface trailing edge and ending at the lower surface trailing edge.
Updates the coordinates of the airfoil, and passes this data to the canvas item if it exists.
Updates the airfoil-coordinate-system-relative points that are part of this airfoil.
visualize_contains_line_string(points[, ...])Gets the data necessary to visualize the containment of an input line string inside the airfoil.
Gets airfoil data necessary to visualize the maximum thickness.
Gets airfoil data necessary to visualize the minimum radius of curvature.
visualize_thickness_at_points(x_arr, ...[, ...])Computes the thickness at a set of x-locations with additional data for visualization purposes.
Attributes
- add_relative_points(points: list[Point])[source]#
Marks a list of control points tied to an airfoil as airfoil-relative
- check_closed() None[source]#
This method checks if the airfoil is composed of a closed set of curves. If the airfoil is closed, the method passes, but if the airfoil is not closed, a
ClosureErroris raised. This method also determines which curves need to be evaluated in the opposite parametric direction of their point sequences.- Returns:
Nothing is returned if the closure check passes, but an error is raised pre-return if the closure check does not pass
- Return type:
None
- check_self_intersection() bool[source]#
Determines whether the airfoil intersects itself using the is_simple() function of the shapely library.
- Returns:
Describes whether the airfoil intersects itself
- Return type:
- compute_area(airfoil_frame_relative: bool = False) float[source]#
Computes the area of the airfoil as the area of a many-sided polygon enclosed by the airfoil coordinates using the shapely library.
- compute_camber_at_points(x_over_c: ndarray, airfoil_frame_relative: bool = False, start_y_over_c: float = -1.0, end_y_over_c: float = 1.0) ndarray[source]#
Calculates the thickness (t/c) at a set of x-locations (x/c)
- Parameters:
x_over_c (float or list or np.ndarray) – The \(x/c\) locations at which to evaluate the camber
airfoil_frame_relative (bool) – Whether to compute the area in the airfoil-relative frame. If
True, the thickness based on a chord-relative scaling will be returned. Default:Falsestart_y_over_c (float) – The \(y/c\) location to draw the first point in a line whose intersection with the airfoil is checked. May need to decrease this value for unusually thick airfoils
end_y_over_c (float) – The \(y/c\) location to draw the last point in a line whose intersection with the airfoil is checked. May need to increase this value for unusually thick airfoils
- Returns:
An array of thickness (\(t/c\)) values corresponding to the input \(x/c\) values
- Return type:
np.ndarray
- compute_min_radius(chord_relative: bool = False) float[source]#
Computes the minimum radius of curvature for the airfoil.
- compute_thickness(airfoil_frame_relative: bool = False, n_lines: int = 201) dict[str, float][source]#
Calculates the thickness distribution and maximum thickness of the airfoil.
- Parameters:
airfoil_frame_relative (bool) – Whether to compute the thickness distribution in the airfoil-relative frame. If
True, the thickness based on a chord-relative scaling will be returned. Default:Falsen_lines (int) – Describes the number of lines evenly spaced along the chordline produced to determine the thickness distribution. Default: 201
- Returns:
The list of \(x\)-values used for the thickness distribution calculation, the thickness distribution, the maximum value of the thickness distribution, and, if
return_max_thickness_location=True, the \(x/c\)-location of the maximum thickness value.- Return type:
- compute_thickness_at_points(x_arr: ndarray, airfoil_frame_relative: bool = False, vertical_check: bool = False) ndarray[source]#
Calculates the thickness (t/c) at a set of x-locations (x/c)
Warning
If the airfoil’s angle of attack is far from zero and
vertical_check==True, this method may yield undesirable results.- Parameters:
x_arr (float or list or np.ndarray) – The \(x\) (or \(x/c\) if
airfoil_frame_relative==True) locations at which to evaluate the thicknessairfoil_frame_relative (bool) – Whether to compute the area in the airfoil-relative frame. If
True, the thickness based on a chord-relative scaling will be returned. Default:Falsevertical_check (bool) – Whether to compute the thickness vertically from the chordline (rather than perpendicular). This value is ignored unless``airfoil_frame_relative==False``.
- Returns:
An array of thickness (\(t/c\)) values corresponding to the input \(x/c\) values
- Return type:
np.ndarray
- contains_line_string(points: ndarray | list, airfoil_frame_relative: bool = False, rotate_with_airfoil: bool = True, translate_with_airfoil: bool = True, scale_with_airfoil: bool = True) bool[source]#
Whether a connected string of points is contained inside the airfoil.
- Parameters:
points (np.ndarray or list) – Should be a 2-D array or list of the form
[[<x_val_1>, <y_val_1>], [<x_val_2>, <y_val_2>], ...]airfoil_frame_relative (bool) – Whether to run the enclosure test with the line string defined in the airfoil-relative frame. Default:
Falserotate_with_airfoil (bool) – Whether to rotate the line string by the opposite of the airfoil’s angle of attack before running the test. Default:
Truetranslate_with_airfoil (bool) – Whether to translate the line string by a displacement equal to the airfoil’s leading edge location before running the test. Default:
Truescale_with_airfoil (bool) – Whether to scale the line string by the airfoil’s chord before running the test. Default:
True
- Returns:
Whether the line string is contained inside the airfoil
- Return type:
- contains_point(point: ndarray, airfoil_frame_relative: bool = False) bool[source]#
Determines whether a point is contained inside the airfoil
- Parameters:
point (np.ndarray or list) – The point to test. Should be either a 1-D
ndarrayof the formatarray([<x_val>,<y_val>])or a list of the format[<x_val>,<y_val>]airfoil_frame_relative (bool) – Whether to check for point containment in the airfoil-relative frame. If
True, the airfoil will be scaled by the chord, de-rotated, and the leading edge moved to \((0,0)\) before checking if the point is inside the airfoil. Default:False
- Returns:
Whether the point is contained inside the airfoil
- Return type:
- downsample(max_airfoil_points: int, curvature_exp: float = 2.0) list[ndarray][source]#
Downsamples the airfoil coordinates based on a curvature exponent. This method works by evaluating each Bézier curve using a set number of points (150) and then calculating \(\mathbf{R_e} = \mathbf{R}^{1/e_c}\), where \(\mathbf{R}\) is the radius of curvature vector and \(e_c\) is the curvature exponent (an input to this method). Then, \(\mathbf{R_e}\) is normalized by its maximum value and concatenated to a single array for all curves in a given airfoil. Finally,
max_airfoil_pointsare chosen from this array to create a new set of parameter vectors for the airfoil.- Parameters:
max_airfoil_points (int) – Maximum number of points in the airfoil (the actual number in the final airfoil may be slightly less)
curvature_exp (float) – Curvature exponent used to scale the radius of curvature. Values close to 0 place high emphasis on curvature, while values close to \(\infty\) place low emphasis on curvature (creating nearly uniform spacing)
- Returns:
List of parameter vectors (one for each Bézier curve)
- Return type:
list[np.ndarray]
- get_chord_relative_coords(coords: ndarray | None = None, max_airfoil_points: int | None = None, curvature_exp: float = 2.0) ndarray[source]#
Gets the chord-relative values of the airfoil coordinates. The airfoil is transformed such that the leading edge is at \((0,0)\) and the trailing edge is at \((1,0)\).
- Parameters:
coords (np.ndarray or None) – Optional Selig format airfoil coordinates (only specified if computational speed is important). If the coordinates are not specified, they are calculated.
max_airfoil_points (int) – Optional value specifying the maximum number of airfoil points. If this value is left as
None, no downsampling will be performed. Default:Nonecurvature_exp (float) – Optional value specifying the curvature exponent used in the
downsamplemethod. Ifmax_airfoil_pointsis left asNone, this value will be ignored. Default: 2
- Returns:
An \(N imes 2\) array of transformed airfoil coordinates
- Return type:
np.ndarray
- get_coords_selig_format(max_airfoil_points: int | None = None, curvature_exp: float = 2.0, n_points_per_curve: int = 150) ndarray[source]#
Gets the coordinates of the airfoil in the Selig file format (coordinate array of size \(N \times 2\), where \(N\) is the number of airfoil coordinates, and the columns represent \(x\) and \(y\)). The order of the points is counter-clockwise, with the start and end at the upper surface trailing edge point and lower surface trailing edge point, respectively.
- Parameters:
max_airfoil_points (int) – Optional value specifying the maximum number of airfoil points. If this value is left as
None, no downsampling will be performed. Default:Nonecurvature_exp (float) – Optional value specifying the curvature exponent used in the
downsamplemethod. Ifmax_airfoil_pointsis left asNone, this value will be ignored. Default: 2n_points_per_curve (int) – Number of points to evaluate for each Bézier curve. Default: 150
- Returns:
Coordinate array (size \(N \times 2\))
- Return type:
np.ndarray
- get_dict_rep() dict[source]#
Gets a dictionary representation of the pymead object. In general, this dictionary should consist of only the required arguments for object instantiation. For example, the dictionary representation of a point looks something like this:
{"x": 0.3, "y": 0.5}. If the argument requires a reference to aPymeadObjrather than a string or float value, thename()method should be the value that is stored. For an example, see the overridden value of this method inpymead.core.airfoil.Airfoil. All subclasses ofPymeadObjmust implement this method, since it is the way pymead objects are stored in saved instances of aGeometryCollection(.jmeafiles).
- get_scaled_coords(coords: ndarray | None = None, max_airfoil_points: int | None = None, curvature_exp: float = 2.0) ndarray[source]#
Gets the chord-relative values of the airfoil coordinates. The airfoil is transformed such that the leading edge is at \((0,0)\) and the trailing edge is at \((1,0)\).
- Parameters:
coords (np.ndarray or None) – Optional Selig format airfoil coordinates (only specified if computational speed is important). If the coordinates are not specified, they are calculated.
max_airfoil_points (int) – Optional value specifying the maximum number of airfoil points. If this value is left as
None, no downsampling will be performed. Default:Nonecurvature_exp (float) – Optional value specifying the curvature exponent used in the
downsamplemethod. Ifmax_airfoil_pointsis left asNone, this value will be ignored. Default: 2
- Returns:
An \(N \times 2\) array of transformed airfoil coordinates
- Return type:
np.ndarray
- measure_alpha() float[source]#
Measures the angle of attack in radians
- Returns:
The airfoil’s current angle of attack
- Return type:
- measure_chord() float[source]#
Measures the chord length
- Returns:
The airfoil’s current chord length
- Return type:
- plot(ax: Axes | None = None, show: bool = True, save_file: str | None = None, **plt_kwargs)[source]#
Plots the airfoil to a
matplotlibfigure.- Parameters:
ax (plt.Axes or None) – Matplotlib Axes object on which the airfoil will be plotted. If specified, this method will only plot the airfoil curves and ignore the subsequent functionality. Default:
Noneshow (bool) – Whether to immediately show the airfoil plot. Ignored if
axis notNone. Default:Truesave_file (str or None) – Name of the file to save. If
None, the airfoil image will not be saved to file. Ignored ifaxis notNone. Default:Noneplt_kwargs – Additional keyword arguments to pass to
matplotlib.pyplot.plot
- remove_relative_points(points: list[Point])[source]#
Removes the relative assignment of a list of points in an airfoil.
- save_coords_selig_format(file_name: str) None[source]#
Saves this airfoil’s coords in Selig file format: \(x\)- and \(y\)-columns in counter-clockwise order, starting at the upper surface trailing edge and ending at the lower surface trailing edge. File saves as a text file (usually a
.txtor.datfile extension).- Parameters:
file_name (str) – Full path to the coordinate file save location
- update_coords()[source]#
Updates the coordinates of the airfoil, and passes this data to the canvas item if it exists.
- update_relative_points(original_geo_col_point_values: dict[str, ndarray])[source]#
Updates the airfoil-coordinate-system-relative points that are part of this airfoil.
- visualize_contains_line_string(points: ndarray | list, airfoil_frame_relative: bool = False, rotate_with_airfoil: bool = True, translate_with_airfoil: bool = True, scale_with_airfoil: bool = True) dict[source]#
Gets the data necessary to visualize the containment of an input line string inside the airfoil.
- Parameters:
points (np.ndarray or list) – Array of points of the form
[[x1, y1], [x2, y2], ...]corresponding to the sequence of points defining a line string that must be contained inside the airfoil for the constraint test to passairfoil_frame_relative (bool) – Whether the line string is defined in the airfoil-relative frame. Default:
Falserotate_with_airfoil (bool) – Whether the line string should be rotated by the angle corresponding to the opposite of the airfoil angle of attack before performing the line string containment check. Default:
Truetranslate_with_airfoil (bool) – Whether the line string should be translated by
(x_LE, y_LE), which is the point corresponding to the airfoil leading edge, before performing the line string containment check. Default:Truescale_with_airfoil (bool) – Whether the line string should be scaled by the airfoil chord length before performing the line string containment check. Default:
True
- Returns:
Data with the following fields:
"pass": abooldescribing whether the line string containment check passed"xy_polyline": anumpyarray of the formnp.array([[x1, y1], [x2, y2], ...])matching the points input to the method
- Return type:
- visualize_max_thickness() dict[source]#
Gets airfoil data necessary to visualize the maximum thickness.
- Returns:
Data for maximum thickness with the following fields:
"xy":numpyarray of the formnp.array([[x1, y1], [x2, y2]])wherex1andy1are the \(x\)- and \(y\)-locations of the starting point of the maximum thickness line, andx2andy2are the \(x\)- and \(y\)-locations of the maximum thickness line"t_max": dimensional maximum thickness value"t/c_max": non-dimensional maximum thickness value (maximum thickness divided by the chord length)"x/c": non-dimensional \(x\)-location corresponding where the maximum thickness was found
- Return type:
- visualize_min_radius() dict[source]#
Gets airfoil data necessary to visualize the minimum radius of curvature.
- Returns:
Data for minimum radius of curvature with the following fields:
"R_abs_min": absolute value of the minimum radius of curvature"R_abs_min_over_c": absolute value of the minimum radius of curvature normalized by the chord length"xy": Two-element 1-Dnumpyarray containing the \(x\)- and \(y\)-values of the point on the airfoil surface corresponding to the minimum radius of curvature
- Return type:
- visualize_thickness_at_points(x_arr: ndarray, thickness_constraints, airfoil_frame_relative: bool = False, vertical_check: bool = False) dict[source]#
Computes the thickness at a set of x-locations with additional data for visualization purposes.
Warning
If the airfoil’s angle of attack is far from zero and
vertical_check==True, this method may yield undesirable results.- Parameters:
x_arr (float or list or np.ndarray) – The \(x\) (or \(x/c\) if
airfoil_frame_relative==True) locations at which to evaluate the thicknessairfoil_frame_relative (bool) – Whether to compute the area in the airfoil-relative frame. If
True, the thickness based on a chord-relative scaling will be returned. Default:Falsevertical_check (bool) – Whether to compute the thickness vertically from the chordline (rather than perpendicular). This value is ignored unless``airfoil_frame_relative==False``.
- Returns:
Data with the following fields:
"slices": List of slices for visualization of the form[np.array([[x1, y1], [x2, y2]]), np.array([[x3, y3], [x4, y4]]), ...], where each pair of points corresponds to a line of length equal to the value of a thickness constraint at an angle corresponding to the thickness evaluation direction (either chord-normal or vertical) and centered about the midpoint between the intersections of a line passing through that \(x\)-value on the airfoil"warning_x_vals": \(x\)-locations of the input set where an individual thickness test does notpass
- Return type: