Source code for RCAIDE.Library.Mission.Common.Pre_Process.geometry

# RCAIDE/Library/Missions/Common/Pre_Process/geometry.py
# 
# 
# Created:  Apr 2023, M. Clarke

# ----------------------------------------------------------------------------------------------------------------------
#  IMPORT
# ---------------------------------------------------------------------------------------------------------------------- 
import RCAIDE
from RCAIDE.Framework.Core import Units
from RCAIDE.Library.Methods.Geometry.LOPA      import  compute_layout_of_passenger_accommodations
from RCAIDE.Library.Methods.Geometry.Planform  import  fuselage_planform, wing_planform , compute_fuel_volume 

# python imports 
import numpy as  np 
import os, sys
import pandas as pd
from copy import deepcopy 
# ----------------------------------------------------------------------------------------------------------------------
#  geometry
# ----------------------------------------------------------------------------------------------------------------------  
[docs] def geometry(mission): """ Initializes and processes geometry for mission segments Parameters ---------- mission : Mission The mission containing segments to be analyzed - analyses.geometry : Analysis Stability analysis module - vehicle : Vehicle Aircraft geometry definition - wings : list Wing geometry definitions - process.compute.lift.inviscid_wings : Process Lift computation process - surrogates : Data Stability surrogate models Returns ------- None Updates mission segment analyses directly Notes ----- This function prepares the geometry for each mission segment See Also -------- RCAIDE.Library.Methods.Geometry.Planform RCAIDE.Framework.Mission.Segments """ for i , segment in enumerate(mission.segments): # -------------------------------------------------------------------------------------------------------------------- # check if geometry analysis is defined # -------------------------------------------------------------------------------------------------------------------- if segment.analyses.geometry is None: raise AssertionError('Geometry Analyses not defined') if i == 0 or segment.analyses.geometry.settings.unique_geometry: geometry_preprocess_routine(segment.analyses) else: # Reuses previous segment pre processed data to save computational time. # Ensures that changes in configuration are not overwritten. vehicle_0 = deepcopy(segment.analyses.vehicle) segment.analyses.vehicle = deepcopy(mission.segments[i-1].analyses.vehicle) for wing in segment.analyses.vehicle.wings: for control_surface in wing.control_surfaces: control_surface.deflection = vehicle_0.wings[wing.tag].control_surfaces[control_surface.tag].deflection for landing_gear in segment.analyses.vehicle.landing_gears: landing_gear.gear_extended = vehicle_0.landing_gears[landing_gear.tag].gear_extended for network in segment.analyses.vehicle.networks: network.reverse_thrust = vehicle_0.networks[network.tag].reverse_thrust for bus in network.busses: bus.active = vehicle_0.networks[network.tag].busses[bus.tag].active for propulsor in network.propulsors: propulsor_0 = vehicle_0.networks[network.tag].propulsors[propulsor.tag] propulsor.active = propulsor_0.active if isinstance(propulsor, RCAIDE.Library.Components.Powertrain.Propulsors.Turbofan): propulsor.fan.angular_velocity = propulsor_0.fan.angular_velocity propulsor.fan_nozzle.exit_velocity = propulsor_0.fan_nozzle.exit_velocity propulsor.core_nozzle.exit_velocity = propulsor_0.core_nozzle.exit_velocity if isinstance(propulsor, RCAIDE.Library.Components.Powertrain.Propulsors.Electric_Rotor): propulsor.rotor.orientation_euler_angles = propulsor_0.rotor.orientation_euler_angles propulsor.rotor.blade_pitch_command = propulsor_0.rotor.blade_pitch_command return
[docs] def geometry_preprocess_routine(analyses): settings = analyses.geometry.settings vehicle = analyses.vehicle # initalize variables sectional_area = 0 defined_cabins = False NPF = 0 NPB = 0 NPE = 0 # ================================================================================================================================================ # update fuselage properties # ================================================================================================================================================ total_seats = 0 for fuselage in vehicle.fuselages: compute_layout_of_passenger_accommodations(fuselage) fuselage_planform(fuselage) vehicle.length = np.maximum(vehicle.length, fuselage.lengths.total) sectional_area = fuselage.areas.front_projected for cabin in fuselage.cabins: defined_cabins = True for cabin_class in cabin.classes: if type(cabin_class) == RCAIDE.Library.Components.Fuselages.Cabins.Classes.Economy: NPE += cabin_class.number_of_seats elif type(cabin_class) == RCAIDE.Library.Components.Fuselages.Cabins.Classes.Business: NPB += cabin_class.number_of_seats elif type(cabin_class) == RCAIDE.Library.Components.Fuselages.Cabins.Classes.First: NPF += cabin_class.number_of_seats total_seats += cabin.number_of_seats for cabin in fuselage.cabins: if cabin.number_of_passengers == 0: # if cabin class passengers are not defined, use ratio of cabin to aircraft cabin.number_of_passengers = min(total_seats,int( np.round((cabin.number_of_seats / total_seats) * vehicle.number_of_passengers))) # ================================================================================================================================================ # update landing gear properties # ================================================================================================================================================ for landing_gear in vehicle.landing_gears: symm = landing_gear.xz_plane_symmetric landing_gear.wheels = landing_gear.number_of_gear_types_in_tandem * landing_gear.number_of_wheels_in_gear_type * (symm + 1) # ================================================================================================================================================ # update wing properties # ================================================================================================================================================ for wing in vehicle.wings: # -------------------------------------------------------------------------------------------------------------------- # Blended Wing Body # -------------------------------------------------------------------------------------------------------------------- if isinstance(wing, RCAIDE.Library.Components.Wings.Blended_Wing_Body): # compute planform properties wing_planform(wing) compute_layout_of_passenger_accommodations(wing) # update reference properties if settings.overwrite_reference: vehicle.reference_area = wing.areas.reference vehicle.LEMAC = wing.LEMAC for cabin in wing.cabins: defined_cabins = True for cabin_class in cabin.classes: if type(cabin_class) == RCAIDE.Library.Components.Fuselages.Cabins.Classes.Economy: NPE += cabin_class.number_of_seats elif type(cabin_class) == RCAIDE.Library.Components.Fuselages.Cabins.Classes.Business: NPB += cabin_class.number_of_seats elif type(cabin_class) == RCAIDE.Library.Components.Fuselages.Cabins.Classes.First: NPF += cabin_class.number_of_seats total_seats += cabin.number_of_seats if cabin.number_of_passengers == 0: # if cabin class passengers are not defined, use ratio of cabin to aircraft cabin.number_of_passengers = min(total_seats,int( np.round((cabin.number_of_seats / total_seats) * vehicle.number_of_passengers))) # -------------------------------------------------------------------------------------------------------------------- # All other wing surfaces # -------------------------------------------------------------------------------------------------------------------- else: wing_planform(wing) if isinstance(wing, RCAIDE.Library.Components.Wings.Main_Wing) and settings.overwrite_reference: vehicle.reference_area = wing.areas.reference vehicle.LEMAC = wing.LEMAC # reference chord vehicle.reference_chord = np.maximum(vehicle.reference_chord , wing.chords.mean_aerodynamic) # reference span vehicle.reference_span = np.maximum(vehicle.reference_span , wing.spans.projected) # total length vehicle.length = np.maximum(vehicle.length, wing.chords.root) # max cross sectional area sectional_area += wing.areas.front_projected for network in vehicle.networks: for propulsor in network.propulsors: sectional_area += (propulsor.diameter**2) * np.pi / 4.0 vehicle.maximum_cross_sectional_area = sectional_area # -------------------------------------------------------------------------------------------------------------------- # Update passenger imformation # -------------------------------------------------------------------------------------------------------------------- if vehicle.number_of_passengers == 0: pass else: if defined_cabins: vehicle.number_of_first_class_seats = NPF vehicle.number_of_business_class_seats = NPB vehicle.number_of_economy_class_seats = NPE else: vehicle.number_of_first_class_seats = vehicle.number_of_passengers / 20. vehicle.number_of_business_class_seats = vehicle.number_of_passengers / 10. vehicle.number_of_economy_class_seats = vehicle.number_of_passengers - NPF - NPB # -------------------------------------------------------------------------------------------------------------------- # Compute fuel volume # -------------------------------------------------------------------------------------------------------------------- compute_fuel_volume(vehicle, compute_fuel_volume=settings.compute_fuel_volume, update_max_fuel=settings.update_max_fuel) if settings.write_geometry_properties: write_geometry_to_excel(vehicle) return
[docs] def write_geometry_to_excel(vehicle): """ Export vehicle geometry and related fuel/propulsor data to an Excel workbook. Parameters ---------- vehicle : RCAIDE.Vehicle Vehicle object containing fuselages, wings, segments, networks, fuel tanks, and propulsors to be serialized into tabular sheets. Notes ----- None """ excel_filename = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])), os.path.splitext(os.path.basename(sys.argv[0]))[0] + "_geometry_description.xlsx") fuselage_rows = [] wing_rows = [] segment_rows = [] fuel_rows = [] prop_rows = [] # Collect Fuselage Level Properties for fuselage in vehicle.fuselages: fuselage_rows.append({ "Fuselage Tag" : fuselage.tag, "Fuselage Origin" : fuselage.origin[0], "Total Length (m)" : fuselage.lengths.total, "Nose Length (m)" : fuselage.lengths.nose, "Tail Length (m)" : fuselage.lengths.tail, "Maximum Height (m)" : fuselage.heights.maximum, "Width (m)" : fuselage.width, "Effective Diameter (m)" : fuselage.effective_diameter, "Fineness Nose" : fuselage.fineness.nose, "Fineness Tail" : fuselage.fineness.tail, "Front Projected Area (m^2)" : fuselage.areas.front_projected, "Side Projected Area (m^2)" : fuselage.areas.side_projected, "Wetted Area (m^2)" : fuselage.areas.wetted, "Passengers" : fuselage.number_of_passengers, "Seats" : fuselage.number_of_seats, }) # Collect wing-level properties for wing in vehicle.wings: wing_rows.append({ "Wing Tag" : wing.tag, "Wing Origin" : wing.origin[0], "Projected Span (m)" : wing.spans.projected, "Root Chord (m)" : wing.chords.root, "Mean Aerodynamic Chord (m)" : wing.chords.mean_aerodynamic, "Gross Aspect Ratio" : wing.aspect_ratio, "Trapezoid Aspect Ratio" : wing.spans.projected**2/wing.areas.reference, "LEMAC (m)" : wing.LEMAC, "Reference Area (m^2)" : wing.areas.reference, "Wetted Area (m^2)" : wing.areas.wetted, "XZ Symmetric" : wing.xz_plane_symmetric, "XY Symmetric" : wing.xy_plane_symmetric, }) # Collect segment-level properties for each wing for segment in wing.segments: segment_rows.append({ "Wing Tag" : wing.tag, "Segment Tag" : segment.tag, "Segment Origin" : f'[{str(segment.origin[0][0])}, {str(segment.origin[0][1])}, {str(segment.origin[0][2])}]', "Spanwise Location (%)" : segment.percent_span_location * 100.0, "Root Chord Fraction" : segment.root_chord_percent, "Twist (deg)" : segment.twist / Units.degree, "Outboard Dihedral (deg)" : segment.dihedral_outboard / Units.degree, "Quarter-Chord Sweep (deg)" : segment.sweeps.quarter_chord / Units.degree, "Leading-Edge Sweep (deg)" : segment.sweeps.leading_edge / Units.degree }) # Collect fuel tank properties from fuel lines and busses for network in vehicle.networks: network_tag = getattr(network, "tag", None) # Propulsors for propulsor in network.propulsors: prop_rows.append({ "Network Tag" : network_tag, "Propulsor Origin" : propulsor.origin[0], "Propulsor Tag" : getattr(propulsor, "tag", None), "Type" : propulsor.__class__.__name__, "Length (m)" : getattr(propulsor, "length", None), "Diameter (m)" : getattr(propulsor, "diameter", None), "Bypass Ratio" : getattr(propulsor, "bypass_ratio", None), "Sealevel Static Thrust [lbf]" : getattr(propulsor, "sealevel_static_thrust", None)/Units.lbf, "TSFC [lb/lbf-hr]" : getattr(propulsor, "TSFC", None)[0][0] }) for fuel_line in network.fuel_lines: container_tag = getattr(fuel_line, "tag", None) for fuel_tank in fuel_line.fuel_tanks: fuel_rows.append({ "Network Tag" : network_tag, "Tank Type" : str(type(fuel_tank)[0]).split('.')[-1], "Container Type" : "fuel_line", "Container Tag" : container_tag, "Fuel Tank Tag" : fuel_tank.tag, "Wing Tag" : getattr(fuel_tank, "wing_tag", None), "Fuselage Tag" : getattr(fuel_tank, "fuselage_tag", None), "Percent Span Location" : getattr(fuel_tank, "percent_span_location", None), "Segments Bounding Tank" : getattr(fuel_tank, "segments_bounding_tank", None), "Segments % Chord Start" : getattr(fuel_tank, "segments_percent_chord_start", None), "Segments % Chord End" : getattr(fuel_tank, "segments_percent_chord_end", None), "BWB Aft Tank" : getattr(fuel_tank, "transverse_tank", None), "XZ Plane Symmetric" : getattr(fuel_tank, "xz_plane_symmetric", None), "Fuel Net Volume (m^3)" : getattr(getattr(fuel_tank.fuel, "volume_properties", None), "net_volume", None) if fuel_tank.fuel else None, "Fuel Gross Volume (m^3)" : getattr(getattr(fuel_tank, "volume_properties", None), "gross_volume", None) if fuel_tank.fuel else None, "Fuel Mass (kg)" : getattr(getattr(fuel_tank.fuel, "mass_properties", None), "mass", None) if fuel_tank.fuel else None, }) # Write to Excel with separate sheets for wings and segments with pd.ExcelWriter(excel_filename) as writer: pd.DataFrame(fuselage_rows).to_excel(writer, sheet_name='Fuselage_Properties', index=False) pd.DataFrame(wing_rows).to_excel(writer, sheet_name='Wing_Properties', index=False) pd.DataFrame(segment_rows).to_excel(writer, sheet_name='Segment_Properties', index=False) pd.DataFrame(fuel_rows).to_excel(writer, sheet_name='Fuel_Tanks', index=False) pd.DataFrame(prop_rows).to_excel(writer, sheet_name='Propulsors', index=False) print(f"Geometry Description written to Excel:\n {excel_filename}") return