RCAIDE-GUI 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- common_widgets/__init__.py +6 -0
- common_widgets/animated_toggle.py +141 -0
- common_widgets/color.py +17 -0
- common_widgets/data_entry_widget.py +337 -0
- common_widgets/image_widget.py +21 -0
- common_widgets/unit_picker_widget.py +48 -0
- main.py +168 -0
- rcaide_gui-1.0.0.dist-info/METADATA +96 -0
- rcaide_gui-1.0.0.dist-info/RECORD +170 -0
- rcaide_gui-1.0.0.dist-info/WHEEL +5 -0
- rcaide_gui-1.0.0.dist-info/entry_points.txt +2 -0
- rcaide_gui-1.0.0.dist-info/top_level.txt +5 -0
- rcaide_io.py +818 -0
- tabs/__init__.py +10 -0
- tabs/aircraft_configs/__init__.py +3 -0
- tabs/aircraft_configs/aircraft_configs.py +301 -0
- tabs/analysis/__init__.py +4 -0
- tabs/analysis/analysis.py +92 -0
- tabs/analysis/widgets/__init__.py +13 -0
- tabs/analysis/widgets/aeroacoustics_widget.py +158 -0
- tabs/analysis/widgets/aerodynamics_widget.py +108 -0
- tabs/analysis/widgets/analysis_data_widget.py +29 -0
- tabs/analysis/widgets/atmosphere_widget.py +49 -0
- tabs/analysis/widgets/costs_widget.py +35 -0
- tabs/analysis/widgets/energy_widget.py +32 -0
- tabs/analysis/widgets/geometry_widget.py +55 -0
- tabs/analysis/widgets/planets_widget.py +34 -0
- tabs/analysis/widgets/propulsion_widget.py +53 -0
- tabs/analysis/widgets/stability_widget.py +34 -0
- tabs/analysis/widgets/weights_widget.py +94 -0
- tabs/geometry/__init__.py +6 -0
- tabs/geometry/aircraft_configs.py +232 -0
- tabs/geometry/frames/__init__.py +15 -0
- tabs/geometry/frames/booms/__init__.py +5 -0
- tabs/geometry/frames/booms/boom_frame.py +238 -0
- tabs/geometry/frames/cargo_bays/__init__.py +5 -0
- tabs/geometry/frames/cargo_bays/cargo_bay_frame.py +159 -0
- tabs/geometry/frames/default_frame.py +23 -0
- tabs/geometry/frames/energy_network/__init__.py +2 -0
- tabs/geometry/frames/energy_network/turbofan_network/__init__.py +3 -0
- tabs/geometry/frames/energy_network/turbofan_network/frames/__init__.py +1 -0
- tabs/geometry/frames/energy_network/turbofan_network/widgets/__init__.py +1 -0
- tabs/geometry/frames/fuselages/__init__.py +5 -0
- tabs/geometry/frames/fuselages/fuselage_frame.py +294 -0
- tabs/geometry/frames/geometry_frame.py +91 -0
- tabs/geometry/frames/landing_gears/__init__.py +5 -0
- tabs/geometry/frames/landing_gears/landing_gear_frame.py +189 -0
- tabs/geometry/frames/nacelles/__init__.py +1 -0
- tabs/geometry/frames/powertrain/__init__.py +6 -0
- tabs/geometry/frames/powertrain/converters/__init__.py +5 -0
- tabs/geometry/frames/powertrain/converters/converter_frame.py +137 -0
- tabs/geometry/frames/powertrain/distributors/__init__.py +5 -0
- tabs/geometry/frames/powertrain/distributors/distributor_frame.py +143 -0
- tabs/geometry/frames/powertrain/nacelles/__init__.py +5 -0
- tabs/geometry/frames/powertrain/nacelles/nacelle_frame.py +283 -0
- tabs/geometry/frames/powertrain/powertrain_frame.py +259 -0
- tabs/geometry/frames/powertrain/propulsors/__init__.py +5 -0
- tabs/geometry/frames/powertrain/propulsors/propulsor_frame.py +146 -0
- tabs/geometry/frames/powertrain/sources/__init__.py +6 -0
- tabs/geometry/frames/powertrain/sources/energy_source_frame.py +147 -0
- tabs/geometry/frames/vehicle_frame.py +171 -0
- tabs/geometry/frames/wings/__init__.py +5 -0
- tabs/geometry/frames/wings/wings_frame.py +457 -0
- tabs/geometry/geometry.py +513 -0
- tabs/geometry/widgets/__init__.py +12 -0
- tabs/geometry/widgets/booms/__init__.py +6 -0
- tabs/geometry/widgets/booms/boom_section_widget.py +109 -0
- tabs/geometry/widgets/cargo_bays/__init__.py +1 -0
- tabs/geometry/widgets/fuselages/__init__.py +8 -0
- tabs/geometry/widgets/fuselages/cabin_class_widget.py +188 -0
- tabs/geometry/widgets/fuselages/cabin_widget.py +217 -0
- tabs/geometry/widgets/fuselages/fuselage_section_widget.py +190 -0
- tabs/geometry/widgets/geometry_data_widget.py +25 -0
- tabs/geometry/widgets/landing_gears/__init__.py +6 -0
- tabs/geometry/widgets/nacelles/__init__.py +1 -0
- tabs/geometry/widgets/powertrain/__init__.py +9 -0
- tabs/geometry/widgets/powertrain/converters/__init__.py +5 -0
- tabs/geometry/widgets/powertrain/converters/turboelectric_generator_widget.py +74 -0
- tabs/geometry/widgets/powertrain/distributors/__init__.py +5 -0
- tabs/geometry/widgets/powertrain/distributors/fuel_line_widget.py +81 -0
- tabs/geometry/widgets/powertrain/modulators/__init__.py +5 -0
- tabs/geometry/widgets/powertrain/modulators/esc_widget.py +58 -0
- tabs/geometry/widgets/powertrain/nacelles/__init__.py +5 -0
- tabs/geometry/widgets/powertrain/nacelles/nacelle_section_widget.py +115 -0
- tabs/geometry/widgets/powertrain/powertrain_connector_widget.py +136 -0
- tabs/geometry/widgets/powertrain/powertrain_widget.py +206 -0
- tabs/geometry/widgets/powertrain/propulsors/__init__.py +5 -0
- tabs/geometry/widgets/powertrain/propulsors/turbofan_widget.py +462 -0
- tabs/geometry/widgets/powertrain/sources/__init__.py +6 -0
- tabs/geometry/widgets/powertrain/sources/fuel_tank_widget.py +103 -0
- tabs/geometry/widgets/powertrain/sources/source_selector_widget.py +35 -0
- tabs/geometry/widgets/wings/__init__.py +7 -0
- tabs/geometry/widgets/wings/wing_cs_widget.py +198 -0
- tabs/geometry/widgets/wings/wing_section_widget.py +298 -0
- tabs/home/__init__.py +3 -0
- tabs/home/home.py +585 -0
- tabs/mission/__init__.py +4 -0
- tabs/mission/mission.py +1124 -0
- tabs/mission/widgets/__init__.py +3 -0
- tabs/mission/widgets/flight_controls_widget.py +186 -0
- tabs/mission/widgets/mission_analysis_widget.py +166 -0
- tabs/mission/widgets/mission_segment_helper.py +358 -0
- tabs/mission/widgets/mission_segment_widget.py +358 -0
- tabs/solve/__init__.py +4 -0
- tabs/solve/plots/__init__.py +12 -0
- tabs/solve/plots/aeroacoustics/__init__.py +6 -0
- tabs/solve/plots/aeroacoustics/plot_2D_noise_contour.py +184 -0
- tabs/solve/plots/aeroacoustics/plot_3D_noise_contour.py +219 -0
- tabs/solve/plots/aeroacoustics/plot_noise_certification_contour.py +115 -0
- tabs/solve/plots/aeroacoustics/plot_noise_level.py +118 -0
- tabs/solve/plots/aerodynamics/__init__.py +10 -0
- tabs/solve/plots/aerodynamics/plot_aerodynamic_coefficients.py +156 -0
- tabs/solve/plots/aerodynamics/plot_aerodynamic_forces.py +155 -0
- tabs/solve/plots/aerodynamics/plot_aircraft_aerodynamics.py +136 -0
- tabs/solve/plots/aerodynamics/plot_drag_components.py +157 -0
- tabs/solve/plots/aerodynamics/plot_lift_distribution.py +107 -0
- tabs/solve/plots/aerodynamics/plot_rotor_conditions.py +255 -0
- tabs/solve/plots/aerodynamics/plot_rotor_disc_performance.py +144 -0
- tabs/solve/plots/aerodynamics/plot_rotor_performance.py +124 -0
- tabs/solve/plots/common/__init__.py +4 -0
- tabs/solve/plots/common/plot_style.py +71 -0
- tabs/solve/plots/common/set_axes.py +55 -0
- tabs/solve/plots/create_plot_widgets.py +34 -0
- tabs/solve/plots/emissions/__init__.py +3 -0
- tabs/solve/plots/emissions/plot_emissions.py +167 -0
- tabs/solve/plots/energy/__init__.py +12 -0
- tabs/solve/plots/energy/plot_altitude_sfc_weight.py +134 -0
- tabs/solve/plots/energy/plot_battery_cell_conditions.py +154 -0
- tabs/solve/plots/energy/plot_battery_degradation.py +157 -0
- tabs/solve/plots/energy/plot_battery_module_C_rates.py +139 -0
- tabs/solve/plots/energy/plot_battery_module_conditions.py +157 -0
- tabs/solve/plots/energy/plot_battery_pack_conditions.py +164 -0
- tabs/solve/plots/energy/plot_battery_ragone_diagram.py +97 -0
- tabs/solve/plots/energy/plot_battery_temperature.py +136 -0
- tabs/solve/plots/energy/plot_electric_propulsor_efficiencies.py +136 -0
- tabs/solve/plots/energy/plot_propulsor_throttles.py +119 -0
- tabs/solve/plots/mission/__init__.py +5 -0
- tabs/solve/plots/mission/plot_aircraft_velocities.py +145 -0
- tabs/solve/plots/mission/plot_flight_conditions.py +236 -0
- tabs/solve/plots/mission/plot_flight_trajectory.py +172 -0
- tabs/solve/plots/stability/__init__.py +5 -0
- tabs/solve/plots/stability/plot_flight_forces_and_moments.py +163 -0
- tabs/solve/plots/stability/plot_lateral_stability.py +151 -0
- tabs/solve/plots/stability/plot_longitudinal_stability.py +173 -0
- tabs/solve/plots/thermal_management/__init__.py +7 -0
- tabs/solve/plots/thermal_management/plot_air_cooled_conditions.py +152 -0
- tabs/solve/plots/thermal_management/plot_cross_flow_heat_exchanger_conditions.py +185 -0
- tabs/solve/plots/thermal_management/plot_reservoir_conditions.py +141 -0
- tabs/solve/plots/thermal_management/plot_thermal_management_performance.py +105 -0
- tabs/solve/plots/thermal_management/plot_wavy_channel_conditions.py +161 -0
- tabs/solve/plots/weights/__init__.py +4 -0
- tabs/solve/plots/weights/plot_load_diagram.py +163 -0
- tabs/solve/plots/weights/plot_weight_breakdown.py +164 -0
- tabs/solve/solve.py +1498 -0
- tabs/style_sheet.py +114 -0
- tabs/tab_widget.py +14 -0
- tabs/visualize_geometry/__init__.py +4 -0
- tabs/visualize_geometry/core_3d_viewer.py +253 -0
- tabs/visualize_geometry/features/__init__.py +10 -0
- tabs/visualize_geometry/features/axes_gizmo.py +173 -0
- tabs/visualize_geometry/features/background.py +161 -0
- tabs/visualize_geometry/features/blueprint.py +685 -0
- tabs/visualize_geometry/features/camera.py +364 -0
- tabs/visualize_geometry/features/drag_aircraft.py +219 -0
- tabs/visualize_geometry/features/grid.py +194 -0
- tabs/visualize_geometry/features/measurement.py +367 -0
- tabs/visualize_geometry/features/screenshot.py +91 -0
- tabs/visualize_geometry/geometry_helper_functions.py +3 -0
- tabs/visualize_geometry/visualize_geometry.py +731 -0
- utilities.py +257 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# RCAIDE/Library/Plots/Thermal_Management/plot_wavy_channel_conditions.py
|
|
2
|
+
#
|
|
3
|
+
#
|
|
4
|
+
# Created: Sep 2024, S. Shekar
|
|
5
|
+
|
|
6
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
|
7
|
+
# IMPORT
|
|
8
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
from RCAIDE.Framework.Core import Units
|
|
11
|
+
from RCAIDE.Library.Plots.Common import set_axes, plot_style
|
|
12
|
+
import matplotlib.pyplot as plt
|
|
13
|
+
import matplotlib.cm as cm
|
|
14
|
+
import numpy as np
|
|
15
|
+
|
|
16
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
|
17
|
+
# plot_wavy_channel_conditions
|
|
18
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
|
19
|
+
def plot_wavy_channel_conditions(wavy_channel, results, coolant_line,
|
|
20
|
+
save_figure = False,
|
|
21
|
+
show_legend = True,
|
|
22
|
+
save_filename = "Wavy_Channel_Conditions",
|
|
23
|
+
file_type = ".png",
|
|
24
|
+
width = 11, height = 7):
|
|
25
|
+
"""
|
|
26
|
+
Creates a multi-panel visualization of wavy channel heat exchanger performance.
|
|
27
|
+
|
|
28
|
+
Parameters
|
|
29
|
+
----------
|
|
30
|
+
wavy_channel : Component
|
|
31
|
+
Wavy channel heat exchanger component containing:
|
|
32
|
+
- tag : str
|
|
33
|
+
Unique identifier for the heat exchanger
|
|
34
|
+
|
|
35
|
+
results : Results
|
|
36
|
+
RCAIDE results data structure containing:
|
|
37
|
+
- segments[i].conditions.frames.inertial.time[:,0]
|
|
38
|
+
Time history for each segment
|
|
39
|
+
- segments[i].conditions.energy.coolant_lines[coolant_line.tag][wavy_channel.tag]
|
|
40
|
+
Heat exchanger data containing:
|
|
41
|
+
- outlet_coolant_temperature[:,0]
|
|
42
|
+
Coolant outlet temperature in K
|
|
43
|
+
- coolant_mass_flow_rate[:,0]
|
|
44
|
+
Coolant flow rate in kg/s
|
|
45
|
+
- power[:,0]
|
|
46
|
+
Heat transfer rate in watts
|
|
47
|
+
|
|
48
|
+
coolant_line : Component
|
|
49
|
+
Coolant line component containing:
|
|
50
|
+
- tag : str
|
|
51
|
+
Unique identifier for the coolant circuit
|
|
52
|
+
|
|
53
|
+
save_figure : bool, optional
|
|
54
|
+
Flag for saving the figure (default: False)
|
|
55
|
+
|
|
56
|
+
show_legend : bool, optional
|
|
57
|
+
Flag to display segment legend (default: True)
|
|
58
|
+
|
|
59
|
+
save_filename : str, optional
|
|
60
|
+
Name of file for saved figure (default: "Wavy_Channel_Conditions")
|
|
61
|
+
|
|
62
|
+
file_type : str, optional
|
|
63
|
+
File extension for saved figure (default: ".png")
|
|
64
|
+
|
|
65
|
+
width : float, optional
|
|
66
|
+
Figure width in inches (default: 11)
|
|
67
|
+
|
|
68
|
+
height : float, optional
|
|
69
|
+
Figure height in inches (default: 7)
|
|
70
|
+
|
|
71
|
+
Returns
|
|
72
|
+
-------
|
|
73
|
+
fig : matplotlib.figure.Figure
|
|
74
|
+
Handle to the generated figure containing three subplots
|
|
75
|
+
|
|
76
|
+
Notes
|
|
77
|
+
-----
|
|
78
|
+
Creates visualization showing:
|
|
79
|
+
* Thermal performance metrics
|
|
80
|
+
* Flow conditions
|
|
81
|
+
* Heat transfer characteristics
|
|
82
|
+
* Time history for each segment
|
|
83
|
+
|
|
84
|
+
**Definitions**
|
|
85
|
+
|
|
86
|
+
'Wavy Channel'
|
|
87
|
+
Heat exchanger with sinusoidal flow paths
|
|
88
|
+
'Hydraulic Diameter'
|
|
89
|
+
4 × (flow area) / (wetted perimeter)
|
|
90
|
+
'Heat Transfer Rate'
|
|
91
|
+
Rate of thermal energy transfer
|
|
92
|
+
'Mass Flow Rate'
|
|
93
|
+
Mass of fluid flowing per unit time
|
|
94
|
+
|
|
95
|
+
See Also
|
|
96
|
+
--------
|
|
97
|
+
RCAIDE.Library.Plots.Thermal_Management.plot_thermal_management_performance : Overall system performance
|
|
98
|
+
RCAIDE.Library.Plots.Thermal_Management.plot_cross_flow_heat_exchanger_conditions : Cross-flow heat exchanger analysis
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
# get plotting style
|
|
102
|
+
ps = plot_style()
|
|
103
|
+
|
|
104
|
+
parameters = {'axes.labelsize': ps.axis_font_size,
|
|
105
|
+
'xtick.labelsize': ps.axis_font_size,
|
|
106
|
+
'ytick.labelsize': ps.axis_font_size,
|
|
107
|
+
'axes.titlesize': ps.title_font_size}
|
|
108
|
+
plt.rcParams.update(parameters)
|
|
109
|
+
|
|
110
|
+
# get line colors for plots
|
|
111
|
+
line_colors = cm.inferno(np.linspace(0,0.9,len(results.segments)))
|
|
112
|
+
|
|
113
|
+
fig = plt.figure('Identical_'+ save_filename)
|
|
114
|
+
fig.set_size_inches(width,height)
|
|
115
|
+
axis_1 = plt.subplot(2,2,1)
|
|
116
|
+
axis_2 = plt.subplot(2,2,2)
|
|
117
|
+
axis_3 = plt.subplot(2,2,3)
|
|
118
|
+
|
|
119
|
+
for network in results.segments[0].analyses.vehicle.networks:
|
|
120
|
+
busses = network.busses
|
|
121
|
+
for bus in busses:
|
|
122
|
+
for b_i, battery in enumerate(bus.battery_modules):
|
|
123
|
+
if b_i == 0 or bus.identical_battery_modules == False:
|
|
124
|
+
for i in range(len(results.segments)):
|
|
125
|
+
time = results.segments[i].conditions.frames.inertial.time[:,0] / Units.min
|
|
126
|
+
wavy_channel_conditions = results.segments[i].conditions.energy.coolant_lines[coolant_line.tag][wavy_channel.tag]
|
|
127
|
+
outlet_coolant_temperature = wavy_channel_conditions.outlet_coolant_temperature[:,0]
|
|
128
|
+
coolant_mass_flow_rate = wavy_channel_conditions.coolant_mass_flow_rate[:,0]
|
|
129
|
+
power = wavy_channel_conditions.power[:,0]
|
|
130
|
+
|
|
131
|
+
if i == 0:
|
|
132
|
+
axis_1.plot(time, outlet_coolant_temperature, color = line_colors[i], marker = ps.markers[b_i], linewidth = ps.line_width, label = wavy_channel.tag)
|
|
133
|
+
else:
|
|
134
|
+
axis_1.plot(time, outlet_coolant_temperature, color = line_colors[i], marker = ps.markers[b_i], linewidth = ps.line_width)
|
|
135
|
+
axis_1.set_ylabel(r'Coolant Temp. (K)')
|
|
136
|
+
set_axes(axis_1)
|
|
137
|
+
|
|
138
|
+
axis_2.plot(time, coolant_mass_flow_rate, color = line_colors[i], marker = ps.markers[b_i], linewidth = ps.line_width)
|
|
139
|
+
axis_2.set_ylabel(r'Coolant $\dot{m}$ (kg/s)')
|
|
140
|
+
set_axes(axis_2)
|
|
141
|
+
|
|
142
|
+
axis_3.plot(time, power, color = line_colors[i], marker = ps.markers[b_i], linewidth = ps.line_width)
|
|
143
|
+
axis_3.set_ylabel(r'HAS Power (W)')
|
|
144
|
+
axis_3.set_xlabel(r'Time (mins)')
|
|
145
|
+
set_axes(axis_3)
|
|
146
|
+
|
|
147
|
+
if show_legend:
|
|
148
|
+
leg = fig.legend(bbox_to_anchor=(0.5, 0.95), loc='upper center', ncol = 4)
|
|
149
|
+
leg.set_title('Flight Segment', prop={'size': ps.legend_font_size, 'weight': 'heavy'})
|
|
150
|
+
|
|
151
|
+
# Adjusting the sub-plots for legend
|
|
152
|
+
fig.tight_layout()
|
|
153
|
+
fig.subplots_adjust(top=0.8)
|
|
154
|
+
|
|
155
|
+
# set title of plot
|
|
156
|
+
title_text = 'Wavy_Channel_Properties'
|
|
157
|
+
fig.suptitle(title_text)
|
|
158
|
+
|
|
159
|
+
if save_figure:
|
|
160
|
+
plt.savefig(wavy_channel.tag + file_type)
|
|
161
|
+
return fig
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# RCAIDE/Library/Plots/Weights/plot_load_diagram.py
|
|
2
|
+
#
|
|
3
|
+
#
|
|
4
|
+
# Created: Aug 2025, M. Clarke
|
|
5
|
+
|
|
6
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
|
7
|
+
# IMPORT
|
|
8
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
|
9
|
+
from RCAIDE.Framework.Core import Units
|
|
10
|
+
from RCAIDE.Library.Plots.Common import set_axes, plot_style
|
|
11
|
+
import matplotlib.pyplot as plt
|
|
12
|
+
from scipy.spatial import ConvexHull
|
|
13
|
+
from shapely.geometry import Polygon
|
|
14
|
+
import matplotlib.cm as cm
|
|
15
|
+
from scipy.interpolate import griddata
|
|
16
|
+
import matplotlib.tri as tri
|
|
17
|
+
import numpy as np
|
|
18
|
+
|
|
19
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
|
20
|
+
# PLOTS
|
|
21
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
|
22
|
+
def plot_load_diagram(results,
|
|
23
|
+
save_figure = False,
|
|
24
|
+
show_legend = True,
|
|
25
|
+
save_filename = "Aircraft_Loading_Trim_Dragram",
|
|
26
|
+
file_type = ".png",
|
|
27
|
+
width = 11, height = 7):
|
|
28
|
+
"""
|
|
29
|
+
Creates a comprehensive aircraft loading diagram showing mass and center of gravity relationships.
|
|
30
|
+
|
|
31
|
+
Parameters
|
|
32
|
+
----------
|
|
33
|
+
results : RCAIDE.Framework.Core.Data
|
|
34
|
+
Results from load and trim diagram analysis containing:
|
|
35
|
+
- loading_mass : numpy.ndarray
|
|
36
|
+
Aircraft mass for loading diagram [kg]
|
|
37
|
+
- loading_LEMAC_location : numpy.ndarray
|
|
38
|
+
LEMAC location as percentage of reference chord [%]
|
|
39
|
+
- aerodynamic_LEMAC_location : numpy.ndarray
|
|
40
|
+
LEMAC location for trim diagram [%]
|
|
41
|
+
- aerodynamic_mass : numpy.ndarray
|
|
42
|
+
Aircraft mass for trim diagram [kg]
|
|
43
|
+
- aerodynamic_static_margin : numpy.ndarray
|
|
44
|
+
Static margin values [unitless]
|
|
45
|
+
- MTOW : float
|
|
46
|
+
Maximum takeoff weight [kg]
|
|
47
|
+
- MLW : float
|
|
48
|
+
Maximum landing weight [kg]
|
|
49
|
+
|
|
50
|
+
Returns
|
|
51
|
+
-------
|
|
52
|
+
None
|
|
53
|
+
Creates and displays a matplotlib figure with the loading diagram
|
|
54
|
+
|
|
55
|
+
Notes
|
|
56
|
+
-----
|
|
57
|
+
This function generates a comprehensive aircraft loading diagram that visualizes
|
|
58
|
+
the relationship between aircraft mass, loading, and center of gravity position. The diagram
|
|
59
|
+
includes fuel loading curves, payload loading curves, weight limits, and stability
|
|
60
|
+
contours to provide a complete view of the aircraft's loading envelope.
|
|
61
|
+
|
|
62
|
+
**Major Assumptions**
|
|
63
|
+
* Convex hull calculation is valid for the data points
|
|
64
|
+
|
|
65
|
+
**Definitions**
|
|
66
|
+
|
|
67
|
+
'Loading Diagram'
|
|
68
|
+
Plot showing aircraft mass versus center of gravity position for different loading conditions.
|
|
69
|
+
|
|
70
|
+
'Convex Hull'
|
|
71
|
+
Smallest convex polygon that contains all the data points.
|
|
72
|
+
|
|
73
|
+
'Static Margin'
|
|
74
|
+
Distance between center of gravity and neutral point as percentage of reference chord.
|
|
75
|
+
|
|
76
|
+
'LEMAC'
|
|
77
|
+
Leading Edge Mean Aerodynamic Chord reference point for center of gravity calculations.
|
|
78
|
+
|
|
79
|
+
See Also
|
|
80
|
+
--------
|
|
81
|
+
matplotlib.pyplot
|
|
82
|
+
scipy.spatial.ConvexHull
|
|
83
|
+
shapely.geometry.Polygon
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
# get plotting style
|
|
87
|
+
ps = plot_style()
|
|
88
|
+
|
|
89
|
+
parameters = {'axes.labelsize': ps.axis_font_size,
|
|
90
|
+
'xtick.labelsize': ps.axis_font_size,
|
|
91
|
+
'ytick.labelsize': ps.axis_font_size,
|
|
92
|
+
'axes.titlesize': ps.title_font_size}
|
|
93
|
+
plt.rcParams.update(parameters)
|
|
94
|
+
|
|
95
|
+
fig = plt.figure(save_filename)
|
|
96
|
+
fig.set_size_inches(width,height)
|
|
97
|
+
axis = fig.add_subplot(1,1,1)
|
|
98
|
+
|
|
99
|
+
min_range = 0
|
|
100
|
+
max_range = 0
|
|
101
|
+
|
|
102
|
+
# ------------------------------------------------------------------------
|
|
103
|
+
# cumulative
|
|
104
|
+
# ------------------------------------------------------------------------
|
|
105
|
+
|
|
106
|
+
# 1. Generate sample scattered data
|
|
107
|
+
points = np.hstack(( np.atleast_2d(results.loading_LEMAC_location.flatten()).T, np.atleast_2d(results.loading_mass.flatten()).T ))
|
|
108
|
+
|
|
109
|
+
# 2. Compute the convex hull
|
|
110
|
+
hull = ConvexHull(points)
|
|
111
|
+
|
|
112
|
+
# 3. Extract the vertices of the hull in a counter-clockwise order
|
|
113
|
+
hull_points = points[hull.vertices]
|
|
114
|
+
|
|
115
|
+
# 4. Create a Shapely Polygon from the hull vertices
|
|
116
|
+
# The vertices are already ordered, but Shapely can handle it
|
|
117
|
+
polygon = Polygon(hull_points)
|
|
118
|
+
|
|
119
|
+
# Plot the convex hull polygon boundary
|
|
120
|
+
x_hull, y_hull = polygon.exterior.xy
|
|
121
|
+
|
|
122
|
+
axis.fill(x_hull, y_hull, color='grey', alpha=0.3, edgecolor='black', linewidth=2)
|
|
123
|
+
axis.plot(x_hull, y_hull, 'k-')
|
|
124
|
+
|
|
125
|
+
# ------------------------------------------------------------------------
|
|
126
|
+
# Maximum Takeoff Weight line
|
|
127
|
+
# ------------------------------------------------------------------------
|
|
128
|
+
x_pts_MTOW = np.linspace(0, 100)
|
|
129
|
+
y_pts_MTOW = np.ones_like(x_pts_MTOW) * results.MTOW
|
|
130
|
+
axis.plot(x_pts_MTOW, y_pts_MTOW, 'r-', label = 'MTOW')
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
# ------------------------------------------------------------------------
|
|
134
|
+
# Maximum Landing Weight line
|
|
135
|
+
# ------------------------------------------------------------------------
|
|
136
|
+
x_pts_MLW = x_pts_MTOW
|
|
137
|
+
y_pts_MLW = np.ones_like(x_pts_MLW) * results.MLW
|
|
138
|
+
axis.plot(x_pts_MLW, y_pts_MLW, 'r--', label = 'MLW')
|
|
139
|
+
|
|
140
|
+
# ------------------------------------------------------------------------
|
|
141
|
+
# Stability Contours
|
|
142
|
+
# ------------------------------------------------------------------------
|
|
143
|
+
SM_levels = np.linspace(-5, 100, 22)
|
|
144
|
+
CS = axis.contourf(results.aerodynamic_LEMAC_location, results.aerodynamic_mass, results.aerodynamic_static_margin*100, levels=SM_levels, cmap='viridis')
|
|
145
|
+
CS2 = axis.contour(results.aerodynamic_LEMAC_location, results.aerodynamic_mass, results.aerodynamic_static_margin*100, levels=SM_levels, colors='black')
|
|
146
|
+
cbar = fig.colorbar(CS, ax=axis)
|
|
147
|
+
axis.clabel(CS2, fontsize=10)
|
|
148
|
+
cbar.ax.set_ylabel('Static Margin', rotation = 90)
|
|
149
|
+
|
|
150
|
+
# ------------------------------------------------------------------------
|
|
151
|
+
# Axis Items
|
|
152
|
+
# ------------------------------------------------------------------------
|
|
153
|
+
axis.set_xlim(0, 100)
|
|
154
|
+
axis.legend(loc='upper right')
|
|
155
|
+
axis.set_xlabel(r'$X_{CG}$ (%MAC)')
|
|
156
|
+
axis.set_ylabel('Mass (kg)')
|
|
157
|
+
axis.grid(True)
|
|
158
|
+
fig.tight_layout()
|
|
159
|
+
|
|
160
|
+
if save_figure:
|
|
161
|
+
plt.savefig(save_filename + file_type)
|
|
162
|
+
|
|
163
|
+
return
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# RCAIDE/Library/Plots/Weights/plot_weight_breakdown.py
|
|
2
|
+
#
|
|
3
|
+
#
|
|
4
|
+
# Created: Jul 2023, M. Clarke
|
|
5
|
+
|
|
6
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
|
7
|
+
# IMPORT
|
|
8
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
|
9
|
+
import RCAIDE
|
|
10
|
+
import numpy as np
|
|
11
|
+
import plotly.express as px
|
|
12
|
+
import pandas as pd
|
|
13
|
+
|
|
14
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
|
15
|
+
# PLOTS
|
|
16
|
+
# ----------------------------------------------------------------------------------------------------------------------
|
|
17
|
+
def plot_weight_breakdown(vehicle,
|
|
18
|
+
save_figure = False,
|
|
19
|
+
show_figure = True,
|
|
20
|
+
show_legend = True,
|
|
21
|
+
save_filename = "Weight_Breakdown",
|
|
22
|
+
aircraft_name = None,
|
|
23
|
+
file_type = ".png",
|
|
24
|
+
width = 10, height = 7.2):
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
"""
|
|
28
|
+
Creates an interactive sunburst visualization of aircraft weight breakdown.
|
|
29
|
+
|
|
30
|
+
Parameters
|
|
31
|
+
----------
|
|
32
|
+
vehicle : Vehicle
|
|
33
|
+
RCAIDE vehicle data structure containing:
|
|
34
|
+
|
|
35
|
+
* weight_breakdown : Data
|
|
36
|
+
Hierarchical weight data with structure:
|
|
37
|
+
* zero_fuel_weight : float
|
|
38
|
+
Aircraft weight without fuel
|
|
39
|
+
* max_takeoff : float
|
|
40
|
+
Maximum takeoff weight
|
|
41
|
+
* systems : Data
|
|
42
|
+
System weights containing:
|
|
43
|
+
* total : float
|
|
44
|
+
Total systems weight
|
|
45
|
+
* [system_name] : float/Data
|
|
46
|
+
Individual system weights/subcomponents
|
|
47
|
+
* fuel : float
|
|
48
|
+
Total fuel weight
|
|
49
|
+
|
|
50
|
+
save_figure : bool, optional
|
|
51
|
+
Flag for saving the figure (default: False)
|
|
52
|
+
|
|
53
|
+
show_figure : bool, optional
|
|
54
|
+
Flag to display interactive plot (default: True)
|
|
55
|
+
|
|
56
|
+
show_legend : bool, optional
|
|
57
|
+
Flag to display weight legend (default: True)
|
|
58
|
+
|
|
59
|
+
save_filename : str, optional
|
|
60
|
+
Name of file for saved figure (default: "Weight_Breakdown")
|
|
61
|
+
|
|
62
|
+
aircraft_name : str, optional
|
|
63
|
+
Name to display in plot title (default: None)
|
|
64
|
+
|
|
65
|
+
file_type : str, optional
|
|
66
|
+
File extension for saved figure (default: ".png")
|
|
67
|
+
|
|
68
|
+
width : float, optional
|
|
69
|
+
Figure width in inches (default: 10)
|
|
70
|
+
|
|
71
|
+
height : float, optional
|
|
72
|
+
Figure height in inches (default: 7.2)
|
|
73
|
+
|
|
74
|
+
Returns
|
|
75
|
+
-------
|
|
76
|
+
fig : plotly.graph_objects.Figure
|
|
77
|
+
Handle to the generated figure containing:
|
|
78
|
+
|
|
79
|
+
Notes
|
|
80
|
+
-----
|
|
81
|
+
Creates visualization showing:
|
|
82
|
+
* Hierarchical weight breakdown
|
|
83
|
+
* Weight percentages
|
|
84
|
+
* Multi-level weight relationships
|
|
85
|
+
* Interactive exploration
|
|
86
|
+
|
|
87
|
+
**Major Assumptions**
|
|
88
|
+
* All weights are positive
|
|
89
|
+
* Hierarchy is properly structured
|
|
90
|
+
* No duplicate component names
|
|
91
|
+
* Subcomponent weights sum to totals
|
|
92
|
+
|
|
93
|
+
**Definitions**
|
|
94
|
+
|
|
95
|
+
'Weight Breakdown'
|
|
96
|
+
Hierarchical decomposition of vehicle mass
|
|
97
|
+
'Weight Fraction'
|
|
98
|
+
Component weight divided by total weight
|
|
99
|
+
'Zero Fuel Weight'
|
|
100
|
+
Aircraft weight excluding fuel
|
|
101
|
+
'Maximum Takeoff Weight'
|
|
102
|
+
Maximum allowable total weight
|
|
103
|
+
|
|
104
|
+
See Also
|
|
105
|
+
--------
|
|
106
|
+
RCAIDE.Library.Analysis.Weights : Weight analysis tools
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
breakdown = vehicle.mass_properties.weight_breakdown
|
|
110
|
+
|
|
111
|
+
level_1 = []
|
|
112
|
+
level_2 = []
|
|
113
|
+
level_3 = []
|
|
114
|
+
values = []
|
|
115
|
+
|
|
116
|
+
for tag , item in breakdown.items():
|
|
117
|
+
if tag == 'zero_fuel_weight' or tag == 'max_takeoff':
|
|
118
|
+
pass
|
|
119
|
+
else:
|
|
120
|
+
if type(item) == RCAIDE.Framework.Core.Data:
|
|
121
|
+
for sub_tag , sub_item in item.items():
|
|
122
|
+
if type(sub_item) == RCAIDE.Framework.Core.Data:
|
|
123
|
+
for sub_sub_tag , sub_sub_item in sub_item.items():
|
|
124
|
+
if sub_sub_tag != 'total':
|
|
125
|
+
level_1.append(tag.replace("_", " "))
|
|
126
|
+
level_2.append(sub_tag.replace("_", " "))
|
|
127
|
+
level_3.append(sub_sub_tag.replace("_", " "))
|
|
128
|
+
values.append(sub_sub_item )
|
|
129
|
+
elif sub_tag != 'total':
|
|
130
|
+
level_1.append(tag.replace("_", " "))
|
|
131
|
+
level_2.append(sub_tag.replace("_", " "))
|
|
132
|
+
level_3.append(np.nan)
|
|
133
|
+
values.append(sub_item)
|
|
134
|
+
elif tag == 'fuel':
|
|
135
|
+
level_1.append(tag.replace("_", " "))
|
|
136
|
+
level_2.append(np.nan)
|
|
137
|
+
level_3.append(np.nan)
|
|
138
|
+
values.append(sub_item)
|
|
139
|
+
|
|
140
|
+
df = pd.DataFrame(
|
|
141
|
+
dict(level_1=level_1, level_2=level_2, level_3=level_3, values=values)
|
|
142
|
+
)
|
|
143
|
+
fig = px.sunburst(df,
|
|
144
|
+
path=['level_1', 'level_2', 'level_3'],
|
|
145
|
+
values='values',
|
|
146
|
+
color_discrete_sequence=px.colors.qualitative.G10)
|
|
147
|
+
|
|
148
|
+
# Add a dummy inner layer for the hole
|
|
149
|
+
fig.update_traces(
|
|
150
|
+
textfont=dict(size=20),
|
|
151
|
+
insidetextorientation='horizontal',
|
|
152
|
+
textinfo='label+percent entry',
|
|
153
|
+
marker=dict(colors=['rgba(0,0,0,0)'] + px.colors.qualitative.G10)
|
|
154
|
+
)
|
|
155
|
+
fig.update_layout(
|
|
156
|
+
uniformtext=dict(minsize=12, mode='hide'),
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
if save_figure:
|
|
160
|
+
fig.write_image(save_filename + file_type)
|
|
161
|
+
|
|
162
|
+
if show_figure:
|
|
163
|
+
fig.write_html( save_filename + '.html', auto_open=True)
|
|
164
|
+
return fig
|