Source code for RCAIDE.Library.Methods.Performance.aircraft_aerodynamic_analysis

# RCAIDE/Methods/Performance/aircraft_aerodynamic_analysis.py
# 
# 
# Created:  Dec 2024, M. Clarke

# ----------------------------------------------------------------------------------------------------------------------
#  IMPORT
# ----------------------------------------------------------------------------------------------------------------------

# RCAIDE imports 
import RCAIDE
from RCAIDE.Framework.Core import  Data  
from RCAIDE.Library.Mission.Common.Pre_Process  import geometry_preprocess_routine 
 
# Pacakge imports 
import numpy as np  
import os, sys 

#------------------------------------------------------------------------------
# aircraft_aerodynamic_analysis
#------------------------------------------------------------------------------  
[docs] def aircraft_aerodynamic_analysis(analyses = None, angle_of_attacks = None, mach_numbers = None, non_dimensional_reynolds_numbers = None, temperatures = None, overwrite_reference = True, altitude = None ): """ Computes aerodynamic coefficients across ranges of angle of attack and Mach numbers using vortex lattice methods. Parameters -------- vehicle : Vehicle The vehicle instance to be analyzed angle_of_attacks : ndarray Array of angle of attack values to evaluate [radians] mach_numbers : ndarray Array of Mach numbers to evaluate altitude : float, optional Altitude for atmospheric properties [m], default 0 Returns -------- results : Data Container of analysis results including: * Mach : ndarray Evaluated Mach numbers * alpha : ndarray Evaluated angles of attack [rad] * lift_coefficient : ndarray Computed lift coefficients * drag_coefficient : ndarray Computed drag coefficients * moment_coefficient : ndarray Computed Y-moment coefficients Notes ----- The function uses the US Standard Atmosphere 1976 model for atmospheric properties and evaluates aerodynamic coefficients using vortex lattice methods. Can use a surrogate model for faster evaluation or just direct evaluation of the aerodynamics. **Major Assumptions** * Flow is steady and inviscid * Small angle approximations apply * Linear aerodynamics * Atmospheric properties follow US Standard Atmosphere 1976 See Also -------- RCAIDE.Library.Methods.Aerodynamics.Vortex_Lattice_Method RCAIDE.Library.Attributes.Atmospheres.Earth.US_Standard_1976 """ if type(analyses) != RCAIDE.Framework.Analyses.Vehicle: raise AttributeError('RCAIDE analyses must be defined') #------------------------------------------------------------------------ # Preprocess Geometry #------------------------------------------------------------------------ geometry_preprocess_routine(analyses) #------------------------------------------------------------------------ # Check size of arrays #------------------------------------------------------------------------ if angle_of_attacks is None: raise ValueError("Angle of attack range must be defined as nx1 2d-array") if mach_numbers is None: raise ValueError("Mach number range must be defined as nx1 2d-array ") dim_AoA = len(angle_of_attacks[:, 0] ) dim_Mach = len(mach_numbers[:, 0] ) if dim_Mach != dim_AoA: raise ValueError("Angle of attack and Mach number range must same dimension") #------------------------------------------------------------------------ # setup flight conditions #------------------------------------------------------------------------ # if altitude is specified if altitude is not None: atmosphere = RCAIDE.Framework.Analyses.Atmospheric.US_Standard_1976() atmo_data = atmosphere.compute_values(altitude) P = atmo_data.pressure T = atmo_data.temperature rho = atmo_data.density a = atmo_data.speed_of_sound mu = atmo_data.dynamic_viscosity V = mach_numbers * a non_dimensional_reynolds_numbers = V * rho / mu # if non_dimensional_reynolds_numbers and temperatures are specified elif non_dimensional_reynolds_numbers is not None and temperatures is not None: dim_Re = len(non_dimensional_reynolds_numbers[:, 0] ) dim_T = len(temperatures[:, 0] ) if dim_Re != dim_T: raise ValueError("Reynolds number and temperature range must same dimension") elif dim_AoA != dim_T: raise ValueError("Angle of attack and temperature range must same dimension") atmosphere = RCAIDE.Framework.Analyses.Atmospheric.US_Standard_1976() atmo_data = atmosphere.compute_values(0) P = atmo_data.pressure T = temperatures a = RCAIDE.Library.Attributes.Gases.Air().compute_speed_of_sound(T=T) V = mach_numbers * a mu = RCAIDE.Library.Attributes.Gases.Air().compute_absolute_viscosity(T=T) rho = non_dimensional_reynolds_numbers * mu / V else: raise ValueError("Specify either 1) altitude or combination or 2) non dimensional reynolds numbers and temperature arrays") # ----------------------------------------------------------------- # Evaluate Without Surrogate # ----------------------------------------------------------------- ctrl_pts = len(angle_of_attacks[:, 0] ) state = RCAIDE.Framework.Mission.Common.State() state.conditions = RCAIDE.Framework.Mission.Common.Results() state.conditions.freestream.density = rho * np.ones_like(angle_of_attacks) state.conditions.freestream.dynamic_viscosity = mu * np.ones_like(angle_of_attacks) state.conditions.freestream.temperature = T * np.ones_like(angle_of_attacks) state.conditions.freestream.pressure = P * np.ones_like(angle_of_attacks) state.conditions.freestream.dynamic_pressure = 0.5 * rho * V**2 state.conditions.aerodynamics.angles.alpha = angle_of_attacks state.conditions.aerodynamics.angles.beta = angle_of_attacks *0 state.conditions.freestream.u = angle_of_attacks *0 state.conditions.freestream.v = angle_of_attacks *0 state.conditions.freestream.w = angle_of_attacks *0 state.conditions.static_stability.roll_rate = angle_of_attacks *0 state.conditions.static_stability.pitch_rate = angle_of_attacks *0 state.conditions.static_stability.yaw_rate = angle_of_attacks *0 state.conditions.frames.wind.transform_to_inertial = np.tile( np.array([[[1., 0., 0.],[0., 1., 0.],[0., 0., 1.]]]) , ( ctrl_pts, 1, 1) ) state.conditions.expand_rows(ctrl_pts) state.conditions.control_surfaces = Data() analyses.aerodynamics.aileron_flag = False analyses.aerodynamics.rudder_flag = False analyses.aerodynamics.elevator_flag = False analyses.aerodynamics.flap_flag = False analyses.aerodynamics.slat_flag = False for wing in analyses.vehicle.wings: for control_surface in wing.control_surfaces: if type(control_surface) == RCAIDE.Library.Components.Wings.Control_Surfaces.Aileron: analyses.aerodynamics.aileron_flag = True state.conditions.control_surfaces.aileron = Data() state.conditions.control_surfaces.aileron.deflection = control_surface.deflection * np.ones_like(angle_of_attacks) state.conditions.control_surfaces.aileron.static_stability = Data() state.conditions.control_surfaces.aileron.static_stability.coefficients = Data() if type(control_surface) == RCAIDE.Library.Components.Wings.Control_Surfaces.Elevator: analyses.aerodynamics.elevator_flag = True state.conditions.control_surfaces.elevator = Data() state.conditions.control_surfaces.elevator.deflection = control_surface.deflection * np.ones_like(angle_of_attacks) state.conditions.control_surfaces.elevator.static_stability = Data() state.conditions.control_surfaces.elevator.static_stability.coefficients = Data() if type(control_surface) == RCAIDE.Library.Components.Wings.Control_Surfaces.Rudder: analyses.aerodynamics.rudder_flag = True state.conditions.control_surfaces.rudder = Data() state.conditions.control_surfaces.rudder.deflection = control_surface.deflection * np.ones_like(angle_of_attacks) state.conditions.control_surfaces.rudder.static_stability = Data() state.conditions.control_surfaces.rudder.static_stability.coefficients = Data() if type(control_surface) == RCAIDE.Library.Components.Wings.Control_Surfaces.Flap: analyses.aerodynamics.flap_flag = True state.conditions.control_surfaces.flap = Data() state.conditions.control_surfaces.flap.deflection = control_surface.deflection * np.ones_like(angle_of_attacks) state.conditions.control_surfaces.flap.static_stability = Data() state.conditions.control_surfaces.flap.static_stability.coefficients = Data() if type(control_surface) == RCAIDE.Library.Components.Wings.Control_Surfaces.Slat: analyses.aerodynamics.slat_flag = True state.conditions.control_surfaces.slat = Data() state.conditions.control_surfaces.slat.deflection = control_surface.deflection * np.ones_like(angle_of_attacks) state.conditions.control_surfaces.slat.static_stability = Data() state.conditions.control_surfaces.slat.static_stability.coefficients = Data() state.analyses = analyses state.analyses.aerodynamics.filename = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), "aerodynamic_training_data.pkl" ) state.analyses.aerodynamics.initialize(state.analyses.vehicle) state.conditions.freestream.mach_number = mach_numbers state.conditions.freestream.velocity = V state.conditions.freestream.reynolds_number = non_dimensional_reynolds_numbers state.conditions.frames.inertial.velocity_vector = np.tile(np.array([[0, 0, 0]]), ( ctrl_pts, 1)) state.conditions.frames.inertial.velocity_vector[:,0] = V[:,0] _ = state.analyses.aerodynamics.evaluate(state,state.analyses.vehicle) results = Data( freestream = state.conditions.freestream, aerodynamics = state.conditions.aerodynamics, static_stability = state.conditions.static_stability, dynamic_stability = state.conditions.dynamic_stability, ) if type(state.analyses.aerodynamics) == RCAIDE.Framework.Analyses.Aerodynamics.Vortex_Lattice_Method: results.vortex_distribution = state.analyses.aerodynamics.settings.vortex_distribution return results