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.
Files changed (170) hide show
  1. common_widgets/__init__.py +6 -0
  2. common_widgets/animated_toggle.py +141 -0
  3. common_widgets/color.py +17 -0
  4. common_widgets/data_entry_widget.py +337 -0
  5. common_widgets/image_widget.py +21 -0
  6. common_widgets/unit_picker_widget.py +48 -0
  7. main.py +168 -0
  8. rcaide_gui-1.0.0.dist-info/METADATA +96 -0
  9. rcaide_gui-1.0.0.dist-info/RECORD +170 -0
  10. rcaide_gui-1.0.0.dist-info/WHEEL +5 -0
  11. rcaide_gui-1.0.0.dist-info/entry_points.txt +2 -0
  12. rcaide_gui-1.0.0.dist-info/top_level.txt +5 -0
  13. rcaide_io.py +818 -0
  14. tabs/__init__.py +10 -0
  15. tabs/aircraft_configs/__init__.py +3 -0
  16. tabs/aircraft_configs/aircraft_configs.py +301 -0
  17. tabs/analysis/__init__.py +4 -0
  18. tabs/analysis/analysis.py +92 -0
  19. tabs/analysis/widgets/__init__.py +13 -0
  20. tabs/analysis/widgets/aeroacoustics_widget.py +158 -0
  21. tabs/analysis/widgets/aerodynamics_widget.py +108 -0
  22. tabs/analysis/widgets/analysis_data_widget.py +29 -0
  23. tabs/analysis/widgets/atmosphere_widget.py +49 -0
  24. tabs/analysis/widgets/costs_widget.py +35 -0
  25. tabs/analysis/widgets/energy_widget.py +32 -0
  26. tabs/analysis/widgets/geometry_widget.py +55 -0
  27. tabs/analysis/widgets/planets_widget.py +34 -0
  28. tabs/analysis/widgets/propulsion_widget.py +53 -0
  29. tabs/analysis/widgets/stability_widget.py +34 -0
  30. tabs/analysis/widgets/weights_widget.py +94 -0
  31. tabs/geometry/__init__.py +6 -0
  32. tabs/geometry/aircraft_configs.py +232 -0
  33. tabs/geometry/frames/__init__.py +15 -0
  34. tabs/geometry/frames/booms/__init__.py +5 -0
  35. tabs/geometry/frames/booms/boom_frame.py +238 -0
  36. tabs/geometry/frames/cargo_bays/__init__.py +5 -0
  37. tabs/geometry/frames/cargo_bays/cargo_bay_frame.py +159 -0
  38. tabs/geometry/frames/default_frame.py +23 -0
  39. tabs/geometry/frames/energy_network/__init__.py +2 -0
  40. tabs/geometry/frames/energy_network/turbofan_network/__init__.py +3 -0
  41. tabs/geometry/frames/energy_network/turbofan_network/frames/__init__.py +1 -0
  42. tabs/geometry/frames/energy_network/turbofan_network/widgets/__init__.py +1 -0
  43. tabs/geometry/frames/fuselages/__init__.py +5 -0
  44. tabs/geometry/frames/fuselages/fuselage_frame.py +294 -0
  45. tabs/geometry/frames/geometry_frame.py +91 -0
  46. tabs/geometry/frames/landing_gears/__init__.py +5 -0
  47. tabs/geometry/frames/landing_gears/landing_gear_frame.py +189 -0
  48. tabs/geometry/frames/nacelles/__init__.py +1 -0
  49. tabs/geometry/frames/powertrain/__init__.py +6 -0
  50. tabs/geometry/frames/powertrain/converters/__init__.py +5 -0
  51. tabs/geometry/frames/powertrain/converters/converter_frame.py +137 -0
  52. tabs/geometry/frames/powertrain/distributors/__init__.py +5 -0
  53. tabs/geometry/frames/powertrain/distributors/distributor_frame.py +143 -0
  54. tabs/geometry/frames/powertrain/nacelles/__init__.py +5 -0
  55. tabs/geometry/frames/powertrain/nacelles/nacelle_frame.py +283 -0
  56. tabs/geometry/frames/powertrain/powertrain_frame.py +259 -0
  57. tabs/geometry/frames/powertrain/propulsors/__init__.py +5 -0
  58. tabs/geometry/frames/powertrain/propulsors/propulsor_frame.py +146 -0
  59. tabs/geometry/frames/powertrain/sources/__init__.py +6 -0
  60. tabs/geometry/frames/powertrain/sources/energy_source_frame.py +147 -0
  61. tabs/geometry/frames/vehicle_frame.py +171 -0
  62. tabs/geometry/frames/wings/__init__.py +5 -0
  63. tabs/geometry/frames/wings/wings_frame.py +457 -0
  64. tabs/geometry/geometry.py +513 -0
  65. tabs/geometry/widgets/__init__.py +12 -0
  66. tabs/geometry/widgets/booms/__init__.py +6 -0
  67. tabs/geometry/widgets/booms/boom_section_widget.py +109 -0
  68. tabs/geometry/widgets/cargo_bays/__init__.py +1 -0
  69. tabs/geometry/widgets/fuselages/__init__.py +8 -0
  70. tabs/geometry/widgets/fuselages/cabin_class_widget.py +188 -0
  71. tabs/geometry/widgets/fuselages/cabin_widget.py +217 -0
  72. tabs/geometry/widgets/fuselages/fuselage_section_widget.py +190 -0
  73. tabs/geometry/widgets/geometry_data_widget.py +25 -0
  74. tabs/geometry/widgets/landing_gears/__init__.py +6 -0
  75. tabs/geometry/widgets/nacelles/__init__.py +1 -0
  76. tabs/geometry/widgets/powertrain/__init__.py +9 -0
  77. tabs/geometry/widgets/powertrain/converters/__init__.py +5 -0
  78. tabs/geometry/widgets/powertrain/converters/turboelectric_generator_widget.py +74 -0
  79. tabs/geometry/widgets/powertrain/distributors/__init__.py +5 -0
  80. tabs/geometry/widgets/powertrain/distributors/fuel_line_widget.py +81 -0
  81. tabs/geometry/widgets/powertrain/modulators/__init__.py +5 -0
  82. tabs/geometry/widgets/powertrain/modulators/esc_widget.py +58 -0
  83. tabs/geometry/widgets/powertrain/nacelles/__init__.py +5 -0
  84. tabs/geometry/widgets/powertrain/nacelles/nacelle_section_widget.py +115 -0
  85. tabs/geometry/widgets/powertrain/powertrain_connector_widget.py +136 -0
  86. tabs/geometry/widgets/powertrain/powertrain_widget.py +206 -0
  87. tabs/geometry/widgets/powertrain/propulsors/__init__.py +5 -0
  88. tabs/geometry/widgets/powertrain/propulsors/turbofan_widget.py +462 -0
  89. tabs/geometry/widgets/powertrain/sources/__init__.py +6 -0
  90. tabs/geometry/widgets/powertrain/sources/fuel_tank_widget.py +103 -0
  91. tabs/geometry/widgets/powertrain/sources/source_selector_widget.py +35 -0
  92. tabs/geometry/widgets/wings/__init__.py +7 -0
  93. tabs/geometry/widgets/wings/wing_cs_widget.py +198 -0
  94. tabs/geometry/widgets/wings/wing_section_widget.py +298 -0
  95. tabs/home/__init__.py +3 -0
  96. tabs/home/home.py +585 -0
  97. tabs/mission/__init__.py +4 -0
  98. tabs/mission/mission.py +1124 -0
  99. tabs/mission/widgets/__init__.py +3 -0
  100. tabs/mission/widgets/flight_controls_widget.py +186 -0
  101. tabs/mission/widgets/mission_analysis_widget.py +166 -0
  102. tabs/mission/widgets/mission_segment_helper.py +358 -0
  103. tabs/mission/widgets/mission_segment_widget.py +358 -0
  104. tabs/solve/__init__.py +4 -0
  105. tabs/solve/plots/__init__.py +12 -0
  106. tabs/solve/plots/aeroacoustics/__init__.py +6 -0
  107. tabs/solve/plots/aeroacoustics/plot_2D_noise_contour.py +184 -0
  108. tabs/solve/plots/aeroacoustics/plot_3D_noise_contour.py +219 -0
  109. tabs/solve/plots/aeroacoustics/plot_noise_certification_contour.py +115 -0
  110. tabs/solve/plots/aeroacoustics/plot_noise_level.py +118 -0
  111. tabs/solve/plots/aerodynamics/__init__.py +10 -0
  112. tabs/solve/plots/aerodynamics/plot_aerodynamic_coefficients.py +156 -0
  113. tabs/solve/plots/aerodynamics/plot_aerodynamic_forces.py +155 -0
  114. tabs/solve/plots/aerodynamics/plot_aircraft_aerodynamics.py +136 -0
  115. tabs/solve/plots/aerodynamics/plot_drag_components.py +157 -0
  116. tabs/solve/plots/aerodynamics/plot_lift_distribution.py +107 -0
  117. tabs/solve/plots/aerodynamics/plot_rotor_conditions.py +255 -0
  118. tabs/solve/plots/aerodynamics/plot_rotor_disc_performance.py +144 -0
  119. tabs/solve/plots/aerodynamics/plot_rotor_performance.py +124 -0
  120. tabs/solve/plots/common/__init__.py +4 -0
  121. tabs/solve/plots/common/plot_style.py +71 -0
  122. tabs/solve/plots/common/set_axes.py +55 -0
  123. tabs/solve/plots/create_plot_widgets.py +34 -0
  124. tabs/solve/plots/emissions/__init__.py +3 -0
  125. tabs/solve/plots/emissions/plot_emissions.py +167 -0
  126. tabs/solve/plots/energy/__init__.py +12 -0
  127. tabs/solve/plots/energy/plot_altitude_sfc_weight.py +134 -0
  128. tabs/solve/plots/energy/plot_battery_cell_conditions.py +154 -0
  129. tabs/solve/plots/energy/plot_battery_degradation.py +157 -0
  130. tabs/solve/plots/energy/plot_battery_module_C_rates.py +139 -0
  131. tabs/solve/plots/energy/plot_battery_module_conditions.py +157 -0
  132. tabs/solve/plots/energy/plot_battery_pack_conditions.py +164 -0
  133. tabs/solve/plots/energy/plot_battery_ragone_diagram.py +97 -0
  134. tabs/solve/plots/energy/plot_battery_temperature.py +136 -0
  135. tabs/solve/plots/energy/plot_electric_propulsor_efficiencies.py +136 -0
  136. tabs/solve/plots/energy/plot_propulsor_throttles.py +119 -0
  137. tabs/solve/plots/mission/__init__.py +5 -0
  138. tabs/solve/plots/mission/plot_aircraft_velocities.py +145 -0
  139. tabs/solve/plots/mission/plot_flight_conditions.py +236 -0
  140. tabs/solve/plots/mission/plot_flight_trajectory.py +172 -0
  141. tabs/solve/plots/stability/__init__.py +5 -0
  142. tabs/solve/plots/stability/plot_flight_forces_and_moments.py +163 -0
  143. tabs/solve/plots/stability/plot_lateral_stability.py +151 -0
  144. tabs/solve/plots/stability/plot_longitudinal_stability.py +173 -0
  145. tabs/solve/plots/thermal_management/__init__.py +7 -0
  146. tabs/solve/plots/thermal_management/plot_air_cooled_conditions.py +152 -0
  147. tabs/solve/plots/thermal_management/plot_cross_flow_heat_exchanger_conditions.py +185 -0
  148. tabs/solve/plots/thermal_management/plot_reservoir_conditions.py +141 -0
  149. tabs/solve/plots/thermal_management/plot_thermal_management_performance.py +105 -0
  150. tabs/solve/plots/thermal_management/plot_wavy_channel_conditions.py +161 -0
  151. tabs/solve/plots/weights/__init__.py +4 -0
  152. tabs/solve/plots/weights/plot_load_diagram.py +163 -0
  153. tabs/solve/plots/weights/plot_weight_breakdown.py +164 -0
  154. tabs/solve/solve.py +1498 -0
  155. tabs/style_sheet.py +114 -0
  156. tabs/tab_widget.py +14 -0
  157. tabs/visualize_geometry/__init__.py +4 -0
  158. tabs/visualize_geometry/core_3d_viewer.py +253 -0
  159. tabs/visualize_geometry/features/__init__.py +10 -0
  160. tabs/visualize_geometry/features/axes_gizmo.py +173 -0
  161. tabs/visualize_geometry/features/background.py +161 -0
  162. tabs/visualize_geometry/features/blueprint.py +685 -0
  163. tabs/visualize_geometry/features/camera.py +364 -0
  164. tabs/visualize_geometry/features/drag_aircraft.py +219 -0
  165. tabs/visualize_geometry/features/grid.py +194 -0
  166. tabs/visualize_geometry/features/measurement.py +367 -0
  167. tabs/visualize_geometry/features/screenshot.py +91 -0
  168. tabs/visualize_geometry/geometry_helper_functions.py +3 -0
  169. tabs/visualize_geometry/visualize_geometry.py +731 -0
  170. 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,4 @@
1
+ # RCAIDE_GUI/tabs/solve/plots/weights/__init__.py
2
+
3
+ from .plot_weight_breakdown import plot_weight_breakdown
4
+ from .plot_load_diagram import plot_load_diagram
@@ -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