Source code for rocketpy.plots.aero_surface_plots

from abc import ABC, abstractmethod

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Ellipse


[docs] class _AeroSurfacePlots(ABC): """Abstract class that contains all aero surface plots."""
[docs] def __init__(self, aero_surface): """Initialize the class Parameters ---------- aero_surface : rocketpy.AeroSurface AeroSurface object to be plotted Returns ------- None """ self.aero_surface = aero_surface return None
@abstractmethod def draw(self): pass
[docs] def lift(self): """Plots the lift coefficient of the aero surface as a function of Mach and the angle of attack. A 3D plot is expected. See the rocketpy.Function class for more information on how this plot is made. Returns ------- None """ self.aero_surface.cl() return None
[docs] def all(self): """Plots all aero surface plots. Returns ------- None """ self.draw() self.lift() return None
[docs] class _NoseConePlots(_AeroSurfacePlots): """Class that contains all nosecone plots. This class inherits from the _AeroSurfacePlots class."""
[docs] def __init__(self, nosecone): """Initialize the class Parameters ---------- nosecone : rocketpy.AeroSurface.NoseCone Nosecone object to be plotted Returns ------- None """ super().__init__(nosecone) return None
[docs] def draw(self): """Draw the nosecone shape along with some important information, including the center line and the center of pressure position. Returns ------- None """ # Create the vectors X and Y with the points of the curve nosecone_x, nosecone_y = self.aero_surface.shape_vec # Figure creation and set up fig_ogive, ax = plt.subplots() ax.set_xlim(-0.05, self.aero_surface.length * 1.02) # Horizontal size ax.set_ylim( -self.aero_surface.base_radius * 1.05, self.aero_surface.base_radius * 1.05 ) # Vertical size ax.set_aspect("equal") # Makes the graduation be the same on both axis ax.set_facecolor("#EEEEEE") # Background color ax.grid(True, linestyle="--", linewidth=0.5) cp_plot = (self.aero_surface.cpz, 0) # Plotting ax.plot( nosecone_x, nosecone_y, linestyle="-", color="#A60628", ) # Ogive's upper side ax.plot( nosecone_x, -nosecone_y, linestyle="-", color="#A60628", ) # Ogive's lower side ax.scatter( *cp_plot, label="Center Of Pressure", color="red", s=100, zorder=10 ) # Center of pressure inner circle ax.scatter( *cp_plot, facecolors="none", edgecolors="red", s=500, zorder=10 ) # Center of pressure outer circle # Center Line ax.plot( [0, nosecone_x[len(nosecone_x) - 1]], [0, 0], linestyle="--", color="#7A68A6", linewidth=1.5, label="Center Line", ) # Vertical base line ax.plot( [ nosecone_x[len(nosecone_x) - 1], nosecone_x[len(nosecone_x) - 1], ], [ nosecone_y[len(nosecone_y) - 1], -nosecone_y[len(nosecone_y) - 1], ], linestyle="-", color="#A60628", linewidth=1.5, ) # Labels and legend ax.set_xlabel("Length") ax.set_ylabel("Radius") ax.set_title(self.aero_surface.kind + " Nose Cone") ax.legend(bbox_to_anchor=(1, -0.2)) # Show Plot plt.show() return None
[docs] class _FinsPlots(_AeroSurfacePlots): """Abstract class that contains all fin plots. This class inherits from the _AeroSurfacePlots class."""
[docs] def __init__(self, fin_set): """Initialize the class Parameters ---------- fin_set : rocketpy.AeroSurface.fin_set fin_set object to be plotted Returns ------- None """ super().__init__(fin_set) return None
@abstractmethod def draw(self): pass
[docs] def airfoil(self): """Plots the airfoil information when the fin has an airfoil shape. If the fin does not have an airfoil shape, this method does nothing. Returns ------- None """ if self.aero_surface.airfoil: print("Airfoil lift curve:") self.aero_surface.airfoil_cl.plot_1d(force_data=True) return None
[docs] def roll(self): """Plots the roll parameters of the fin set. Returns ------- None """ print("Roll parameters:") # TODO: lacks a title in the plots self.aero_surface.roll_parameters[0]() self.aero_surface.roll_parameters[1]() return None
[docs] def lift(self): """Plots the lift coefficient of the aero surface as a function of Mach and the angle of attack. A 3D plot is expected. See the rocketpy.Function class for more information on how this plot is made. Also, this method plots the lift coefficient considering a single fin and the lift coefficient considering all fins. Returns ------- None """ print("Lift coefficient:") self.aero_surface.cl() self.aero_surface.clalpha_single_fin() self.aero_surface.clalpha_multiple_fins() return None
[docs] def all(self): """Plots all available fin plots. Returns ------- None """ self.draw() self.airfoil() self.roll() self.lift() return None
[docs] class _TrapezoidalFinsPlots(_FinsPlots): """Class that contains all trapezoidal fin plots."""
[docs] def __init__(self, fin_set): super().__init__(fin_set) return None
[docs] def draw(self): """Draw the fin shape along with some important information, including the center line, the quarter line and the center of pressure position. Returns ------- None """ # Color cycle [#348ABD, #A60628, #7A68A6, #467821, #D55E00, #CC79A7, # #56B4E9, #009E73, #F0E442, #0072B2] # Fin leading_edge = plt.Line2D( (0, self.aero_surface.sweep_length), (0, self.aero_surface.span), color="#A60628", ) tip = plt.Line2D( ( self.aero_surface.sweep_length, self.aero_surface.sweep_length + self.aero_surface.tip_chord, ), (self.aero_surface.span, self.aero_surface.span), color="#A60628", ) back_edge = plt.Line2D( ( self.aero_surface.sweep_length + self.aero_surface.tip_chord, self.aero_surface.root_chord, ), (self.aero_surface.span, 0), color="#A60628", ) root = plt.Line2D((self.aero_surface.root_chord, 0), (0, 0), color="#A60628") # Center and Quarter line center_line = plt.Line2D( ( self.aero_surface.root_chord / 2, self.aero_surface.sweep_length + self.aero_surface.tip_chord / 2, ), (0, self.aero_surface.span), color="#7A68A6", alpha=0.35, linestyle="--", label="Center Line", ) quarter_line = plt.Line2D( ( self.aero_surface.root_chord / 4, self.aero_surface.sweep_length + self.aero_surface.tip_chord / 4, ), (0, self.aero_surface.span), color="#7A68A6", alpha=1, linestyle="--", label="Quarter Line", ) # Center of pressure cp_point = [self.aero_surface.cpz, self.aero_surface.Yma] # Mean Aerodynamic Chord yma_start = ( self.aero_surface.sweep_length * (self.aero_surface.root_chord + 2 * self.aero_surface.tip_chord) / (3 * (self.aero_surface.root_chord + self.aero_surface.tip_chord)) ) yma_end = ( 2 * self.aero_surface.root_chord**2 + self.aero_surface.root_chord * self.aero_surface.sweep_length + 2 * self.aero_surface.root_chord * self.aero_surface.tip_chord + 2 * self.aero_surface.sweep_length * self.aero_surface.tip_chord + 2 * self.aero_surface.tip_chord**2 ) / (3 * (self.aero_surface.root_chord + self.aero_surface.tip_chord)) yma_line = plt.Line2D( (yma_start, yma_end), (self.aero_surface.Yma, self.aero_surface.Yma), color="#467821", linestyle="--", label="Mean Aerodynamic Chord", ) # Plotting fig = plt.figure(figsize=(7, 4)) with plt.style.context("bmh"): ax = fig.add_subplot(111) # Fin ax.add_line(leading_edge) ax.add_line(tip) ax.add_line(back_edge) ax.add_line(root) ax.add_line(center_line) ax.add_line(quarter_line) ax.add_line(yma_line) ax.scatter(*cp_point, label="Center of Pressure", color="red", s=100, zorder=10) ax.scatter(*cp_point, facecolors="none", edgecolors="red", s=500, zorder=10) # Plot settings xlim = ( self.aero_surface.root_chord if self.aero_surface.sweep_length + self.aero_surface.tip_chord < self.aero_surface.root_chord else self.aero_surface.sweep_length + self.aero_surface.tip_chord ) ax.set_xlim(0, xlim * 1.1) ax.set_ylim(0, self.aero_surface.span * 1.1) ax.set_xlabel("Root chord (m)") ax.set_ylabel("Span (m)") ax.set_title("Trapezoidal Fin Cross Section") ax.legend(bbox_to_anchor=(1.05, 1.0), loc="upper left") plt.tight_layout() plt.show() return None
[docs] class _EllipticalFinsPlots(_FinsPlots): """Class that contains all elliptical fin plots."""
[docs] def __init__(self, fin_set): super().__init__(fin_set) return None
[docs] def draw(self): """Draw the fin shape along with some important information. These being: the center line and the center of pressure position. Returns ------- None """ # Ellipse ellipse = Ellipse( (self.aero_surface.root_chord / 2, 0), self.aero_surface.root_chord, self.aero_surface.span * 2, fill=False, edgecolor="#A60628", linewidth=2, ) # Mean Aerodynamic Chord # From Barrowman's theory yma_length = 8 * self.aero_surface.root_chord / (3 * np.pi) yma_start = (self.aero_surface.root_chord - yma_length) / 2 yma_end = ( self.aero_surface.root_chord - (self.aero_surface.root_chord - yma_length) / 2 ) yma_line = plt.Line2D( (yma_start, yma_end), (self.aero_surface.Yma, self.aero_surface.Yma), label="Mean Aerodynamic Chord", color="#467821", ) # Center Line center_line = plt.Line2D( (self.aero_surface.root_chord / 2, self.aero_surface.root_chord / 2), (0, self.aero_surface.span), color="#7A68A6", alpha=0.35, linestyle="--", label="Center Line", ) # Center of pressure cp_point = [self.aero_surface.cpz, self.aero_surface.Yma] # Plotting fig = plt.figure(figsize=(7, 4)) with plt.style.context("bmh"): ax = fig.add_subplot(111) ax.add_patch(ellipse) ax.add_line(yma_line) ax.add_line(center_line) ax.scatter(*cp_point, label="Center of Pressure", color="red", s=100, zorder=10) ax.scatter(*cp_point, facecolors="none", edgecolors="red", s=500, zorder=10) # Plot settings ax.set_xlim(0, self.aero_surface.root_chord) ax.set_ylim(0, self.aero_surface.span * 1.1) ax.set_xlabel("Root chord (m)") ax.set_ylabel("Span (m)") ax.set_title("Elliptical Fin Cross Section") ax.legend(bbox_to_anchor=(1.05, 1.0), loc="upper left") plt.tight_layout() plt.show() return None
[docs] class _TailPlots(_AeroSurfacePlots): """Class that contains all tail plots."""
[docs] def __init__(self, tail): """Initialize the class Parameters ---------- tail : rocketpy.AeroSurface.Tail Tail object to be plotted Returns ------- None """ super().__init__(tail) return None
def draw(self): # This will de done in the future return None
class _AirBrakesPlots(_AeroSurfacePlots): """Class that contains all air brakes plots.""" def __init__(self, air_brakes): """Initialize the class Parameters ---------- air_brakes : rocketpy.AeroSurface.air_brakes AirBrakes object to be plotted Returns ------- None """ super().__init__(air_brakes) def drag_coefficient_curve(self): """Plots the drag coefficient curve of the air_brakes.""" if self.aero_surface.clamp is True: return self.aero_surface.drag_coefficient.plot(0, 1) else: return self.aero_surface.drag_coefficient.plot() def draw(self): raise NotImplementedError def all(self): """Plots all available air_brakes plots. Returns ------- None """ self.drag_coefficient_curve()