Source code for fastoad.models.aerodynamics.components.compute_polar

"""
    FAST - Copyright (c) 2016 ONERA ISAE
"""
#  This file is part of FAST-OAD : A framework for rapid Overall Aircraft Design
#  Copyright (C) 2021 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 aenum import Enum
from openmdao.core.explicitcomponent import ExplicitComponent


[docs]class PolarType(Enum): HIGH_SPEED = "high_speed" LOW_SPEED = "low_speed" TAKEOFF = "takeoff" LANDING = "landing"
[docs]class ComputePolar(ExplicitComponent):
[docs] def initialize(self): self.options.declare("type", default=PolarType.HIGH_SPEED, types=PolarType)
[docs] def setup(self): self.add_input("tuning:aerodynamics:aircraft:cruise:CD:k", val=np.nan) self.add_input("tuning:aerodynamics:aircraft:cruise:CD:offset", val=np.nan) self.add_input("tuning:aerodynamics:aircraft:cruise:CD:winglet_effect:k", val=np.nan) self.add_input("tuning:aerodynamics:aircraft:cruise:CD:winglet_effect:offset", val=np.nan) if self.options["type"] != PolarType.HIGH_SPEED: self.add_input( "data:aerodynamics:aircraft:low_speed:CL", shape_by_conn=True, val=np.nan ) self.add_input( "data:aerodynamics:aircraft:low_speed:CD0", shape_by_conn=True, val=np.nan ) self.add_input( "data:aerodynamics:aircraft:low_speed:CD:trim", shape_by_conn=True, val=np.nan ) self.add_input( "data:aerodynamics:aircraft:low_speed:induced_drag_coefficient", val=np.nan ) if self.options["type"] == PolarType.TAKEOFF: self.add_input("data:aerodynamics:high_lift_devices:takeoff:CL", val=np.nan) self.add_input("data:aerodynamics:high_lift_devices:takeoff:CD", val=np.nan) self.add_output( "data:aerodynamics:aircraft:takeoff:CL", copy_shape="data:aerodynamics:aircraft:low_speed:CL", ) self.add_output( "data:aerodynamics:aircraft:takeoff:CD", copy_shape="data:aerodynamics:aircraft:low_speed:CL", ) elif self.options["type"] == PolarType.LANDING: self.add_input("data:aerodynamics:high_lift_devices:landing:CL", val=np.nan) self.add_input("data:aerodynamics:high_lift_devices:landing:CD", val=np.nan) self.add_output( "data:aerodynamics:landing:CL", copy_shape="data:aerodynamics:aircraft:low_speed:CL", ) self.add_output( "data:aerodynamics:aircraft:landing:CL", copy_shape="data:aerodynamics:aircraft:low_speed:CL", ) self.add_output( "data:aerodynamics:aircraft:landing:CD", copy_shape="data:aerodynamics:aircraft:low_speed:CL", ) else: self.add_output( "data:aerodynamics:aircraft:low_speed:CD", copy_shape="data:aerodynamics:aircraft:low_speed:CL", ) else: self.add_input("data:aerodynamics:aircraft:cruise:CL", shape_by_conn=True, val=np.nan) self.add_input("data:aerodynamics:aircraft:cruise:CD0", shape_by_conn=True, val=np.nan) self.add_input( "data:aerodynamics:aircraft:cruise:CD:trim", shape_by_conn=True, val=np.nan ) self.add_input( "data:aerodynamics:aircraft:cruise:CD:compressibility", shape_by_conn=True, val=np.nan, ) self.add_input("data:aerodynamics:aircraft:cruise:induced_drag_coefficient", val=np.nan) self.add_output( "data:aerodynamics:aircraft:cruise:CD", copy_shape="data:aerodynamics:aircraft:cruise:CL", ) self.add_output("data:aerodynamics:aircraft:cruise:L_D_max") self.add_output("data:aerodynamics:aircraft:cruise:optimal_CL") self.add_output("data:aerodynamics:aircraft:cruise:optimal_CD")
[docs] def setup_partials(self): self.declare_partials("*", "*", method="fd")
[docs] def compute(self, inputs, outputs): k_cd = inputs["tuning:aerodynamics:aircraft:cruise:CD:k"] offset_cd = inputs["tuning:aerodynamics:aircraft:cruise:CD:offset"] k_winglet_cd = inputs["tuning:aerodynamics:aircraft:cruise:CD:winglet_effect:k"] offset_winglet_cd = inputs["tuning:aerodynamics:aircraft:cruise:CD:winglet_effect:offset"] if self.options["type"] != PolarType.HIGH_SPEED: cl = inputs["data:aerodynamics:aircraft:low_speed:CL"] cd0 = inputs["data:aerodynamics:aircraft:low_speed:CD0"] cd_trim = inputs["data:aerodynamics:aircraft:low_speed:CD:trim"] cd_c = 0.0 coef_k = inputs["data:aerodynamics:aircraft:low_speed:induced_drag_coefficient"] if self.options["type"] == PolarType.TAKEOFF: delta_cl_hl = inputs["data:aerodynamics:high_lift_devices:takeoff:CL"] delta_cd_hl = inputs["data:aerodynamics:high_lift_devices:takeoff:CD"] elif self.options["type"] == PolarType.LANDING: delta_cl_hl = inputs["data:aerodynamics:high_lift_devices:landing:CL"] delta_cd_hl = inputs["data:aerodynamics:high_lift_devices:landing:CD"] else: delta_cl_hl = 0.0 delta_cd_hl = 0.0 else: cl = inputs["data:aerodynamics:aircraft:cruise:CL"] cd0 = inputs["data:aerodynamics:aircraft:cruise:CD0"] cd_trim = inputs["data:aerodynamics:aircraft:cruise:CD:trim"] cd_c = inputs["data:aerodynamics:aircraft:cruise:CD:compressibility"] coef_k = inputs["data:aerodynamics:aircraft:cruise:induced_drag_coefficient"] delta_cl_hl = 0.0 delta_cd_hl = 0.0 cl = cl + delta_cl_hl cd = ( cd0 + cd_c + cd_trim + coef_k * cl ** 2 * k_winglet_cd + offset_winglet_cd + delta_cd_hl ) * k_cd + offset_cd if self.options["type"] == PolarType.LOW_SPEED: outputs["data:aerodynamics:aircraft:low_speed:CD"] = cd elif self.options["type"] == PolarType.TAKEOFF: outputs["data:aerodynamics:aircraft:takeoff:CL"] = cl outputs["data:aerodynamics:aircraft:takeoff:CD"] = cd elif self.options["type"] == PolarType.LANDING: outputs["data:aerodynamics:aircraft:landing:CL"] = cl outputs["data:aerodynamics:aircraft:landing:CD"] = cd else: outputs["data:aerodynamics:aircraft:cruise:CD"] = cd Cl_opt, Cd_opt = get_optimum_ClCd(np.array([cd, cl]))[0:2] outputs["data:aerodynamics:aircraft:cruise:L_D_max"] = Cl_opt / Cd_opt outputs["data:aerodynamics:aircraft:cruise:optimal_CL"] = Cl_opt outputs["data:aerodynamics:aircraft:cruise:optimal_CD"] = Cd_opt
[docs]def get_optimum_ClCd(ClCd): lift_drag_ratio = ClCd[1, :] / ClCd[0, :] optimum_index = np.argmax(lift_drag_ratio) optimum_Cz = ClCd[1][optimum_index] optimum_Cd = ClCd[0][optimum_index] return optimum_Cz, optimum_Cd