Source code for fastga.models.aerodynamics.components.compute_equilibrated_polar

"""
Computation of the non-equilibrated aircraft polars
"""
#  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
from stdatm import Atmosphere

from fastga.models.aerodynamics.constants import POLAR_POINT_COUNT, FIRST_INVALID_COEFF
from fastga.models.performances.mission.dynamic_equilibrium import DynamicEquilibrium


[docs]class ComputeEquilibratedPolar(DynamicEquilibrium):
[docs] def initialize(self): self.options.declare("low_speed_aero", default=False, types=bool) self.options.declare("cg_ratio", default=-0.0, types=float)
[docs] def setup(self): self.add_input("data:geometry:wing:MAC:leading_edge:x:local", val=np.nan, units="m") self.add_input("data:geometry:wing:MAC:length", np.nan, units="m") self.add_input("data:geometry:wing:root:virtual_chord", np.nan, units="m") self.add_input("data:geometry:fuselage:maximum_width", np.nan, units="m") self.add_input("data:geometry:wing:MAC:at25percent:x", np.nan, units="m") self.add_input("data:geometry:fuselage:length", np.nan, units="m") self.add_input("data:geometry:wing:area", np.nan, units="m**2") self.add_input( "data:geometry:horizontal_tail:MAC:at25percent:x:from_wingMAC25", np.nan, units="m" ) self.add_input("data:aerodynamics:wing:low_speed:CL_max_clean", val=np.nan) self.add_input("data:weight:aircraft:CG:aft:x", np.nan, units="m") self.add_input("data:weight:aircraft:CG:fwd:x", np.nan, units="m") self.add_input("data:weight:aircraft_empty:CG:z", val=np.nan, units="m") self.add_input("data:weight:propulsion:engine:CG:z", val=np.nan, units="m") self.add_input( "data:weight:aircraft:in_flight_variation:fixed_mass_comp:equivalent_moment", np.nan, units="kg*m", ) self.add_input("data:weight:propulsion:tank:CG:x", np.nan, units="m") self.add_input( "data:weight:aircraft:in_flight_variation:fixed_mass_comp:mass", np.nan, units="kg" ) self.add_input("data:weight:aircraft:MTOW", np.nan, units="kg") self.add_input("data:aerodynamics:horizontal_tail:cruise:CL0", val=np.nan) self.add_input( "data:aerodynamics:horizontal_tail:cruise:CL_alpha", val=np.nan, units="rad**-1" ) self.add_input( "data:aerodynamics:horizontal_tail:cruise:CL_alpha_isolated", val=np.nan, units="rad**-1", ) self.add_input("data:aerodynamics:horizontal_tail:low_speed:CL0", val=np.nan) self.add_input( "data:aerodynamics:horizontal_tail:low_speed:CL_alpha", val=np.nan, units="rad**-1" ) self.add_input( "data:aerodynamics:horizontal_tail:low_speed:CL_alpha_isolated", val=np.nan, units="rad**-1", ) self.add_input("data:aerodynamics:horizontal_tail:low_speed:CL_max_clean", val=np.nan) self.add_input("data:aerodynamics:horizontal_tail:low_speed:CL_min_clean", val=np.nan) self.add_input("data:aerodynamics:elevator:low_speed:CL_delta", val=np.nan, units="rad**-1") self.add_input("data:aerodynamics:elevator:low_speed:CD_delta", val=np.nan, units="rad**-2") self.add_input("data:aerodynamics:fuselage:cm_alpha", val=np.nan, units="rad**-1") if self.options["low_speed_aero"]: self.add_input("data:aerodynamics:low_speed:mach", val=np.nan) self.add_input("data:aerodynamics:wing:low_speed:CL0_clean", val=np.nan) self.add_input("data:aerodynamics:wing:low_speed:induced_drag_coefficient", val=np.nan) self.add_input("data:aerodynamics:wing:low_speed:CL_alpha", val=np.nan, units="rad**-1") self.add_input("data:aerodynamics:aircraft:low_speed:CD0", val=np.nan) self.add_input("data:aerodynamics:wing:low_speed:CM0_clean", val=np.nan) self.add_input( "data:aerodynamics:horizontal_tail:low_speed:induced_drag_coefficient", val=np.nan ) self.add_input("data:TLAR:v_approach", np.nan, units="m/s") self.add_output( "data:aerodynamics:aircraft:low_speed:equilibrated:CD", shape=POLAR_POINT_COUNT, ) self.add_output( "data:aerodynamics:aircraft:low_speed:equilibrated:CL", shape=POLAR_POINT_COUNT, ) else: self.add_input("data:aerodynamics:cruise:mach", val=np.nan) self.add_input("data:aerodynamics:wing:cruise:CL0_clean", val=np.nan) self.add_input("data:aerodynamics:wing:cruise:induced_drag_coefficient", val=np.nan) self.add_input("data:aerodynamics:wing:cruise:CL_alpha", val=np.nan, units="rad**-1") self.add_input("data:aerodynamics:aircraft:cruise:CD0", val=np.nan) self.add_input("data:aerodynamics:wing:cruise:CM0_clean", val=np.nan) self.add_input( "data:aerodynamics:horizontal_tail:cruise:induced_drag_coefficient", val=np.nan ) self.add_input("data:mission:sizing:main_route:cruise:altitude", np.nan, units="m") self.add_input("data:TLAR:v_cruise", np.nan, units="m/s") self.add_output( "data:aerodynamics:aircraft:cruise:equilibrated:CD", shape=POLAR_POINT_COUNT ) self.add_output( "data:aerodynamics:aircraft:cruise:equilibrated:CL", shape=POLAR_POINT_COUNT ) self.declare_partials("*", "*", method="fd")
[docs] def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None): mtow = inputs["data:weight:aircraft:MTOW"] wing_area = inputs["data:geometry:wing:area"] cl_max_clean = inputs["data:aerodynamics:wing:low_speed:CL_max_clean"] x_cg_fwd = inputs["data:weight:aircraft:CG:fwd:x"] x_cg_aft = inputs["data:weight:aircraft:CG:aft:x"] if self.options["low_speed_aero"]: altitude = 0 v_tas = inputs["data:TLAR:v_approach"] else: altitude = inputs["data:mission:sizing:main_route:cruise:altitude"] v_tas = inputs["data:TLAR:v_cruise"] cl_array = np.array([]) cd_array = np.array([]) atm = Atmosphere(altitude, altitude_in_feet=False) # Computation of the maximum aircraft mass that can be used before exceeding # the CL0 clean of the wing in found_cl_repartition init_mass_guess = (0.5 * atm.density * v_tas**2 * wing_area * cl_max_clean) / 9.81 cg_ratio = self.options["cg_ratio"] x_cg = x_cg_aft + cg_ratio * (x_cg_fwd - x_cg_aft) mass_array = np.linspace(0.1 * mtow, 1.15 * init_mass_guess, POLAR_POINT_COUNT) # previous_step = () for mass in mass_array: previous_step = self.dynamic_equilibrium( inputs, 0.0, (0.5 * atm.density * v_tas**2), 0.0, 0.0, mass, "none", (), low_speed=self.options["low_speed_aero"], x_cg=x_cg, ) if previous_step[-1]: break else: cl_wing = float(previous_step[2]) cl_tail = float(previous_step[3]) thrust = float(previous_step[1]) cl_array = np.append(cl_array, cl_wing + cl_tail) cd = thrust / (0.5 * atm.density * v_tas**2 * wing_area) cd_array = np.append(cd_array, cd) additional_zeros = np.linspace( FIRST_INVALID_COEFF, 2 * FIRST_INVALID_COEFF, POLAR_POINT_COUNT - len(cd_array) ) cd_array = np.append(cd_array, additional_zeros) cl_array = np.append(cl_array, additional_zeros) if self.options["low_speed_aero"]: outputs["data:aerodynamics:aircraft:low_speed:equilibrated:CD"] = cd_array outputs["data:aerodynamics:aircraft:low_speed:equilibrated:CL"] = cl_array else: outputs["data:aerodynamics:aircraft:cruise:equilibrated:CD"] = cd_array outputs["data:aerodynamics:aircraft:cruise:equilibrated:CL"] = cl_array