Source code for fastga.utils.postprocessing.load_analysis.analysis_and_plots_la

"""
Defines the analysis and plotting functions for postprocessing of load analysis.
"""
#  This file is part of FAST-OAD_CS23 : A framework for rapid Overall Aircraft Design
#  Copyright (C) 2022  ONERA & ISAE-SUPAERO
#  FAST is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <https://www.gnu.org/licenses/>.

import numpy as np
import plotly
import plotly.graph_objects as go
from fastoad.io import VariableIO

from fastga.models.load_analysis.wing.constants import (
    POINT_MASS_SPAN_RATIO,
    NB_POINTS_POINT_MASS,
)

COLS = plotly.colors.DEFAULT_PLOTLY_COLORS


[docs]def force_repartition_diagram( aircraft_file_path: str, name="", fig=None, file_formatter=None ) -> go.FigureWidget: """ Returns a figure plot of the force repartition on the wing. Different designs can be superposed by providing an existing fig. Each design can be provided a name. :param aircraft_file_path: path of data file :param name: name to give to the trace added to the figure :param fig: existing figure to which add the plot :param file_formatter: the formatter that defines the format of data file. If not provided, default format will be assumed. :return: force repartition diagram. """ variables = VariableIO(aircraft_file_path, file_formatter).read() y_vector = list(variables["data:loads:y_vector"].value) wing_weight = list(variables["data:loads:structure:ultimate:force_distribution:wing"].value) fuel_weight = list(variables["data:loads:structure:ultimate:force_distribution:fuel"].value) point_weight = list( variables["data:loads:structure:ultimate:force_distribution:point_mass"].value ) lift = list(variables["data:loads:aerodynamic:ultimate:force_distribution"].value) span = variables["data:geometry:wing:span"].value semi_span = span[0] / 2.0 interval_len = POINT_MASS_SPAN_RATIO * semi_span / NB_POINTS_POINT_MASS readjust_point = 1.5 * interval_len y_vector_tmp = np.array(y_vector) wing_weight_tmp = np.array(wing_weight) fuel_weight_tmp = np.array(fuel_weight) point_weight_tmp = np.array(point_weight) lift_tmp = np.array(lift) y_vector = _delete_additional_zeros(y_vector_tmp) index = len(y_vector) + 1 wing_weight = wing_weight_tmp[: int(index)] fuel_weight = fuel_weight_tmp[: int(index)] # We have to readjust the point mass since because of the way we represented it (finite over # a small interval) the value of the array is artificially high point_weight = readjust_point * point_weight_tmp[: int(index)] lift = lift_tmp[0 : int(index)] if fig is None: fig = go.Figure() wing_weight_scatter = go.Scatter( x=y_vector, y=wing_weight, mode="lines", name=name + " - wing weight" ) fig.add_trace(wing_weight_scatter) fuel_weight_scatter = go.Scatter( x=y_vector, y=fuel_weight, mode="lines", name=name + " - fuel weight" ) fig.add_trace(fuel_weight_scatter) point_weight_scatter = go.Scatter( x=y_vector, y=point_weight, mode="lines", name=name + " - point masses weight" ) fig.add_trace(point_weight_scatter) lift_scatter = go.Scatter(x=y_vector, y=lift, mode="lines", name=name + " - lift") fig.add_trace(lift_scatter) fig = go.FigureWidget(fig) fig.update_layout( title_text="Forces distribution on the wing", title_x=0.5, xaxis_title="spanwise position [m]", yaxis_title="distributed force [N/m]", ) return fig
[docs]def shear_diagram( aircraft_file_path: str, name="", fig=None, file_formatter=None ) -> go.FigureWidget: """ Returns a figure plot of the shear repartition on the wing. Different designs can be superposed by providing an existing fig. Each design can be provided a name. :param aircraft_file_path: path of data file :param name: name to give to the trace added to the figure :param fig: existing figure to which add the plot :param file_formatter: the formatter that defines the format of data file. If not provided, default format will be assumed. :return: force repartition diagram. """ variables = VariableIO(aircraft_file_path, file_formatter).read() y_vector = list(variables["data:loads:y_vector"].value) wing_shear = list(variables["data:loads:structure:ultimate:shear:wing"].value) fuel_shear = list(variables["data:loads:structure:ultimate:shear:fuel"].value) point_shear = list(variables["data:loads:structure:ultimate:shear:point_mass"].value) lift_shear = list(variables["data:loads:max_shear:lift_shear"].value) y_vector_tmp = np.array(y_vector) wing_shear_tmp = np.array(wing_shear) fuel_shear_tmp = np.array(fuel_shear) point_shear_tmp = np.array(point_shear) lift_shear_tmp = np.array(lift_shear) y_vector = _delete_additional_zeros(y_vector_tmp) index = len(y_vector) + 1 wing_shear = wing_shear_tmp[: int(index)] fuel_shear = fuel_shear_tmp[: int(index)] point_shear = point_shear_tmp[: int(index)] lift_shear = lift_shear_tmp[: int(index)] if fig is None: fig = go.Figure() wing_shear_scatter = go.Scatter( x=y_vector, y=wing_shear, mode="lines", name=name + " - wing weight shear" ) fig.add_trace(wing_shear_scatter) fuel_shear_scatter = go.Scatter( x=y_vector, y=fuel_shear, mode="lines", name=name + " - fuel weight shear" ) fig.add_trace(fuel_shear_scatter) point_shear_scatter = go.Scatter( x=y_vector, y=point_shear, mode="lines", name=name + " - point masses shear" ) fig.add_trace(point_shear_scatter) lift_scatter = go.Scatter(x=y_vector, y=lift_shear, mode="lines", name=name + " - lift shear") fig.add_trace(lift_scatter) fig = go.FigureWidget(fig) fig.update_layout( title_text="Shear forces on the wing", title_x=0.5, xaxis_title="spanwise position [m]", yaxis_title="shear force [N]", ) return fig
[docs]def rbm_diagram(aircraft_file_path: str, name="", fig=None, file_formatter=None) -> go.FigureWidget: """ Returns a figure plot of the root bending moment repartition on the wing. Different designs can be superposed by providing an existing fig. Each design can be provided a name. :param aircraft_file_path: path of data file :param name: name to give to the trace added to the figure :param fig: existing figure to which add the plot :param file_formatter: the formatter that defines the format of data file. If not provided, default format will be assumed. :return: force repartition diagram. """ variables = VariableIO(aircraft_file_path, file_formatter).read() y_vector = list(variables["data:loads:y_vector"].value) wing_rbm = list(variables["data:loads:structure:ultimate:root_bending:wing"].value) fuel_rbm = list(variables["data:loads:structure:ultimate:root_bending:fuel"].value) point_rbm = list(variables["data:loads:structure:ultimate:root_bending:point_mass"].value) lift_rbm = list(variables["data:loads:max_rbm:lift_rbm"].value) y_vector_tmp = np.array(y_vector) wing_rbm_tmp = np.array(wing_rbm) fuel_rbm_tmp = np.array(fuel_rbm) point_rbm_tmp = np.array(point_rbm) lift_rbm_tmp = np.array(lift_rbm) y_vector = _delete_additional_zeros(y_vector_tmp) index = len(y_vector) + 1 wing_rbm = wing_rbm_tmp[: int(index)] fuel_rbm = fuel_rbm_tmp[: int(index)] point_rbm = point_rbm_tmp[: int(index)] lift_rbm = lift_rbm_tmp[: int(index)] if fig is None: fig = go.Figure() wing_rbm_scatter = go.Scatter( x=y_vector, y=wing_rbm, mode="lines", name=name + " - wing weight bending moment" ) fig.add_trace(wing_rbm_scatter) fuel_rbm_scatter = go.Scatter( x=y_vector, y=fuel_rbm, mode="lines", name=name + " - fuel weight bending moment" ) fig.add_trace(fuel_rbm_scatter) point_rbm_scatter = go.Scatter( x=y_vector, y=point_rbm, mode="lines", name=name + " - point masses bending moment" ) fig.add_trace(point_rbm_scatter) lift_scatter = go.Scatter( x=y_vector, y=lift_rbm, mode="lines", name=name + " - lift bending moment" ) fig.add_trace(lift_scatter) fig = go.FigureWidget(fig) fig.update_layout( title_text="Bending moments on the wing", title_x=0.5, xaxis_title="spanwise position [m]", yaxis_title="Root bending moment [Nm]", ) return fig
def _delete_additional_zeros(array, length: int = None): """ Function that delete the additional zeros we had to add to fit the format imposed by OpenMDAO @param array: an array with additional zeros we want to delete @param length: if len is specified leave zeros up until the length of the array is len @return: final_array an array containing the same elements of the initial array but with the additional zeros deleted """ last_zero = np.amax(np.where(array != 0.0)) + 1 if length is not None: final_array = array[: max(int(last_zero), length)] else: final_array = array[: int(last_zero)] return final_array