Source code for rocketpy.plots.tank_plots

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation
from matplotlib.patches import Polygon

from rocketpy.mathutils.function import Function

from .plot_helpers import show_or_save_animation, show_or_save_plot


[docs] class _TankPlots: """Class that holds plot methods for Tank class. Attributes ---------- _TankPlots.tank : Tank Tank object that will be used for the plots. """
[docs] def __init__(self, tank): """Initializes _MotorClass class. Parameters ---------- tank : Tank Instance of the Tank class Returns ------- None """ self.tank = tank self.name = tank.name self.flux_time = tank.flux_time self.geometry = tank.geometry
[docs] def _generate_tank(self, translate=(0, 0), csys=1): """Generates a matplotlib patch object that represents the tank. Parameters ---------- ax : matplotlib.axes.Axes, optional Axes object to plot the tank on. If None, a new figure and axes will be created. translate : tuple, optional Tuple of floats that represents the translation of the tank geometry. csys : float, optional Coordinate system of the tank, this will define the orientation of the tank. Default is 1, which means that the tank will be drawn with the nose cone pointing left. Returns ------- tank : matplotlib.patches.Polygon Polygon object that represents the tank. """ # get positions of all points x = csys * self.geometry.radius.x_array + translate[0] y = csys * self.geometry.radius.y_array + translate[1] x = np.concatenate([x, x[::-1]]) y = np.concatenate([y, -y[::-1]]) xy = np.column_stack([x, y]) tank = Polygon( xy, label=self.name, facecolor="dimgray", edgecolor="black", ) # Don't set any plot config here. Use the draw methods for that return tank
[docs] def draw(self, *, filename=None): """Draws the tank geometry. Parameters ---------- filename : str | None, optional The path the plot should be saved to. By default None, in which case the plot will be shown instead of saved. Supported file endings are: eps, jpg, jpeg, pdf, pgf, png, ps, raw, rgba, svg, svgz, tif, tiff and webp (these are the formats supported by matplotlib). Returns ------- None """ _, ax = plt.subplots(facecolor="#EEEEEE") ax.add_patch(self._generate_tank()) ax.set_aspect("equal") ax.grid(True, linestyle="--", linewidth=0.5) ax.set_xlabel("Length (m)") ax.set_ylabel("Radius (m)") ax.set_title("Tank Geometry") x_max = self.geometry.radius.x_array.max() y_max = self.geometry.radius.y_array.max() ax.set_xlim(-1.2 * x_max, 1.2 * x_max) ax.set_ylim(-1.5 * y_max, 1.5 * y_max) show_or_save_plot(filename)
[docs] def fluid_volume(self, filename=None): """Plots both the liquid and gas fluid volumes. Parameters ---------- filename : str | None, optional The path the plot should be saved to. By default None, in which case the plot will be shown instead of saved. Supported file endings are: eps, jpg, jpeg, pdf, pgf, png, ps, raw, rgba, svg, svgz, tif, tiff and webp (these are the formats supported by matplotlib). """ _, ax = Function.compare_plots( [self.tank.liquid_volume, self.tank.gas_volume], *self.flux_time, title="Fluid Volume (m^3) x Time (s)", xlabel="Time (s)", ylabel="Volume (m^3)", show=False, return_object=True, ) ax.legend(["Liquid", "Gas"]) show_or_save_plot(filename)
[docs] def fluid_height(self, filename=None): """Plots both the liquid and gas fluid height. Parameters ---------- filename : str | None, optional The path the plot should be saved to. By default None, in which case the plot will be shown instead of saved. Supported file endings are: eps, jpg, jpeg, pdf, pgf, png, ps, raw, rgba, svg, svgz, tif, tiff and webp (these are the formats supported by matplotlib). """ _, ax = Function.compare_plots( [self.tank.liquid_height, self.tank.gas_height], *self.flux_time, title="Fluid Height (m) x Time (s)", xlabel="Time (s)", ylabel="Height (m)", show=False, return_object=True, ) ax.legend(["Liquid", "Gas"]) show_or_save_plot(filename)
[docs] def fluid_center_of_mass(self, filename=None): """Plots the gas, liquid and combined center of mass. Parameters ---------- filename : str | None, optional The path the plot should be saved to. By default None, in which case the plot will be shown instead of saved. Supported file endings are: eps, jpg, jpeg, pdf, pgf, png, ps, raw, rgba, svg, svgz, tif, tiff and webp (these are the formats supported by matplotlib). """ _, ax = Function.compare_plots( [ self.tank.liquid_center_of_mass, self.tank.gas_center_of_mass, self.tank.center_of_mass, ], *self.flux_time, title="Fluid Center of Mass (m) x Time (s)", xlabel="Time (s)", ylabel="Center of Mass (m)", show=False, return_object=True, ) # Change style of lines ax.lines[0].set_linestyle("--") ax.lines[1].set_linestyle("-.") ax.legend(["Liquid", "Gas", "Total"]) show_or_save_plot(filename)
[docs] def animate_fluid_volume(self, filename=None, fps=30): """Animates the liquid and gas volumes inside the tank as a function of time. Parameters ---------- filename : str | None, optional The path the animation should be saved to. By default None, in which case the animation will be shown instead of saved. Supported file ending is: .gif fps : int, optional Frames per second for the animation. Default is 30. Returns ------- matplotlib.animation.FuncAnimation The created animation object. """ t_start, t_end = self.flux_time times = np.linspace(t_start, t_end, 200) liquid_values = self.tank.liquid_volume.get_value(times) gas_values = self.tank.gas_volume.get_value(times) fig, ax = plt.subplots() ax.set_xlim(times[0], times[-1]) ax.set_ylim(0, max(liquid_values.max(), gas_values.max()) * 1.1) ax.set_xlabel("Time (s)") ax.set_ylabel("Volume (m³)") ax.set_title("Liquid/Gas Volume Evolution") (line_liquid,) = ax.plot([], [], lw=2, color="blue", label="Liquid Volume") (line_gas,) = ax.plot([], [], lw=2, color="red", label="Gas Volume") (point_liquid,) = ax.plot([], [], "ko") (point_gas,) = ax.plot([], [], "ko") ax.legend() def init(): for item in (line_liquid, line_gas, point_liquid, point_gas): item.set_data([], []) return line_liquid, line_gas, point_liquid, point_gas def update(frame_index): # Liquid part line_liquid.set_data( times[: frame_index + 1], liquid_values[: frame_index + 1] ) point_liquid.set_data([times[frame_index]], [liquid_values[frame_index]]) # Gas part line_gas.set_data(times[: frame_index + 1], gas_values[: frame_index + 1]) point_gas.set_data([times[frame_index]], [gas_values[frame_index]]) return line_liquid, line_gas, point_liquid, point_gas animation = FuncAnimation( fig, update, frames=len(times), init_func=init, interval=1000 / fps, blit=True, ) show_or_save_animation(animation, filename, fps=fps) return animation
[docs] def all(self): """Prints out all graphs available about the Tank. It simply calls all the other plotter methods in this class. Returns ------- None """ self.draw() self.tank.fluid_mass.plot(*self.flux_time) self.tank.net_mass_flow_rate.plot(*self.flux_time) self.fluid_height() self.fluid_volume() self.fluid_center_of_mass() self.tank.inertia.plot(*self.flux_time)