From e5c400baff2aeff198cf4bc5a64062b7c58b4867 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 14 Jan 2025 13:36:28 -0600 Subject: [PATCH 001/147] Add files via upload --- .../examples/additional_flight_phases.ipynb | 157 ++++++++++++++++-- ...oupled_aircraft_mission_optimization.ipynb | 47 ++++-- .../docs/examples/more_advanced_example.ipynb | 8 +- .../examples/simple_mission_example.ipynb | 8 +- 4 files changed, 186 insertions(+), 34 deletions(-) diff --git a/aviary/docs/examples/additional_flight_phases.ipynb b/aviary/docs/examples/additional_flight_phases.ipynb index 2c026f3d0..aa882eb6e 100644 --- a/aviary/docs/examples/additional_flight_phases.ipynb +++ b/aviary/docs/examples/additional_flight_phases.ipynb @@ -2,13 +2,25 @@ "cells": [ { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": { "tags": [ "remove-cell" ] }, - "outputs": [], + "outputs": [ + { + "ename": "ModuleNotFoundError", + "evalue": "No module named 'aviary.utils.doctape'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[1], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Testing Cell\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdoctape\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m glue_variable\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01minterface\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mcmd_entry_points\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m _command_map\n\u001b[1;32m 5\u001b[0m draw_mission \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdraw_mission\u001b[39m\u001b[38;5;124m'\u001b[39m\n", + "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'aviary.utils.doctape'" + ] + } + ], "source": [ "# Testing Cell\n", "from aviary.utils.doctape import glue_variable\n", @@ -43,7 +55,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -71,7 +83,7 @@ " \"initial_bounds\": ((0.0, 0.0), \"min\"),\n", " \"duration_bounds\": ((25.5, 76.5), \"min\"),\n", " },\n", - " \"initial_guesses\": {\"time\": ([0, 51], \"min\")},\n", + " \"initial_guesses\": {\"times\": ([0, 51], \"min\")},\n", " },\n", " \"cruise_1\": {\n", " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", @@ -95,7 +107,7 @@ " \"initial_bounds\": ((25.5, 76.5), \"min\"),\n", " \"duration_bounds\": ((23.5, 70.5), \"min\"),\n", " },\n", - " \"initial_guesses\": {\"time\": ([51, 47], \"min\")},\n", + " \"initial_guesses\": {\"times\": ([51, 47], \"min\")},\n", " },\n", " \"climb_2\": {\n", " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", @@ -119,7 +131,7 @@ " \"initial_bounds\": ((49.0, 147.0), \"min\"),\n", " \"duration_bounds\": ((5.0, 15.0), \"min\"),\n", " },\n", - " \"initial_guesses\": {\"time\": ([98, 10], \"min\")},\n", + " \"initial_guesses\": {\"times\": ([98, 10], \"min\")},\n", " },\n", " \"cruise_2\": {\n", " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", @@ -143,7 +155,7 @@ " \"initial_bounds\": ((54.0, 162.0), \"min\"),\n", " \"duration_bounds\": ((24.0, 72.0), \"min\"),\n", " },\n", - " \"initial_guesses\": {\"time\": ([108, 48], \"min\")},\n", + " \"initial_guesses\": {\"times\": ([108, 48], \"min\")},\n", " },\n", " \"climb_3\": {\n", " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", @@ -167,7 +179,7 @@ " \"initial_bounds\": ((78.0, 234.0), \"min\"),\n", " \"duration_bounds\": ((7.0, 21.0), \"min\"),\n", " },\n", - " \"initial_guesses\": {\"time\": ([156, 14], \"min\")},\n", + " \"initial_guesses\": {\"times\": ([156, 14], \"min\")},\n", " },\n", " \"climb_4\": {\n", " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", @@ -191,7 +203,7 @@ " \"initial_bounds\": ((85.0, 255.0), \"min\"),\n", " \"duration_bounds\": ((43.0, 129.0), \"min\"),\n", " },\n", - " \"initial_guesses\": {\"time\": ([170, 86], \"min\")},\n", + " \"initial_guesses\": {\"times\": ([170, 86], \"min\")},\n", " },\n", " \"descent_1\": {\n", " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", @@ -215,7 +227,7 @@ " \"initial_bounds\": ((128.0, 384.0), \"min\"),\n", " \"duration_bounds\": ((41.0, 123.0), \"min\"),\n", " },\n", - " \"initial_guesses\": {\"time\": ([256, 82], \"min\")},\n", + " \"initial_guesses\": {\"times\": ([256, 82], \"min\")},\n", " },\n", " \"post_mission\": {\n", " \"include_landing\": False,\n", @@ -227,13 +239,25 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": { "tags": [ "remove-cell" ] }, - "outputs": [], + "outputs": [ + { + "ename": "ModuleNotFoundError", + "evalue": "No module named 'aviary.utils.doctape'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[3], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Testing Cell\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdoctape\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m glue_keys\n\u001b[1;32m 3\u001b[0m glue_keys(phase_info, display\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m)\n", + "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'aviary.utils.doctape'" + ] + } + ], "source": [ "# Testing Cell\n", "from aviary.utils.doctape import glue_keys\n", @@ -251,9 +275,110 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/sazoppelt/opt/anaconda3/lib/python3.8/site-packages/aviary/subsystems/propulsion/engine_model.py:131: UserWarning: The value of aircraft:engine:wing_locations passed to EngineModel is type . Only the first entry in this iterable will be used.\n", + " warnings.warn(\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "The following variables have been overridden:\n", + " 'aircraft:design:touchdown_mass\n", + " 'aircraft:engine:mass\n", + " 'aircraft:fins:mass\n", + " 'aircraft:fuel:auxiliary_fuel_capacity\n", + " 'aircraft:fuel:fuselage_fuel_capacity\n", + " 'aircraft:fuel:total_capacity\n", + " 'aircraft:fuselage:planform_area\n", + " 'aircraft:fuselage:wetted_area\n", + " 'aircraft:horizontal_tail:wetted_area\n", + " 'aircraft:landing_gear:main_gear_oleo_length\n", + " 'aircraft:landing_gear:nose_gear_oleo_length\n", + " 'aircraft:vertical_tail:wetted_area\n", + " 'aircraft:wing:aspect_ratio\n", + " 'aircraft:wing:control_surface_area\n", + " 'aircraft:wing:wetted_area\n", + "\n", + "--- Constraint Report [traj] ---\n", + " --- climb_1 ---\n", + " [path] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " --- cruise_1 ---\n", + " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " --- climb_2 ---\n", + " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " --- cruise_2 ---\n", + " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " --- climb_3 ---\n", + " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " --- climb_4 ---\n", + " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " --- descent_1 ---\n", + " [path] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/sazoppelt/opt/anaconda3/lib/python3.8/site-packages/openmdao/recorders/sqlite_recorder.py:227: UserWarning:The existing case recorder file, dymos_solution.db, is being overwritten.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Model viewer data has already been recorded for Driver.\n", + "Full total jacobian was computed 3 times, taking 1.195775 seconds.\n", + "Total jacobian shape: (163, 135) \n", + "\n", + "\n", + "Jacobian shape: (163, 135) (7.26% nonzero)\n", + "FWD solves: 15 REV solves: 0\n", + "Total colors vs. total size: 15 vs 135 (88.89% improvement)\n", + "\n", + "Sparsity computed using tolerance: 1e-25\n", + "Time to compute sparsity: 1.1958 sec\n", + "Time to compute coloring: 0.1298 sec\n", + "Memory to compute coloring: -0.2969 MB\n", + "Coloring created on: 2025-01-14 13:44:26\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/sazoppelt/opt/anaconda3/lib/python3.8/site-packages/openmdao/core/total_jac.py:1788: DerivativesWarning:Design variables [('traj.climb_1.t_initial', inds=[0])] have no impact on the constraints or objective.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimization terminated successfully (Exit mode 0)\n", + " Current function value: [2.8050298]\n", + " Iterations: 16\n", + " Function evaluations: 16\n", + " Gradient evaluations: 16\n", + "Optimization Complete\n", + "-----------------------------------\n" + ] + } + ], "source": [ "import aviary.api as av\n", "\n", @@ -296,7 +421,7 @@ ], "metadata": { "kernelspec": { - "display_name": "base", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -310,7 +435,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.8.19" } }, "nbformat": 4, diff --git a/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb b/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb index 1546e6ae6..cef62ddd4 100644 --- a/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb +++ b/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb @@ -40,7 +40,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ @@ -68,7 +68,7 @@ " \"initial_bounds\": ((0.0, 0.0), \"min\"),\n", " \"duration_bounds\": ((35.0, 105.0), \"min\"),\n", " },\n", - " \"initial_guesses\": {\"time\": ([0, 70], \"min\")},\n", + " \"initial_guesses\": {\"times\": ([0, 70], \"min\")},\n", " },\n", " \"cruise\": {\n", " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", @@ -92,7 +92,7 @@ " \"initial_bounds\": ((35.0, 105.0), \"min\"),\n", " \"duration_bounds\": ((91.5, 274.5), \"min\"),\n", " },\n", - " \"initial_guesses\": {\"time\": ([70, 183], \"min\")},\n", + " \"initial_guesses\": {\"times\": ([70, 183], \"min\")},\n", " },\n", " \"descent_1\": {\n", " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", @@ -116,7 +116,7 @@ " \"initial_bounds\": ((126.5, 379.5), \"min\"),\n", " \"duration_bounds\": ((25.0, 75.0), \"min\"),\n", " },\n", - " \"initial_guesses\": {\"time\": ([253, 50], \"min\")},\n", + " \"initial_guesses\": {\"times\": ([253, 50], \"min\")},\n", " },\n", " \"post_mission\": {\n", " \"include_landing\": False,\n", @@ -128,13 +128,25 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": { "tags": [ "remove-cell" ] }, - "outputs": [], + "outputs": [ + { + "ename": "ModuleNotFoundError", + "evalue": "No module named 'aviary.utils.doctape'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[7], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Testing Cell\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdoctape\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m check_value, glue_variable\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01minterface\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mcheck_phase_info\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m check_phase_info, HEIGHT_ENERGY\n\u001b[1;32m 5\u001b[0m \u001b[38;5;66;03m# checking that the phase info example is valid\u001b[39;00m\n", + "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'aviary.utils.doctape'" + ] + } + ], "source": [ "# Testing Cell\n", "from aviary.utils.doctape import check_value, glue_variable\n", @@ -172,7 +184,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": { "tags": [ "remove-cell" @@ -188,9 +200,24 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "RuntimeError", + "evalue": "pyOptSparseDriver is not available, pyOptsparse is not installed.", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mRuntimeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[9], line 8\u001b[0m\n\u001b[1;32m 5\u001b[0m make_plots \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[1;32m 6\u001b[0m max_iter \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m100\u001b[39m\n\u001b[0;32m----> 8\u001b[0m prob \u001b[38;5;241m=\u001b[39m \u001b[43mav\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_aviary\u001b[49m\u001b[43m(\u001b[49m\u001b[43maircraft_filename\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mphase_info\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43moptimizer\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43moptimizer\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 9\u001b[0m \u001b[43m \u001b[49m\u001b[43mmake_plots\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmake_plots\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmax_iter\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmax_iter\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/opt/anaconda3/lib/python3.8/site-packages/aviary/interface/methods_for_level1.py:81\u001b[0m, in \u001b[0;36mrun_aviary\u001b[0;34m(aircraft_filename, phase_info, optimizer, analysis_scheme, objective_type, record_filename, restart_filename, max_iter, run_driver, make_plots, phase_info_parameterization, optimization_history_filename)\u001b[0m\n\u001b[1;32m 78\u001b[0m \u001b[38;5;66;03m# Link phases and variables\u001b[39;00m\n\u001b[1;32m 79\u001b[0m prob\u001b[38;5;241m.\u001b[39mlink_phases()\n\u001b[0;32m---> 81\u001b[0m \u001b[43mprob\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43madd_driver\u001b[49m\u001b[43m(\u001b[49m\u001b[43moptimizer\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmax_iter\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmax_iter\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 83\u001b[0m prob\u001b[38;5;241m.\u001b[39madd_design_variables()\n\u001b[1;32m 85\u001b[0m \u001b[38;5;66;03m# Load optimization problem formulation\u001b[39;00m\n\u001b[1;32m 86\u001b[0m \u001b[38;5;66;03m# Detail which variables the optimizer can control\u001b[39;00m\n", + "File \u001b[0;32m~/opt/anaconda3/lib/python3.8/site-packages/aviary/interface/methods_for_level2.py:1502\u001b[0m, in \u001b[0;36mAviaryProblem.add_driver\u001b[0;34m(self, optimizer, use_coloring, max_iter, debug_print)\u001b[0m\n\u001b[1;32m 1500\u001b[0m driver \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdriver \u001b[38;5;241m=\u001b[39m om\u001b[38;5;241m.\u001b[39mScipyOptimizeDriver()\n\u001b[1;32m 1501\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m-> 1502\u001b[0m driver \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdriver \u001b[38;5;241m=\u001b[39m \u001b[43mom\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpyOptSparseDriver\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1504\u001b[0m driver\u001b[38;5;241m.\u001b[39moptions[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124moptimizer\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m optimizer\n\u001b[1;32m 1505\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m use_coloring:\n", + "File \u001b[0;32m~/opt/anaconda3/lib/python3.8/site-packages/openmdao/drivers/pyoptsparse_driver.py:193\u001b[0m, in \u001b[0;36mpyOptSparseDriver.__init__\u001b[0;34m(self, **kwargs)\u001b[0m\n\u001b[1;32m 188\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 189\u001b[0m \u001b[38;5;124;03mInitialize pyopt.\u001b[39;00m\n\u001b[1;32m 190\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 191\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m pyoptsparse \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 192\u001b[0m \u001b[38;5;66;03m# pyoptsparse is not installed\u001b[39;00m\n\u001b[0;32m--> 193\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mRuntimeError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mpyOptSparseDriver is not available, pyOptsparse is not installed.\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 195\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(pyoptsparse, \u001b[38;5;167;01mException\u001b[39;00m):\n\u001b[1;32m 196\u001b[0m \u001b[38;5;66;03m# there is some other issue with the pyoptsparse installation\u001b[39;00m\n\u001b[1;32m 197\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m pyoptsparse\n", + "\u001b[0;31mRuntimeError\u001b[0m: pyOptSparseDriver is not available, pyOptsparse is not installed." + ] + } + ], "source": [ "import aviary.api as av\n", "\n", @@ -562,7 +589,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.3" + "version": "3.8.19" } }, "nbformat": 4, diff --git a/aviary/docs/examples/more_advanced_example.ipynb b/aviary/docs/examples/more_advanced_example.ipynb index e1bb5f382..aa92550f2 100644 --- a/aviary/docs/examples/more_advanced_example.ipynb +++ b/aviary/docs/examples/more_advanced_example.ipynb @@ -66,7 +66,7 @@ " \"initial_bounds\": ((0.0, 0.0), \"min\"),\n", " \"duration_bounds\": ((27.0, 81.0), \"min\"),\n", " },\n", - " \"initial_guesses\": {\"time\": ([0, 54], \"min\")},\n", + " \"initial_guesses\": {\"times\": ([0, 54], \"min\")},\n", " },\n", " \"cruise\": {\n", " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", @@ -90,7 +90,7 @@ " \"initial_bounds\": ((27.0, 81.0), \"min\"),\n", " \"duration_bounds\": ((85.5, 256.5), \"min\"),\n", " },\n", - " \"initial_guesses\": {\"time\": ([54, 171], \"min\")},\n", + " \"initial_guesses\": {\"times\": ([54, 171], \"min\")},\n", " },\n", " \"descent_1\": {\n", " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", @@ -114,7 +114,7 @@ " \"initial_bounds\": ((112.5, 337.5), \"min\"),\n", " \"duration_bounds\": ((26.5, 79.5), \"min\"),\n", " },\n", - " \"initial_guesses\": {\"time\": ([225, 53], \"min\")},\n", + " \"initial_guesses\": {\"times\": ([225, 53], \"min\")},\n", " },\n", " \"post_mission\": {\n", " \"include_landing\": False,\n", @@ -454,7 +454,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.8.19" } }, "nbformat": 4, diff --git a/aviary/docs/examples/simple_mission_example.ipynb b/aviary/docs/examples/simple_mission_example.ipynb index e712dd1ed..951197a2a 100644 --- a/aviary/docs/examples/simple_mission_example.ipynb +++ b/aviary/docs/examples/simple_mission_example.ipynb @@ -190,7 +190,7 @@ " \"initial_bounds\": ((0.0, 0.0), \"min\"),\n", " \"duration_bounds\": ((27.0, 81.0), \"min\"),\n", " },\n", - " \"initial_guesses\": {\"time\": ([0, 54], \"min\")},\n", + " \"initial_guesses\": {\"times\": ([0, 54], \"min\")},\n", " },\n", " \"cruise\": {\n", " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", @@ -214,7 +214,7 @@ " \"initial_bounds\": ((27.0, 81.0), \"min\"),\n", " \"duration_bounds\": ((85.5, 256.5), \"min\"),\n", " },\n", - " \"initial_guesses\": {\"time\": ([54, 171], \"min\")},\n", + " \"initial_guesses\": {\"times\": ([54, 171], \"min\")},\n", " },\n", " \"descent_1\": {\n", " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", @@ -238,7 +238,7 @@ " \"initial_bounds\": ((112.5, 337.5), \"min\"),\n", " \"duration_bounds\": ((26.5, 79.5), \"min\"),\n", " },\n", - " \"initial_guesses\": {\"time\": ([225, 53], \"min\")},\n", + " \"initial_guesses\": {\"times\": ([225, 53], \"min\")},\n", " },\n", " \"post_mission\": {\n", " \"include_landing\": False,\n", @@ -414,7 +414,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.8.19" } }, "nbformat": 4, From 6874eb876399293742cb0349c1cae2047681507d Mon Sep 17 00:00:00 2001 From: jkirk5 Date: Thu, 16 Jan 2025 16:43:53 -0500 Subject: [PATCH 002/147] removed jupyter output cells --- .../examples/additional_flight_phases.ipynb | 137 +----------------- ...oupled_aircraft_mission_optimization.ipynb | 39 +---- 2 files changed, 12 insertions(+), 164 deletions(-) diff --git a/aviary/docs/examples/additional_flight_phases.ipynb b/aviary/docs/examples/additional_flight_phases.ipynb index aa882eb6e..b2a2b8fa2 100644 --- a/aviary/docs/examples/additional_flight_phases.ipynb +++ b/aviary/docs/examples/additional_flight_phases.ipynb @@ -2,25 +2,13 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": { "tags": [ "remove-cell" ] }, - "outputs": [ - { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'aviary.utils.doctape'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[1], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Testing Cell\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdoctape\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m glue_variable\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01minterface\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mcmd_entry_points\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m _command_map\n\u001b[1;32m 5\u001b[0m draw_mission \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdraw_mission\u001b[39m\u001b[38;5;124m'\u001b[39m\n", - "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'aviary.utils.doctape'" - ] - } - ], + "outputs": [], "source": [ "# Testing Cell\n", "from aviary.utils.doctape import glue_variable\n", @@ -239,25 +227,13 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": { "tags": [ "remove-cell" ] }, - "outputs": [ - { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'aviary.utils.doctape'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[3], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Testing Cell\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdoctape\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m glue_keys\n\u001b[1;32m 3\u001b[0m glue_keys(phase_info, display\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m)\n", - "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'aviary.utils.doctape'" - ] - } - ], + "outputs": [], "source": [ "# Testing Cell\n", "from aviary.utils.doctape import glue_keys\n", @@ -275,110 +251,9 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/sazoppelt/opt/anaconda3/lib/python3.8/site-packages/aviary/subsystems/propulsion/engine_model.py:131: UserWarning: The value of aircraft:engine:wing_locations passed to EngineModel is type . Only the first entry in this iterable will be used.\n", - " warnings.warn(\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "The following variables have been overridden:\n", - " 'aircraft:design:touchdown_mass\n", - " 'aircraft:engine:mass\n", - " 'aircraft:fins:mass\n", - " 'aircraft:fuel:auxiliary_fuel_capacity\n", - " 'aircraft:fuel:fuselage_fuel_capacity\n", - " 'aircraft:fuel:total_capacity\n", - " 'aircraft:fuselage:planform_area\n", - " 'aircraft:fuselage:wetted_area\n", - " 'aircraft:horizontal_tail:wetted_area\n", - " 'aircraft:landing_gear:main_gear_oleo_length\n", - " 'aircraft:landing_gear:nose_gear_oleo_length\n", - " 'aircraft:vertical_tail:wetted_area\n", - " 'aircraft:wing:aspect_ratio\n", - " 'aircraft:wing:control_surface_area\n", - " 'aircraft:wing:wetted_area\n", - "\n", - "--- Constraint Report [traj] ---\n", - " --- climb_1 ---\n", - " [path] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- cruise_1 ---\n", - " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- climb_2 ---\n", - " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- cruise_2 ---\n", - " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- climb_3 ---\n", - " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- climb_4 ---\n", - " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- descent_1 ---\n", - " [path] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/sazoppelt/opt/anaconda3/lib/python3.8/site-packages/openmdao/recorders/sqlite_recorder.py:227: UserWarning:The existing case recorder file, dymos_solution.db, is being overwritten.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Model viewer data has already been recorded for Driver.\n", - "Full total jacobian was computed 3 times, taking 1.195775 seconds.\n", - "Total jacobian shape: (163, 135) \n", - "\n", - "\n", - "Jacobian shape: (163, 135) (7.26% nonzero)\n", - "FWD solves: 15 REV solves: 0\n", - "Total colors vs. total size: 15 vs 135 (88.89% improvement)\n", - "\n", - "Sparsity computed using tolerance: 1e-25\n", - "Time to compute sparsity: 1.1958 sec\n", - "Time to compute coloring: 0.1298 sec\n", - "Memory to compute coloring: -0.2969 MB\n", - "Coloring created on: 2025-01-14 13:44:26\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/sazoppelt/opt/anaconda3/lib/python3.8/site-packages/openmdao/core/total_jac.py:1788: DerivativesWarning:Design variables [('traj.climb_1.t_initial', inds=[0])] have no impact on the constraints or objective.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimization terminated successfully (Exit mode 0)\n", - " Current function value: [2.8050298]\n", - " Iterations: 16\n", - " Function evaluations: 16\n", - " Gradient evaluations: 16\n", - "Optimization Complete\n", - "-----------------------------------\n" - ] - } - ], + "outputs": [], "source": [ "import aviary.api as av\n", "\n", diff --git a/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb b/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb index cef62ddd4..5ea490af9 100644 --- a/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb +++ b/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb @@ -128,25 +128,13 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": { "tags": [ "remove-cell" ] }, - "outputs": [ - { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'aviary.utils.doctape'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[7], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Testing Cell\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdoctape\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m check_value, glue_variable\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01minterface\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mcheck_phase_info\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m check_phase_info, HEIGHT_ENERGY\n\u001b[1;32m 5\u001b[0m \u001b[38;5;66;03m# checking that the phase info example is valid\u001b[39;00m\n", - "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'aviary.utils.doctape'" - ] - } - ], + "outputs": [], "source": [ "# Testing Cell\n", "from aviary.utils.doctape import check_value, glue_variable\n", @@ -200,24 +188,9 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "ename": "RuntimeError", - "evalue": "pyOptSparseDriver is not available, pyOptsparse is not installed.", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mRuntimeError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[9], line 8\u001b[0m\n\u001b[1;32m 5\u001b[0m make_plots \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[1;32m 6\u001b[0m max_iter \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m100\u001b[39m\n\u001b[0;32m----> 8\u001b[0m prob \u001b[38;5;241m=\u001b[39m \u001b[43mav\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_aviary\u001b[49m\u001b[43m(\u001b[49m\u001b[43maircraft_filename\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mphase_info\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43moptimizer\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43moptimizer\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 9\u001b[0m \u001b[43m \u001b[49m\u001b[43mmake_plots\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmake_plots\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmax_iter\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmax_iter\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m~/opt/anaconda3/lib/python3.8/site-packages/aviary/interface/methods_for_level1.py:81\u001b[0m, in \u001b[0;36mrun_aviary\u001b[0;34m(aircraft_filename, phase_info, optimizer, analysis_scheme, objective_type, record_filename, restart_filename, max_iter, run_driver, make_plots, phase_info_parameterization, optimization_history_filename)\u001b[0m\n\u001b[1;32m 78\u001b[0m \u001b[38;5;66;03m# Link phases and variables\u001b[39;00m\n\u001b[1;32m 79\u001b[0m prob\u001b[38;5;241m.\u001b[39mlink_phases()\n\u001b[0;32m---> 81\u001b[0m \u001b[43mprob\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43madd_driver\u001b[49m\u001b[43m(\u001b[49m\u001b[43moptimizer\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmax_iter\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmax_iter\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 83\u001b[0m prob\u001b[38;5;241m.\u001b[39madd_design_variables()\n\u001b[1;32m 85\u001b[0m \u001b[38;5;66;03m# Load optimization problem formulation\u001b[39;00m\n\u001b[1;32m 86\u001b[0m \u001b[38;5;66;03m# Detail which variables the optimizer can control\u001b[39;00m\n", - "File \u001b[0;32m~/opt/anaconda3/lib/python3.8/site-packages/aviary/interface/methods_for_level2.py:1502\u001b[0m, in \u001b[0;36mAviaryProblem.add_driver\u001b[0;34m(self, optimizer, use_coloring, max_iter, debug_print)\u001b[0m\n\u001b[1;32m 1500\u001b[0m driver \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdriver \u001b[38;5;241m=\u001b[39m om\u001b[38;5;241m.\u001b[39mScipyOptimizeDriver()\n\u001b[1;32m 1501\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m-> 1502\u001b[0m driver \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdriver \u001b[38;5;241m=\u001b[39m \u001b[43mom\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpyOptSparseDriver\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1504\u001b[0m driver\u001b[38;5;241m.\u001b[39moptions[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124moptimizer\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m optimizer\n\u001b[1;32m 1505\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m use_coloring:\n", - "File \u001b[0;32m~/opt/anaconda3/lib/python3.8/site-packages/openmdao/drivers/pyoptsparse_driver.py:193\u001b[0m, in \u001b[0;36mpyOptSparseDriver.__init__\u001b[0;34m(self, **kwargs)\u001b[0m\n\u001b[1;32m 188\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 189\u001b[0m \u001b[38;5;124;03mInitialize pyopt.\u001b[39;00m\n\u001b[1;32m 190\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 191\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m pyoptsparse \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 192\u001b[0m \u001b[38;5;66;03m# pyoptsparse is not installed\u001b[39;00m\n\u001b[0;32m--> 193\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mRuntimeError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mpyOptSparseDriver is not available, pyOptsparse is not installed.\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 195\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(pyoptsparse, \u001b[38;5;167;01mException\u001b[39;00m):\n\u001b[1;32m 196\u001b[0m \u001b[38;5;66;03m# there is some other issue with the pyoptsparse installation\u001b[39;00m\n\u001b[1;32m 197\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m pyoptsparse\n", - "\u001b[0;31mRuntimeError\u001b[0m: pyOptSparseDriver is not available, pyOptsparse is not installed." - ] - } - ], + "outputs": [], "source": [ "import aviary.api as av\n", "\n", @@ -575,7 +548,7 @@ "metadata": { "celltoolbar": "Tags", "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "aviary", "language": "python", "name": "python3" }, @@ -589,7 +562,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.19" + "version": "3.12.3" } }, "nbformat": 4, From 28386bd0dd3165a7acd79ec0fbb318403d533810 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 21 Jan 2025 15:29:58 -0500 Subject: [PATCH 003/147] Add files via upload From ed26f0c6b7f0968c98162d0d55b8ca5c82ec8f1e Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 21 Jan 2025 15:32:23 -0500 Subject: [PATCH 004/147] Add files via upload From a8cb4a435db565fb2b00371aae0b3632a70b1cb4 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 21 Jan 2025 15:37:49 -0500 Subject: [PATCH 005/147] Add files via upload From 03ee6644fdaae151900cc21800f5ab6aa1d5f575 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 21 Jan 2025 15:55:42 -0500 Subject: [PATCH 006/147] Add files via upload --- additional_flight_phases.ipynb | 443 +++++++++++++++ coupled_aircraft_mission_optimization.ipynb | 597 ++++++++++++++++++++ 2 files changed, 1040 insertions(+) create mode 100644 additional_flight_phases.ipynb create mode 100644 coupled_aircraft_mission_optimization.ipynb diff --git a/additional_flight_phases.ipynb b/additional_flight_phases.ipynb new file mode 100644 index 000000000..aa882eb6e --- /dev/null +++ b/additional_flight_phases.ipynb @@ -0,0 +1,443 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [ + { + "ename": "ModuleNotFoundError", + "evalue": "No module named 'aviary.utils.doctape'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[1], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Testing Cell\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdoctape\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m glue_variable\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01minterface\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mcmd_entry_points\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m _command_map\n\u001b[1;32m 5\u001b[0m draw_mission \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdraw_mission\u001b[39m\u001b[38;5;124m'\u001b[39m\n", + "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'aviary.utils.doctape'" + ] + } + ], + "source": [ + "# Testing Cell\n", + "from aviary.utils.doctape import glue_variable\n", + "from aviary.interface.cmd_entry_points import _command_map\n", + "\n", + "draw_mission = 'draw_mission'\n", + "_command_map[draw_mission];\n", + "glue_variable(draw_mission, 'aviary '+draw_mission, md_code=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Mission Optimization with Many Phases for a Commercial Aircraft\n", + "\n", + "So far within these example docs we have been building up the complexity of our coupled aircraft-mission design problem.\n", + "In [the simple mission example](simple_mission_example), we flew the aircraft in straight line phases.\n", + "In [the more advanced mission example](more_advanced_example), we allowed the optimizer to find the optimal Mach profiles for phases.\n", + "\n", + "In this example, we will build on the prior examples by adding more phases to the mission.\n", + "This will allow us to model more complex missions, such as a commercial aircraft flying a long-haul route with multiple cruise segments, intermediary climb segments, and a cruise-climb segment.\n", + "\n", + "## Problem Formulation\n", + "\n", + "We use the {glue:md}`draw_mission` GUI as shown below:\n", + "\n", + "![multiple_phases_gui](images/multiple_phases_gui.png)\n", + "\n", + "This results in the following `phase_info` dictionary:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "phase_info = {\n", + " \"pre_mission\": {\"include_takeoff\": False, \"optimize_mass\": True},\n", + " \"climb_1\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 3,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.2, \"unitless\"),\n", + " \"final_mach\": (0.72, \"unitless\"),\n", + " \"mach_bounds\": ((0.18, 0.74), \"unitless\"),\n", + " \"initial_altitude\": (0.0, \"ft\"),\n", + " \"final_altitude\": (31000.0, \"ft\"),\n", + " \"altitude_bounds\": ((0.0, 31500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"path_constraint\",\n", + " \"fix_initial\": True,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((0.0, 0.0), \"min\"),\n", + " \"duration_bounds\": ((25.5, 76.5), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([0, 51], \"min\")},\n", + " },\n", + " \"cruise_1\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 3,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.72, \"unitless\"),\n", + " \"final_mach\": (0.72, \"unitless\"),\n", + " \"mach_bounds\": ((0.7, 0.74), \"unitless\"),\n", + " \"initial_altitude\": (31000.0, \"ft\"),\n", + " \"final_altitude\": (31000.0, \"ft\"),\n", + " \"altitude_bounds\": ((30500.0, 31500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"boundary_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((25.5, 76.5), \"min\"),\n", + " \"duration_bounds\": ((23.5, 70.5), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([51, 47], \"min\")},\n", + " },\n", + " \"climb_2\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 3,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.72, \"unitless\"),\n", + " \"final_mach\": (0.74, \"unitless\"),\n", + " \"mach_bounds\": ((0.7, 0.76), \"unitless\"),\n", + " \"initial_altitude\": (31000.0, \"ft\"),\n", + " \"final_altitude\": (33000.0, \"ft\"),\n", + " \"altitude_bounds\": ((30500.0, 33500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"boundary_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((49.0, 147.0), \"min\"),\n", + " \"duration_bounds\": ((5.0, 15.0), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([98, 10], \"min\")},\n", + " },\n", + " \"cruise_2\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 3,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.74, \"unitless\"),\n", + " \"final_mach\": (0.74, \"unitless\"),\n", + " \"mach_bounds\": ((0.72, 0.76), \"unitless\"),\n", + " \"initial_altitude\": (33000.0, \"ft\"),\n", + " \"final_altitude\": (33000.0, \"ft\"),\n", + " \"altitude_bounds\": ((32500.0, 33500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"boundary_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((54.0, 162.0), \"min\"),\n", + " \"duration_bounds\": ((24.0, 72.0), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([108, 48], \"min\")},\n", + " },\n", + " \"climb_3\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 3,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.74, \"unitless\"),\n", + " \"final_mach\": (0.76, \"unitless\"),\n", + " \"mach_bounds\": ((0.72, 0.78), \"unitless\"),\n", + " \"initial_altitude\": (33000.0, \"ft\"),\n", + " \"final_altitude\": (34500.0, \"ft\"),\n", + " \"altitude_bounds\": ((32500.0, 35000.0), \"ft\"),\n", + " \"throttle_enforcement\": \"boundary_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((78.0, 234.0), \"min\"),\n", + " \"duration_bounds\": ((7.0, 21.0), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([156, 14], \"min\")},\n", + " },\n", + " \"climb_4\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 3,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.76, \"unitless\"),\n", + " \"final_mach\": (0.76, \"unitless\"),\n", + " \"mach_bounds\": ((0.74, 0.78), \"unitless\"),\n", + " \"initial_altitude\": (34500.0, \"ft\"),\n", + " \"final_altitude\": (36000.0, \"ft\"),\n", + " \"altitude_bounds\": ((34000.0, 36500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"boundary_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((85.0, 255.0), \"min\"),\n", + " \"duration_bounds\": ((43.0, 129.0), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([170, 86], \"min\")},\n", + " },\n", + " \"descent_1\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 3,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.76, \"unitless\"),\n", + " \"final_mach\": (0.2, \"unitless\"),\n", + " \"mach_bounds\": ((0.18, 0.78), \"unitless\"),\n", + " \"initial_altitude\": (36000.0, \"ft\"),\n", + " \"final_altitude\": (500.0, \"ft\"),\n", + " \"altitude_bounds\": ((0.0, 36500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"path_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": True,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((128.0, 384.0), \"min\"),\n", + " \"duration_bounds\": ((41.0, 123.0), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([256, 82], \"min\")},\n", + " },\n", + " \"post_mission\": {\n", + " \"include_landing\": False,\n", + " \"constrain_range\": True,\n", + " \"target_range\": (2393, \"nmi\"),\n", + " },\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [ + { + "ename": "ModuleNotFoundError", + "evalue": "No module named 'aviary.utils.doctape'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[3], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Testing Cell\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdoctape\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m glue_keys\n\u001b[1;32m 3\u001b[0m glue_keys(phase_info, display\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m)\n", + "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'aviary.utils.doctape'" + ] + } + ], + "source": [ + "# Testing Cell\n", + "from aviary.utils.doctape import glue_keys\n", + "glue_keys(phase_info, display=False)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Running Aviary with Updated Parameters\n", + "\n", + "Let's now run Aviary with this multiphase mission and view the results." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/sazoppelt/opt/anaconda3/lib/python3.8/site-packages/aviary/subsystems/propulsion/engine_model.py:131: UserWarning: The value of aircraft:engine:wing_locations passed to EngineModel is type . Only the first entry in this iterable will be used.\n", + " warnings.warn(\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "The following variables have been overridden:\n", + " 'aircraft:design:touchdown_mass\n", + " 'aircraft:engine:mass\n", + " 'aircraft:fins:mass\n", + " 'aircraft:fuel:auxiliary_fuel_capacity\n", + " 'aircraft:fuel:fuselage_fuel_capacity\n", + " 'aircraft:fuel:total_capacity\n", + " 'aircraft:fuselage:planform_area\n", + " 'aircraft:fuselage:wetted_area\n", + " 'aircraft:horizontal_tail:wetted_area\n", + " 'aircraft:landing_gear:main_gear_oleo_length\n", + " 'aircraft:landing_gear:nose_gear_oleo_length\n", + " 'aircraft:vertical_tail:wetted_area\n", + " 'aircraft:wing:aspect_ratio\n", + " 'aircraft:wing:control_surface_area\n", + " 'aircraft:wing:wetted_area\n", + "\n", + "--- Constraint Report [traj] ---\n", + " --- climb_1 ---\n", + " [path] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " --- cruise_1 ---\n", + " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " --- climb_2 ---\n", + " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " --- cruise_2 ---\n", + " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " --- climb_3 ---\n", + " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " --- climb_4 ---\n", + " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " --- descent_1 ---\n", + " [path] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/sazoppelt/opt/anaconda3/lib/python3.8/site-packages/openmdao/recorders/sqlite_recorder.py:227: UserWarning:The existing case recorder file, dymos_solution.db, is being overwritten.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Model viewer data has already been recorded for Driver.\n", + "Full total jacobian was computed 3 times, taking 1.195775 seconds.\n", + "Total jacobian shape: (163, 135) \n", + "\n", + "\n", + "Jacobian shape: (163, 135) (7.26% nonzero)\n", + "FWD solves: 15 REV solves: 0\n", + "Total colors vs. total size: 15 vs 135 (88.89% improvement)\n", + "\n", + "Sparsity computed using tolerance: 1e-25\n", + "Time to compute sparsity: 1.1958 sec\n", + "Time to compute coloring: 0.1298 sec\n", + "Memory to compute coloring: -0.2969 MB\n", + "Coloring created on: 2025-01-14 13:44:26\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/sazoppelt/opt/anaconda3/lib/python3.8/site-packages/openmdao/core/total_jac.py:1788: DerivativesWarning:Design variables [('traj.climb_1.t_initial', inds=[0])] have no impact on the constraints or objective.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimization terminated successfully (Exit mode 0)\n", + " Current function value: [2.8050298]\n", + " Iterations: 16\n", + " Function evaluations: 16\n", + " Gradient evaluations: 16\n", + "Optimization Complete\n", + "-----------------------------------\n" + ] + } + ], + "source": [ + "import aviary.api as av\n", + "\n", + "prob = av.run_aviary('models/test_aircraft/aircraft_for_bench_FwFm.csv',\n", + " phase_info, optimizer=\"SLSQP\", make_plots=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that we've run Aviary, we can look at the results.\n", + "Open up the automatically generated `traj_results_report.html` and scroll through it to visualize the results.\n", + "\n", + "Here are the altitude and Mach profiles:\n", + "\n", + "![Altitude and Mach Profiles](images/multiphase_flight_profile.png)\n", + "\n", + "\n", + "```{note}\n", + "Remember, we did not allow the optimizer to control either the Mach _or_ the altitude profiles. The optimizer varied the phase durations until the optimal mission profile was found.\n", + "```\n", + "\n", + "## What Next?\n", + "\n", + "The point of this doc page is to show that missions can be arbitrarily complex in terms of the number of phases and how they're classified.\n", + "If you want multiple climb, cruise, descent phases, that's absolutely something Aviary can handle.\n", + "\n", + "There are a lot of options for how you could modify this example.\n", + "You could:\n", + "\n", + "- enable the {glue:md}`optimize_mach` or {glue:md}`optimize_altitude` flags\n", + "- increase the {glue:md}`polynomial_control_order` so there's more flexibility in the optimized mission\n", + "- try different {glue:md}`target_range` values for the full mission range\n", + "- add an external subsystem to the phases\n", + "\n", + "Playing around with a model and seeing how different settings affect the optimization and resulting aircraft design is always an enlightening experience." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.19" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/coupled_aircraft_mission_optimization.ipynb b/coupled_aircraft_mission_optimization.ipynb new file mode 100644 index 000000000..2915da6b4 --- /dev/null +++ b/coupled_aircraft_mission_optimization.ipynb @@ -0,0 +1,597 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Coupled Aircraft-Mission Optimization\n", + "\n", + "One of the most exciting features of Aviary is the ability to formulate and solve coupled aircraft-mission design optimization problems.\n", + "Here, we mean that we are finding the optimal aircraft design parameters while simultaneously finding the optimal mission trajectory.\n", + "The reason why this is so valuable is that it enables exploration of a larger design space much more efficiently.\n", + "\n", + "Solving coupled design-mission problems leads to optimal designs that would not be findable without simultaneously designing the aircraft and the trajectory.\n", + "This is especially useful for unconventional aircraft designs, operations with complex missions, and many more future-focused studies than what is commonly flying today.\n", + "\n", + "This doc page builds up a coupled design problem and explains what we're doing along the way.\n", + "This process is relatively straightforward in Aviary.\n", + "We will briefly discuss the optimal results, but that is not necessarily the focus here.\n", + "Instead, we want to showcase how to do a simple coupled design study in Aviary.\n", + "\n", + "You can use this as a starting point for your own exciting aircraft and mission design studies.\n", + "\n", + "## Problem Definition and Explanation\n", + "\n", + "We will use a conventional single-aisle commercial aircraft design as our starting point.\n", + "For all of these examples we allow the aircraft to be sized by the optimizer.\n", + "This means the gross takeoff weight is controlled to meet a mass balance.\n", + "\n", + "We will perform four different optimization cases as part of this study:\n", + "\n", + "- fixed mission profile, fixed aircraft wing aspect ratio\n", + "- fixed mission profile, optimized aircraft wing aspect ratio\n", + "- optimized mission profile, fixed aircraft wing aspect ratio\n", + "- optimized mission profile, optimized aircraft wing aspect ratio\n", + "\n", + "We'll provide more detail individually for each case.\n", + "\n", + "When we call Aviary, we will use a common `phase_info` object that we modify for each optimization case shown here:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "phase_info = {\n", + " \"pre_mission\": {\"include_takeoff\": False, \"optimize_mass\": True},\n", + " \"climb_1\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 5,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.2, \"unitless\"),\n", + " \"final_mach\": (0.72, \"unitless\"),\n", + " \"mach_bounds\": ((0.18, 0.84), \"unitless\"),\n", + " \"initial_altitude\": (0.0, \"ft\"),\n", + " \"final_altitude\": (32500.0, \"ft\"),\n", + " \"altitude_bounds\": ((0.0, 33000.0), \"ft\"),\n", + " \"throttle_enforcement\": \"path_constraint\",\n", + " \"fix_initial\": True,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((0.0, 0.0), \"min\"),\n", + " \"duration_bounds\": ((35.0, 105.0), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([0, 70], \"min\")},\n", + " },\n", + " \"cruise\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 5,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.72, \"unitless\"),\n", + " \"final_mach\": (0.80, \"unitless\"),\n", + " \"mach_bounds\": ((0.7, 0.84), \"unitless\"),\n", + " \"initial_altitude\": (32500.0, \"ft\"),\n", + " \"final_altitude\": (36000.0, \"ft\"),\n", + " \"altitude_bounds\": ((32000.0, 36500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"boundary_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((35.0, 105.0), \"min\"),\n", + " \"duration_bounds\": ((91.5, 274.5), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([70, 183], \"min\")},\n", + " },\n", + " \"descent_1\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 5,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.72, \"unitless\"),\n", + " \"final_mach\": (0.21, \"unitless\"),\n", + " \"mach_bounds\": ((0.19, 0.84), \"unitless\"),\n", + " \"initial_altitude\": (36000.0, \"ft\"),\n", + " \"final_altitude\": (0.0, \"ft\"),\n", + " \"altitude_bounds\": ((0.0, 36500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"path_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": True,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((126.5, 379.5), \"min\"),\n", + " \"duration_bounds\": ((25.0, 75.0), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([253, 50], \"min\")},\n", + " },\n", + " \"post_mission\": {\n", + " \"include_landing\": False,\n", + " \"constrain_range\": True,\n", + " \"target_range\": (2080, \"nmi\"),\n", + " },\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [ + { + "ename": "ModuleNotFoundError", + "evalue": "No module named 'aviary.utils.doctape'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[7], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Testing Cell\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdoctape\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m check_value, glue_variable\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01minterface\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mcheck_phase_info\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m check_phase_info, HEIGHT_ENERGY\n\u001b[1;32m 5\u001b[0m \u001b[38;5;66;03m# checking that the phase info example is valid\u001b[39;00m\n", + "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'aviary.utils.doctape'" + ] + } + ], + "source": [ + "# Testing Cell\n", + "from aviary.utils.doctape import check_value, glue_variable\n", + "from aviary.interface.utils.check_phase_info import check_phase_info, HEIGHT_ENERGY\n", + "\n", + "# checking that the phase info example is valid\n", + "check_phase_info(phase_info, HEIGHT_ENERGY);\n", + "\n", + "# checking that optimize mach and altitude are False in the example\n", + "for phase, info in phase_info.items():\n", + " if phase not in ('pre_mission','post_mission'):\n", + " opt_mach = info['user_options']['optimize_mach']\n", + " check_value(opt_mach,False)\n", + " opt_alt = info['user_options']['optimize_altitude']\n", + " check_value(opt_alt,False)\n", + "\n", + "# gluing optimize_altitude and optimize_mach\n", + "glue_variable('optimize_altitude','optimize_altitude = False', md_code=True)\n", + "glue_variable('optimize_mach','optimize_mach = False', md_code=True)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, let us explain each case, formulate the Aviary problem, and optimize.\n", + "We'll discuss the results from each case and explain why they vary.\n", + "\n", + "## Fixed Mission Profile, Fixed Aircraft Wing Aspect Ratio\n", + "\n", + "First, let us run Aviary with a simple setup: fly a prescribed mission profile with an unchanged wing design.\n", + "Here we are varying the durations of each of the phases (climb, cruise, and descent) to minimize fuel burn across the mission.\n", + "The altitude and Mach profiles of the mission are fixed because {glue:md}`optimize_altitude` and {glue:md}`optimize_mach` for each of the phases in the `phase_info` object." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "from openmdao.core.problem import _clear_problem_names\n", + "_clear_problem_names() # need to reset these to simulate separate runs\n", + "from openmdao.utils.reports_system import clear_reports\n", + "clear_reports()" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "ename": "RuntimeError", + "evalue": "pyOptSparseDriver is not available, pyOptsparse is not installed.", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mRuntimeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[9], line 8\u001b[0m\n\u001b[1;32m 5\u001b[0m make_plots \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[1;32m 6\u001b[0m max_iter \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m100\u001b[39m\n\u001b[0;32m----> 8\u001b[0m prob \u001b[38;5;241m=\u001b[39m \u001b[43mav\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_aviary\u001b[49m\u001b[43m(\u001b[49m\u001b[43maircraft_filename\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mphase_info\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43moptimizer\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43moptimizer\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 9\u001b[0m \u001b[43m \u001b[49m\u001b[43mmake_plots\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmake_plots\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmax_iter\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmax_iter\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/opt/anaconda3/lib/python3.8/site-packages/aviary/interface/methods_for_level1.py:81\u001b[0m, in \u001b[0;36mrun_aviary\u001b[0;34m(aircraft_filename, phase_info, optimizer, analysis_scheme, objective_type, record_filename, restart_filename, max_iter, run_driver, make_plots, phase_info_parameterization, optimization_history_filename)\u001b[0m\n\u001b[1;32m 78\u001b[0m \u001b[38;5;66;03m# Link phases and variables\u001b[39;00m\n\u001b[1;32m 79\u001b[0m prob\u001b[38;5;241m.\u001b[39mlink_phases()\n\u001b[0;32m---> 81\u001b[0m \u001b[43mprob\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43madd_driver\u001b[49m\u001b[43m(\u001b[49m\u001b[43moptimizer\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmax_iter\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmax_iter\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 83\u001b[0m prob\u001b[38;5;241m.\u001b[39madd_design_variables()\n\u001b[1;32m 85\u001b[0m \u001b[38;5;66;03m# Load optimization problem formulation\u001b[39;00m\n\u001b[1;32m 86\u001b[0m \u001b[38;5;66;03m# Detail which variables the optimizer can control\u001b[39;00m\n", + "File \u001b[0;32m~/opt/anaconda3/lib/python3.8/site-packages/aviary/interface/methods_for_level2.py:1502\u001b[0m, in \u001b[0;36mAviaryProblem.add_driver\u001b[0;34m(self, optimizer, use_coloring, max_iter, debug_print)\u001b[0m\n\u001b[1;32m 1500\u001b[0m driver \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdriver \u001b[38;5;241m=\u001b[39m om\u001b[38;5;241m.\u001b[39mScipyOptimizeDriver()\n\u001b[1;32m 1501\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m-> 1502\u001b[0m driver \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdriver \u001b[38;5;241m=\u001b[39m \u001b[43mom\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpyOptSparseDriver\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1504\u001b[0m driver\u001b[38;5;241m.\u001b[39moptions[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124moptimizer\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m optimizer\n\u001b[1;32m 1505\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m use_coloring:\n", + "File \u001b[0;32m~/opt/anaconda3/lib/python3.8/site-packages/openmdao/drivers/pyoptsparse_driver.py:193\u001b[0m, in \u001b[0;36mpyOptSparseDriver.__init__\u001b[0;34m(self, **kwargs)\u001b[0m\n\u001b[1;32m 188\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 189\u001b[0m \u001b[38;5;124;03mInitialize pyopt.\u001b[39;00m\n\u001b[1;32m 190\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 191\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m pyoptsparse \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 192\u001b[0m \u001b[38;5;66;03m# pyoptsparse is not installed\u001b[39;00m\n\u001b[0;32m--> 193\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mRuntimeError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mpyOptSparseDriver is not available, pyOptsparse is not installed.\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 195\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(pyoptsparse, \u001b[38;5;167;01mException\u001b[39;00m):\n\u001b[1;32m 196\u001b[0m \u001b[38;5;66;03m# there is some other issue with the pyoptsparse installation\u001b[39;00m\n\u001b[1;32m 197\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m pyoptsparse\n", + "\u001b[0;31mRuntimeError\u001b[0m: pyOptSparseDriver is not available, pyOptsparse is not installed." + ] + } + ], + "source": [ + "import aviary.api as av\n", + "\n", + "aircraft_filename = 'models/test_aircraft/aircraft_for_bench_FwFm.csv'\n", + "optimizer = \"IPOPT\"\n", + "make_plots = True\n", + "max_iter = 100\n", + "\n", + "prob = av.run_aviary(aircraft_filename, phase_info, optimizer=optimizer,\n", + " make_plots=make_plots, max_iter=max_iter)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that we've run the case successfully, let's save and print out the fuel burn value:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fixed_mission_fixed_wing_fuel_burn = prob.get_val(av.Mission.Summary.FUEL_BURNED, units='kg')[0]\n", + "fixed_mission_fixed_wing_aspect_ratio = prob.get_val(av.Aircraft.Wing.ASPECT_RATIO)[0]\n", + "print('Mission fuel burn, kg:', fixed_mission_fixed_wing_fuel_burn)\n", + "print('Aspect ratio:', fixed_mission_fixed_wing_aspect_ratio)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.interface.methods_for_level1 import run_aviary\n", + "from aviary.utils.doctape import glue_variable\n", + "\n", + "glue_variable(run_aviary.__name__,md_code=True)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Fixed Mission Profile, Optimized Aircraft Wing Aspect Ratio\n", + "\n", + "Now we will use the exact same `phase_info` object but set up our Aviary problem such that the aspect ratio of the wing is a design variable.\n", + "This means that Aviary is optimizing the wing aspect ratio while flying the same mission profile as above.\n", + "We would expect that by varying the wing aspect ratio, Aviary could find a lower fuel burn value.\n", + "\n", + "```{note}\n", + "All of the realistic design tradeoffs associated with varying the wing aspect ratio are not necessarily captured in this problem, e.g. the wing structure would need to change. We are simply using this as an example of an aircraft design variable available in Aviary.\n", + "```\n", + "\n", + "When we want to add an aircraft design variable to the Aviary problem, we need to use the Level 2 interface for Aviary.\n", + "This means we can no longer use the all-inclusive {glue:md}`run_aviary` function and instead need to call its constituent methods individually.\n", + "This allows us to insert a line adding the wing aspect ratio as a design variable as shown below.\n", + "This line is highlighted with an in-line comment." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "from openmdao.core.problem import _clear_problem_names\n", + "_clear_problem_names() # need to reset these to simulate separate runs\n", + "from openmdao.utils.reports_system import clear_reports\n", + "clear_reports()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "prob = av.AviaryProblem(av.AnalysisScheme.COLLOCATION)\n", + "\n", + "# Load aircraft and options data from user\n", + "# Allow for user overrides here\n", + "prob.load_inputs(aircraft_filename, phase_info)\n", + "\n", + "prob.check_and_preprocess_inputs()\n", + "\n", + "prob.add_pre_mission_systems()\n", + "\n", + "prob.add_phases()\n", + "\n", + "prob.add_post_mission_systems()\n", + "\n", + "# Link phases and variables\n", + "prob.link_phases()\n", + "\n", + "prob.add_driver(optimizer, max_iter=max_iter)\n", + "\n", + "prob.add_design_variables()\n", + "\n", + "# The following line is an example of how to add a design variable for the aspect ratio of the wing\n", + "prob.model.add_design_var(av.Aircraft.Wing.ASPECT_RATIO, lower=10., upper=14., ref=12.)\n", + "\n", + "# Load optimization problem formulation\n", + "# Detail which variables the optimizer can control\n", + "prob.add_objective()\n", + "\n", + "prob.setup()\n", + "\n", + "prob.set_initial_guesses()\n", + "\n", + "prob.run_aviary_problem(make_plots=make_plots)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fixed_mission_optimized_wing_fuel_burn = prob.get_val(av.Mission.Summary.FUEL_BURNED, units='kg')[0]\n", + "fixed_mission_optimized_wing_aspect_ratio = prob.get_val(av.Aircraft.Wing.ASPECT_RATIO)[0]\n", + "print('Mission fuel burn, kg:', fixed_mission_optimized_wing_fuel_burn)\n", + "print('Aspect ratio:', fixed_mission_optimized_wing_aspect_ratio)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As expected, the optimal fuel burn value is lower for this case.\n", + "We'll discuss this in more detail after running two more cases.\n", + "\n", + "## Optimized Mission Profile, Fixed Aircraft Wing Aspect Ratio\n", + "\n", + "We just investigated giving the optimizer flexibility with the aircraft design while not varying the mission.\n", + "Let's now look at the results when we optimize the mission but keep the wing aspect ratio unchanged.\n", + "\n", + "To do this, we will allow the optimizer to control the Mach and altitude profiles by modifying the `phase_info` object:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "from openmdao.core.problem import _clear_problem_names\n", + "_clear_problem_names() # need to reset these to simulate separate runs\n", + "from openmdao.utils.reports_system import clear_reports\n", + "clear_reports()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "phase_info['climb_1']['user_options']['optimize_mach'] = True\n", + "phase_info['climb_1']['user_options']['optimize_altitude'] = True\n", + "phase_info['cruise']['user_options']['optimize_mach'] = True\n", + "phase_info['cruise']['user_options']['optimize_altitude'] = True\n", + "phase_info['descent_1']['user_options']['optimize_mach'] = True\n", + "phase_info['descent_1']['user_options']['optimize_altitude'] = True\n", + "\n", + "prob = av.run_aviary(aircraft_filename, phase_info, optimizer=optimizer,\n", + " make_plots=make_plots, max_iter=max_iter)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, let's see the fuel burn:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "optimized_mission_fixed_wing_fuel_burn = prob.get_val(av.Mission.Summary.FUEL_BURNED, units='kg')[0]\n", + "optimized_mission_fixed_wing_aspect_ratio = prob.get_val(av.Aircraft.Wing.ASPECT_RATIO)[0]\n", + "print('Mission fuel burn, kg:', optimized_mission_fixed_wing_fuel_burn)\n", + "print('Aspect ratio:', optimized_mission_fixed_wing_aspect_ratio)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Optimizing the mission did not have nearly as large of an impact on the fuel burn as optimizing the aspect ratio did.\n", + "However, the fuel burn still decreased.\n", + "Let us now look at the fully coupled case.\n", + "\n", + "## Optimized Mission Profile, Optimized Aircraft Wing Aspect Ratio\n", + "\n", + "Remember we have already modified the `phase_info` object so that the Mach and altitude profiles are optimized.\n", + "Now we return to the Level 2 way of running the problem with the wing aspect ratio as a design variable." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "from openmdao.core.problem import _clear_problem_names\n", + "_clear_problem_names() # need to reset these to simulate separate runs\n", + "from openmdao.utils.reports_system import clear_reports\n", + "clear_reports()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "prob = av.AviaryProblem(av.AnalysisScheme.COLLOCATION)\n", + "\n", + "# Load aircraft and options data from user\n", + "# Allow for user overrides here\n", + "prob.load_inputs(aircraft_filename, phase_info)\n", + "\n", + "prob.check_and_preprocess_inputs()\n", + "# Preprocess inputs\n", + "prob.add_pre_mission_systems()\n", + "\n", + "prob.add_phases()\n", + "\n", + "prob.add_post_mission_systems()\n", + "\n", + "# Link phases and variables\n", + "prob.link_phases()\n", + "\n", + "prob.add_driver(optimizer, max_iter=max_iter)\n", + "\n", + "prob.add_design_variables()\n", + "\n", + "# prob.model.add_design_var(av.Aircraft.Engine.SCALED_SLS_THRUST, lower=25.e3, upper=30.e3, units='lbf', ref=28.e3)\n", + "prob.model.add_design_var(av.Aircraft.Wing.ASPECT_RATIO, lower=10., upper=14., ref=12.)\n", + "\n", + "# Load optimization problem formulation\n", + "# Detail which variables the optimizer can control\n", + "prob.add_objective()\n", + "\n", + "prob.setup()\n", + "\n", + "prob.set_initial_guesses()\n", + "\n", + "prob.run_aviary_problem(make_plots=make_plots)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "All right, let's check out this final case's fuel burn value:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "optimized_mission_optimized_wing_fuel_burn = prob.get_val(av.Mission.Summary.FUEL_BURNED, units='kg')[0]\n", + "optimized_mission_optimized_wing_aspect_ratio = prob.get_val(av.Aircraft.Wing.ASPECT_RATIO)[0]\n", + "print('Mission fuel burn, kg:', optimized_mission_optimized_wing_fuel_burn)\n", + "print('Aspect ratio:', optimized_mission_optimized_wing_aspect_ratio)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Cool, it's the lowest yet!\n", + "Let's discuss these results in more detail now.\n", + "\n", + "## Summary and Takeaways\n", + "\n", + "We have showcased one of Aviary's most powerful capabilities here -- the ability to simultaneously design an aircraft and optimal trajectory.\n", + "By building up problem complexity, we can see how optimizing different parts of the problem lead to optimization objective improvements.\n", + "\n", + "Here is a summary table of the results:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "hide-input" + ] + }, + "outputs": [], + "source": [ + "import pandas as pd\n", + "\n", + "# Create a dictionary with the data\n", + "data = {\n", + " 'Case': ['Fixed Mission, Fixed Wing', 'Fixed Mission, Optimized Wing', 'Optimized Mission, Fixed Wing', 'Optimized Mission, Optimized Wing'],\n", + " 'Optimize Mission': ['-', '-', '✓', '✓'],\n", + " 'Optimize Wing': ['-', '✓', '-', '✓'],\n", + " 'Aspect Ratio': [fixed_mission_fixed_wing_aspect_ratio, fixed_mission_optimized_wing_aspect_ratio, optimized_mission_fixed_wing_aspect_ratio, optimized_mission_optimized_wing_aspect_ratio],\n", + " 'Fuel Burn Value': [fixed_mission_fixed_wing_fuel_burn, fixed_mission_optimized_wing_fuel_burn, optimized_mission_fixed_wing_fuel_burn, optimized_mission_optimized_wing_fuel_burn]\n", + "}\n", + "\n", + "# Create a DataFrame from the dictionary\n", + "df = pd.DataFrame(data).round(2)\n", + "\n", + "# Display the DataFrame\n", + "df\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We see that the fully coupled case finds the lowest fuel burn value, as expected.\n", + "In both cases where the wing aspect ratio is optimized, it moves to the higher bound.\n", + "\n", + "If we didn't simultaneously design the aircraft and the mission, you would have to manually iterate by first optimizing the aircraft, then the mission, then the aircraft again, etc.\n", + "This cumbersome process is known as sequential optimization and can lead to non-optimal results for coupled systems, as detailed in Section 13.1 of the [Engineering Design Optimization textbook](https://flowlab.groups.et.byu.net/mdobook.pdf) (available for free).\n", + "\n", + "Aviary is unique in its ability to solve these coupled systems using efficient gradient-based optimization.\n", + "\n", + "This doc page contains a simple example, but the true power of coupled multidisciplinary optimization lies in solving more complex design problems.\n", + "We hope that you can effectively use Aviary to optimally design the next generation of exciting aircraft!\n" + ] + } + ], + "metadata": { + "celltoolbar": "Tags", + "kernelspec": { + "display_name": "aviary", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.19" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} From 98ce55abeafe91755501867cddf95a4613bb835e Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 21 Jan 2025 15:58:11 -0500 Subject: [PATCH 007/147] Rename additional_flight_phases.ipynb to aviary/docs/examples/additional_flight_phases_2.ipynb --- .../docs/examples/additional_flight_phases_2.ipynb | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename additional_flight_phases.ipynb => aviary/docs/examples/additional_flight_phases_2.ipynb (100%) diff --git a/additional_flight_phases.ipynb b/aviary/docs/examples/additional_flight_phases_2.ipynb similarity index 100% rename from additional_flight_phases.ipynb rename to aviary/docs/examples/additional_flight_phases_2.ipynb From f255033a02425506ae8926925b14500bd71dfb93 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 21 Jan 2025 16:18:04 -0500 Subject: [PATCH 008/147] Create .gitattributes --- aviary/docs/examples/.gitattributes | 1 + 1 file changed, 1 insertion(+) create mode 100644 aviary/docs/examples/.gitattributes diff --git a/aviary/docs/examples/.gitattributes b/aviary/docs/examples/.gitattributes new file mode 100644 index 000000000..8425c58da --- /dev/null +++ b/aviary/docs/examples/.gitattributes @@ -0,0 +1 @@ +*.ipynb filter=strip-notebook-output From ad19bb00d0359e11ebd5c8d4f8bbbee40370bf10 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 21 Jan 2025 16:18:52 -0500 Subject: [PATCH 009/147] Delete aviary/docs/examples/additional_flight_phases.ipynb --- .../examples/additional_flight_phases.ipynb | 443 ------------------ 1 file changed, 443 deletions(-) delete mode 100644 aviary/docs/examples/additional_flight_phases.ipynb diff --git a/aviary/docs/examples/additional_flight_phases.ipynb b/aviary/docs/examples/additional_flight_phases.ipynb deleted file mode 100644 index aa882eb6e..000000000 --- a/aviary/docs/examples/additional_flight_phases.ipynb +++ /dev/null @@ -1,443 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [ - { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'aviary.utils.doctape'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[1], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Testing Cell\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdoctape\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m glue_variable\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01minterface\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mcmd_entry_points\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m _command_map\n\u001b[1;32m 5\u001b[0m draw_mission \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdraw_mission\u001b[39m\u001b[38;5;124m'\u001b[39m\n", - "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'aviary.utils.doctape'" - ] - } - ], - "source": [ - "# Testing Cell\n", - "from aviary.utils.doctape import glue_variable\n", - "from aviary.interface.cmd_entry_points import _command_map\n", - "\n", - "draw_mission = 'draw_mission'\n", - "_command_map[draw_mission];\n", - "glue_variable(draw_mission, 'aviary '+draw_mission, md_code=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Mission Optimization with Many Phases for a Commercial Aircraft\n", - "\n", - "So far within these example docs we have been building up the complexity of our coupled aircraft-mission design problem.\n", - "In [the simple mission example](simple_mission_example), we flew the aircraft in straight line phases.\n", - "In [the more advanced mission example](more_advanced_example), we allowed the optimizer to find the optimal Mach profiles for phases.\n", - "\n", - "In this example, we will build on the prior examples by adding more phases to the mission.\n", - "This will allow us to model more complex missions, such as a commercial aircraft flying a long-haul route with multiple cruise segments, intermediary climb segments, and a cruise-climb segment.\n", - "\n", - "## Problem Formulation\n", - "\n", - "We use the {glue:md}`draw_mission` GUI as shown below:\n", - "\n", - "![multiple_phases_gui](images/multiple_phases_gui.png)\n", - "\n", - "This results in the following `phase_info` dictionary:" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "phase_info = {\n", - " \"pre_mission\": {\"include_takeoff\": False, \"optimize_mass\": True},\n", - " \"climb_1\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 3,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.2, \"unitless\"),\n", - " \"final_mach\": (0.72, \"unitless\"),\n", - " \"mach_bounds\": ((0.18, 0.74), \"unitless\"),\n", - " \"initial_altitude\": (0.0, \"ft\"),\n", - " \"final_altitude\": (31000.0, \"ft\"),\n", - " \"altitude_bounds\": ((0.0, 31500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"path_constraint\",\n", - " \"fix_initial\": True,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((0.0, 0.0), \"min\"),\n", - " \"duration_bounds\": ((25.5, 76.5), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([0, 51], \"min\")},\n", - " },\n", - " \"cruise_1\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 3,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.72, \"unitless\"),\n", - " \"final_mach\": (0.72, \"unitless\"),\n", - " \"mach_bounds\": ((0.7, 0.74), \"unitless\"),\n", - " \"initial_altitude\": (31000.0, \"ft\"),\n", - " \"final_altitude\": (31000.0, \"ft\"),\n", - " \"altitude_bounds\": ((30500.0, 31500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"boundary_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((25.5, 76.5), \"min\"),\n", - " \"duration_bounds\": ((23.5, 70.5), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([51, 47], \"min\")},\n", - " },\n", - " \"climb_2\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 3,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.72, \"unitless\"),\n", - " \"final_mach\": (0.74, \"unitless\"),\n", - " \"mach_bounds\": ((0.7, 0.76), \"unitless\"),\n", - " \"initial_altitude\": (31000.0, \"ft\"),\n", - " \"final_altitude\": (33000.0, \"ft\"),\n", - " \"altitude_bounds\": ((30500.0, 33500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"boundary_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((49.0, 147.0), \"min\"),\n", - " \"duration_bounds\": ((5.0, 15.0), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([98, 10], \"min\")},\n", - " },\n", - " \"cruise_2\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 3,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.74, \"unitless\"),\n", - " \"final_mach\": (0.74, \"unitless\"),\n", - " \"mach_bounds\": ((0.72, 0.76), \"unitless\"),\n", - " \"initial_altitude\": (33000.0, \"ft\"),\n", - " \"final_altitude\": (33000.0, \"ft\"),\n", - " \"altitude_bounds\": ((32500.0, 33500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"boundary_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((54.0, 162.0), \"min\"),\n", - " \"duration_bounds\": ((24.0, 72.0), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([108, 48], \"min\")},\n", - " },\n", - " \"climb_3\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 3,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.74, \"unitless\"),\n", - " \"final_mach\": (0.76, \"unitless\"),\n", - " \"mach_bounds\": ((0.72, 0.78), \"unitless\"),\n", - " \"initial_altitude\": (33000.0, \"ft\"),\n", - " \"final_altitude\": (34500.0, \"ft\"),\n", - " \"altitude_bounds\": ((32500.0, 35000.0), \"ft\"),\n", - " \"throttle_enforcement\": \"boundary_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((78.0, 234.0), \"min\"),\n", - " \"duration_bounds\": ((7.0, 21.0), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([156, 14], \"min\")},\n", - " },\n", - " \"climb_4\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 3,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.76, \"unitless\"),\n", - " \"final_mach\": (0.76, \"unitless\"),\n", - " \"mach_bounds\": ((0.74, 0.78), \"unitless\"),\n", - " \"initial_altitude\": (34500.0, \"ft\"),\n", - " \"final_altitude\": (36000.0, \"ft\"),\n", - " \"altitude_bounds\": ((34000.0, 36500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"boundary_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((85.0, 255.0), \"min\"),\n", - " \"duration_bounds\": ((43.0, 129.0), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([170, 86], \"min\")},\n", - " },\n", - " \"descent_1\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 3,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.76, \"unitless\"),\n", - " \"final_mach\": (0.2, \"unitless\"),\n", - " \"mach_bounds\": ((0.18, 0.78), \"unitless\"),\n", - " \"initial_altitude\": (36000.0, \"ft\"),\n", - " \"final_altitude\": (500.0, \"ft\"),\n", - " \"altitude_bounds\": ((0.0, 36500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"path_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": True,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((128.0, 384.0), \"min\"),\n", - " \"duration_bounds\": ((41.0, 123.0), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([256, 82], \"min\")},\n", - " },\n", - " \"post_mission\": {\n", - " \"include_landing\": False,\n", - " \"constrain_range\": True,\n", - " \"target_range\": (2393, \"nmi\"),\n", - " },\n", - "}" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [ - { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'aviary.utils.doctape'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[3], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Testing Cell\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdoctape\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m glue_keys\n\u001b[1;32m 3\u001b[0m glue_keys(phase_info, display\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m)\n", - "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'aviary.utils.doctape'" - ] - } - ], - "source": [ - "# Testing Cell\n", - "from aviary.utils.doctape import glue_keys\n", - "glue_keys(phase_info, display=False)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Running Aviary with Updated Parameters\n", - "\n", - "Let's now run Aviary with this multiphase mission and view the results." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/sazoppelt/opt/anaconda3/lib/python3.8/site-packages/aviary/subsystems/propulsion/engine_model.py:131: UserWarning: The value of aircraft:engine:wing_locations passed to EngineModel is type . Only the first entry in this iterable will be used.\n", - " warnings.warn(\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "The following variables have been overridden:\n", - " 'aircraft:design:touchdown_mass\n", - " 'aircraft:engine:mass\n", - " 'aircraft:fins:mass\n", - " 'aircraft:fuel:auxiliary_fuel_capacity\n", - " 'aircraft:fuel:fuselage_fuel_capacity\n", - " 'aircraft:fuel:total_capacity\n", - " 'aircraft:fuselage:planform_area\n", - " 'aircraft:fuselage:wetted_area\n", - " 'aircraft:horizontal_tail:wetted_area\n", - " 'aircraft:landing_gear:main_gear_oleo_length\n", - " 'aircraft:landing_gear:nose_gear_oleo_length\n", - " 'aircraft:vertical_tail:wetted_area\n", - " 'aircraft:wing:aspect_ratio\n", - " 'aircraft:wing:control_surface_area\n", - " 'aircraft:wing:wetted_area\n", - "\n", - "--- Constraint Report [traj] ---\n", - " --- climb_1 ---\n", - " [path] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- cruise_1 ---\n", - " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- climb_2 ---\n", - " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- cruise_2 ---\n", - " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- climb_3 ---\n", - " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- climb_4 ---\n", - " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- descent_1 ---\n", - " [path] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/sazoppelt/opt/anaconda3/lib/python3.8/site-packages/openmdao/recorders/sqlite_recorder.py:227: UserWarning:The existing case recorder file, dymos_solution.db, is being overwritten.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Model viewer data has already been recorded for Driver.\n", - "Full total jacobian was computed 3 times, taking 1.195775 seconds.\n", - "Total jacobian shape: (163, 135) \n", - "\n", - "\n", - "Jacobian shape: (163, 135) (7.26% nonzero)\n", - "FWD solves: 15 REV solves: 0\n", - "Total colors vs. total size: 15 vs 135 (88.89% improvement)\n", - "\n", - "Sparsity computed using tolerance: 1e-25\n", - "Time to compute sparsity: 1.1958 sec\n", - "Time to compute coloring: 0.1298 sec\n", - "Memory to compute coloring: -0.2969 MB\n", - "Coloring created on: 2025-01-14 13:44:26\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/sazoppelt/opt/anaconda3/lib/python3.8/site-packages/openmdao/core/total_jac.py:1788: DerivativesWarning:Design variables [('traj.climb_1.t_initial', inds=[0])] have no impact on the constraints or objective.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimization terminated successfully (Exit mode 0)\n", - " Current function value: [2.8050298]\n", - " Iterations: 16\n", - " Function evaluations: 16\n", - " Gradient evaluations: 16\n", - "Optimization Complete\n", - "-----------------------------------\n" - ] - } - ], - "source": [ - "import aviary.api as av\n", - "\n", - "prob = av.run_aviary('models/test_aircraft/aircraft_for_bench_FwFm.csv',\n", - " phase_info, optimizer=\"SLSQP\", make_plots=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that we've run Aviary, we can look at the results.\n", - "Open up the automatically generated `traj_results_report.html` and scroll through it to visualize the results.\n", - "\n", - "Here are the altitude and Mach profiles:\n", - "\n", - "![Altitude and Mach Profiles](images/multiphase_flight_profile.png)\n", - "\n", - "\n", - "```{note}\n", - "Remember, we did not allow the optimizer to control either the Mach _or_ the altitude profiles. The optimizer varied the phase durations until the optimal mission profile was found.\n", - "```\n", - "\n", - "## What Next?\n", - "\n", - "The point of this doc page is to show that missions can be arbitrarily complex in terms of the number of phases and how they're classified.\n", - "If you want multiple climb, cruise, descent phases, that's absolutely something Aviary can handle.\n", - "\n", - "There are a lot of options for how you could modify this example.\n", - "You could:\n", - "\n", - "- enable the {glue:md}`optimize_mach` or {glue:md}`optimize_altitude` flags\n", - "- increase the {glue:md}`polynomial_control_order` so there's more flexibility in the optimized mission\n", - "- try different {glue:md}`target_range` values for the full mission range\n", - "- add an external subsystem to the phases\n", - "\n", - "Playing around with a model and seeing how different settings affect the optimization and resulting aircraft design is always an enlightening experience." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.19" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} From d8f6667a5b4199fa9f93495c3b670c36d9c3e607 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 21 Jan 2025 16:19:03 -0500 Subject: [PATCH 010/147] Delete aviary/docs/examples/additional_flight_phases_2.ipynb --- .../examples/additional_flight_phases_2.ipynb | 443 ------------------ 1 file changed, 443 deletions(-) delete mode 100644 aviary/docs/examples/additional_flight_phases_2.ipynb diff --git a/aviary/docs/examples/additional_flight_phases_2.ipynb b/aviary/docs/examples/additional_flight_phases_2.ipynb deleted file mode 100644 index aa882eb6e..000000000 --- a/aviary/docs/examples/additional_flight_phases_2.ipynb +++ /dev/null @@ -1,443 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [ - { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'aviary.utils.doctape'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[1], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Testing Cell\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdoctape\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m glue_variable\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01minterface\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mcmd_entry_points\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m _command_map\n\u001b[1;32m 5\u001b[0m draw_mission \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdraw_mission\u001b[39m\u001b[38;5;124m'\u001b[39m\n", - "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'aviary.utils.doctape'" - ] - } - ], - "source": [ - "# Testing Cell\n", - "from aviary.utils.doctape import glue_variable\n", - "from aviary.interface.cmd_entry_points import _command_map\n", - "\n", - "draw_mission = 'draw_mission'\n", - "_command_map[draw_mission];\n", - "glue_variable(draw_mission, 'aviary '+draw_mission, md_code=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Mission Optimization with Many Phases for a Commercial Aircraft\n", - "\n", - "So far within these example docs we have been building up the complexity of our coupled aircraft-mission design problem.\n", - "In [the simple mission example](simple_mission_example), we flew the aircraft in straight line phases.\n", - "In [the more advanced mission example](more_advanced_example), we allowed the optimizer to find the optimal Mach profiles for phases.\n", - "\n", - "In this example, we will build on the prior examples by adding more phases to the mission.\n", - "This will allow us to model more complex missions, such as a commercial aircraft flying a long-haul route with multiple cruise segments, intermediary climb segments, and a cruise-climb segment.\n", - "\n", - "## Problem Formulation\n", - "\n", - "We use the {glue:md}`draw_mission` GUI as shown below:\n", - "\n", - "![multiple_phases_gui](images/multiple_phases_gui.png)\n", - "\n", - "This results in the following `phase_info` dictionary:" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "phase_info = {\n", - " \"pre_mission\": {\"include_takeoff\": False, \"optimize_mass\": True},\n", - " \"climb_1\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 3,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.2, \"unitless\"),\n", - " \"final_mach\": (0.72, \"unitless\"),\n", - " \"mach_bounds\": ((0.18, 0.74), \"unitless\"),\n", - " \"initial_altitude\": (0.0, \"ft\"),\n", - " \"final_altitude\": (31000.0, \"ft\"),\n", - " \"altitude_bounds\": ((0.0, 31500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"path_constraint\",\n", - " \"fix_initial\": True,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((0.0, 0.0), \"min\"),\n", - " \"duration_bounds\": ((25.5, 76.5), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([0, 51], \"min\")},\n", - " },\n", - " \"cruise_1\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 3,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.72, \"unitless\"),\n", - " \"final_mach\": (0.72, \"unitless\"),\n", - " \"mach_bounds\": ((0.7, 0.74), \"unitless\"),\n", - " \"initial_altitude\": (31000.0, \"ft\"),\n", - " \"final_altitude\": (31000.0, \"ft\"),\n", - " \"altitude_bounds\": ((30500.0, 31500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"boundary_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((25.5, 76.5), \"min\"),\n", - " \"duration_bounds\": ((23.5, 70.5), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([51, 47], \"min\")},\n", - " },\n", - " \"climb_2\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 3,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.72, \"unitless\"),\n", - " \"final_mach\": (0.74, \"unitless\"),\n", - " \"mach_bounds\": ((0.7, 0.76), \"unitless\"),\n", - " \"initial_altitude\": (31000.0, \"ft\"),\n", - " \"final_altitude\": (33000.0, \"ft\"),\n", - " \"altitude_bounds\": ((30500.0, 33500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"boundary_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((49.0, 147.0), \"min\"),\n", - " \"duration_bounds\": ((5.0, 15.0), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([98, 10], \"min\")},\n", - " },\n", - " \"cruise_2\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 3,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.74, \"unitless\"),\n", - " \"final_mach\": (0.74, \"unitless\"),\n", - " \"mach_bounds\": ((0.72, 0.76), \"unitless\"),\n", - " \"initial_altitude\": (33000.0, \"ft\"),\n", - " \"final_altitude\": (33000.0, \"ft\"),\n", - " \"altitude_bounds\": ((32500.0, 33500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"boundary_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((54.0, 162.0), \"min\"),\n", - " \"duration_bounds\": ((24.0, 72.0), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([108, 48], \"min\")},\n", - " },\n", - " \"climb_3\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 3,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.74, \"unitless\"),\n", - " \"final_mach\": (0.76, \"unitless\"),\n", - " \"mach_bounds\": ((0.72, 0.78), \"unitless\"),\n", - " \"initial_altitude\": (33000.0, \"ft\"),\n", - " \"final_altitude\": (34500.0, \"ft\"),\n", - " \"altitude_bounds\": ((32500.0, 35000.0), \"ft\"),\n", - " \"throttle_enforcement\": \"boundary_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((78.0, 234.0), \"min\"),\n", - " \"duration_bounds\": ((7.0, 21.0), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([156, 14], \"min\")},\n", - " },\n", - " \"climb_4\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 3,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.76, \"unitless\"),\n", - " \"final_mach\": (0.76, \"unitless\"),\n", - " \"mach_bounds\": ((0.74, 0.78), \"unitless\"),\n", - " \"initial_altitude\": (34500.0, \"ft\"),\n", - " \"final_altitude\": (36000.0, \"ft\"),\n", - " \"altitude_bounds\": ((34000.0, 36500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"boundary_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((85.0, 255.0), \"min\"),\n", - " \"duration_bounds\": ((43.0, 129.0), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([170, 86], \"min\")},\n", - " },\n", - " \"descent_1\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 3,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.76, \"unitless\"),\n", - " \"final_mach\": (0.2, \"unitless\"),\n", - " \"mach_bounds\": ((0.18, 0.78), \"unitless\"),\n", - " \"initial_altitude\": (36000.0, \"ft\"),\n", - " \"final_altitude\": (500.0, \"ft\"),\n", - " \"altitude_bounds\": ((0.0, 36500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"path_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": True,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((128.0, 384.0), \"min\"),\n", - " \"duration_bounds\": ((41.0, 123.0), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([256, 82], \"min\")},\n", - " },\n", - " \"post_mission\": {\n", - " \"include_landing\": False,\n", - " \"constrain_range\": True,\n", - " \"target_range\": (2393, \"nmi\"),\n", - " },\n", - "}" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [ - { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'aviary.utils.doctape'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[3], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Testing Cell\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdoctape\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m glue_keys\n\u001b[1;32m 3\u001b[0m glue_keys(phase_info, display\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m)\n", - "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'aviary.utils.doctape'" - ] - } - ], - "source": [ - "# Testing Cell\n", - "from aviary.utils.doctape import glue_keys\n", - "glue_keys(phase_info, display=False)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Running Aviary with Updated Parameters\n", - "\n", - "Let's now run Aviary with this multiphase mission and view the results." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/sazoppelt/opt/anaconda3/lib/python3.8/site-packages/aviary/subsystems/propulsion/engine_model.py:131: UserWarning: The value of aircraft:engine:wing_locations passed to EngineModel is type . Only the first entry in this iterable will be used.\n", - " warnings.warn(\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "The following variables have been overridden:\n", - " 'aircraft:design:touchdown_mass\n", - " 'aircraft:engine:mass\n", - " 'aircraft:fins:mass\n", - " 'aircraft:fuel:auxiliary_fuel_capacity\n", - " 'aircraft:fuel:fuselage_fuel_capacity\n", - " 'aircraft:fuel:total_capacity\n", - " 'aircraft:fuselage:planform_area\n", - " 'aircraft:fuselage:wetted_area\n", - " 'aircraft:horizontal_tail:wetted_area\n", - " 'aircraft:landing_gear:main_gear_oleo_length\n", - " 'aircraft:landing_gear:nose_gear_oleo_length\n", - " 'aircraft:vertical_tail:wetted_area\n", - " 'aircraft:wing:aspect_ratio\n", - " 'aircraft:wing:control_surface_area\n", - " 'aircraft:wing:wetted_area\n", - "\n", - "--- Constraint Report [traj] ---\n", - " --- climb_1 ---\n", - " [path] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- cruise_1 ---\n", - " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- climb_2 ---\n", - " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- cruise_2 ---\n", - " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- climb_3 ---\n", - " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- climb_4 ---\n", - " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- descent_1 ---\n", - " [path] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/sazoppelt/opt/anaconda3/lib/python3.8/site-packages/openmdao/recorders/sqlite_recorder.py:227: UserWarning:The existing case recorder file, dymos_solution.db, is being overwritten.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Model viewer data has already been recorded for Driver.\n", - "Full total jacobian was computed 3 times, taking 1.195775 seconds.\n", - "Total jacobian shape: (163, 135) \n", - "\n", - "\n", - "Jacobian shape: (163, 135) (7.26% nonzero)\n", - "FWD solves: 15 REV solves: 0\n", - "Total colors vs. total size: 15 vs 135 (88.89% improvement)\n", - "\n", - "Sparsity computed using tolerance: 1e-25\n", - "Time to compute sparsity: 1.1958 sec\n", - "Time to compute coloring: 0.1298 sec\n", - "Memory to compute coloring: -0.2969 MB\n", - "Coloring created on: 2025-01-14 13:44:26\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/sazoppelt/opt/anaconda3/lib/python3.8/site-packages/openmdao/core/total_jac.py:1788: DerivativesWarning:Design variables [('traj.climb_1.t_initial', inds=[0])] have no impact on the constraints or objective.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimization terminated successfully (Exit mode 0)\n", - " Current function value: [2.8050298]\n", - " Iterations: 16\n", - " Function evaluations: 16\n", - " Gradient evaluations: 16\n", - "Optimization Complete\n", - "-----------------------------------\n" - ] - } - ], - "source": [ - "import aviary.api as av\n", - "\n", - "prob = av.run_aviary('models/test_aircraft/aircraft_for_bench_FwFm.csv',\n", - " phase_info, optimizer=\"SLSQP\", make_plots=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that we've run Aviary, we can look at the results.\n", - "Open up the automatically generated `traj_results_report.html` and scroll through it to visualize the results.\n", - "\n", - "Here are the altitude and Mach profiles:\n", - "\n", - "![Altitude and Mach Profiles](images/multiphase_flight_profile.png)\n", - "\n", - "\n", - "```{note}\n", - "Remember, we did not allow the optimizer to control either the Mach _or_ the altitude profiles. The optimizer varied the phase durations until the optimal mission profile was found.\n", - "```\n", - "\n", - "## What Next?\n", - "\n", - "The point of this doc page is to show that missions can be arbitrarily complex in terms of the number of phases and how they're classified.\n", - "If you want multiple climb, cruise, descent phases, that's absolutely something Aviary can handle.\n", - "\n", - "There are a lot of options for how you could modify this example.\n", - "You could:\n", - "\n", - "- enable the {glue:md}`optimize_mach` or {glue:md}`optimize_altitude` flags\n", - "- increase the {glue:md}`polynomial_control_order` so there's more flexibility in the optimized mission\n", - "- try different {glue:md}`target_range` values for the full mission range\n", - "- add an external subsystem to the phases\n", - "\n", - "Playing around with a model and seeing how different settings affect the optimization and resulting aircraft design is always an enlightening experience." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.19" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} From 74049aaac0805286e8d184c75b52988652851d36 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 21 Jan 2025 16:19:30 -0500 Subject: [PATCH 011/147] Add files via upload --- .../examples/additional_flight_phases.ipynb | 443 ++++++++++++++++++ 1 file changed, 443 insertions(+) create mode 100644 aviary/docs/examples/additional_flight_phases.ipynb diff --git a/aviary/docs/examples/additional_flight_phases.ipynb b/aviary/docs/examples/additional_flight_phases.ipynb new file mode 100644 index 000000000..aa882eb6e --- /dev/null +++ b/aviary/docs/examples/additional_flight_phases.ipynb @@ -0,0 +1,443 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [ + { + "ename": "ModuleNotFoundError", + "evalue": "No module named 'aviary.utils.doctape'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[1], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Testing Cell\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdoctape\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m glue_variable\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01minterface\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mcmd_entry_points\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m _command_map\n\u001b[1;32m 5\u001b[0m draw_mission \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdraw_mission\u001b[39m\u001b[38;5;124m'\u001b[39m\n", + "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'aviary.utils.doctape'" + ] + } + ], + "source": [ + "# Testing Cell\n", + "from aviary.utils.doctape import glue_variable\n", + "from aviary.interface.cmd_entry_points import _command_map\n", + "\n", + "draw_mission = 'draw_mission'\n", + "_command_map[draw_mission];\n", + "glue_variable(draw_mission, 'aviary '+draw_mission, md_code=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Mission Optimization with Many Phases for a Commercial Aircraft\n", + "\n", + "So far within these example docs we have been building up the complexity of our coupled aircraft-mission design problem.\n", + "In [the simple mission example](simple_mission_example), we flew the aircraft in straight line phases.\n", + "In [the more advanced mission example](more_advanced_example), we allowed the optimizer to find the optimal Mach profiles for phases.\n", + "\n", + "In this example, we will build on the prior examples by adding more phases to the mission.\n", + "This will allow us to model more complex missions, such as a commercial aircraft flying a long-haul route with multiple cruise segments, intermediary climb segments, and a cruise-climb segment.\n", + "\n", + "## Problem Formulation\n", + "\n", + "We use the {glue:md}`draw_mission` GUI as shown below:\n", + "\n", + "![multiple_phases_gui](images/multiple_phases_gui.png)\n", + "\n", + "This results in the following `phase_info` dictionary:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "phase_info = {\n", + " \"pre_mission\": {\"include_takeoff\": False, \"optimize_mass\": True},\n", + " \"climb_1\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 3,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.2, \"unitless\"),\n", + " \"final_mach\": (0.72, \"unitless\"),\n", + " \"mach_bounds\": ((0.18, 0.74), \"unitless\"),\n", + " \"initial_altitude\": (0.0, \"ft\"),\n", + " \"final_altitude\": (31000.0, \"ft\"),\n", + " \"altitude_bounds\": ((0.0, 31500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"path_constraint\",\n", + " \"fix_initial\": True,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((0.0, 0.0), \"min\"),\n", + " \"duration_bounds\": ((25.5, 76.5), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([0, 51], \"min\")},\n", + " },\n", + " \"cruise_1\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 3,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.72, \"unitless\"),\n", + " \"final_mach\": (0.72, \"unitless\"),\n", + " \"mach_bounds\": ((0.7, 0.74), \"unitless\"),\n", + " \"initial_altitude\": (31000.0, \"ft\"),\n", + " \"final_altitude\": (31000.0, \"ft\"),\n", + " \"altitude_bounds\": ((30500.0, 31500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"boundary_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((25.5, 76.5), \"min\"),\n", + " \"duration_bounds\": ((23.5, 70.5), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([51, 47], \"min\")},\n", + " },\n", + " \"climb_2\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 3,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.72, \"unitless\"),\n", + " \"final_mach\": (0.74, \"unitless\"),\n", + " \"mach_bounds\": ((0.7, 0.76), \"unitless\"),\n", + " \"initial_altitude\": (31000.0, \"ft\"),\n", + " \"final_altitude\": (33000.0, \"ft\"),\n", + " \"altitude_bounds\": ((30500.0, 33500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"boundary_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((49.0, 147.0), \"min\"),\n", + " \"duration_bounds\": ((5.0, 15.0), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([98, 10], \"min\")},\n", + " },\n", + " \"cruise_2\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 3,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.74, \"unitless\"),\n", + " \"final_mach\": (0.74, \"unitless\"),\n", + " \"mach_bounds\": ((0.72, 0.76), \"unitless\"),\n", + " \"initial_altitude\": (33000.0, \"ft\"),\n", + " \"final_altitude\": (33000.0, \"ft\"),\n", + " \"altitude_bounds\": ((32500.0, 33500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"boundary_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((54.0, 162.0), \"min\"),\n", + " \"duration_bounds\": ((24.0, 72.0), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([108, 48], \"min\")},\n", + " },\n", + " \"climb_3\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 3,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.74, \"unitless\"),\n", + " \"final_mach\": (0.76, \"unitless\"),\n", + " \"mach_bounds\": ((0.72, 0.78), \"unitless\"),\n", + " \"initial_altitude\": (33000.0, \"ft\"),\n", + " \"final_altitude\": (34500.0, \"ft\"),\n", + " \"altitude_bounds\": ((32500.0, 35000.0), \"ft\"),\n", + " \"throttle_enforcement\": \"boundary_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((78.0, 234.0), \"min\"),\n", + " \"duration_bounds\": ((7.0, 21.0), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([156, 14], \"min\")},\n", + " },\n", + " \"climb_4\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 3,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.76, \"unitless\"),\n", + " \"final_mach\": (0.76, \"unitless\"),\n", + " \"mach_bounds\": ((0.74, 0.78), \"unitless\"),\n", + " \"initial_altitude\": (34500.0, \"ft\"),\n", + " \"final_altitude\": (36000.0, \"ft\"),\n", + " \"altitude_bounds\": ((34000.0, 36500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"boundary_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((85.0, 255.0), \"min\"),\n", + " \"duration_bounds\": ((43.0, 129.0), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([170, 86], \"min\")},\n", + " },\n", + " \"descent_1\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 3,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.76, \"unitless\"),\n", + " \"final_mach\": (0.2, \"unitless\"),\n", + " \"mach_bounds\": ((0.18, 0.78), \"unitless\"),\n", + " \"initial_altitude\": (36000.0, \"ft\"),\n", + " \"final_altitude\": (500.0, \"ft\"),\n", + " \"altitude_bounds\": ((0.0, 36500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"path_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": True,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((128.0, 384.0), \"min\"),\n", + " \"duration_bounds\": ((41.0, 123.0), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([256, 82], \"min\")},\n", + " },\n", + " \"post_mission\": {\n", + " \"include_landing\": False,\n", + " \"constrain_range\": True,\n", + " \"target_range\": (2393, \"nmi\"),\n", + " },\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [ + { + "ename": "ModuleNotFoundError", + "evalue": "No module named 'aviary.utils.doctape'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[3], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Testing Cell\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdoctape\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m glue_keys\n\u001b[1;32m 3\u001b[0m glue_keys(phase_info, display\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m)\n", + "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'aviary.utils.doctape'" + ] + } + ], + "source": [ + "# Testing Cell\n", + "from aviary.utils.doctape import glue_keys\n", + "glue_keys(phase_info, display=False)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Running Aviary with Updated Parameters\n", + "\n", + "Let's now run Aviary with this multiphase mission and view the results." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/sazoppelt/opt/anaconda3/lib/python3.8/site-packages/aviary/subsystems/propulsion/engine_model.py:131: UserWarning: The value of aircraft:engine:wing_locations passed to EngineModel is type . Only the first entry in this iterable will be used.\n", + " warnings.warn(\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "The following variables have been overridden:\n", + " 'aircraft:design:touchdown_mass\n", + " 'aircraft:engine:mass\n", + " 'aircraft:fins:mass\n", + " 'aircraft:fuel:auxiliary_fuel_capacity\n", + " 'aircraft:fuel:fuselage_fuel_capacity\n", + " 'aircraft:fuel:total_capacity\n", + " 'aircraft:fuselage:planform_area\n", + " 'aircraft:fuselage:wetted_area\n", + " 'aircraft:horizontal_tail:wetted_area\n", + " 'aircraft:landing_gear:main_gear_oleo_length\n", + " 'aircraft:landing_gear:nose_gear_oleo_length\n", + " 'aircraft:vertical_tail:wetted_area\n", + " 'aircraft:wing:aspect_ratio\n", + " 'aircraft:wing:control_surface_area\n", + " 'aircraft:wing:wetted_area\n", + "\n", + "--- Constraint Report [traj] ---\n", + " --- climb_1 ---\n", + " [path] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " --- cruise_1 ---\n", + " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " --- climb_2 ---\n", + " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " --- cruise_2 ---\n", + " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " --- climb_3 ---\n", + " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " --- climb_4 ---\n", + " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " --- descent_1 ---\n", + " [path] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/sazoppelt/opt/anaconda3/lib/python3.8/site-packages/openmdao/recorders/sqlite_recorder.py:227: UserWarning:The existing case recorder file, dymos_solution.db, is being overwritten.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Model viewer data has already been recorded for Driver.\n", + "Full total jacobian was computed 3 times, taking 1.195775 seconds.\n", + "Total jacobian shape: (163, 135) \n", + "\n", + "\n", + "Jacobian shape: (163, 135) (7.26% nonzero)\n", + "FWD solves: 15 REV solves: 0\n", + "Total colors vs. total size: 15 vs 135 (88.89% improvement)\n", + "\n", + "Sparsity computed using tolerance: 1e-25\n", + "Time to compute sparsity: 1.1958 sec\n", + "Time to compute coloring: 0.1298 sec\n", + "Memory to compute coloring: -0.2969 MB\n", + "Coloring created on: 2025-01-14 13:44:26\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/sazoppelt/opt/anaconda3/lib/python3.8/site-packages/openmdao/core/total_jac.py:1788: DerivativesWarning:Design variables [('traj.climb_1.t_initial', inds=[0])] have no impact on the constraints or objective.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimization terminated successfully (Exit mode 0)\n", + " Current function value: [2.8050298]\n", + " Iterations: 16\n", + " Function evaluations: 16\n", + " Gradient evaluations: 16\n", + "Optimization Complete\n", + "-----------------------------------\n" + ] + } + ], + "source": [ + "import aviary.api as av\n", + "\n", + "prob = av.run_aviary('models/test_aircraft/aircraft_for_bench_FwFm.csv',\n", + " phase_info, optimizer=\"SLSQP\", make_plots=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that we've run Aviary, we can look at the results.\n", + "Open up the automatically generated `traj_results_report.html` and scroll through it to visualize the results.\n", + "\n", + "Here are the altitude and Mach profiles:\n", + "\n", + "![Altitude and Mach Profiles](images/multiphase_flight_profile.png)\n", + "\n", + "\n", + "```{note}\n", + "Remember, we did not allow the optimizer to control either the Mach _or_ the altitude profiles. The optimizer varied the phase durations until the optimal mission profile was found.\n", + "```\n", + "\n", + "## What Next?\n", + "\n", + "The point of this doc page is to show that missions can be arbitrarily complex in terms of the number of phases and how they're classified.\n", + "If you want multiple climb, cruise, descent phases, that's absolutely something Aviary can handle.\n", + "\n", + "There are a lot of options for how you could modify this example.\n", + "You could:\n", + "\n", + "- enable the {glue:md}`optimize_mach` or {glue:md}`optimize_altitude` flags\n", + "- increase the {glue:md}`polynomial_control_order` so there's more flexibility in the optimized mission\n", + "- try different {glue:md}`target_range` values for the full mission range\n", + "- add an external subsystem to the phases\n", + "\n", + "Playing around with a model and seeing how different settings affect the optimization and resulting aircraft design is always an enlightening experience." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.19" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From b579a38a321aa41cda7c86071ba81ec0d0d94543 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 21 Jan 2025 16:19:45 -0500 Subject: [PATCH 012/147] Delete coupled_aircraft_mission_optimization.ipynb --- coupled_aircraft_mission_optimization.ipynb | 597 -------------------- 1 file changed, 597 deletions(-) delete mode 100644 coupled_aircraft_mission_optimization.ipynb diff --git a/coupled_aircraft_mission_optimization.ipynb b/coupled_aircraft_mission_optimization.ipynb deleted file mode 100644 index 2915da6b4..000000000 --- a/coupled_aircraft_mission_optimization.ipynb +++ /dev/null @@ -1,597 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Coupled Aircraft-Mission Optimization\n", - "\n", - "One of the most exciting features of Aviary is the ability to formulate and solve coupled aircraft-mission design optimization problems.\n", - "Here, we mean that we are finding the optimal aircraft design parameters while simultaneously finding the optimal mission trajectory.\n", - "The reason why this is so valuable is that it enables exploration of a larger design space much more efficiently.\n", - "\n", - "Solving coupled design-mission problems leads to optimal designs that would not be findable without simultaneously designing the aircraft and the trajectory.\n", - "This is especially useful for unconventional aircraft designs, operations with complex missions, and many more future-focused studies than what is commonly flying today.\n", - "\n", - "This doc page builds up a coupled design problem and explains what we're doing along the way.\n", - "This process is relatively straightforward in Aviary.\n", - "We will briefly discuss the optimal results, but that is not necessarily the focus here.\n", - "Instead, we want to showcase how to do a simple coupled design study in Aviary.\n", - "\n", - "You can use this as a starting point for your own exciting aircraft and mission design studies.\n", - "\n", - "## Problem Definition and Explanation\n", - "\n", - "We will use a conventional single-aisle commercial aircraft design as our starting point.\n", - "For all of these examples we allow the aircraft to be sized by the optimizer.\n", - "This means the gross takeoff weight is controlled to meet a mass balance.\n", - "\n", - "We will perform four different optimization cases as part of this study:\n", - "\n", - "- fixed mission profile, fixed aircraft wing aspect ratio\n", - "- fixed mission profile, optimized aircraft wing aspect ratio\n", - "- optimized mission profile, fixed aircraft wing aspect ratio\n", - "- optimized mission profile, optimized aircraft wing aspect ratio\n", - "\n", - "We'll provide more detail individually for each case.\n", - "\n", - "When we call Aviary, we will use a common `phase_info` object that we modify for each optimization case shown here:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "phase_info = {\n", - " \"pre_mission\": {\"include_takeoff\": False, \"optimize_mass\": True},\n", - " \"climb_1\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 5,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.2, \"unitless\"),\n", - " \"final_mach\": (0.72, \"unitless\"),\n", - " \"mach_bounds\": ((0.18, 0.84), \"unitless\"),\n", - " \"initial_altitude\": (0.0, \"ft\"),\n", - " \"final_altitude\": (32500.0, \"ft\"),\n", - " \"altitude_bounds\": ((0.0, 33000.0), \"ft\"),\n", - " \"throttle_enforcement\": \"path_constraint\",\n", - " \"fix_initial\": True,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((0.0, 0.0), \"min\"),\n", - " \"duration_bounds\": ((35.0, 105.0), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([0, 70], \"min\")},\n", - " },\n", - " \"cruise\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 5,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.72, \"unitless\"),\n", - " \"final_mach\": (0.80, \"unitless\"),\n", - " \"mach_bounds\": ((0.7, 0.84), \"unitless\"),\n", - " \"initial_altitude\": (32500.0, \"ft\"),\n", - " \"final_altitude\": (36000.0, \"ft\"),\n", - " \"altitude_bounds\": ((32000.0, 36500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"boundary_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((35.0, 105.0), \"min\"),\n", - " \"duration_bounds\": ((91.5, 274.5), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([70, 183], \"min\")},\n", - " },\n", - " \"descent_1\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 5,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.72, \"unitless\"),\n", - " \"final_mach\": (0.21, \"unitless\"),\n", - " \"mach_bounds\": ((0.19, 0.84), \"unitless\"),\n", - " \"initial_altitude\": (36000.0, \"ft\"),\n", - " \"final_altitude\": (0.0, \"ft\"),\n", - " \"altitude_bounds\": ((0.0, 36500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"path_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": True,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((126.5, 379.5), \"min\"),\n", - " \"duration_bounds\": ((25.0, 75.0), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([253, 50], \"min\")},\n", - " },\n", - " \"post_mission\": {\n", - " \"include_landing\": False,\n", - " \"constrain_range\": True,\n", - " \"target_range\": (2080, \"nmi\"),\n", - " },\n", - "}" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [ - { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'aviary.utils.doctape'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[7], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Testing Cell\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdoctape\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m check_value, glue_variable\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01minterface\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mcheck_phase_info\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m check_phase_info, HEIGHT_ENERGY\n\u001b[1;32m 5\u001b[0m \u001b[38;5;66;03m# checking that the phase info example is valid\u001b[39;00m\n", - "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'aviary.utils.doctape'" - ] - } - ], - "source": [ - "# Testing Cell\n", - "from aviary.utils.doctape import check_value, glue_variable\n", - "from aviary.interface.utils.check_phase_info import check_phase_info, HEIGHT_ENERGY\n", - "\n", - "# checking that the phase info example is valid\n", - "check_phase_info(phase_info, HEIGHT_ENERGY);\n", - "\n", - "# checking that optimize mach and altitude are False in the example\n", - "for phase, info in phase_info.items():\n", - " if phase not in ('pre_mission','post_mission'):\n", - " opt_mach = info['user_options']['optimize_mach']\n", - " check_value(opt_mach,False)\n", - " opt_alt = info['user_options']['optimize_altitude']\n", - " check_value(opt_alt,False)\n", - "\n", - "# gluing optimize_altitude and optimize_mach\n", - "glue_variable('optimize_altitude','optimize_altitude = False', md_code=True)\n", - "glue_variable('optimize_mach','optimize_mach = False', md_code=True)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, let us explain each case, formulate the Aviary problem, and optimize.\n", - "We'll discuss the results from each case and explain why they vary.\n", - "\n", - "## Fixed Mission Profile, Fixed Aircraft Wing Aspect Ratio\n", - "\n", - "First, let us run Aviary with a simple setup: fly a prescribed mission profile with an unchanged wing design.\n", - "Here we are varying the durations of each of the phases (climb, cruise, and descent) to minimize fuel burn across the mission.\n", - "The altitude and Mach profiles of the mission are fixed because {glue:md}`optimize_altitude` and {glue:md}`optimize_mach` for each of the phases in the `phase_info` object." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [], - "source": [ - "from openmdao.core.problem import _clear_problem_names\n", - "_clear_problem_names() # need to reset these to simulate separate runs\n", - "from openmdao.utils.reports_system import clear_reports\n", - "clear_reports()" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "ename": "RuntimeError", - "evalue": "pyOptSparseDriver is not available, pyOptsparse is not installed.", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mRuntimeError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[9], line 8\u001b[0m\n\u001b[1;32m 5\u001b[0m make_plots \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[1;32m 6\u001b[0m max_iter \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m100\u001b[39m\n\u001b[0;32m----> 8\u001b[0m prob \u001b[38;5;241m=\u001b[39m \u001b[43mav\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_aviary\u001b[49m\u001b[43m(\u001b[49m\u001b[43maircraft_filename\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mphase_info\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43moptimizer\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43moptimizer\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 9\u001b[0m \u001b[43m \u001b[49m\u001b[43mmake_plots\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmake_plots\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmax_iter\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmax_iter\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m~/opt/anaconda3/lib/python3.8/site-packages/aviary/interface/methods_for_level1.py:81\u001b[0m, in \u001b[0;36mrun_aviary\u001b[0;34m(aircraft_filename, phase_info, optimizer, analysis_scheme, objective_type, record_filename, restart_filename, max_iter, run_driver, make_plots, phase_info_parameterization, optimization_history_filename)\u001b[0m\n\u001b[1;32m 78\u001b[0m \u001b[38;5;66;03m# Link phases and variables\u001b[39;00m\n\u001b[1;32m 79\u001b[0m prob\u001b[38;5;241m.\u001b[39mlink_phases()\n\u001b[0;32m---> 81\u001b[0m \u001b[43mprob\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43madd_driver\u001b[49m\u001b[43m(\u001b[49m\u001b[43moptimizer\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmax_iter\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmax_iter\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 83\u001b[0m prob\u001b[38;5;241m.\u001b[39madd_design_variables()\n\u001b[1;32m 85\u001b[0m \u001b[38;5;66;03m# Load optimization problem formulation\u001b[39;00m\n\u001b[1;32m 86\u001b[0m \u001b[38;5;66;03m# Detail which variables the optimizer can control\u001b[39;00m\n", - "File \u001b[0;32m~/opt/anaconda3/lib/python3.8/site-packages/aviary/interface/methods_for_level2.py:1502\u001b[0m, in \u001b[0;36mAviaryProblem.add_driver\u001b[0;34m(self, optimizer, use_coloring, max_iter, debug_print)\u001b[0m\n\u001b[1;32m 1500\u001b[0m driver \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdriver \u001b[38;5;241m=\u001b[39m om\u001b[38;5;241m.\u001b[39mScipyOptimizeDriver()\n\u001b[1;32m 1501\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m-> 1502\u001b[0m driver \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdriver \u001b[38;5;241m=\u001b[39m \u001b[43mom\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpyOptSparseDriver\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1504\u001b[0m driver\u001b[38;5;241m.\u001b[39moptions[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124moptimizer\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m optimizer\n\u001b[1;32m 1505\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m use_coloring:\n", - "File \u001b[0;32m~/opt/anaconda3/lib/python3.8/site-packages/openmdao/drivers/pyoptsparse_driver.py:193\u001b[0m, in \u001b[0;36mpyOptSparseDriver.__init__\u001b[0;34m(self, **kwargs)\u001b[0m\n\u001b[1;32m 188\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 189\u001b[0m \u001b[38;5;124;03mInitialize pyopt.\u001b[39;00m\n\u001b[1;32m 190\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 191\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m pyoptsparse \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 192\u001b[0m \u001b[38;5;66;03m# pyoptsparse is not installed\u001b[39;00m\n\u001b[0;32m--> 193\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mRuntimeError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mpyOptSparseDriver is not available, pyOptsparse is not installed.\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 195\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(pyoptsparse, \u001b[38;5;167;01mException\u001b[39;00m):\n\u001b[1;32m 196\u001b[0m \u001b[38;5;66;03m# there is some other issue with the pyoptsparse installation\u001b[39;00m\n\u001b[1;32m 197\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m pyoptsparse\n", - "\u001b[0;31mRuntimeError\u001b[0m: pyOptSparseDriver is not available, pyOptsparse is not installed." - ] - } - ], - "source": [ - "import aviary.api as av\n", - "\n", - "aircraft_filename = 'models/test_aircraft/aircraft_for_bench_FwFm.csv'\n", - "optimizer = \"IPOPT\"\n", - "make_plots = True\n", - "max_iter = 100\n", - "\n", - "prob = av.run_aviary(aircraft_filename, phase_info, optimizer=optimizer,\n", - " make_plots=make_plots, max_iter=max_iter)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that we've run the case successfully, let's save and print out the fuel burn value:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fixed_mission_fixed_wing_fuel_burn = prob.get_val(av.Mission.Summary.FUEL_BURNED, units='kg')[0]\n", - "fixed_mission_fixed_wing_aspect_ratio = prob.get_val(av.Aircraft.Wing.ASPECT_RATIO)[0]\n", - "print('Mission fuel burn, kg:', fixed_mission_fixed_wing_fuel_burn)\n", - "print('Aspect ratio:', fixed_mission_fixed_wing_aspect_ratio)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [], - "source": [ - "# Testing Cell\n", - "from aviary.interface.methods_for_level1 import run_aviary\n", - "from aviary.utils.doctape import glue_variable\n", - "\n", - "glue_variable(run_aviary.__name__,md_code=True)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Fixed Mission Profile, Optimized Aircraft Wing Aspect Ratio\n", - "\n", - "Now we will use the exact same `phase_info` object but set up our Aviary problem such that the aspect ratio of the wing is a design variable.\n", - "This means that Aviary is optimizing the wing aspect ratio while flying the same mission profile as above.\n", - "We would expect that by varying the wing aspect ratio, Aviary could find a lower fuel burn value.\n", - "\n", - "```{note}\n", - "All of the realistic design tradeoffs associated with varying the wing aspect ratio are not necessarily captured in this problem, e.g. the wing structure would need to change. We are simply using this as an example of an aircraft design variable available in Aviary.\n", - "```\n", - "\n", - "When we want to add an aircraft design variable to the Aviary problem, we need to use the Level 2 interface for Aviary.\n", - "This means we can no longer use the all-inclusive {glue:md}`run_aviary` function and instead need to call its constituent methods individually.\n", - "This allows us to insert a line adding the wing aspect ratio as a design variable as shown below.\n", - "This line is highlighted with an in-line comment." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [], - "source": [ - "from openmdao.core.problem import _clear_problem_names\n", - "_clear_problem_names() # need to reset these to simulate separate runs\n", - "from openmdao.utils.reports_system import clear_reports\n", - "clear_reports()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "prob = av.AviaryProblem(av.AnalysisScheme.COLLOCATION)\n", - "\n", - "# Load aircraft and options data from user\n", - "# Allow for user overrides here\n", - "prob.load_inputs(aircraft_filename, phase_info)\n", - "\n", - "prob.check_and_preprocess_inputs()\n", - "\n", - "prob.add_pre_mission_systems()\n", - "\n", - "prob.add_phases()\n", - "\n", - "prob.add_post_mission_systems()\n", - "\n", - "# Link phases and variables\n", - "prob.link_phases()\n", - "\n", - "prob.add_driver(optimizer, max_iter=max_iter)\n", - "\n", - "prob.add_design_variables()\n", - "\n", - "# The following line is an example of how to add a design variable for the aspect ratio of the wing\n", - "prob.model.add_design_var(av.Aircraft.Wing.ASPECT_RATIO, lower=10., upper=14., ref=12.)\n", - "\n", - "# Load optimization problem formulation\n", - "# Detail which variables the optimizer can control\n", - "prob.add_objective()\n", - "\n", - "prob.setup()\n", - "\n", - "prob.set_initial_guesses()\n", - "\n", - "prob.run_aviary_problem(make_plots=make_plots)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fixed_mission_optimized_wing_fuel_burn = prob.get_val(av.Mission.Summary.FUEL_BURNED, units='kg')[0]\n", - "fixed_mission_optimized_wing_aspect_ratio = prob.get_val(av.Aircraft.Wing.ASPECT_RATIO)[0]\n", - "print('Mission fuel burn, kg:', fixed_mission_optimized_wing_fuel_burn)\n", - "print('Aspect ratio:', fixed_mission_optimized_wing_aspect_ratio)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As expected, the optimal fuel burn value is lower for this case.\n", - "We'll discuss this in more detail after running two more cases.\n", - "\n", - "## Optimized Mission Profile, Fixed Aircraft Wing Aspect Ratio\n", - "\n", - "We just investigated giving the optimizer flexibility with the aircraft design while not varying the mission.\n", - "Let's now look at the results when we optimize the mission but keep the wing aspect ratio unchanged.\n", - "\n", - "To do this, we will allow the optimizer to control the Mach and altitude profiles by modifying the `phase_info` object:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [], - "source": [ - "from openmdao.core.problem import _clear_problem_names\n", - "_clear_problem_names() # need to reset these to simulate separate runs\n", - "from openmdao.utils.reports_system import clear_reports\n", - "clear_reports()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "phase_info['climb_1']['user_options']['optimize_mach'] = True\n", - "phase_info['climb_1']['user_options']['optimize_altitude'] = True\n", - "phase_info['cruise']['user_options']['optimize_mach'] = True\n", - "phase_info['cruise']['user_options']['optimize_altitude'] = True\n", - "phase_info['descent_1']['user_options']['optimize_mach'] = True\n", - "phase_info['descent_1']['user_options']['optimize_altitude'] = True\n", - "\n", - "prob = av.run_aviary(aircraft_filename, phase_info, optimizer=optimizer,\n", - " make_plots=make_plots, max_iter=max_iter)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, let's see the fuel burn:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "optimized_mission_fixed_wing_fuel_burn = prob.get_val(av.Mission.Summary.FUEL_BURNED, units='kg')[0]\n", - "optimized_mission_fixed_wing_aspect_ratio = prob.get_val(av.Aircraft.Wing.ASPECT_RATIO)[0]\n", - "print('Mission fuel burn, kg:', optimized_mission_fixed_wing_fuel_burn)\n", - "print('Aspect ratio:', optimized_mission_fixed_wing_aspect_ratio)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Optimizing the mission did not have nearly as large of an impact on the fuel burn as optimizing the aspect ratio did.\n", - "However, the fuel burn still decreased.\n", - "Let us now look at the fully coupled case.\n", - "\n", - "## Optimized Mission Profile, Optimized Aircraft Wing Aspect Ratio\n", - "\n", - "Remember we have already modified the `phase_info` object so that the Mach and altitude profiles are optimized.\n", - "Now we return to the Level 2 way of running the problem with the wing aspect ratio as a design variable." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [], - "source": [ - "from openmdao.core.problem import _clear_problem_names\n", - "_clear_problem_names() # need to reset these to simulate separate runs\n", - "from openmdao.utils.reports_system import clear_reports\n", - "clear_reports()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "prob = av.AviaryProblem(av.AnalysisScheme.COLLOCATION)\n", - "\n", - "# Load aircraft and options data from user\n", - "# Allow for user overrides here\n", - "prob.load_inputs(aircraft_filename, phase_info)\n", - "\n", - "prob.check_and_preprocess_inputs()\n", - "# Preprocess inputs\n", - "prob.add_pre_mission_systems()\n", - "\n", - "prob.add_phases()\n", - "\n", - "prob.add_post_mission_systems()\n", - "\n", - "# Link phases and variables\n", - "prob.link_phases()\n", - "\n", - "prob.add_driver(optimizer, max_iter=max_iter)\n", - "\n", - "prob.add_design_variables()\n", - "\n", - "# prob.model.add_design_var(av.Aircraft.Engine.SCALED_SLS_THRUST, lower=25.e3, upper=30.e3, units='lbf', ref=28.e3)\n", - "prob.model.add_design_var(av.Aircraft.Wing.ASPECT_RATIO, lower=10., upper=14., ref=12.)\n", - "\n", - "# Load optimization problem formulation\n", - "# Detail which variables the optimizer can control\n", - "prob.add_objective()\n", - "\n", - "prob.setup()\n", - "\n", - "prob.set_initial_guesses()\n", - "\n", - "prob.run_aviary_problem(make_plots=make_plots)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "All right, let's check out this final case's fuel burn value:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "optimized_mission_optimized_wing_fuel_burn = prob.get_val(av.Mission.Summary.FUEL_BURNED, units='kg')[0]\n", - "optimized_mission_optimized_wing_aspect_ratio = prob.get_val(av.Aircraft.Wing.ASPECT_RATIO)[0]\n", - "print('Mission fuel burn, kg:', optimized_mission_optimized_wing_fuel_burn)\n", - "print('Aspect ratio:', optimized_mission_optimized_wing_aspect_ratio)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Cool, it's the lowest yet!\n", - "Let's discuss these results in more detail now.\n", - "\n", - "## Summary and Takeaways\n", - "\n", - "We have showcased one of Aviary's most powerful capabilities here -- the ability to simultaneously design an aircraft and optimal trajectory.\n", - "By building up problem complexity, we can see how optimizing different parts of the problem lead to optimization objective improvements.\n", - "\n", - "Here is a summary table of the results:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "hide-input" - ] - }, - "outputs": [], - "source": [ - "import pandas as pd\n", - "\n", - "# Create a dictionary with the data\n", - "data = {\n", - " 'Case': ['Fixed Mission, Fixed Wing', 'Fixed Mission, Optimized Wing', 'Optimized Mission, Fixed Wing', 'Optimized Mission, Optimized Wing'],\n", - " 'Optimize Mission': ['-', '-', '✓', '✓'],\n", - " 'Optimize Wing': ['-', '✓', '-', '✓'],\n", - " 'Aspect Ratio': [fixed_mission_fixed_wing_aspect_ratio, fixed_mission_optimized_wing_aspect_ratio, optimized_mission_fixed_wing_aspect_ratio, optimized_mission_optimized_wing_aspect_ratio],\n", - " 'Fuel Burn Value': [fixed_mission_fixed_wing_fuel_burn, fixed_mission_optimized_wing_fuel_burn, optimized_mission_fixed_wing_fuel_burn, optimized_mission_optimized_wing_fuel_burn]\n", - "}\n", - "\n", - "# Create a DataFrame from the dictionary\n", - "df = pd.DataFrame(data).round(2)\n", - "\n", - "# Display the DataFrame\n", - "df\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We see that the fully coupled case finds the lowest fuel burn value, as expected.\n", - "In both cases where the wing aspect ratio is optimized, it moves to the higher bound.\n", - "\n", - "If we didn't simultaneously design the aircraft and the mission, you would have to manually iterate by first optimizing the aircraft, then the mission, then the aircraft again, etc.\n", - "This cumbersome process is known as sequential optimization and can lead to non-optimal results for coupled systems, as detailed in Section 13.1 of the [Engineering Design Optimization textbook](https://flowlab.groups.et.byu.net/mdobook.pdf) (available for free).\n", - "\n", - "Aviary is unique in its ability to solve these coupled systems using efficient gradient-based optimization.\n", - "\n", - "This doc page contains a simple example, but the true power of coupled multidisciplinary optimization lies in solving more complex design problems.\n", - "We hope that you can effectively use Aviary to optimally design the next generation of exciting aircraft!\n" - ] - } - ], - "metadata": { - "celltoolbar": "Tags", - "kernelspec": { - "display_name": "aviary", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.19" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} From 544306b678981aade9d585c564572df27ed7cb5a Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 21 Jan 2025 16:20:29 -0500 Subject: [PATCH 013/147] Delete aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb --- ...oupled_aircraft_mission_optimization.ipynb | 597 ------------------ 1 file changed, 597 deletions(-) delete mode 100644 aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb diff --git a/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb b/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb deleted file mode 100644 index 2915da6b4..000000000 --- a/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb +++ /dev/null @@ -1,597 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Coupled Aircraft-Mission Optimization\n", - "\n", - "One of the most exciting features of Aviary is the ability to formulate and solve coupled aircraft-mission design optimization problems.\n", - "Here, we mean that we are finding the optimal aircraft design parameters while simultaneously finding the optimal mission trajectory.\n", - "The reason why this is so valuable is that it enables exploration of a larger design space much more efficiently.\n", - "\n", - "Solving coupled design-mission problems leads to optimal designs that would not be findable without simultaneously designing the aircraft and the trajectory.\n", - "This is especially useful for unconventional aircraft designs, operations with complex missions, and many more future-focused studies than what is commonly flying today.\n", - "\n", - "This doc page builds up a coupled design problem and explains what we're doing along the way.\n", - "This process is relatively straightforward in Aviary.\n", - "We will briefly discuss the optimal results, but that is not necessarily the focus here.\n", - "Instead, we want to showcase how to do a simple coupled design study in Aviary.\n", - "\n", - "You can use this as a starting point for your own exciting aircraft and mission design studies.\n", - "\n", - "## Problem Definition and Explanation\n", - "\n", - "We will use a conventional single-aisle commercial aircraft design as our starting point.\n", - "For all of these examples we allow the aircraft to be sized by the optimizer.\n", - "This means the gross takeoff weight is controlled to meet a mass balance.\n", - "\n", - "We will perform four different optimization cases as part of this study:\n", - "\n", - "- fixed mission profile, fixed aircraft wing aspect ratio\n", - "- fixed mission profile, optimized aircraft wing aspect ratio\n", - "- optimized mission profile, fixed aircraft wing aspect ratio\n", - "- optimized mission profile, optimized aircraft wing aspect ratio\n", - "\n", - "We'll provide more detail individually for each case.\n", - "\n", - "When we call Aviary, we will use a common `phase_info` object that we modify for each optimization case shown here:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "phase_info = {\n", - " \"pre_mission\": {\"include_takeoff\": False, \"optimize_mass\": True},\n", - " \"climb_1\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 5,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.2, \"unitless\"),\n", - " \"final_mach\": (0.72, \"unitless\"),\n", - " \"mach_bounds\": ((0.18, 0.84), \"unitless\"),\n", - " \"initial_altitude\": (0.0, \"ft\"),\n", - " \"final_altitude\": (32500.0, \"ft\"),\n", - " \"altitude_bounds\": ((0.0, 33000.0), \"ft\"),\n", - " \"throttle_enforcement\": \"path_constraint\",\n", - " \"fix_initial\": True,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((0.0, 0.0), \"min\"),\n", - " \"duration_bounds\": ((35.0, 105.0), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([0, 70], \"min\")},\n", - " },\n", - " \"cruise\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 5,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.72, \"unitless\"),\n", - " \"final_mach\": (0.80, \"unitless\"),\n", - " \"mach_bounds\": ((0.7, 0.84), \"unitless\"),\n", - " \"initial_altitude\": (32500.0, \"ft\"),\n", - " \"final_altitude\": (36000.0, \"ft\"),\n", - " \"altitude_bounds\": ((32000.0, 36500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"boundary_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((35.0, 105.0), \"min\"),\n", - " \"duration_bounds\": ((91.5, 274.5), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([70, 183], \"min\")},\n", - " },\n", - " \"descent_1\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 5,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.72, \"unitless\"),\n", - " \"final_mach\": (0.21, \"unitless\"),\n", - " \"mach_bounds\": ((0.19, 0.84), \"unitless\"),\n", - " \"initial_altitude\": (36000.0, \"ft\"),\n", - " \"final_altitude\": (0.0, \"ft\"),\n", - " \"altitude_bounds\": ((0.0, 36500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"path_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": True,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((126.5, 379.5), \"min\"),\n", - " \"duration_bounds\": ((25.0, 75.0), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([253, 50], \"min\")},\n", - " },\n", - " \"post_mission\": {\n", - " \"include_landing\": False,\n", - " \"constrain_range\": True,\n", - " \"target_range\": (2080, \"nmi\"),\n", - " },\n", - "}" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [ - { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'aviary.utils.doctape'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[7], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Testing Cell\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdoctape\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m check_value, glue_variable\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01minterface\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mcheck_phase_info\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m check_phase_info, HEIGHT_ENERGY\n\u001b[1;32m 5\u001b[0m \u001b[38;5;66;03m# checking that the phase info example is valid\u001b[39;00m\n", - "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'aviary.utils.doctape'" - ] - } - ], - "source": [ - "# Testing Cell\n", - "from aviary.utils.doctape import check_value, glue_variable\n", - "from aviary.interface.utils.check_phase_info import check_phase_info, HEIGHT_ENERGY\n", - "\n", - "# checking that the phase info example is valid\n", - "check_phase_info(phase_info, HEIGHT_ENERGY);\n", - "\n", - "# checking that optimize mach and altitude are False in the example\n", - "for phase, info in phase_info.items():\n", - " if phase not in ('pre_mission','post_mission'):\n", - " opt_mach = info['user_options']['optimize_mach']\n", - " check_value(opt_mach,False)\n", - " opt_alt = info['user_options']['optimize_altitude']\n", - " check_value(opt_alt,False)\n", - "\n", - "# gluing optimize_altitude and optimize_mach\n", - "glue_variable('optimize_altitude','optimize_altitude = False', md_code=True)\n", - "glue_variable('optimize_mach','optimize_mach = False', md_code=True)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, let us explain each case, formulate the Aviary problem, and optimize.\n", - "We'll discuss the results from each case and explain why they vary.\n", - "\n", - "## Fixed Mission Profile, Fixed Aircraft Wing Aspect Ratio\n", - "\n", - "First, let us run Aviary with a simple setup: fly a prescribed mission profile with an unchanged wing design.\n", - "Here we are varying the durations of each of the phases (climb, cruise, and descent) to minimize fuel burn across the mission.\n", - "The altitude and Mach profiles of the mission are fixed because {glue:md}`optimize_altitude` and {glue:md}`optimize_mach` for each of the phases in the `phase_info` object." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [], - "source": [ - "from openmdao.core.problem import _clear_problem_names\n", - "_clear_problem_names() # need to reset these to simulate separate runs\n", - "from openmdao.utils.reports_system import clear_reports\n", - "clear_reports()" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "ename": "RuntimeError", - "evalue": "pyOptSparseDriver is not available, pyOptsparse is not installed.", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mRuntimeError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[9], line 8\u001b[0m\n\u001b[1;32m 5\u001b[0m make_plots \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[1;32m 6\u001b[0m max_iter \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m100\u001b[39m\n\u001b[0;32m----> 8\u001b[0m prob \u001b[38;5;241m=\u001b[39m \u001b[43mav\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_aviary\u001b[49m\u001b[43m(\u001b[49m\u001b[43maircraft_filename\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mphase_info\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43moptimizer\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43moptimizer\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 9\u001b[0m \u001b[43m \u001b[49m\u001b[43mmake_plots\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmake_plots\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmax_iter\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmax_iter\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m~/opt/anaconda3/lib/python3.8/site-packages/aviary/interface/methods_for_level1.py:81\u001b[0m, in \u001b[0;36mrun_aviary\u001b[0;34m(aircraft_filename, phase_info, optimizer, analysis_scheme, objective_type, record_filename, restart_filename, max_iter, run_driver, make_plots, phase_info_parameterization, optimization_history_filename)\u001b[0m\n\u001b[1;32m 78\u001b[0m \u001b[38;5;66;03m# Link phases and variables\u001b[39;00m\n\u001b[1;32m 79\u001b[0m prob\u001b[38;5;241m.\u001b[39mlink_phases()\n\u001b[0;32m---> 81\u001b[0m \u001b[43mprob\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43madd_driver\u001b[49m\u001b[43m(\u001b[49m\u001b[43moptimizer\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmax_iter\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmax_iter\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 83\u001b[0m prob\u001b[38;5;241m.\u001b[39madd_design_variables()\n\u001b[1;32m 85\u001b[0m \u001b[38;5;66;03m# Load optimization problem formulation\u001b[39;00m\n\u001b[1;32m 86\u001b[0m \u001b[38;5;66;03m# Detail which variables the optimizer can control\u001b[39;00m\n", - "File \u001b[0;32m~/opt/anaconda3/lib/python3.8/site-packages/aviary/interface/methods_for_level2.py:1502\u001b[0m, in \u001b[0;36mAviaryProblem.add_driver\u001b[0;34m(self, optimizer, use_coloring, max_iter, debug_print)\u001b[0m\n\u001b[1;32m 1500\u001b[0m driver \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdriver \u001b[38;5;241m=\u001b[39m om\u001b[38;5;241m.\u001b[39mScipyOptimizeDriver()\n\u001b[1;32m 1501\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m-> 1502\u001b[0m driver \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdriver \u001b[38;5;241m=\u001b[39m \u001b[43mom\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpyOptSparseDriver\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1504\u001b[0m driver\u001b[38;5;241m.\u001b[39moptions[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124moptimizer\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m optimizer\n\u001b[1;32m 1505\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m use_coloring:\n", - "File \u001b[0;32m~/opt/anaconda3/lib/python3.8/site-packages/openmdao/drivers/pyoptsparse_driver.py:193\u001b[0m, in \u001b[0;36mpyOptSparseDriver.__init__\u001b[0;34m(self, **kwargs)\u001b[0m\n\u001b[1;32m 188\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 189\u001b[0m \u001b[38;5;124;03mInitialize pyopt.\u001b[39;00m\n\u001b[1;32m 190\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 191\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m pyoptsparse \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 192\u001b[0m \u001b[38;5;66;03m# pyoptsparse is not installed\u001b[39;00m\n\u001b[0;32m--> 193\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mRuntimeError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mpyOptSparseDriver is not available, pyOptsparse is not installed.\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 195\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(pyoptsparse, \u001b[38;5;167;01mException\u001b[39;00m):\n\u001b[1;32m 196\u001b[0m \u001b[38;5;66;03m# there is some other issue with the pyoptsparse installation\u001b[39;00m\n\u001b[1;32m 197\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m pyoptsparse\n", - "\u001b[0;31mRuntimeError\u001b[0m: pyOptSparseDriver is not available, pyOptsparse is not installed." - ] - } - ], - "source": [ - "import aviary.api as av\n", - "\n", - "aircraft_filename = 'models/test_aircraft/aircraft_for_bench_FwFm.csv'\n", - "optimizer = \"IPOPT\"\n", - "make_plots = True\n", - "max_iter = 100\n", - "\n", - "prob = av.run_aviary(aircraft_filename, phase_info, optimizer=optimizer,\n", - " make_plots=make_plots, max_iter=max_iter)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that we've run the case successfully, let's save and print out the fuel burn value:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fixed_mission_fixed_wing_fuel_burn = prob.get_val(av.Mission.Summary.FUEL_BURNED, units='kg')[0]\n", - "fixed_mission_fixed_wing_aspect_ratio = prob.get_val(av.Aircraft.Wing.ASPECT_RATIO)[0]\n", - "print('Mission fuel burn, kg:', fixed_mission_fixed_wing_fuel_burn)\n", - "print('Aspect ratio:', fixed_mission_fixed_wing_aspect_ratio)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [], - "source": [ - "# Testing Cell\n", - "from aviary.interface.methods_for_level1 import run_aviary\n", - "from aviary.utils.doctape import glue_variable\n", - "\n", - "glue_variable(run_aviary.__name__,md_code=True)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Fixed Mission Profile, Optimized Aircraft Wing Aspect Ratio\n", - "\n", - "Now we will use the exact same `phase_info` object but set up our Aviary problem such that the aspect ratio of the wing is a design variable.\n", - "This means that Aviary is optimizing the wing aspect ratio while flying the same mission profile as above.\n", - "We would expect that by varying the wing aspect ratio, Aviary could find a lower fuel burn value.\n", - "\n", - "```{note}\n", - "All of the realistic design tradeoffs associated with varying the wing aspect ratio are not necessarily captured in this problem, e.g. the wing structure would need to change. We are simply using this as an example of an aircraft design variable available in Aviary.\n", - "```\n", - "\n", - "When we want to add an aircraft design variable to the Aviary problem, we need to use the Level 2 interface for Aviary.\n", - "This means we can no longer use the all-inclusive {glue:md}`run_aviary` function and instead need to call its constituent methods individually.\n", - "This allows us to insert a line adding the wing aspect ratio as a design variable as shown below.\n", - "This line is highlighted with an in-line comment." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [], - "source": [ - "from openmdao.core.problem import _clear_problem_names\n", - "_clear_problem_names() # need to reset these to simulate separate runs\n", - "from openmdao.utils.reports_system import clear_reports\n", - "clear_reports()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "prob = av.AviaryProblem(av.AnalysisScheme.COLLOCATION)\n", - "\n", - "# Load aircraft and options data from user\n", - "# Allow for user overrides here\n", - "prob.load_inputs(aircraft_filename, phase_info)\n", - "\n", - "prob.check_and_preprocess_inputs()\n", - "\n", - "prob.add_pre_mission_systems()\n", - "\n", - "prob.add_phases()\n", - "\n", - "prob.add_post_mission_systems()\n", - "\n", - "# Link phases and variables\n", - "prob.link_phases()\n", - "\n", - "prob.add_driver(optimizer, max_iter=max_iter)\n", - "\n", - "prob.add_design_variables()\n", - "\n", - "# The following line is an example of how to add a design variable for the aspect ratio of the wing\n", - "prob.model.add_design_var(av.Aircraft.Wing.ASPECT_RATIO, lower=10., upper=14., ref=12.)\n", - "\n", - "# Load optimization problem formulation\n", - "# Detail which variables the optimizer can control\n", - "prob.add_objective()\n", - "\n", - "prob.setup()\n", - "\n", - "prob.set_initial_guesses()\n", - "\n", - "prob.run_aviary_problem(make_plots=make_plots)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fixed_mission_optimized_wing_fuel_burn = prob.get_val(av.Mission.Summary.FUEL_BURNED, units='kg')[0]\n", - "fixed_mission_optimized_wing_aspect_ratio = prob.get_val(av.Aircraft.Wing.ASPECT_RATIO)[0]\n", - "print('Mission fuel burn, kg:', fixed_mission_optimized_wing_fuel_burn)\n", - "print('Aspect ratio:', fixed_mission_optimized_wing_aspect_ratio)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As expected, the optimal fuel burn value is lower for this case.\n", - "We'll discuss this in more detail after running two more cases.\n", - "\n", - "## Optimized Mission Profile, Fixed Aircraft Wing Aspect Ratio\n", - "\n", - "We just investigated giving the optimizer flexibility with the aircraft design while not varying the mission.\n", - "Let's now look at the results when we optimize the mission but keep the wing aspect ratio unchanged.\n", - "\n", - "To do this, we will allow the optimizer to control the Mach and altitude profiles by modifying the `phase_info` object:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [], - "source": [ - "from openmdao.core.problem import _clear_problem_names\n", - "_clear_problem_names() # need to reset these to simulate separate runs\n", - "from openmdao.utils.reports_system import clear_reports\n", - "clear_reports()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "phase_info['climb_1']['user_options']['optimize_mach'] = True\n", - "phase_info['climb_1']['user_options']['optimize_altitude'] = True\n", - "phase_info['cruise']['user_options']['optimize_mach'] = True\n", - "phase_info['cruise']['user_options']['optimize_altitude'] = True\n", - "phase_info['descent_1']['user_options']['optimize_mach'] = True\n", - "phase_info['descent_1']['user_options']['optimize_altitude'] = True\n", - "\n", - "prob = av.run_aviary(aircraft_filename, phase_info, optimizer=optimizer,\n", - " make_plots=make_plots, max_iter=max_iter)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, let's see the fuel burn:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "optimized_mission_fixed_wing_fuel_burn = prob.get_val(av.Mission.Summary.FUEL_BURNED, units='kg')[0]\n", - "optimized_mission_fixed_wing_aspect_ratio = prob.get_val(av.Aircraft.Wing.ASPECT_RATIO)[0]\n", - "print('Mission fuel burn, kg:', optimized_mission_fixed_wing_fuel_burn)\n", - "print('Aspect ratio:', optimized_mission_fixed_wing_aspect_ratio)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Optimizing the mission did not have nearly as large of an impact on the fuel burn as optimizing the aspect ratio did.\n", - "However, the fuel burn still decreased.\n", - "Let us now look at the fully coupled case.\n", - "\n", - "## Optimized Mission Profile, Optimized Aircraft Wing Aspect Ratio\n", - "\n", - "Remember we have already modified the `phase_info` object so that the Mach and altitude profiles are optimized.\n", - "Now we return to the Level 2 way of running the problem with the wing aspect ratio as a design variable." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [], - "source": [ - "from openmdao.core.problem import _clear_problem_names\n", - "_clear_problem_names() # need to reset these to simulate separate runs\n", - "from openmdao.utils.reports_system import clear_reports\n", - "clear_reports()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "prob = av.AviaryProblem(av.AnalysisScheme.COLLOCATION)\n", - "\n", - "# Load aircraft and options data from user\n", - "# Allow for user overrides here\n", - "prob.load_inputs(aircraft_filename, phase_info)\n", - "\n", - "prob.check_and_preprocess_inputs()\n", - "# Preprocess inputs\n", - "prob.add_pre_mission_systems()\n", - "\n", - "prob.add_phases()\n", - "\n", - "prob.add_post_mission_systems()\n", - "\n", - "# Link phases and variables\n", - "prob.link_phases()\n", - "\n", - "prob.add_driver(optimizer, max_iter=max_iter)\n", - "\n", - "prob.add_design_variables()\n", - "\n", - "# prob.model.add_design_var(av.Aircraft.Engine.SCALED_SLS_THRUST, lower=25.e3, upper=30.e3, units='lbf', ref=28.e3)\n", - "prob.model.add_design_var(av.Aircraft.Wing.ASPECT_RATIO, lower=10., upper=14., ref=12.)\n", - "\n", - "# Load optimization problem formulation\n", - "# Detail which variables the optimizer can control\n", - "prob.add_objective()\n", - "\n", - "prob.setup()\n", - "\n", - "prob.set_initial_guesses()\n", - "\n", - "prob.run_aviary_problem(make_plots=make_plots)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "All right, let's check out this final case's fuel burn value:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "optimized_mission_optimized_wing_fuel_burn = prob.get_val(av.Mission.Summary.FUEL_BURNED, units='kg')[0]\n", - "optimized_mission_optimized_wing_aspect_ratio = prob.get_val(av.Aircraft.Wing.ASPECT_RATIO)[0]\n", - "print('Mission fuel burn, kg:', optimized_mission_optimized_wing_fuel_burn)\n", - "print('Aspect ratio:', optimized_mission_optimized_wing_aspect_ratio)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Cool, it's the lowest yet!\n", - "Let's discuss these results in more detail now.\n", - "\n", - "## Summary and Takeaways\n", - "\n", - "We have showcased one of Aviary's most powerful capabilities here -- the ability to simultaneously design an aircraft and optimal trajectory.\n", - "By building up problem complexity, we can see how optimizing different parts of the problem lead to optimization objective improvements.\n", - "\n", - "Here is a summary table of the results:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "hide-input" - ] - }, - "outputs": [], - "source": [ - "import pandas as pd\n", - "\n", - "# Create a dictionary with the data\n", - "data = {\n", - " 'Case': ['Fixed Mission, Fixed Wing', 'Fixed Mission, Optimized Wing', 'Optimized Mission, Fixed Wing', 'Optimized Mission, Optimized Wing'],\n", - " 'Optimize Mission': ['-', '-', '✓', '✓'],\n", - " 'Optimize Wing': ['-', '✓', '-', '✓'],\n", - " 'Aspect Ratio': [fixed_mission_fixed_wing_aspect_ratio, fixed_mission_optimized_wing_aspect_ratio, optimized_mission_fixed_wing_aspect_ratio, optimized_mission_optimized_wing_aspect_ratio],\n", - " 'Fuel Burn Value': [fixed_mission_fixed_wing_fuel_burn, fixed_mission_optimized_wing_fuel_burn, optimized_mission_fixed_wing_fuel_burn, optimized_mission_optimized_wing_fuel_burn]\n", - "}\n", - "\n", - "# Create a DataFrame from the dictionary\n", - "df = pd.DataFrame(data).round(2)\n", - "\n", - "# Display the DataFrame\n", - "df\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We see that the fully coupled case finds the lowest fuel burn value, as expected.\n", - "In both cases where the wing aspect ratio is optimized, it moves to the higher bound.\n", - "\n", - "If we didn't simultaneously design the aircraft and the mission, you would have to manually iterate by first optimizing the aircraft, then the mission, then the aircraft again, etc.\n", - "This cumbersome process is known as sequential optimization and can lead to non-optimal results for coupled systems, as detailed in Section 13.1 of the [Engineering Design Optimization textbook](https://flowlab.groups.et.byu.net/mdobook.pdf) (available for free).\n", - "\n", - "Aviary is unique in its ability to solve these coupled systems using efficient gradient-based optimization.\n", - "\n", - "This doc page contains a simple example, but the true power of coupled multidisciplinary optimization lies in solving more complex design problems.\n", - "We hope that you can effectively use Aviary to optimally design the next generation of exciting aircraft!\n" - ] - } - ], - "metadata": { - "celltoolbar": "Tags", - "kernelspec": { - "display_name": "aviary", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.19" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} From 1a586cd64ac4c1cf1cd8f2450cd3706f7da2c429 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 21 Jan 2025 16:20:58 -0500 Subject: [PATCH 014/147] Add files via upload --- ...oupled_aircraft_mission_optimization.ipynb | 597 ++++++++++++++++++ 1 file changed, 597 insertions(+) create mode 100644 aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb diff --git a/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb b/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb new file mode 100644 index 000000000..2915da6b4 --- /dev/null +++ b/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb @@ -0,0 +1,597 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Coupled Aircraft-Mission Optimization\n", + "\n", + "One of the most exciting features of Aviary is the ability to formulate and solve coupled aircraft-mission design optimization problems.\n", + "Here, we mean that we are finding the optimal aircraft design parameters while simultaneously finding the optimal mission trajectory.\n", + "The reason why this is so valuable is that it enables exploration of a larger design space much more efficiently.\n", + "\n", + "Solving coupled design-mission problems leads to optimal designs that would not be findable without simultaneously designing the aircraft and the trajectory.\n", + "This is especially useful for unconventional aircraft designs, operations with complex missions, and many more future-focused studies than what is commonly flying today.\n", + "\n", + "This doc page builds up a coupled design problem and explains what we're doing along the way.\n", + "This process is relatively straightforward in Aviary.\n", + "We will briefly discuss the optimal results, but that is not necessarily the focus here.\n", + "Instead, we want to showcase how to do a simple coupled design study in Aviary.\n", + "\n", + "You can use this as a starting point for your own exciting aircraft and mission design studies.\n", + "\n", + "## Problem Definition and Explanation\n", + "\n", + "We will use a conventional single-aisle commercial aircraft design as our starting point.\n", + "For all of these examples we allow the aircraft to be sized by the optimizer.\n", + "This means the gross takeoff weight is controlled to meet a mass balance.\n", + "\n", + "We will perform four different optimization cases as part of this study:\n", + "\n", + "- fixed mission profile, fixed aircraft wing aspect ratio\n", + "- fixed mission profile, optimized aircraft wing aspect ratio\n", + "- optimized mission profile, fixed aircraft wing aspect ratio\n", + "- optimized mission profile, optimized aircraft wing aspect ratio\n", + "\n", + "We'll provide more detail individually for each case.\n", + "\n", + "When we call Aviary, we will use a common `phase_info` object that we modify for each optimization case shown here:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "phase_info = {\n", + " \"pre_mission\": {\"include_takeoff\": False, \"optimize_mass\": True},\n", + " \"climb_1\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 5,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.2, \"unitless\"),\n", + " \"final_mach\": (0.72, \"unitless\"),\n", + " \"mach_bounds\": ((0.18, 0.84), \"unitless\"),\n", + " \"initial_altitude\": (0.0, \"ft\"),\n", + " \"final_altitude\": (32500.0, \"ft\"),\n", + " \"altitude_bounds\": ((0.0, 33000.0), \"ft\"),\n", + " \"throttle_enforcement\": \"path_constraint\",\n", + " \"fix_initial\": True,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((0.0, 0.0), \"min\"),\n", + " \"duration_bounds\": ((35.0, 105.0), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([0, 70], \"min\")},\n", + " },\n", + " \"cruise\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 5,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.72, \"unitless\"),\n", + " \"final_mach\": (0.80, \"unitless\"),\n", + " \"mach_bounds\": ((0.7, 0.84), \"unitless\"),\n", + " \"initial_altitude\": (32500.0, \"ft\"),\n", + " \"final_altitude\": (36000.0, \"ft\"),\n", + " \"altitude_bounds\": ((32000.0, 36500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"boundary_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((35.0, 105.0), \"min\"),\n", + " \"duration_bounds\": ((91.5, 274.5), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([70, 183], \"min\")},\n", + " },\n", + " \"descent_1\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 5,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.72, \"unitless\"),\n", + " \"final_mach\": (0.21, \"unitless\"),\n", + " \"mach_bounds\": ((0.19, 0.84), \"unitless\"),\n", + " \"initial_altitude\": (36000.0, \"ft\"),\n", + " \"final_altitude\": (0.0, \"ft\"),\n", + " \"altitude_bounds\": ((0.0, 36500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"path_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": True,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((126.5, 379.5), \"min\"),\n", + " \"duration_bounds\": ((25.0, 75.0), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([253, 50], \"min\")},\n", + " },\n", + " \"post_mission\": {\n", + " \"include_landing\": False,\n", + " \"constrain_range\": True,\n", + " \"target_range\": (2080, \"nmi\"),\n", + " },\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [ + { + "ename": "ModuleNotFoundError", + "evalue": "No module named 'aviary.utils.doctape'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[7], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Testing Cell\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdoctape\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m check_value, glue_variable\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01minterface\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mcheck_phase_info\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m check_phase_info, HEIGHT_ENERGY\n\u001b[1;32m 5\u001b[0m \u001b[38;5;66;03m# checking that the phase info example is valid\u001b[39;00m\n", + "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'aviary.utils.doctape'" + ] + } + ], + "source": [ + "# Testing Cell\n", + "from aviary.utils.doctape import check_value, glue_variable\n", + "from aviary.interface.utils.check_phase_info import check_phase_info, HEIGHT_ENERGY\n", + "\n", + "# checking that the phase info example is valid\n", + "check_phase_info(phase_info, HEIGHT_ENERGY);\n", + "\n", + "# checking that optimize mach and altitude are False in the example\n", + "for phase, info in phase_info.items():\n", + " if phase not in ('pre_mission','post_mission'):\n", + " opt_mach = info['user_options']['optimize_mach']\n", + " check_value(opt_mach,False)\n", + " opt_alt = info['user_options']['optimize_altitude']\n", + " check_value(opt_alt,False)\n", + "\n", + "# gluing optimize_altitude and optimize_mach\n", + "glue_variable('optimize_altitude','optimize_altitude = False', md_code=True)\n", + "glue_variable('optimize_mach','optimize_mach = False', md_code=True)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, let us explain each case, formulate the Aviary problem, and optimize.\n", + "We'll discuss the results from each case and explain why they vary.\n", + "\n", + "## Fixed Mission Profile, Fixed Aircraft Wing Aspect Ratio\n", + "\n", + "First, let us run Aviary with a simple setup: fly a prescribed mission profile with an unchanged wing design.\n", + "Here we are varying the durations of each of the phases (climb, cruise, and descent) to minimize fuel burn across the mission.\n", + "The altitude and Mach profiles of the mission are fixed because {glue:md}`optimize_altitude` and {glue:md}`optimize_mach` for each of the phases in the `phase_info` object." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "from openmdao.core.problem import _clear_problem_names\n", + "_clear_problem_names() # need to reset these to simulate separate runs\n", + "from openmdao.utils.reports_system import clear_reports\n", + "clear_reports()" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "ename": "RuntimeError", + "evalue": "pyOptSparseDriver is not available, pyOptsparse is not installed.", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mRuntimeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[9], line 8\u001b[0m\n\u001b[1;32m 5\u001b[0m make_plots \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[1;32m 6\u001b[0m max_iter \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m100\u001b[39m\n\u001b[0;32m----> 8\u001b[0m prob \u001b[38;5;241m=\u001b[39m \u001b[43mav\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_aviary\u001b[49m\u001b[43m(\u001b[49m\u001b[43maircraft_filename\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mphase_info\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43moptimizer\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43moptimizer\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 9\u001b[0m \u001b[43m \u001b[49m\u001b[43mmake_plots\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmake_plots\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmax_iter\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmax_iter\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/opt/anaconda3/lib/python3.8/site-packages/aviary/interface/methods_for_level1.py:81\u001b[0m, in \u001b[0;36mrun_aviary\u001b[0;34m(aircraft_filename, phase_info, optimizer, analysis_scheme, objective_type, record_filename, restart_filename, max_iter, run_driver, make_plots, phase_info_parameterization, optimization_history_filename)\u001b[0m\n\u001b[1;32m 78\u001b[0m \u001b[38;5;66;03m# Link phases and variables\u001b[39;00m\n\u001b[1;32m 79\u001b[0m prob\u001b[38;5;241m.\u001b[39mlink_phases()\n\u001b[0;32m---> 81\u001b[0m \u001b[43mprob\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43madd_driver\u001b[49m\u001b[43m(\u001b[49m\u001b[43moptimizer\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmax_iter\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmax_iter\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 83\u001b[0m prob\u001b[38;5;241m.\u001b[39madd_design_variables()\n\u001b[1;32m 85\u001b[0m \u001b[38;5;66;03m# Load optimization problem formulation\u001b[39;00m\n\u001b[1;32m 86\u001b[0m \u001b[38;5;66;03m# Detail which variables the optimizer can control\u001b[39;00m\n", + "File \u001b[0;32m~/opt/anaconda3/lib/python3.8/site-packages/aviary/interface/methods_for_level2.py:1502\u001b[0m, in \u001b[0;36mAviaryProblem.add_driver\u001b[0;34m(self, optimizer, use_coloring, max_iter, debug_print)\u001b[0m\n\u001b[1;32m 1500\u001b[0m driver \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdriver \u001b[38;5;241m=\u001b[39m om\u001b[38;5;241m.\u001b[39mScipyOptimizeDriver()\n\u001b[1;32m 1501\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m-> 1502\u001b[0m driver \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdriver \u001b[38;5;241m=\u001b[39m \u001b[43mom\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpyOptSparseDriver\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1504\u001b[0m driver\u001b[38;5;241m.\u001b[39moptions[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124moptimizer\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m optimizer\n\u001b[1;32m 1505\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m use_coloring:\n", + "File \u001b[0;32m~/opt/anaconda3/lib/python3.8/site-packages/openmdao/drivers/pyoptsparse_driver.py:193\u001b[0m, in \u001b[0;36mpyOptSparseDriver.__init__\u001b[0;34m(self, **kwargs)\u001b[0m\n\u001b[1;32m 188\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 189\u001b[0m \u001b[38;5;124;03mInitialize pyopt.\u001b[39;00m\n\u001b[1;32m 190\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 191\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m pyoptsparse \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 192\u001b[0m \u001b[38;5;66;03m# pyoptsparse is not installed\u001b[39;00m\n\u001b[0;32m--> 193\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mRuntimeError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mpyOptSparseDriver is not available, pyOptsparse is not installed.\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 195\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(pyoptsparse, \u001b[38;5;167;01mException\u001b[39;00m):\n\u001b[1;32m 196\u001b[0m \u001b[38;5;66;03m# there is some other issue with the pyoptsparse installation\u001b[39;00m\n\u001b[1;32m 197\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m pyoptsparse\n", + "\u001b[0;31mRuntimeError\u001b[0m: pyOptSparseDriver is not available, pyOptsparse is not installed." + ] + } + ], + "source": [ + "import aviary.api as av\n", + "\n", + "aircraft_filename = 'models/test_aircraft/aircraft_for_bench_FwFm.csv'\n", + "optimizer = \"IPOPT\"\n", + "make_plots = True\n", + "max_iter = 100\n", + "\n", + "prob = av.run_aviary(aircraft_filename, phase_info, optimizer=optimizer,\n", + " make_plots=make_plots, max_iter=max_iter)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that we've run the case successfully, let's save and print out the fuel burn value:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fixed_mission_fixed_wing_fuel_burn = prob.get_val(av.Mission.Summary.FUEL_BURNED, units='kg')[0]\n", + "fixed_mission_fixed_wing_aspect_ratio = prob.get_val(av.Aircraft.Wing.ASPECT_RATIO)[0]\n", + "print('Mission fuel burn, kg:', fixed_mission_fixed_wing_fuel_burn)\n", + "print('Aspect ratio:', fixed_mission_fixed_wing_aspect_ratio)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.interface.methods_for_level1 import run_aviary\n", + "from aviary.utils.doctape import glue_variable\n", + "\n", + "glue_variable(run_aviary.__name__,md_code=True)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Fixed Mission Profile, Optimized Aircraft Wing Aspect Ratio\n", + "\n", + "Now we will use the exact same `phase_info` object but set up our Aviary problem such that the aspect ratio of the wing is a design variable.\n", + "This means that Aviary is optimizing the wing aspect ratio while flying the same mission profile as above.\n", + "We would expect that by varying the wing aspect ratio, Aviary could find a lower fuel burn value.\n", + "\n", + "```{note}\n", + "All of the realistic design tradeoffs associated with varying the wing aspect ratio are not necessarily captured in this problem, e.g. the wing structure would need to change. We are simply using this as an example of an aircraft design variable available in Aviary.\n", + "```\n", + "\n", + "When we want to add an aircraft design variable to the Aviary problem, we need to use the Level 2 interface for Aviary.\n", + "This means we can no longer use the all-inclusive {glue:md}`run_aviary` function and instead need to call its constituent methods individually.\n", + "This allows us to insert a line adding the wing aspect ratio as a design variable as shown below.\n", + "This line is highlighted with an in-line comment." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "from openmdao.core.problem import _clear_problem_names\n", + "_clear_problem_names() # need to reset these to simulate separate runs\n", + "from openmdao.utils.reports_system import clear_reports\n", + "clear_reports()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "prob = av.AviaryProblem(av.AnalysisScheme.COLLOCATION)\n", + "\n", + "# Load aircraft and options data from user\n", + "# Allow for user overrides here\n", + "prob.load_inputs(aircraft_filename, phase_info)\n", + "\n", + "prob.check_and_preprocess_inputs()\n", + "\n", + "prob.add_pre_mission_systems()\n", + "\n", + "prob.add_phases()\n", + "\n", + "prob.add_post_mission_systems()\n", + "\n", + "# Link phases and variables\n", + "prob.link_phases()\n", + "\n", + "prob.add_driver(optimizer, max_iter=max_iter)\n", + "\n", + "prob.add_design_variables()\n", + "\n", + "# The following line is an example of how to add a design variable for the aspect ratio of the wing\n", + "prob.model.add_design_var(av.Aircraft.Wing.ASPECT_RATIO, lower=10., upper=14., ref=12.)\n", + "\n", + "# Load optimization problem formulation\n", + "# Detail which variables the optimizer can control\n", + "prob.add_objective()\n", + "\n", + "prob.setup()\n", + "\n", + "prob.set_initial_guesses()\n", + "\n", + "prob.run_aviary_problem(make_plots=make_plots)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fixed_mission_optimized_wing_fuel_burn = prob.get_val(av.Mission.Summary.FUEL_BURNED, units='kg')[0]\n", + "fixed_mission_optimized_wing_aspect_ratio = prob.get_val(av.Aircraft.Wing.ASPECT_RATIO)[0]\n", + "print('Mission fuel burn, kg:', fixed_mission_optimized_wing_fuel_burn)\n", + "print('Aspect ratio:', fixed_mission_optimized_wing_aspect_ratio)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As expected, the optimal fuel burn value is lower for this case.\n", + "We'll discuss this in more detail after running two more cases.\n", + "\n", + "## Optimized Mission Profile, Fixed Aircraft Wing Aspect Ratio\n", + "\n", + "We just investigated giving the optimizer flexibility with the aircraft design while not varying the mission.\n", + "Let's now look at the results when we optimize the mission but keep the wing aspect ratio unchanged.\n", + "\n", + "To do this, we will allow the optimizer to control the Mach and altitude profiles by modifying the `phase_info` object:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "from openmdao.core.problem import _clear_problem_names\n", + "_clear_problem_names() # need to reset these to simulate separate runs\n", + "from openmdao.utils.reports_system import clear_reports\n", + "clear_reports()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "phase_info['climb_1']['user_options']['optimize_mach'] = True\n", + "phase_info['climb_1']['user_options']['optimize_altitude'] = True\n", + "phase_info['cruise']['user_options']['optimize_mach'] = True\n", + "phase_info['cruise']['user_options']['optimize_altitude'] = True\n", + "phase_info['descent_1']['user_options']['optimize_mach'] = True\n", + "phase_info['descent_1']['user_options']['optimize_altitude'] = True\n", + "\n", + "prob = av.run_aviary(aircraft_filename, phase_info, optimizer=optimizer,\n", + " make_plots=make_plots, max_iter=max_iter)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, let's see the fuel burn:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "optimized_mission_fixed_wing_fuel_burn = prob.get_val(av.Mission.Summary.FUEL_BURNED, units='kg')[0]\n", + "optimized_mission_fixed_wing_aspect_ratio = prob.get_val(av.Aircraft.Wing.ASPECT_RATIO)[0]\n", + "print('Mission fuel burn, kg:', optimized_mission_fixed_wing_fuel_burn)\n", + "print('Aspect ratio:', optimized_mission_fixed_wing_aspect_ratio)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Optimizing the mission did not have nearly as large of an impact on the fuel burn as optimizing the aspect ratio did.\n", + "However, the fuel burn still decreased.\n", + "Let us now look at the fully coupled case.\n", + "\n", + "## Optimized Mission Profile, Optimized Aircraft Wing Aspect Ratio\n", + "\n", + "Remember we have already modified the `phase_info` object so that the Mach and altitude profiles are optimized.\n", + "Now we return to the Level 2 way of running the problem with the wing aspect ratio as a design variable." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "from openmdao.core.problem import _clear_problem_names\n", + "_clear_problem_names() # need to reset these to simulate separate runs\n", + "from openmdao.utils.reports_system import clear_reports\n", + "clear_reports()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "prob = av.AviaryProblem(av.AnalysisScheme.COLLOCATION)\n", + "\n", + "# Load aircraft and options data from user\n", + "# Allow for user overrides here\n", + "prob.load_inputs(aircraft_filename, phase_info)\n", + "\n", + "prob.check_and_preprocess_inputs()\n", + "# Preprocess inputs\n", + "prob.add_pre_mission_systems()\n", + "\n", + "prob.add_phases()\n", + "\n", + "prob.add_post_mission_systems()\n", + "\n", + "# Link phases and variables\n", + "prob.link_phases()\n", + "\n", + "prob.add_driver(optimizer, max_iter=max_iter)\n", + "\n", + "prob.add_design_variables()\n", + "\n", + "# prob.model.add_design_var(av.Aircraft.Engine.SCALED_SLS_THRUST, lower=25.e3, upper=30.e3, units='lbf', ref=28.e3)\n", + "prob.model.add_design_var(av.Aircraft.Wing.ASPECT_RATIO, lower=10., upper=14., ref=12.)\n", + "\n", + "# Load optimization problem formulation\n", + "# Detail which variables the optimizer can control\n", + "prob.add_objective()\n", + "\n", + "prob.setup()\n", + "\n", + "prob.set_initial_guesses()\n", + "\n", + "prob.run_aviary_problem(make_plots=make_plots)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "All right, let's check out this final case's fuel burn value:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "optimized_mission_optimized_wing_fuel_burn = prob.get_val(av.Mission.Summary.FUEL_BURNED, units='kg')[0]\n", + "optimized_mission_optimized_wing_aspect_ratio = prob.get_val(av.Aircraft.Wing.ASPECT_RATIO)[0]\n", + "print('Mission fuel burn, kg:', optimized_mission_optimized_wing_fuel_burn)\n", + "print('Aspect ratio:', optimized_mission_optimized_wing_aspect_ratio)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Cool, it's the lowest yet!\n", + "Let's discuss these results in more detail now.\n", + "\n", + "## Summary and Takeaways\n", + "\n", + "We have showcased one of Aviary's most powerful capabilities here -- the ability to simultaneously design an aircraft and optimal trajectory.\n", + "By building up problem complexity, we can see how optimizing different parts of the problem lead to optimization objective improvements.\n", + "\n", + "Here is a summary table of the results:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "hide-input" + ] + }, + "outputs": [], + "source": [ + "import pandas as pd\n", + "\n", + "# Create a dictionary with the data\n", + "data = {\n", + " 'Case': ['Fixed Mission, Fixed Wing', 'Fixed Mission, Optimized Wing', 'Optimized Mission, Fixed Wing', 'Optimized Mission, Optimized Wing'],\n", + " 'Optimize Mission': ['-', '-', '✓', '✓'],\n", + " 'Optimize Wing': ['-', '✓', '-', '✓'],\n", + " 'Aspect Ratio': [fixed_mission_fixed_wing_aspect_ratio, fixed_mission_optimized_wing_aspect_ratio, optimized_mission_fixed_wing_aspect_ratio, optimized_mission_optimized_wing_aspect_ratio],\n", + " 'Fuel Burn Value': [fixed_mission_fixed_wing_fuel_burn, fixed_mission_optimized_wing_fuel_burn, optimized_mission_fixed_wing_fuel_burn, optimized_mission_optimized_wing_fuel_burn]\n", + "}\n", + "\n", + "# Create a DataFrame from the dictionary\n", + "df = pd.DataFrame(data).round(2)\n", + "\n", + "# Display the DataFrame\n", + "df\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We see that the fully coupled case finds the lowest fuel burn value, as expected.\n", + "In both cases where the wing aspect ratio is optimized, it moves to the higher bound.\n", + "\n", + "If we didn't simultaneously design the aircraft and the mission, you would have to manually iterate by first optimizing the aircraft, then the mission, then the aircraft again, etc.\n", + "This cumbersome process is known as sequential optimization and can lead to non-optimal results for coupled systems, as detailed in Section 13.1 of the [Engineering Design Optimization textbook](https://flowlab.groups.et.byu.net/mdobook.pdf) (available for free).\n", + "\n", + "Aviary is unique in its ability to solve these coupled systems using efficient gradient-based optimization.\n", + "\n", + "This doc page contains a simple example, but the true power of coupled multidisciplinary optimization lies in solving more complex design problems.\n", + "We hope that you can effectively use Aviary to optimally design the next generation of exciting aircraft!\n" + ] + } + ], + "metadata": { + "celltoolbar": "Tags", + "kernelspec": { + "display_name": "aviary", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.19" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} From 92700d7d906db8c9f36aafc09fb37ab3a9004d6e Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 21 Jan 2025 16:22:09 -0500 Subject: [PATCH 015/147] Delete aviary/docs/examples/additional_flight_phases.ipynb --- .../examples/additional_flight_phases.ipynb | 443 ------------------ 1 file changed, 443 deletions(-) delete mode 100644 aviary/docs/examples/additional_flight_phases.ipynb diff --git a/aviary/docs/examples/additional_flight_phases.ipynb b/aviary/docs/examples/additional_flight_phases.ipynb deleted file mode 100644 index aa882eb6e..000000000 --- a/aviary/docs/examples/additional_flight_phases.ipynb +++ /dev/null @@ -1,443 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [ - { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'aviary.utils.doctape'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[1], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Testing Cell\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdoctape\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m glue_variable\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01minterface\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mcmd_entry_points\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m _command_map\n\u001b[1;32m 5\u001b[0m draw_mission \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdraw_mission\u001b[39m\u001b[38;5;124m'\u001b[39m\n", - "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'aviary.utils.doctape'" - ] - } - ], - "source": [ - "# Testing Cell\n", - "from aviary.utils.doctape import glue_variable\n", - "from aviary.interface.cmd_entry_points import _command_map\n", - "\n", - "draw_mission = 'draw_mission'\n", - "_command_map[draw_mission];\n", - "glue_variable(draw_mission, 'aviary '+draw_mission, md_code=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Mission Optimization with Many Phases for a Commercial Aircraft\n", - "\n", - "So far within these example docs we have been building up the complexity of our coupled aircraft-mission design problem.\n", - "In [the simple mission example](simple_mission_example), we flew the aircraft in straight line phases.\n", - "In [the more advanced mission example](more_advanced_example), we allowed the optimizer to find the optimal Mach profiles for phases.\n", - "\n", - "In this example, we will build on the prior examples by adding more phases to the mission.\n", - "This will allow us to model more complex missions, such as a commercial aircraft flying a long-haul route with multiple cruise segments, intermediary climb segments, and a cruise-climb segment.\n", - "\n", - "## Problem Formulation\n", - "\n", - "We use the {glue:md}`draw_mission` GUI as shown below:\n", - "\n", - "![multiple_phases_gui](images/multiple_phases_gui.png)\n", - "\n", - "This results in the following `phase_info` dictionary:" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "phase_info = {\n", - " \"pre_mission\": {\"include_takeoff\": False, \"optimize_mass\": True},\n", - " \"climb_1\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 3,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.2, \"unitless\"),\n", - " \"final_mach\": (0.72, \"unitless\"),\n", - " \"mach_bounds\": ((0.18, 0.74), \"unitless\"),\n", - " \"initial_altitude\": (0.0, \"ft\"),\n", - " \"final_altitude\": (31000.0, \"ft\"),\n", - " \"altitude_bounds\": ((0.0, 31500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"path_constraint\",\n", - " \"fix_initial\": True,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((0.0, 0.0), \"min\"),\n", - " \"duration_bounds\": ((25.5, 76.5), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([0, 51], \"min\")},\n", - " },\n", - " \"cruise_1\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 3,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.72, \"unitless\"),\n", - " \"final_mach\": (0.72, \"unitless\"),\n", - " \"mach_bounds\": ((0.7, 0.74), \"unitless\"),\n", - " \"initial_altitude\": (31000.0, \"ft\"),\n", - " \"final_altitude\": (31000.0, \"ft\"),\n", - " \"altitude_bounds\": ((30500.0, 31500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"boundary_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((25.5, 76.5), \"min\"),\n", - " \"duration_bounds\": ((23.5, 70.5), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([51, 47], \"min\")},\n", - " },\n", - " \"climb_2\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 3,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.72, \"unitless\"),\n", - " \"final_mach\": (0.74, \"unitless\"),\n", - " \"mach_bounds\": ((0.7, 0.76), \"unitless\"),\n", - " \"initial_altitude\": (31000.0, \"ft\"),\n", - " \"final_altitude\": (33000.0, \"ft\"),\n", - " \"altitude_bounds\": ((30500.0, 33500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"boundary_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((49.0, 147.0), \"min\"),\n", - " \"duration_bounds\": ((5.0, 15.0), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([98, 10], \"min\")},\n", - " },\n", - " \"cruise_2\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 3,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.74, \"unitless\"),\n", - " \"final_mach\": (0.74, \"unitless\"),\n", - " \"mach_bounds\": ((0.72, 0.76), \"unitless\"),\n", - " \"initial_altitude\": (33000.0, \"ft\"),\n", - " \"final_altitude\": (33000.0, \"ft\"),\n", - " \"altitude_bounds\": ((32500.0, 33500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"boundary_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((54.0, 162.0), \"min\"),\n", - " \"duration_bounds\": ((24.0, 72.0), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([108, 48], \"min\")},\n", - " },\n", - " \"climb_3\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 3,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.74, \"unitless\"),\n", - " \"final_mach\": (0.76, \"unitless\"),\n", - " \"mach_bounds\": ((0.72, 0.78), \"unitless\"),\n", - " \"initial_altitude\": (33000.0, \"ft\"),\n", - " \"final_altitude\": (34500.0, \"ft\"),\n", - " \"altitude_bounds\": ((32500.0, 35000.0), \"ft\"),\n", - " \"throttle_enforcement\": \"boundary_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((78.0, 234.0), \"min\"),\n", - " \"duration_bounds\": ((7.0, 21.0), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([156, 14], \"min\")},\n", - " },\n", - " \"climb_4\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 3,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.76, \"unitless\"),\n", - " \"final_mach\": (0.76, \"unitless\"),\n", - " \"mach_bounds\": ((0.74, 0.78), \"unitless\"),\n", - " \"initial_altitude\": (34500.0, \"ft\"),\n", - " \"final_altitude\": (36000.0, \"ft\"),\n", - " \"altitude_bounds\": ((34000.0, 36500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"boundary_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((85.0, 255.0), \"min\"),\n", - " \"duration_bounds\": ((43.0, 129.0), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([170, 86], \"min\")},\n", - " },\n", - " \"descent_1\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 3,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.76, \"unitless\"),\n", - " \"final_mach\": (0.2, \"unitless\"),\n", - " \"mach_bounds\": ((0.18, 0.78), \"unitless\"),\n", - " \"initial_altitude\": (36000.0, \"ft\"),\n", - " \"final_altitude\": (500.0, \"ft\"),\n", - " \"altitude_bounds\": ((0.0, 36500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"path_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": True,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((128.0, 384.0), \"min\"),\n", - " \"duration_bounds\": ((41.0, 123.0), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([256, 82], \"min\")},\n", - " },\n", - " \"post_mission\": {\n", - " \"include_landing\": False,\n", - " \"constrain_range\": True,\n", - " \"target_range\": (2393, \"nmi\"),\n", - " },\n", - "}" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [ - { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'aviary.utils.doctape'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[3], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Testing Cell\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdoctape\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m glue_keys\n\u001b[1;32m 3\u001b[0m glue_keys(phase_info, display\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m)\n", - "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'aviary.utils.doctape'" - ] - } - ], - "source": [ - "# Testing Cell\n", - "from aviary.utils.doctape import glue_keys\n", - "glue_keys(phase_info, display=False)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Running Aviary with Updated Parameters\n", - "\n", - "Let's now run Aviary with this multiphase mission and view the results." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/sazoppelt/opt/anaconda3/lib/python3.8/site-packages/aviary/subsystems/propulsion/engine_model.py:131: UserWarning: The value of aircraft:engine:wing_locations passed to EngineModel is type . Only the first entry in this iterable will be used.\n", - " warnings.warn(\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "The following variables have been overridden:\n", - " 'aircraft:design:touchdown_mass\n", - " 'aircraft:engine:mass\n", - " 'aircraft:fins:mass\n", - " 'aircraft:fuel:auxiliary_fuel_capacity\n", - " 'aircraft:fuel:fuselage_fuel_capacity\n", - " 'aircraft:fuel:total_capacity\n", - " 'aircraft:fuselage:planform_area\n", - " 'aircraft:fuselage:wetted_area\n", - " 'aircraft:horizontal_tail:wetted_area\n", - " 'aircraft:landing_gear:main_gear_oleo_length\n", - " 'aircraft:landing_gear:nose_gear_oleo_length\n", - " 'aircraft:vertical_tail:wetted_area\n", - " 'aircraft:wing:aspect_ratio\n", - " 'aircraft:wing:control_surface_area\n", - " 'aircraft:wing:wetted_area\n", - "\n", - "--- Constraint Report [traj] ---\n", - " --- climb_1 ---\n", - " [path] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- cruise_1 ---\n", - " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- climb_2 ---\n", - " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- cruise_2 ---\n", - " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- climb_3 ---\n", - " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- climb_4 ---\n", - " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- descent_1 ---\n", - " [path] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/sazoppelt/opt/anaconda3/lib/python3.8/site-packages/openmdao/recorders/sqlite_recorder.py:227: UserWarning:The existing case recorder file, dymos_solution.db, is being overwritten.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Model viewer data has already been recorded for Driver.\n", - "Full total jacobian was computed 3 times, taking 1.195775 seconds.\n", - "Total jacobian shape: (163, 135) \n", - "\n", - "\n", - "Jacobian shape: (163, 135) (7.26% nonzero)\n", - "FWD solves: 15 REV solves: 0\n", - "Total colors vs. total size: 15 vs 135 (88.89% improvement)\n", - "\n", - "Sparsity computed using tolerance: 1e-25\n", - "Time to compute sparsity: 1.1958 sec\n", - "Time to compute coloring: 0.1298 sec\n", - "Memory to compute coloring: -0.2969 MB\n", - "Coloring created on: 2025-01-14 13:44:26\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/sazoppelt/opt/anaconda3/lib/python3.8/site-packages/openmdao/core/total_jac.py:1788: DerivativesWarning:Design variables [('traj.climb_1.t_initial', inds=[0])] have no impact on the constraints or objective.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimization terminated successfully (Exit mode 0)\n", - " Current function value: [2.8050298]\n", - " Iterations: 16\n", - " Function evaluations: 16\n", - " Gradient evaluations: 16\n", - "Optimization Complete\n", - "-----------------------------------\n" - ] - } - ], - "source": [ - "import aviary.api as av\n", - "\n", - "prob = av.run_aviary('models/test_aircraft/aircraft_for_bench_FwFm.csv',\n", - " phase_info, optimizer=\"SLSQP\", make_plots=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that we've run Aviary, we can look at the results.\n", - "Open up the automatically generated `traj_results_report.html` and scroll through it to visualize the results.\n", - "\n", - "Here are the altitude and Mach profiles:\n", - "\n", - "![Altitude and Mach Profiles](images/multiphase_flight_profile.png)\n", - "\n", - "\n", - "```{note}\n", - "Remember, we did not allow the optimizer to control either the Mach _or_ the altitude profiles. The optimizer varied the phase durations until the optimal mission profile was found.\n", - "```\n", - "\n", - "## What Next?\n", - "\n", - "The point of this doc page is to show that missions can be arbitrarily complex in terms of the number of phases and how they're classified.\n", - "If you want multiple climb, cruise, descent phases, that's absolutely something Aviary can handle.\n", - "\n", - "There are a lot of options for how you could modify this example.\n", - "You could:\n", - "\n", - "- enable the {glue:md}`optimize_mach` or {glue:md}`optimize_altitude` flags\n", - "- increase the {glue:md}`polynomial_control_order` so there's more flexibility in the optimized mission\n", - "- try different {glue:md}`target_range` values for the full mission range\n", - "- add an external subsystem to the phases\n", - "\n", - "Playing around with a model and seeing how different settings affect the optimization and resulting aircraft design is always an enlightening experience." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.19" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} From e342df68de2ffd368b7127edc480c8c94c4b5144 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 21 Jan 2025 16:22:54 -0500 Subject: [PATCH 016/147] Add files via upload --- .../examples/additional_flight_phases.ipynb | 443 ++++++++++++++++++ 1 file changed, 443 insertions(+) create mode 100644 aviary/docs/examples/additional_flight_phases.ipynb diff --git a/aviary/docs/examples/additional_flight_phases.ipynb b/aviary/docs/examples/additional_flight_phases.ipynb new file mode 100644 index 000000000..3ebe6f155 --- /dev/null +++ b/aviary/docs/examples/additional_flight_phases.ipynb @@ -0,0 +1,443 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [ + { + "ename": "ModuleNotFoundError", + "evalue": "No module named 'aviary.utils.doctape'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[1], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Testing Cell\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdoctape\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m glue_variable\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01minterface\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mcmd_entry_points\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m _command_map\n\u001b[1;32m 5\u001b[0m draw_mission \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdraw_mission\u001b[39m\u001b[38;5;124m'\u001b[39m\n", + "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'aviary.utils.doctape'" + ] + } + ], + "source": [ + "# Testing Cell\n", + "from aviary.utils.doctape import glue_variable\n", + "from aviary.interface.cmd_entry_points import _command_map\n", + "\n", + "draw_mission = 'draw_mission'\n", + "_command_map[draw_mission];\n", + "glue_variable(draw_mission, 'aviary '+draw_mission, md_code=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Mission Optimization with Many Phases for a Commercial Aircraft\n", + "\n", + "So far within these example docs we have been building up the complexity of our coupled aircraft-mission design problem.\n", + "In [the simple mission example](simple_mission_example), we flew the aircraft in straight line phases.\n", + "In [the more advanced mission example](more_advanced_example), we allowed the optimizer to find the optimal Mach profiles for phases.\n", + "\n", + "In this example, we will build on the prior examples by adding more phases to the mission.\n", + "This will allow us to model more complex missions, such as a commercial aircraft flying a long-haul route with multiple cruise segments, intermediary climb segments, and a cruise-climb segment.\n", + "\n", + "## Problem Formulation\n", + "\n", + "We use the {glue:md}`draw_mission` GUI as shown below:\n", + "\n", + "![multiple_phases_gui](images/multiple_phases_gui.png)\n", + "\n", + "This results in the following `phase_info` dictionary:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "phase_info = {\n", + " \"pre_mission\": {\"include_takeoff\": False, \"optimize_mass\": True},\n", + " \"climb_1\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 3,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.2, \"unitless\"),\n", + " \"final_mach\": (0.72, \"unitless\"),\n", + " \"mach_bounds\": ((0.18, 0.74), \"unitless\"),\n", + " \"initial_altitude\": (0.0, \"ft\"),\n", + " \"final_altitude\": (31000.0, \"ft\"),\n", + " \"altitude_bounds\": ((0.0, 31500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"path_constraint\",\n", + " \"fix_initial\": True,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((0.0, 0.0), \"min\"),\n", + " \"duration_bounds\": ((25.5, 76.5), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([0, 51], \"min\")},\n", + " },\n", + " \"cruise_1\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 3,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.72, \"unitless\"),\n", + " \"final_mach\": (0.72, \"unitless\"),\n", + " \"mach_bounds\": ((0.7, 0.74), \"unitless\"),\n", + " \"initial_altitude\": (31000.0, \"ft\"),\n", + " \"final_altitude\": (31000.0, \"ft\"),\n", + " \"altitude_bounds\": ((30500.0, 31500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"boundary_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((25.5, 76.5), \"min\"),\n", + " \"duration_bounds\": ((23.5, 70.5), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([51, 47], \"min\")},\n", + " },\n", + " \"climb_2\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 3,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.72, \"unitless\"),\n", + " \"final_mach\": (0.74, \"unitless\"),\n", + " \"mach_bounds\": ((0.7, 0.76), \"unitless\"),\n", + " \"initial_altitude\": (31000.0, \"ft\"),\n", + " \"final_altitude\": (33000.0, \"ft\"),\n", + " \"altitude_bounds\": ((30500.0, 33500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"boundary_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((49.0, 147.0), \"min\"),\n", + " \"duration_bounds\": ((5.0, 15.0), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([98, 10], \"min\")},\n", + " },\n", + " \"cruise_2\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 3,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.74, \"unitless\"),\n", + " \"final_mach\": (0.74, \"unitless\"),\n", + " \"mach_bounds\": ((0.72, 0.76), \"unitless\"),\n", + " \"initial_altitude\": (33000.0, \"ft\"),\n", + " \"final_altitude\": (33000.0, \"ft\"),\n", + " \"altitude_bounds\": ((32500.0, 33500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"boundary_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((54.0, 162.0), \"min\"),\n", + " \"duration_bounds\": ((24.0, 72.0), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([108, 48], \"min\")},\n", + " },\n", + " \"climb_3\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 3,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.74, \"unitless\"),\n", + " \"final_mach\": (0.76, \"unitless\"),\n", + " \"mach_bounds\": ((0.72, 0.78), \"unitless\"),\n", + " \"initial_altitude\": (33000.0, \"ft\"),\n", + " \"final_altitude\": (34500.0, \"ft\"),\n", + " \"altitude_bounds\": ((32500.0, 35000.0), \"ft\"),\n", + " \"throttle_enforcement\": \"boundary_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((78.0, 234.0), \"min\"),\n", + " \"duration_bounds\": ((7.0, 21.0), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([156, 14], \"min\")},\n", + " },\n", + " \"climb_4\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 3,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.76, \"unitless\"),\n", + " \"final_mach\": (0.76, \"unitless\"),\n", + " \"mach_bounds\": ((0.74, 0.78), \"unitless\"),\n", + " \"initial_altitude\": (34500.0, \"ft\"),\n", + " \"final_altitude\": (36000.0, \"ft\"),\n", + " \"altitude_bounds\": ((34000.0, 36500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"boundary_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((85.0, 255.0), \"min\"),\n", + " \"duration_bounds\": ((43.0, 129.0), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([170, 86], \"min\")},\n", + " },\n", + " \"descent_1\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 3,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.76, \"unitless\"),\n", + " \"final_mach\": (0.2, \"unitless\"),\n", + " \"mach_bounds\": ((0.18, 0.78), \"unitless\"),\n", + " \"initial_altitude\": (36000.0, \"ft\"),\n", + " \"final_altitude\": (500.0, \"ft\"),\n", + " \"altitude_bounds\": ((0.0, 36500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"path_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": True,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((128.0, 384.0), \"min\"),\n", + " \"duration_bounds\": ((41.0, 123.0), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([256, 82], \"min\")},\n", + " },\n", + " \"post_mission\": {\n", + " \"include_landing\": False,\n", + " \"constrain_range\": True,\n", + " \"target_range\": (2393, \"nmi\"),\n", + " },\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [ + { + "ename": "ModuleNotFoundError", + "evalue": "No module named 'aviary.utils.doctape'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[3], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Testing Cell\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdoctape\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m glue_keys\n\u001b[1;32m 3\u001b[0m glue_keys(phase_info, display\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m)\n", + "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'aviary.utils.doctape'" + ] + } + ], + "source": [ + "# Testing Cell\n", + "from aviary.utils.doctape import glue_keys\n", + "glue_keys(phase_info, display=False)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Running Aviary with Updated Parameters\n", + "\n", + "Let's now run Aviary with this multiphase mission and view the results." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/sazoppelt/opt/anaconda3/lib/python3.8/site-packages/aviary/subsystems/propulsion/engine_model.py:131: UserWarning: The value of aircraft:engine:wing_locations passed to EngineModel is type . Only the first entry in this iterable will be used.\n", + " warnings.warn(\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "The following variables have been overridden:\n", + " 'aircraft:design:touchdown_mass\n", + " 'aircraft:engine:mass\n", + " 'aircraft:fins:mass\n", + " 'aircraft:fuel:auxiliary_fuel_capacity\n", + " 'aircraft:fuel:fuselage_fuel_capacity\n", + " 'aircraft:fuel:total_capacity\n", + " 'aircraft:fuselage:planform_area\n", + " 'aircraft:fuselage:wetted_area\n", + " 'aircraft:horizontal_tail:wetted_area\n", + " 'aircraft:landing_gear:main_gear_oleo_length\n", + " 'aircraft:landing_gear:nose_gear_oleo_length\n", + " 'aircraft:vertical_tail:wetted_area\n", + " 'aircraft:wing:aspect_ratio\n", + " 'aircraft:wing:control_surface_area\n", + " 'aircraft:wing:wetted_area\n", + "\n", + "--- Constraint Report [traj] ---\n", + " --- climb_1 ---\n", + " [path] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " --- cruise_1 ---\n", + " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " --- climb_2 ---\n", + " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " --- cruise_2 ---\n", + " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " --- climb_3 ---\n", + " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " --- climb_4 ---\n", + " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + " --- descent_1 ---\n", + " [path] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/sazoppelt/opt/anaconda3/lib/python3.8/site-packages/openmdao/recorders/sqlite_recorder.py:227: UserWarning:The existing case recorder file, dymos_solution.db, is being overwritten.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Model viewer data has already been recorded for Driver.\n", + "Full total jacobian was computed 3 times, taking 1.195775 seconds.\n", + "Total jacobian shape: (163, 135) \n", + "\n", + "\n", + "Jacobian shape: (163, 135) (7.26% nonzero)\n", + "FWD solves: 15 REV solves: 0\n", + "Total colors vs. total size: 15 vs 135 (88.89% improvement)\n", + "\n", + "Sparsity computed using tolerance: 1e-25\n", + "Time to compute sparsity: 1.1958 sec\n", + "Time to compute coloring: 0.1298 sec\n", + "Memory to compute coloring: -0.2969 MB\n", + "Coloring created on: 2025-01-14 13:44:26\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/sazoppelt/opt/anaconda3/lib/python3.8/site-packages/openmdao/core/total_jac.py:1788: DerivativesWarning:Design variables [('traj.climb_1.t_initial', inds=[0])] have no impact on the constraints or objective.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Optimization terminated successfully (Exit mode 0)\n", + " Current function value: [2.8050298]\n", + " Iterations: 16\n", + " Function evaluations: 16\n", + " Gradient evaluations: 16\n", + "Optimization Complete\n", + "-----------------------------------\n" + ] + } + ], + "source": [ + "import aviary.api as av\n", + "\n", + "prob = av.run_aviary('models/test_aircraft/aircraft_for_bench_FwFm.csv',\n", + " phase_info, optimizer=\"SLSQP\", make_plots=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that we've run Aviary, we can look at the results.\n", + "Open up the automatically generated `traj_results_report.html` and scroll through it to visualize the results.\n", + "\n", + "Here are the altitude and Mach profiles:\n", + "\n", + "![Altitude and Mach Profiles](images/multiphase_flight_profile.png)\n", + "\n", + "\n", + "```{note}\n", + "Remember, we did not allow the optimizer to control either the Mach _or_ the altitude profiles. The optimizer varied the phase durations until the optimal mission profile was found.\n", + "```\n", + "\n", + "## What Next?\n", + "\n", + "The point of this doc page is to show that missions can be arbitrarily complex in terms of the number of phases and how they're classified.\n", + "If you want multiple climb, cruise, descent phases, that's absolutely something Aviary can handle.\n", + "\n", + "There are a lot of options for how you could modify this example.\n", + "You could:\n", + "\n", + "- enable the {glue:md}`optimize_mach` or {glue:md}`optimize_altitude` flags\n", + "- increase the {glue:md}`polynomial_control_order` so there's more flexibility in the optimized mission\n", + "- try different {glue:md}`target_range` values for the full mission range\n", + "- add an external subsystem to the phases\n", + "\n", + "Playing around with a model and seeing how different settings affect the optimization and resulting aircraft design is always an enlightening experience." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.19" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From 6e0e6b85dfea87e4b7bb2394b43171f0c7660ee6 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Wed, 22 Jan 2025 11:15:17 -0500 Subject: [PATCH 017/147] Add files via upload --- .../examples/additional_flight_phases-2.ipynb | 325 ++++++++++++++++++ 1 file changed, 325 insertions(+) create mode 100644 aviary/docs/examples/additional_flight_phases-2.ipynb diff --git a/aviary/docs/examples/additional_flight_phases-2.ipynb b/aviary/docs/examples/additional_flight_phases-2.ipynb new file mode 100644 index 000000000..efe30689a --- /dev/null +++ b/aviary/docs/examples/additional_flight_phases-2.ipynb @@ -0,0 +1,325 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.utils.doctape import glue_variable\n", + "from aviary.interface.cmd_entry_points import _command_map\n", + "\n", + "draw_mission = 'draw_mission'\n", + "_command_map[draw_mission];\n", + "glue_variable(draw_mission, 'aviary '+draw_mission, md_code=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Mission Optimization with Many Phases for a Commercial Aircraft\n", + "\n", + "So far within these example docs we have been building up the complexity of our coupled aircraft-mission design problem.\n", + "In [the simple mission example](simple_mission_example), we flew the aircraft in straight line phases.\n", + "In [the more advanced mission example](more_advanced_example), we allowed the optimizer to find the optimal Mach profiles for phases.\n", + "\n", + "In this example, we will build on the prior examples by adding more phases to the mission.\n", + "This will allow us to model more complex missions, such as a commercial aircraft flying a long-haul route with multiple cruise segments, intermediary climb segments, and a cruise-climb segment.\n", + "\n", + "## Problem Formulation\n", + "\n", + "We use the {glue:md}`draw_mission` GUI as shown below:\n", + "\n", + "![multiple_phases_gui](images/multiple_phases_gui.png)\n", + "\n", + "This results in the following `phase_info` dictionary:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "phase_info = {\n", + " \"pre_mission\": {\"include_takeoff\": False, \"optimize_mass\": True},\n", + " \"climb_1\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 3,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.2, \"unitless\"),\n", + " \"final_mach\": (0.72, \"unitless\"),\n", + " \"mach_bounds\": ((0.18, 0.74), \"unitless\"),\n", + " \"initial_altitude\": (0.0, \"ft\"),\n", + " \"final_altitude\": (31000.0, \"ft\"),\n", + " \"altitude_bounds\": ((0.0, 31500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"path_constraint\",\n", + " \"fix_initial\": True,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((0.0, 0.0), \"min\"),\n", + " \"duration_bounds\": ((25.5, 76.5), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([0, 51], \"min\")},\n", + " },\n", + " \"cruise_1\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 3,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.72, \"unitless\"),\n", + " \"final_mach\": (0.72, \"unitless\"),\n", + " \"mach_bounds\": ((0.7, 0.74), \"unitless\"),\n", + " \"initial_altitude\": (31000.0, \"ft\"),\n", + " \"final_altitude\": (31000.0, \"ft\"),\n", + " \"altitude_bounds\": ((30500.0, 31500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"boundary_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((25.5, 76.5), \"min\"),\n", + " \"duration_bounds\": ((23.5, 70.5), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([51, 47], \"min\")},\n", + " },\n", + " \"climb_2\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 3,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.72, \"unitless\"),\n", + " \"final_mach\": (0.74, \"unitless\"),\n", + " \"mach_bounds\": ((0.7, 0.76), \"unitless\"),\n", + " \"initial_altitude\": (31000.0, \"ft\"),\n", + " \"final_altitude\": (33000.0, \"ft\"),\n", + " \"altitude_bounds\": ((30500.0, 33500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"boundary_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((49.0, 147.0), \"min\"),\n", + " \"duration_bounds\": ((5.0, 15.0), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([98, 10], \"min\")},\n", + " },\n", + " \"cruise_2\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 3,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.74, \"unitless\"),\n", + " \"final_mach\": (0.74, \"unitless\"),\n", + " \"mach_bounds\": ((0.72, 0.76), \"unitless\"),\n", + " \"initial_altitude\": (33000.0, \"ft\"),\n", + " \"final_altitude\": (33000.0, \"ft\"),\n", + " \"altitude_bounds\": ((32500.0, 33500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"boundary_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((54.0, 162.0), \"min\"),\n", + " \"duration_bounds\": ((24.0, 72.0), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([108, 48], \"min\")},\n", + " },\n", + " \"climb_3\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 3,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.74, \"unitless\"),\n", + " \"final_mach\": (0.76, \"unitless\"),\n", + " \"mach_bounds\": ((0.72, 0.78), \"unitless\"),\n", + " \"initial_altitude\": (33000.0, \"ft\"),\n", + " \"final_altitude\": (34500.0, \"ft\"),\n", + " \"altitude_bounds\": ((32500.0, 35000.0), \"ft\"),\n", + " \"throttle_enforcement\": \"boundary_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((78.0, 234.0), \"min\"),\n", + " \"duration_bounds\": ((7.0, 21.0), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([156, 14], \"min\")},\n", + " },\n", + " \"climb_4\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 3,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.76, \"unitless\"),\n", + " \"final_mach\": (0.76, \"unitless\"),\n", + " \"mach_bounds\": ((0.74, 0.78), \"unitless\"),\n", + " \"initial_altitude\": (34500.0, \"ft\"),\n", + " \"final_altitude\": (36000.0, \"ft\"),\n", + " \"altitude_bounds\": ((34000.0, 36500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"boundary_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((85.0, 255.0), \"min\"),\n", + " \"duration_bounds\": ((43.0, 129.0), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([170, 86], \"min\")},\n", + " },\n", + " \"descent_1\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 3,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.76, \"unitless\"),\n", + " \"final_mach\": (0.2, \"unitless\"),\n", + " \"mach_bounds\": ((0.18, 0.78), \"unitless\"),\n", + " \"initial_altitude\": (36000.0, \"ft\"),\n", + " \"final_altitude\": (500.0, \"ft\"),\n", + " \"altitude_bounds\": ((0.0, 36500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"path_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": True,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((128.0, 384.0), \"min\"),\n", + " \"duration_bounds\": ((41.0, 123.0), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([256, 82], \"min\")},\n", + " },\n", + " \"post_mission\": {\n", + " \"include_landing\": False,\n", + " \"constrain_range\": True,\n", + " \"target_range\": (2393, \"nmi\"),\n", + " },\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.utils.doctape import glue_keys\n", + "glue_keys(phase_info, display=False)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Running Aviary with Updated Parameters\n", + "\n", + "Let's now run Aviary with this multiphase mission and view the results." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import aviary.api as av\n", + "\n", + "prob = av.run_aviary('models/test_aircraft/aircraft_for_bench_FwFm.csv',\n", + " phase_info, optimizer=\"SLSQP\", make_plots=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that we've run Aviary, we can look at the results.\n", + "Open up the automatically generated `traj_results_report.html` and scroll through it to visualize the results.\n", + "\n", + "Here are the altitude and Mach profiles:\n", + "\n", + "![Altitude and Mach Profiles](images/multiphase_flight_profile.png)\n", + "\n", + "\n", + "```{note}\n", + "Remember, we did not allow the optimizer to control either the Mach _or_ the altitude profiles. The optimizer varied the phase durations until the optimal mission profile was found.\n", + "```\n", + "\n", + "## What Next?\n", + "\n", + "The point of this doc page is to show that missions can be arbitrarily complex in terms of the number of phases and how they're classified.\n", + "If you want multiple climb, cruise, descent phases, that's absolutely something Aviary can handle.\n", + "\n", + "There are a lot of options for how you could modify this example.\n", + "You could:\n", + "\n", + "- enable the {glue:md}`optimize_mach` or {glue:md}`optimize_altitude` flags\n", + "- increase the {glue:md}`polynomial_control_order` so there's more flexibility in the optimized mission\n", + "- try different {glue:md}`target_range` values for the full mission range\n", + "- add an external subsystem to the phases\n", + "\n", + "Playing around with a model and seeing how different settings affect the optimization and resulting aircraft design is always an enlightening experience." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.2" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} From ec9ee457540408c552688ffb297cc92a15618e81 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Wed, 22 Jan 2025 11:15:56 -0500 Subject: [PATCH 018/147] Delete aviary/docs/examples/additional_flight_phases.ipynb --- .../examples/additional_flight_phases.ipynb | 443 ------------------ 1 file changed, 443 deletions(-) delete mode 100644 aviary/docs/examples/additional_flight_phases.ipynb diff --git a/aviary/docs/examples/additional_flight_phases.ipynb b/aviary/docs/examples/additional_flight_phases.ipynb deleted file mode 100644 index 3ebe6f155..000000000 --- a/aviary/docs/examples/additional_flight_phases.ipynb +++ /dev/null @@ -1,443 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [ - { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'aviary.utils.doctape'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[1], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Testing Cell\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdoctape\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m glue_variable\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01minterface\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mcmd_entry_points\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m _command_map\n\u001b[1;32m 5\u001b[0m draw_mission \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdraw_mission\u001b[39m\u001b[38;5;124m'\u001b[39m\n", - "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'aviary.utils.doctape'" - ] - } - ], - "source": [ - "# Testing Cell\n", - "from aviary.utils.doctape import glue_variable\n", - "from aviary.interface.cmd_entry_points import _command_map\n", - "\n", - "draw_mission = 'draw_mission'\n", - "_command_map[draw_mission];\n", - "glue_variable(draw_mission, 'aviary '+draw_mission, md_code=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Mission Optimization with Many Phases for a Commercial Aircraft\n", - "\n", - "So far within these example docs we have been building up the complexity of our coupled aircraft-mission design problem.\n", - "In [the simple mission example](simple_mission_example), we flew the aircraft in straight line phases.\n", - "In [the more advanced mission example](more_advanced_example), we allowed the optimizer to find the optimal Mach profiles for phases.\n", - "\n", - "In this example, we will build on the prior examples by adding more phases to the mission.\n", - "This will allow us to model more complex missions, such as a commercial aircraft flying a long-haul route with multiple cruise segments, intermediary climb segments, and a cruise-climb segment.\n", - "\n", - "## Problem Formulation\n", - "\n", - "We use the {glue:md}`draw_mission` GUI as shown below:\n", - "\n", - "![multiple_phases_gui](images/multiple_phases_gui.png)\n", - "\n", - "This results in the following `phase_info` dictionary:" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "phase_info = {\n", - " \"pre_mission\": {\"include_takeoff\": False, \"optimize_mass\": True},\n", - " \"climb_1\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 3,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.2, \"unitless\"),\n", - " \"final_mach\": (0.72, \"unitless\"),\n", - " \"mach_bounds\": ((0.18, 0.74), \"unitless\"),\n", - " \"initial_altitude\": (0.0, \"ft\"),\n", - " \"final_altitude\": (31000.0, \"ft\"),\n", - " \"altitude_bounds\": ((0.0, 31500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"path_constraint\",\n", - " \"fix_initial\": True,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((0.0, 0.0), \"min\"),\n", - " \"duration_bounds\": ((25.5, 76.5), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([0, 51], \"min\")},\n", - " },\n", - " \"cruise_1\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 3,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.72, \"unitless\"),\n", - " \"final_mach\": (0.72, \"unitless\"),\n", - " \"mach_bounds\": ((0.7, 0.74), \"unitless\"),\n", - " \"initial_altitude\": (31000.0, \"ft\"),\n", - " \"final_altitude\": (31000.0, \"ft\"),\n", - " \"altitude_bounds\": ((30500.0, 31500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"boundary_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((25.5, 76.5), \"min\"),\n", - " \"duration_bounds\": ((23.5, 70.5), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([51, 47], \"min\")},\n", - " },\n", - " \"climb_2\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 3,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.72, \"unitless\"),\n", - " \"final_mach\": (0.74, \"unitless\"),\n", - " \"mach_bounds\": ((0.7, 0.76), \"unitless\"),\n", - " \"initial_altitude\": (31000.0, \"ft\"),\n", - " \"final_altitude\": (33000.0, \"ft\"),\n", - " \"altitude_bounds\": ((30500.0, 33500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"boundary_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((49.0, 147.0), \"min\"),\n", - " \"duration_bounds\": ((5.0, 15.0), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([98, 10], \"min\")},\n", - " },\n", - " \"cruise_2\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 3,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.74, \"unitless\"),\n", - " \"final_mach\": (0.74, \"unitless\"),\n", - " \"mach_bounds\": ((0.72, 0.76), \"unitless\"),\n", - " \"initial_altitude\": (33000.0, \"ft\"),\n", - " \"final_altitude\": (33000.0, \"ft\"),\n", - " \"altitude_bounds\": ((32500.0, 33500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"boundary_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((54.0, 162.0), \"min\"),\n", - " \"duration_bounds\": ((24.0, 72.0), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([108, 48], \"min\")},\n", - " },\n", - " \"climb_3\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 3,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.74, \"unitless\"),\n", - " \"final_mach\": (0.76, \"unitless\"),\n", - " \"mach_bounds\": ((0.72, 0.78), \"unitless\"),\n", - " \"initial_altitude\": (33000.0, \"ft\"),\n", - " \"final_altitude\": (34500.0, \"ft\"),\n", - " \"altitude_bounds\": ((32500.0, 35000.0), \"ft\"),\n", - " \"throttle_enforcement\": \"boundary_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((78.0, 234.0), \"min\"),\n", - " \"duration_bounds\": ((7.0, 21.0), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([156, 14], \"min\")},\n", - " },\n", - " \"climb_4\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 3,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.76, \"unitless\"),\n", - " \"final_mach\": (0.76, \"unitless\"),\n", - " \"mach_bounds\": ((0.74, 0.78), \"unitless\"),\n", - " \"initial_altitude\": (34500.0, \"ft\"),\n", - " \"final_altitude\": (36000.0, \"ft\"),\n", - " \"altitude_bounds\": ((34000.0, 36500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"boundary_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((85.0, 255.0), \"min\"),\n", - " \"duration_bounds\": ((43.0, 129.0), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([170, 86], \"min\")},\n", - " },\n", - " \"descent_1\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 3,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.76, \"unitless\"),\n", - " \"final_mach\": (0.2, \"unitless\"),\n", - " \"mach_bounds\": ((0.18, 0.78), \"unitless\"),\n", - " \"initial_altitude\": (36000.0, \"ft\"),\n", - " \"final_altitude\": (500.0, \"ft\"),\n", - " \"altitude_bounds\": ((0.0, 36500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"path_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": True,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((128.0, 384.0), \"min\"),\n", - " \"duration_bounds\": ((41.0, 123.0), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([256, 82], \"min\")},\n", - " },\n", - " \"post_mission\": {\n", - " \"include_landing\": False,\n", - " \"constrain_range\": True,\n", - " \"target_range\": (2393, \"nmi\"),\n", - " },\n", - "}" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [ - { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'aviary.utils.doctape'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[3], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Testing Cell\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdoctape\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m glue_keys\n\u001b[1;32m 3\u001b[0m glue_keys(phase_info, display\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m)\n", - "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'aviary.utils.doctape'" - ] - } - ], - "source": [ - "# Testing Cell\n", - "from aviary.utils.doctape import glue_keys\n", - "glue_keys(phase_info, display=False)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Running Aviary with Updated Parameters\n", - "\n", - "Let's now run Aviary with this multiphase mission and view the results." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/sazoppelt/opt/anaconda3/lib/python3.8/site-packages/aviary/subsystems/propulsion/engine_model.py:131: UserWarning: The value of aircraft:engine:wing_locations passed to EngineModel is type . Only the first entry in this iterable will be used.\n", - " warnings.warn(\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "The following variables have been overridden:\n", - " 'aircraft:design:touchdown_mass\n", - " 'aircraft:engine:mass\n", - " 'aircraft:fins:mass\n", - " 'aircraft:fuel:auxiliary_fuel_capacity\n", - " 'aircraft:fuel:fuselage_fuel_capacity\n", - " 'aircraft:fuel:total_capacity\n", - " 'aircraft:fuselage:planform_area\n", - " 'aircraft:fuselage:wetted_area\n", - " 'aircraft:horizontal_tail:wetted_area\n", - " 'aircraft:landing_gear:main_gear_oleo_length\n", - " 'aircraft:landing_gear:nose_gear_oleo_length\n", - " 'aircraft:vertical_tail:wetted_area\n", - " 'aircraft:wing:aspect_ratio\n", - " 'aircraft:wing:control_surface_area\n", - " 'aircraft:wing:wetted_area\n", - "\n", - "--- Constraint Report [traj] ---\n", - " --- climb_1 ---\n", - " [path] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- cruise_1 ---\n", - " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- climb_2 ---\n", - " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- cruise_2 ---\n", - " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- climb_3 ---\n", - " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- climb_4 ---\n", - " [initial] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " [final] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - " --- descent_1 ---\n", - " [path] 0.0000e+00 <= throttle <= 1.0000e+00 [unitless]\n", - "\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/sazoppelt/opt/anaconda3/lib/python3.8/site-packages/openmdao/recorders/sqlite_recorder.py:227: UserWarning:The existing case recorder file, dymos_solution.db, is being overwritten.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Model viewer data has already been recorded for Driver.\n", - "Full total jacobian was computed 3 times, taking 1.195775 seconds.\n", - "Total jacobian shape: (163, 135) \n", - "\n", - "\n", - "Jacobian shape: (163, 135) (7.26% nonzero)\n", - "FWD solves: 15 REV solves: 0\n", - "Total colors vs. total size: 15 vs 135 (88.89% improvement)\n", - "\n", - "Sparsity computed using tolerance: 1e-25\n", - "Time to compute sparsity: 1.1958 sec\n", - "Time to compute coloring: 0.1298 sec\n", - "Memory to compute coloring: -0.2969 MB\n", - "Coloring created on: 2025-01-14 13:44:26\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/Users/sazoppelt/opt/anaconda3/lib/python3.8/site-packages/openmdao/core/total_jac.py:1788: DerivativesWarning:Design variables [('traj.climb_1.t_initial', inds=[0])] have no impact on the constraints or objective.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Optimization terminated successfully (Exit mode 0)\n", - " Current function value: [2.8050298]\n", - " Iterations: 16\n", - " Function evaluations: 16\n", - " Gradient evaluations: 16\n", - "Optimization Complete\n", - "-----------------------------------\n" - ] - } - ], - "source": [ - "import aviary.api as av\n", - "\n", - "prob = av.run_aviary('models/test_aircraft/aircraft_for_bench_FwFm.csv',\n", - " phase_info, optimizer=\"SLSQP\", make_plots=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that we've run Aviary, we can look at the results.\n", - "Open up the automatically generated `traj_results_report.html` and scroll through it to visualize the results.\n", - "\n", - "Here are the altitude and Mach profiles:\n", - "\n", - "![Altitude and Mach Profiles](images/multiphase_flight_profile.png)\n", - "\n", - "\n", - "```{note}\n", - "Remember, we did not allow the optimizer to control either the Mach _or_ the altitude profiles. The optimizer varied the phase durations until the optimal mission profile was found.\n", - "```\n", - "\n", - "## What Next?\n", - "\n", - "The point of this doc page is to show that missions can be arbitrarily complex in terms of the number of phases and how they're classified.\n", - "If you want multiple climb, cruise, descent phases, that's absolutely something Aviary can handle.\n", - "\n", - "There are a lot of options for how you could modify this example.\n", - "You could:\n", - "\n", - "- enable the {glue:md}`optimize_mach` or {glue:md}`optimize_altitude` flags\n", - "- increase the {glue:md}`polynomial_control_order` so there's more flexibility in the optimized mission\n", - "- try different {glue:md}`target_range` values for the full mission range\n", - "- add an external subsystem to the phases\n", - "\n", - "Playing around with a model and seeing how different settings affect the optimization and resulting aircraft design is always an enlightening experience." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.19" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} From 0304988ebb0a1f8a062f5fc19d31fc31bd10f180 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Wed, 22 Jan 2025 11:16:21 -0500 Subject: [PATCH 019/147] Rename additional_flight_phases-2.ipynb to additional_flight_phases.ipynb --- ...ional_flight_phases-2.ipynb => additional_flight_phases.ipynb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename aviary/docs/examples/{additional_flight_phases-2.ipynb => additional_flight_phases.ipynb} (100%) diff --git a/aviary/docs/examples/additional_flight_phases-2.ipynb b/aviary/docs/examples/additional_flight_phases.ipynb similarity index 100% rename from aviary/docs/examples/additional_flight_phases-2.ipynb rename to aviary/docs/examples/additional_flight_phases.ipynb From f6ac6d204dc7791a8440c7feebf1674f22b2f9a8 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Wed, 22 Jan 2025 11:18:47 -0500 Subject: [PATCH 020/147] Add files via upload --- ...pled_aircraft_mission_optimization-3.ipynb | 570 ++++++++++++++++++ 1 file changed, 570 insertions(+) create mode 100644 aviary/docs/examples/coupled_aircraft_mission_optimization-3.ipynb diff --git a/aviary/docs/examples/coupled_aircraft_mission_optimization-3.ipynb b/aviary/docs/examples/coupled_aircraft_mission_optimization-3.ipynb new file mode 100644 index 000000000..67101c056 --- /dev/null +++ b/aviary/docs/examples/coupled_aircraft_mission_optimization-3.ipynb @@ -0,0 +1,570 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Coupled Aircraft-Mission Optimization\n", + "\n", + "One of the most exciting features of Aviary is the ability to formulate and solve coupled aircraft-mission design optimization problems.\n", + "Here, we mean that we are finding the optimal aircraft design parameters while simultaneously finding the optimal mission trajectory.\n", + "The reason why this is so valuable is that it enables exploration of a larger design space much more efficiently.\n", + "\n", + "Solving coupled design-mission problems leads to optimal designs that would not be findable without simultaneously designing the aircraft and the trajectory.\n", + "This is especially useful for unconventional aircraft designs, operations with complex missions, and many more future-focused studies than what is commonly flying today.\n", + "\n", + "This doc page builds up a coupled design problem and explains what we're doing along the way.\n", + "This process is relatively straightforward in Aviary.\n", + "We will briefly discuss the optimal results, but that is not necessarily the focus here.\n", + "Instead, we want to showcase how to do a simple coupled design study in Aviary.\n", + "\n", + "You can use this as a starting point for your own exciting aircraft and mission design studies.\n", + "\n", + "## Problem Definition and Explanation\n", + "\n", + "We will use a conventional single-aisle commercial aircraft design as our starting point.\n", + "For all of these examples we allow the aircraft to be sized by the optimizer.\n", + "This means the gross takeoff weight is controlled to meet a mass balance.\n", + "\n", + "We will perform four different optimization cases as part of this study:\n", + "\n", + "- fixed mission profile, fixed aircraft wing aspect ratio\n", + "- fixed mission profile, optimized aircraft wing aspect ratio\n", + "- optimized mission profile, fixed aircraft wing aspect ratio\n", + "- optimized mission profile, optimized aircraft wing aspect ratio\n", + "\n", + "We'll provide more detail individually for each case.\n", + "\n", + "When we call Aviary, we will use a common `phase_info` object that we modify for each optimization case shown here:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "phase_info = {\n", + " \"pre_mission\": {\"include_takeoff\": False, \"optimize_mass\": True},\n", + " \"climb_1\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 5,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.2, \"unitless\"),\n", + " \"final_mach\": (0.72, \"unitless\"),\n", + " \"mach_bounds\": ((0.18, 0.84), \"unitless\"),\n", + " \"initial_altitude\": (0.0, \"ft\"),\n", + " \"final_altitude\": (32500.0, \"ft\"),\n", + " \"altitude_bounds\": ((0.0, 33000.0), \"ft\"),\n", + " \"throttle_enforcement\": \"path_constraint\",\n", + " \"fix_initial\": True,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((0.0, 0.0), \"min\"),\n", + " \"duration_bounds\": ((35.0, 105.0), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([0, 70], \"min\")},\n", + " },\n", + " \"cruise\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 5,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.72, \"unitless\"),\n", + " \"final_mach\": (0.80, \"unitless\"),\n", + " \"mach_bounds\": ((0.7, 0.84), \"unitless\"),\n", + " \"initial_altitude\": (32500.0, \"ft\"),\n", + " \"final_altitude\": (36000.0, \"ft\"),\n", + " \"altitude_bounds\": ((32000.0, 36500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"boundary_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": False,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((35.0, 105.0), \"min\"),\n", + " \"duration_bounds\": ((91.5, 274.5), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([70, 183], \"min\")},\n", + " },\n", + " \"descent_1\": {\n", + " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", + " \"user_options\": {\n", + " \"optimize_mach\": False,\n", + " \"optimize_altitude\": False,\n", + " \"polynomial_control_order\": 1,\n", + " \"num_segments\": 5,\n", + " \"order\": 3,\n", + " \"solve_for_distance\": False,\n", + " \"initial_mach\": (0.72, \"unitless\"),\n", + " \"final_mach\": (0.21, \"unitless\"),\n", + " \"mach_bounds\": ((0.19, 0.84), \"unitless\"),\n", + " \"initial_altitude\": (36000.0, \"ft\"),\n", + " \"final_altitude\": (0.0, \"ft\"),\n", + " \"altitude_bounds\": ((0.0, 36500.0), \"ft\"),\n", + " \"throttle_enforcement\": \"path_constraint\",\n", + " \"fix_initial\": False,\n", + " \"constrain_final\": True,\n", + " \"fix_duration\": False,\n", + " \"initial_bounds\": ((126.5, 379.5), \"min\"),\n", + " \"duration_bounds\": ((25.0, 75.0), \"min\"),\n", + " },\n", + " \"initial_guesses\": {\"times\": ([253, 50], \"min\")},\n", + " },\n", + " \"post_mission\": {\n", + " \"include_landing\": False,\n", + " \"constrain_range\": True,\n", + " \"target_range\": (2080, \"nmi\"),\n", + " },\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.utils.doctape import check_value, glue_variable\n", + "from aviary.interface.utils.check_phase_info import check_phase_info, HEIGHT_ENERGY\n", + "\n", + "# checking that the phase info example is valid\n", + "check_phase_info(phase_info, HEIGHT_ENERGY);\n", + "\n", + "# checking that optimize mach and altitude are False in the example\n", + "for phase, info in phase_info.items():\n", + " if phase not in ('pre_mission','post_mission'):\n", + " opt_mach = info['user_options']['optimize_mach']\n", + " check_value(opt_mach,False)\n", + " opt_alt = info['user_options']['optimize_altitude']\n", + " check_value(opt_alt,False)\n", + "\n", + "# gluing optimize_altitude and optimize_mach\n", + "glue_variable('optimize_altitude','optimize_altitude = False', md_code=True)\n", + "glue_variable('optimize_mach','optimize_mach = False', md_code=True)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, let us explain each case, formulate the Aviary problem, and optimize.\n", + "We'll discuss the results from each case and explain why they vary.\n", + "\n", + "## Fixed Mission Profile, Fixed Aircraft Wing Aspect Ratio\n", + "\n", + "First, let us run Aviary with a simple setup: fly a prescribed mission profile with an unchanged wing design.\n", + "Here we are varying the durations of each of the phases (climb, cruise, and descent) to minimize fuel burn across the mission.\n", + "The altitude and Mach profiles of the mission are fixed because {glue:md}`optimize_altitude` and {glue:md}`optimize_mach` for each of the phases in the `phase_info` object." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "from openmdao.core.problem import _clear_problem_names\n", + "_clear_problem_names() # need to reset these to simulate separate runs\n", + "from openmdao.utils.reports_system import clear_reports\n", + "clear_reports()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import aviary.api as av\n", + "\n", + "aircraft_filename = 'models/test_aircraft/aircraft_for_bench_FwFm.csv'\n", + "optimizer = \"IPOPT\"\n", + "make_plots = True\n", + "max_iter = 100\n", + "\n", + "prob = av.run_aviary(aircraft_filename, phase_info, optimizer=optimizer,\n", + " make_plots=make_plots, max_iter=max_iter)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now that we've run the case successfully, let's save and print out the fuel burn value:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fixed_mission_fixed_wing_fuel_burn = prob.get_val(av.Mission.Summary.FUEL_BURNED, units='kg')[0]\n", + "fixed_mission_fixed_wing_aspect_ratio = prob.get_val(av.Aircraft.Wing.ASPECT_RATIO)[0]\n", + "print('Mission fuel burn, kg:', fixed_mission_fixed_wing_fuel_burn)\n", + "print('Aspect ratio:', fixed_mission_fixed_wing_aspect_ratio)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "# Testing Cell\n", + "from aviary.interface.methods_for_level1 import run_aviary\n", + "from aviary.utils.doctape import glue_variable\n", + "\n", + "glue_variable(run_aviary.__name__,md_code=True)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Fixed Mission Profile, Optimized Aircraft Wing Aspect Ratio\n", + "\n", + "Now we will use the exact same `phase_info` object but set up our Aviary problem such that the aspect ratio of the wing is a design variable.\n", + "This means that Aviary is optimizing the wing aspect ratio while flying the same mission profile as above.\n", + "We would expect that by varying the wing aspect ratio, Aviary could find a lower fuel burn value.\n", + "\n", + "```{note}\n", + "All of the realistic design tradeoffs associated with varying the wing aspect ratio are not necessarily captured in this problem, e.g. the wing structure would need to change. We are simply using this as an example of an aircraft design variable available in Aviary.\n", + "```\n", + "\n", + "When we want to add an aircraft design variable to the Aviary problem, we need to use the Level 2 interface for Aviary.\n", + "This means we can no longer use the all-inclusive {glue:md}`run_aviary` function and instead need to call its constituent methods individually.\n", + "This allows us to insert a line adding the wing aspect ratio as a design variable as shown below.\n", + "This line is highlighted with an in-line comment." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "from openmdao.core.problem import _clear_problem_names\n", + "_clear_problem_names() # need to reset these to simulate separate runs\n", + "from openmdao.utils.reports_system import clear_reports\n", + "clear_reports()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "prob = av.AviaryProblem(av.AnalysisScheme.COLLOCATION)\n", + "\n", + "# Load aircraft and options data from user\n", + "# Allow for user overrides here\n", + "prob.load_inputs(aircraft_filename, phase_info)\n", + "\n", + "prob.check_and_preprocess_inputs()\n", + "\n", + "prob.add_pre_mission_systems()\n", + "\n", + "prob.add_phases()\n", + "\n", + "prob.add_post_mission_systems()\n", + "\n", + "# Link phases and variables\n", + "prob.link_phases()\n", + "\n", + "prob.add_driver(optimizer, max_iter=max_iter)\n", + "\n", + "prob.add_design_variables()\n", + "\n", + "# The following line is an example of how to add a design variable for the aspect ratio of the wing\n", + "prob.model.add_design_var(av.Aircraft.Wing.ASPECT_RATIO, lower=10., upper=14., ref=12.)\n", + "\n", + "# Load optimization problem formulation\n", + "# Detail which variables the optimizer can control\n", + "prob.add_objective()\n", + "\n", + "prob.setup()\n", + "\n", + "prob.set_initial_guesses()\n", + "\n", + "prob.run_aviary_problem(make_plots=make_plots)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fixed_mission_optimized_wing_fuel_burn = prob.get_val(av.Mission.Summary.FUEL_BURNED, units='kg')[0]\n", + "fixed_mission_optimized_wing_aspect_ratio = prob.get_val(av.Aircraft.Wing.ASPECT_RATIO)[0]\n", + "print('Mission fuel burn, kg:', fixed_mission_optimized_wing_fuel_burn)\n", + "print('Aspect ratio:', fixed_mission_optimized_wing_aspect_ratio)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As expected, the optimal fuel burn value is lower for this case.\n", + "We'll discuss this in more detail after running two more cases.\n", + "\n", + "## Optimized Mission Profile, Fixed Aircraft Wing Aspect Ratio\n", + "\n", + "We just investigated giving the optimizer flexibility with the aircraft design while not varying the mission.\n", + "Let's now look at the results when we optimize the mission but keep the wing aspect ratio unchanged.\n", + "\n", + "To do this, we will allow the optimizer to control the Mach and altitude profiles by modifying the `phase_info` object:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "from openmdao.core.problem import _clear_problem_names\n", + "_clear_problem_names() # need to reset these to simulate separate runs\n", + "from openmdao.utils.reports_system import clear_reports\n", + "clear_reports()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "phase_info['climb_1']['user_options']['optimize_mach'] = True\n", + "phase_info['climb_1']['user_options']['optimize_altitude'] = True\n", + "phase_info['cruise']['user_options']['optimize_mach'] = True\n", + "phase_info['cruise']['user_options']['optimize_altitude'] = True\n", + "phase_info['descent_1']['user_options']['optimize_mach'] = True\n", + "phase_info['descent_1']['user_options']['optimize_altitude'] = True\n", + "\n", + "prob = av.run_aviary(aircraft_filename, phase_info, optimizer=optimizer,\n", + " make_plots=make_plots, max_iter=max_iter)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, let's see the fuel burn:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "optimized_mission_fixed_wing_fuel_burn = prob.get_val(av.Mission.Summary.FUEL_BURNED, units='kg')[0]\n", + "optimized_mission_fixed_wing_aspect_ratio = prob.get_val(av.Aircraft.Wing.ASPECT_RATIO)[0]\n", + "print('Mission fuel burn, kg:', optimized_mission_fixed_wing_fuel_burn)\n", + "print('Aspect ratio:', optimized_mission_fixed_wing_aspect_ratio)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Optimizing the mission did not have nearly as large of an impact on the fuel burn as optimizing the aspect ratio did.\n", + "However, the fuel burn still decreased.\n", + "Let us now look at the fully coupled case.\n", + "\n", + "## Optimized Mission Profile, Optimized Aircraft Wing Aspect Ratio\n", + "\n", + "Remember we have already modified the `phase_info` object so that the Mach and altitude profiles are optimized.\n", + "Now we return to the Level 2 way of running the problem with the wing aspect ratio as a design variable." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "remove-cell" + ] + }, + "outputs": [], + "source": [ + "from openmdao.core.problem import _clear_problem_names\n", + "_clear_problem_names() # need to reset these to simulate separate runs\n", + "from openmdao.utils.reports_system import clear_reports\n", + "clear_reports()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "prob = av.AviaryProblem(av.AnalysisScheme.COLLOCATION)\n", + "\n", + "# Load aircraft and options data from user\n", + "# Allow for user overrides here\n", + "prob.load_inputs(aircraft_filename, phase_info)\n", + "\n", + "prob.check_and_preprocess_inputs()\n", + "# Preprocess inputs\n", + "prob.add_pre_mission_systems()\n", + "\n", + "prob.add_phases()\n", + "\n", + "prob.add_post_mission_systems()\n", + "\n", + "# Link phases and variables\n", + "prob.link_phases()\n", + "\n", + "prob.add_driver(optimizer, max_iter=max_iter)\n", + "\n", + "prob.add_design_variables()\n", + "\n", + "# prob.model.add_design_var(av.Aircraft.Engine.SCALED_SLS_THRUST, lower=25.e3, upper=30.e3, units='lbf', ref=28.e3)\n", + "prob.model.add_design_var(av.Aircraft.Wing.ASPECT_RATIO, lower=10., upper=14., ref=12.)\n", + "\n", + "# Load optimization problem formulation\n", + "# Detail which variables the optimizer can control\n", + "prob.add_objective()\n", + "\n", + "prob.setup()\n", + "\n", + "prob.set_initial_guesses()\n", + "\n", + "prob.run_aviary_problem(make_plots=make_plots)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "All right, let's check out this final case's fuel burn value:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "optimized_mission_optimized_wing_fuel_burn = prob.get_val(av.Mission.Summary.FUEL_BURNED, units='kg')[0]\n", + "optimized_mission_optimized_wing_aspect_ratio = prob.get_val(av.Aircraft.Wing.ASPECT_RATIO)[0]\n", + "print('Mission fuel burn, kg:', optimized_mission_optimized_wing_fuel_burn)\n", + "print('Aspect ratio:', optimized_mission_optimized_wing_aspect_ratio)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Cool, it's the lowest yet!\n", + "Let's discuss these results in more detail now.\n", + "\n", + "## Summary and Takeaways\n", + "\n", + "We have showcased one of Aviary's most powerful capabilities here -- the ability to simultaneously design an aircraft and optimal trajectory.\n", + "By building up problem complexity, we can see how optimizing different parts of the problem lead to optimization objective improvements.\n", + "\n", + "Here is a summary table of the results:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [ + "hide-input" + ] + }, + "outputs": [], + "source": [ + "import pandas as pd\n", + "\n", + "# Create a dictionary with the data\n", + "data = {\n", + " 'Case': ['Fixed Mission, Fixed Wing', 'Fixed Mission, Optimized Wing', 'Optimized Mission, Fixed Wing', 'Optimized Mission, Optimized Wing'],\n", + " 'Optimize Mission': ['-', '-', '✓', '✓'],\n", + " 'Optimize Wing': ['-', '✓', '-', '✓'],\n", + " 'Aspect Ratio': [fixed_mission_fixed_wing_aspect_ratio, fixed_mission_optimized_wing_aspect_ratio, optimized_mission_fixed_wing_aspect_ratio, optimized_mission_optimized_wing_aspect_ratio],\n", + " 'Fuel Burn Value': [fixed_mission_fixed_wing_fuel_burn, fixed_mission_optimized_wing_fuel_burn, optimized_mission_fixed_wing_fuel_burn, optimized_mission_optimized_wing_fuel_burn]\n", + "}\n", + "\n", + "# Create a DataFrame from the dictionary\n", + "df = pd.DataFrame(data).round(2)\n", + "\n", + "# Display the DataFrame\n", + "df\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We see that the fully coupled case finds the lowest fuel burn value, as expected.\n", + "In both cases where the wing aspect ratio is optimized, it moves to the higher bound.\n", + "\n", + "If we didn't simultaneously design the aircraft and the mission, you would have to manually iterate by first optimizing the aircraft, then the mission, then the aircraft again, etc.\n", + "This cumbersome process is known as sequential optimization and can lead to non-optimal results for coupled systems, as detailed in Section 13.1 of the [Engineering Design Optimization textbook](https://flowlab.groups.et.byu.net/mdobook.pdf) (available for free).\n", + "\n", + "Aviary is unique in its ability to solve these coupled systems using efficient gradient-based optimization.\n", + "\n", + "This doc page contains a simple example, but the true power of coupled multidisciplinary optimization lies in solving more complex design problems.\n", + "We hope that you can effectively use Aviary to optimally design the next generation of exciting aircraft!\n" + ] + } + ], + "metadata": { + "celltoolbar": "Tags", + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.2" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} From b8185c1d443f948935938422408d5a9b0cb8a264 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Wed, 22 Jan 2025 11:19:20 -0500 Subject: [PATCH 021/147] Delete aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb --- ...oupled_aircraft_mission_optimization.ipynb | 597 ------------------ 1 file changed, 597 deletions(-) delete mode 100644 aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb diff --git a/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb b/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb deleted file mode 100644 index 2915da6b4..000000000 --- a/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb +++ /dev/null @@ -1,597 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Coupled Aircraft-Mission Optimization\n", - "\n", - "One of the most exciting features of Aviary is the ability to formulate and solve coupled aircraft-mission design optimization problems.\n", - "Here, we mean that we are finding the optimal aircraft design parameters while simultaneously finding the optimal mission trajectory.\n", - "The reason why this is so valuable is that it enables exploration of a larger design space much more efficiently.\n", - "\n", - "Solving coupled design-mission problems leads to optimal designs that would not be findable without simultaneously designing the aircraft and the trajectory.\n", - "This is especially useful for unconventional aircraft designs, operations with complex missions, and many more future-focused studies than what is commonly flying today.\n", - "\n", - "This doc page builds up a coupled design problem and explains what we're doing along the way.\n", - "This process is relatively straightforward in Aviary.\n", - "We will briefly discuss the optimal results, but that is not necessarily the focus here.\n", - "Instead, we want to showcase how to do a simple coupled design study in Aviary.\n", - "\n", - "You can use this as a starting point for your own exciting aircraft and mission design studies.\n", - "\n", - "## Problem Definition and Explanation\n", - "\n", - "We will use a conventional single-aisle commercial aircraft design as our starting point.\n", - "For all of these examples we allow the aircraft to be sized by the optimizer.\n", - "This means the gross takeoff weight is controlled to meet a mass balance.\n", - "\n", - "We will perform four different optimization cases as part of this study:\n", - "\n", - "- fixed mission profile, fixed aircraft wing aspect ratio\n", - "- fixed mission profile, optimized aircraft wing aspect ratio\n", - "- optimized mission profile, fixed aircraft wing aspect ratio\n", - "- optimized mission profile, optimized aircraft wing aspect ratio\n", - "\n", - "We'll provide more detail individually for each case.\n", - "\n", - "When we call Aviary, we will use a common `phase_info` object that we modify for each optimization case shown here:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "phase_info = {\n", - " \"pre_mission\": {\"include_takeoff\": False, \"optimize_mass\": True},\n", - " \"climb_1\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 5,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.2, \"unitless\"),\n", - " \"final_mach\": (0.72, \"unitless\"),\n", - " \"mach_bounds\": ((0.18, 0.84), \"unitless\"),\n", - " \"initial_altitude\": (0.0, \"ft\"),\n", - " \"final_altitude\": (32500.0, \"ft\"),\n", - " \"altitude_bounds\": ((0.0, 33000.0), \"ft\"),\n", - " \"throttle_enforcement\": \"path_constraint\",\n", - " \"fix_initial\": True,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((0.0, 0.0), \"min\"),\n", - " \"duration_bounds\": ((35.0, 105.0), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([0, 70], \"min\")},\n", - " },\n", - " \"cruise\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 5,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.72, \"unitless\"),\n", - " \"final_mach\": (0.80, \"unitless\"),\n", - " \"mach_bounds\": ((0.7, 0.84), \"unitless\"),\n", - " \"initial_altitude\": (32500.0, \"ft\"),\n", - " \"final_altitude\": (36000.0, \"ft\"),\n", - " \"altitude_bounds\": ((32000.0, 36500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"boundary_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": False,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((35.0, 105.0), \"min\"),\n", - " \"duration_bounds\": ((91.5, 274.5), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([70, 183], \"min\")},\n", - " },\n", - " \"descent_1\": {\n", - " \"subsystem_options\": {\"core_aerodynamics\": {\"method\": \"computed\"}},\n", - " \"user_options\": {\n", - " \"optimize_mach\": False,\n", - " \"optimize_altitude\": False,\n", - " \"polynomial_control_order\": 1,\n", - " \"num_segments\": 5,\n", - " \"order\": 3,\n", - " \"solve_for_distance\": False,\n", - " \"initial_mach\": (0.72, \"unitless\"),\n", - " \"final_mach\": (0.21, \"unitless\"),\n", - " \"mach_bounds\": ((0.19, 0.84), \"unitless\"),\n", - " \"initial_altitude\": (36000.0, \"ft\"),\n", - " \"final_altitude\": (0.0, \"ft\"),\n", - " \"altitude_bounds\": ((0.0, 36500.0), \"ft\"),\n", - " \"throttle_enforcement\": \"path_constraint\",\n", - " \"fix_initial\": False,\n", - " \"constrain_final\": True,\n", - " \"fix_duration\": False,\n", - " \"initial_bounds\": ((126.5, 379.5), \"min\"),\n", - " \"duration_bounds\": ((25.0, 75.0), \"min\"),\n", - " },\n", - " \"initial_guesses\": {\"times\": ([253, 50], \"min\")},\n", - " },\n", - " \"post_mission\": {\n", - " \"include_landing\": False,\n", - " \"constrain_range\": True,\n", - " \"target_range\": (2080, \"nmi\"),\n", - " },\n", - "}" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [ - { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'aviary.utils.doctape'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[7], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# Testing Cell\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mdoctape\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m check_value, glue_variable\n\u001b[1;32m 3\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01maviary\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01minterface\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mutils\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mcheck_phase_info\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m check_phase_info, HEIGHT_ENERGY\n\u001b[1;32m 5\u001b[0m \u001b[38;5;66;03m# checking that the phase info example is valid\u001b[39;00m\n", - "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'aviary.utils.doctape'" - ] - } - ], - "source": [ - "# Testing Cell\n", - "from aviary.utils.doctape import check_value, glue_variable\n", - "from aviary.interface.utils.check_phase_info import check_phase_info, HEIGHT_ENERGY\n", - "\n", - "# checking that the phase info example is valid\n", - "check_phase_info(phase_info, HEIGHT_ENERGY);\n", - "\n", - "# checking that optimize mach and altitude are False in the example\n", - "for phase, info in phase_info.items():\n", - " if phase not in ('pre_mission','post_mission'):\n", - " opt_mach = info['user_options']['optimize_mach']\n", - " check_value(opt_mach,False)\n", - " opt_alt = info['user_options']['optimize_altitude']\n", - " check_value(opt_alt,False)\n", - "\n", - "# gluing optimize_altitude and optimize_mach\n", - "glue_variable('optimize_altitude','optimize_altitude = False', md_code=True)\n", - "glue_variable('optimize_mach','optimize_mach = False', md_code=True)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, let us explain each case, formulate the Aviary problem, and optimize.\n", - "We'll discuss the results from each case and explain why they vary.\n", - "\n", - "## Fixed Mission Profile, Fixed Aircraft Wing Aspect Ratio\n", - "\n", - "First, let us run Aviary with a simple setup: fly a prescribed mission profile with an unchanged wing design.\n", - "Here we are varying the durations of each of the phases (climb, cruise, and descent) to minimize fuel burn across the mission.\n", - "The altitude and Mach profiles of the mission are fixed because {glue:md}`optimize_altitude` and {glue:md}`optimize_mach` for each of the phases in the `phase_info` object." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [], - "source": [ - "from openmdao.core.problem import _clear_problem_names\n", - "_clear_problem_names() # need to reset these to simulate separate runs\n", - "from openmdao.utils.reports_system import clear_reports\n", - "clear_reports()" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "ename": "RuntimeError", - "evalue": "pyOptSparseDriver is not available, pyOptsparse is not installed.", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mRuntimeError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[9], line 8\u001b[0m\n\u001b[1;32m 5\u001b[0m make_plots \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[1;32m 6\u001b[0m max_iter \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m100\u001b[39m\n\u001b[0;32m----> 8\u001b[0m prob \u001b[38;5;241m=\u001b[39m \u001b[43mav\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun_aviary\u001b[49m\u001b[43m(\u001b[49m\u001b[43maircraft_filename\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mphase_info\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43moptimizer\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43moptimizer\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 9\u001b[0m \u001b[43m \u001b[49m\u001b[43mmake_plots\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmake_plots\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmax_iter\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmax_iter\u001b[49m\u001b[43m)\u001b[49m\n", - "File \u001b[0;32m~/opt/anaconda3/lib/python3.8/site-packages/aviary/interface/methods_for_level1.py:81\u001b[0m, in \u001b[0;36mrun_aviary\u001b[0;34m(aircraft_filename, phase_info, optimizer, analysis_scheme, objective_type, record_filename, restart_filename, max_iter, run_driver, make_plots, phase_info_parameterization, optimization_history_filename)\u001b[0m\n\u001b[1;32m 78\u001b[0m \u001b[38;5;66;03m# Link phases and variables\u001b[39;00m\n\u001b[1;32m 79\u001b[0m prob\u001b[38;5;241m.\u001b[39mlink_phases()\n\u001b[0;32m---> 81\u001b[0m \u001b[43mprob\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43madd_driver\u001b[49m\u001b[43m(\u001b[49m\u001b[43moptimizer\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmax_iter\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmax_iter\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 83\u001b[0m prob\u001b[38;5;241m.\u001b[39madd_design_variables()\n\u001b[1;32m 85\u001b[0m \u001b[38;5;66;03m# Load optimization problem formulation\u001b[39;00m\n\u001b[1;32m 86\u001b[0m \u001b[38;5;66;03m# Detail which variables the optimizer can control\u001b[39;00m\n", - "File \u001b[0;32m~/opt/anaconda3/lib/python3.8/site-packages/aviary/interface/methods_for_level2.py:1502\u001b[0m, in \u001b[0;36mAviaryProblem.add_driver\u001b[0;34m(self, optimizer, use_coloring, max_iter, debug_print)\u001b[0m\n\u001b[1;32m 1500\u001b[0m driver \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdriver \u001b[38;5;241m=\u001b[39m om\u001b[38;5;241m.\u001b[39mScipyOptimizeDriver()\n\u001b[1;32m 1501\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m-> 1502\u001b[0m driver \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdriver \u001b[38;5;241m=\u001b[39m \u001b[43mom\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpyOptSparseDriver\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1504\u001b[0m driver\u001b[38;5;241m.\u001b[39moptions[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124moptimizer\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m optimizer\n\u001b[1;32m 1505\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m use_coloring:\n", - "File \u001b[0;32m~/opt/anaconda3/lib/python3.8/site-packages/openmdao/drivers/pyoptsparse_driver.py:193\u001b[0m, in \u001b[0;36mpyOptSparseDriver.__init__\u001b[0;34m(self, **kwargs)\u001b[0m\n\u001b[1;32m 188\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 189\u001b[0m \u001b[38;5;124;03mInitialize pyopt.\u001b[39;00m\n\u001b[1;32m 190\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 191\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m pyoptsparse \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 192\u001b[0m \u001b[38;5;66;03m# pyoptsparse is not installed\u001b[39;00m\n\u001b[0;32m--> 193\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mRuntimeError\u001b[39;00m(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mpyOptSparseDriver is not available, pyOptsparse is not installed.\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 195\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(pyoptsparse, \u001b[38;5;167;01mException\u001b[39;00m):\n\u001b[1;32m 196\u001b[0m \u001b[38;5;66;03m# there is some other issue with the pyoptsparse installation\u001b[39;00m\n\u001b[1;32m 197\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m pyoptsparse\n", - "\u001b[0;31mRuntimeError\u001b[0m: pyOptSparseDriver is not available, pyOptsparse is not installed." - ] - } - ], - "source": [ - "import aviary.api as av\n", - "\n", - "aircraft_filename = 'models/test_aircraft/aircraft_for_bench_FwFm.csv'\n", - "optimizer = \"IPOPT\"\n", - "make_plots = True\n", - "max_iter = 100\n", - "\n", - "prob = av.run_aviary(aircraft_filename, phase_info, optimizer=optimizer,\n", - " make_plots=make_plots, max_iter=max_iter)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now that we've run the case successfully, let's save and print out the fuel burn value:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fixed_mission_fixed_wing_fuel_burn = prob.get_val(av.Mission.Summary.FUEL_BURNED, units='kg')[0]\n", - "fixed_mission_fixed_wing_aspect_ratio = prob.get_val(av.Aircraft.Wing.ASPECT_RATIO)[0]\n", - "print('Mission fuel burn, kg:', fixed_mission_fixed_wing_fuel_burn)\n", - "print('Aspect ratio:', fixed_mission_fixed_wing_aspect_ratio)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [], - "source": [ - "# Testing Cell\n", - "from aviary.interface.methods_for_level1 import run_aviary\n", - "from aviary.utils.doctape import glue_variable\n", - "\n", - "glue_variable(run_aviary.__name__,md_code=True)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Fixed Mission Profile, Optimized Aircraft Wing Aspect Ratio\n", - "\n", - "Now we will use the exact same `phase_info` object but set up our Aviary problem such that the aspect ratio of the wing is a design variable.\n", - "This means that Aviary is optimizing the wing aspect ratio while flying the same mission profile as above.\n", - "We would expect that by varying the wing aspect ratio, Aviary could find a lower fuel burn value.\n", - "\n", - "```{note}\n", - "All of the realistic design tradeoffs associated with varying the wing aspect ratio are not necessarily captured in this problem, e.g. the wing structure would need to change. We are simply using this as an example of an aircraft design variable available in Aviary.\n", - "```\n", - "\n", - "When we want to add an aircraft design variable to the Aviary problem, we need to use the Level 2 interface for Aviary.\n", - "This means we can no longer use the all-inclusive {glue:md}`run_aviary` function and instead need to call its constituent methods individually.\n", - "This allows us to insert a line adding the wing aspect ratio as a design variable as shown below.\n", - "This line is highlighted with an in-line comment." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [], - "source": [ - "from openmdao.core.problem import _clear_problem_names\n", - "_clear_problem_names() # need to reset these to simulate separate runs\n", - "from openmdao.utils.reports_system import clear_reports\n", - "clear_reports()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "prob = av.AviaryProblem(av.AnalysisScheme.COLLOCATION)\n", - "\n", - "# Load aircraft and options data from user\n", - "# Allow for user overrides here\n", - "prob.load_inputs(aircraft_filename, phase_info)\n", - "\n", - "prob.check_and_preprocess_inputs()\n", - "\n", - "prob.add_pre_mission_systems()\n", - "\n", - "prob.add_phases()\n", - "\n", - "prob.add_post_mission_systems()\n", - "\n", - "# Link phases and variables\n", - "prob.link_phases()\n", - "\n", - "prob.add_driver(optimizer, max_iter=max_iter)\n", - "\n", - "prob.add_design_variables()\n", - "\n", - "# The following line is an example of how to add a design variable for the aspect ratio of the wing\n", - "prob.model.add_design_var(av.Aircraft.Wing.ASPECT_RATIO, lower=10., upper=14., ref=12.)\n", - "\n", - "# Load optimization problem formulation\n", - "# Detail which variables the optimizer can control\n", - "prob.add_objective()\n", - "\n", - "prob.setup()\n", - "\n", - "prob.set_initial_guesses()\n", - "\n", - "prob.run_aviary_problem(make_plots=make_plots)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fixed_mission_optimized_wing_fuel_burn = prob.get_val(av.Mission.Summary.FUEL_BURNED, units='kg')[0]\n", - "fixed_mission_optimized_wing_aspect_ratio = prob.get_val(av.Aircraft.Wing.ASPECT_RATIO)[0]\n", - "print('Mission fuel burn, kg:', fixed_mission_optimized_wing_fuel_burn)\n", - "print('Aspect ratio:', fixed_mission_optimized_wing_aspect_ratio)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "As expected, the optimal fuel burn value is lower for this case.\n", - "We'll discuss this in more detail after running two more cases.\n", - "\n", - "## Optimized Mission Profile, Fixed Aircraft Wing Aspect Ratio\n", - "\n", - "We just investigated giving the optimizer flexibility with the aircraft design while not varying the mission.\n", - "Let's now look at the results when we optimize the mission but keep the wing aspect ratio unchanged.\n", - "\n", - "To do this, we will allow the optimizer to control the Mach and altitude profiles by modifying the `phase_info` object:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [], - "source": [ - "from openmdao.core.problem import _clear_problem_names\n", - "_clear_problem_names() # need to reset these to simulate separate runs\n", - "from openmdao.utils.reports_system import clear_reports\n", - "clear_reports()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "phase_info['climb_1']['user_options']['optimize_mach'] = True\n", - "phase_info['climb_1']['user_options']['optimize_altitude'] = True\n", - "phase_info['cruise']['user_options']['optimize_mach'] = True\n", - "phase_info['cruise']['user_options']['optimize_altitude'] = True\n", - "phase_info['descent_1']['user_options']['optimize_mach'] = True\n", - "phase_info['descent_1']['user_options']['optimize_altitude'] = True\n", - "\n", - "prob = av.run_aviary(aircraft_filename, phase_info, optimizer=optimizer,\n", - " make_plots=make_plots, max_iter=max_iter)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, let's see the fuel burn:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "optimized_mission_fixed_wing_fuel_burn = prob.get_val(av.Mission.Summary.FUEL_BURNED, units='kg')[0]\n", - "optimized_mission_fixed_wing_aspect_ratio = prob.get_val(av.Aircraft.Wing.ASPECT_RATIO)[0]\n", - "print('Mission fuel burn, kg:', optimized_mission_fixed_wing_fuel_burn)\n", - "print('Aspect ratio:', optimized_mission_fixed_wing_aspect_ratio)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Optimizing the mission did not have nearly as large of an impact on the fuel burn as optimizing the aspect ratio did.\n", - "However, the fuel burn still decreased.\n", - "Let us now look at the fully coupled case.\n", - "\n", - "## Optimized Mission Profile, Optimized Aircraft Wing Aspect Ratio\n", - "\n", - "Remember we have already modified the `phase_info` object so that the Mach and altitude profiles are optimized.\n", - "Now we return to the Level 2 way of running the problem with the wing aspect ratio as a design variable." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "remove-cell" - ] - }, - "outputs": [], - "source": [ - "from openmdao.core.problem import _clear_problem_names\n", - "_clear_problem_names() # need to reset these to simulate separate runs\n", - "from openmdao.utils.reports_system import clear_reports\n", - "clear_reports()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "prob = av.AviaryProblem(av.AnalysisScheme.COLLOCATION)\n", - "\n", - "# Load aircraft and options data from user\n", - "# Allow for user overrides here\n", - "prob.load_inputs(aircraft_filename, phase_info)\n", - "\n", - "prob.check_and_preprocess_inputs()\n", - "# Preprocess inputs\n", - "prob.add_pre_mission_systems()\n", - "\n", - "prob.add_phases()\n", - "\n", - "prob.add_post_mission_systems()\n", - "\n", - "# Link phases and variables\n", - "prob.link_phases()\n", - "\n", - "prob.add_driver(optimizer, max_iter=max_iter)\n", - "\n", - "prob.add_design_variables()\n", - "\n", - "# prob.model.add_design_var(av.Aircraft.Engine.SCALED_SLS_THRUST, lower=25.e3, upper=30.e3, units='lbf', ref=28.e3)\n", - "prob.model.add_design_var(av.Aircraft.Wing.ASPECT_RATIO, lower=10., upper=14., ref=12.)\n", - "\n", - "# Load optimization problem formulation\n", - "# Detail which variables the optimizer can control\n", - "prob.add_objective()\n", - "\n", - "prob.setup()\n", - "\n", - "prob.set_initial_guesses()\n", - "\n", - "prob.run_aviary_problem(make_plots=make_plots)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "All right, let's check out this final case's fuel burn value:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "optimized_mission_optimized_wing_fuel_burn = prob.get_val(av.Mission.Summary.FUEL_BURNED, units='kg')[0]\n", - "optimized_mission_optimized_wing_aspect_ratio = prob.get_val(av.Aircraft.Wing.ASPECT_RATIO)[0]\n", - "print('Mission fuel burn, kg:', optimized_mission_optimized_wing_fuel_burn)\n", - "print('Aspect ratio:', optimized_mission_optimized_wing_aspect_ratio)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Cool, it's the lowest yet!\n", - "Let's discuss these results in more detail now.\n", - "\n", - "## Summary and Takeaways\n", - "\n", - "We have showcased one of Aviary's most powerful capabilities here -- the ability to simultaneously design an aircraft and optimal trajectory.\n", - "By building up problem complexity, we can see how optimizing different parts of the problem lead to optimization objective improvements.\n", - "\n", - "Here is a summary table of the results:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "tags": [ - "hide-input" - ] - }, - "outputs": [], - "source": [ - "import pandas as pd\n", - "\n", - "# Create a dictionary with the data\n", - "data = {\n", - " 'Case': ['Fixed Mission, Fixed Wing', 'Fixed Mission, Optimized Wing', 'Optimized Mission, Fixed Wing', 'Optimized Mission, Optimized Wing'],\n", - " 'Optimize Mission': ['-', '-', '✓', '✓'],\n", - " 'Optimize Wing': ['-', '✓', '-', '✓'],\n", - " 'Aspect Ratio': [fixed_mission_fixed_wing_aspect_ratio, fixed_mission_optimized_wing_aspect_ratio, optimized_mission_fixed_wing_aspect_ratio, optimized_mission_optimized_wing_aspect_ratio],\n", - " 'Fuel Burn Value': [fixed_mission_fixed_wing_fuel_burn, fixed_mission_optimized_wing_fuel_burn, optimized_mission_fixed_wing_fuel_burn, optimized_mission_optimized_wing_fuel_burn]\n", - "}\n", - "\n", - "# Create a DataFrame from the dictionary\n", - "df = pd.DataFrame(data).round(2)\n", - "\n", - "# Display the DataFrame\n", - "df\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We see that the fully coupled case finds the lowest fuel burn value, as expected.\n", - "In both cases where the wing aspect ratio is optimized, it moves to the higher bound.\n", - "\n", - "If we didn't simultaneously design the aircraft and the mission, you would have to manually iterate by first optimizing the aircraft, then the mission, then the aircraft again, etc.\n", - "This cumbersome process is known as sequential optimization and can lead to non-optimal results for coupled systems, as detailed in Section 13.1 of the [Engineering Design Optimization textbook](https://flowlab.groups.et.byu.net/mdobook.pdf) (available for free).\n", - "\n", - "Aviary is unique in its ability to solve these coupled systems using efficient gradient-based optimization.\n", - "\n", - "This doc page contains a simple example, but the true power of coupled multidisciplinary optimization lies in solving more complex design problems.\n", - "We hope that you can effectively use Aviary to optimally design the next generation of exciting aircraft!\n" - ] - } - ], - "metadata": { - "celltoolbar": "Tags", - "kernelspec": { - "display_name": "aviary", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.19" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} From 19332cce0dfc77ca26876d3e4621aa0fc73a28f7 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Wed, 22 Jan 2025 11:19:38 -0500 Subject: [PATCH 022/147] Rename coupled_aircraft_mission_optimization-3.ipynb to coupled_aircraft_mission_optimization.ipynb --- ...zation-3.ipynb => coupled_aircraft_mission_optimization.ipynb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename aviary/docs/examples/{coupled_aircraft_mission_optimization-3.ipynb => coupled_aircraft_mission_optimization.ipynb} (100%) diff --git a/aviary/docs/examples/coupled_aircraft_mission_optimization-3.ipynb b/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb similarity index 100% rename from aviary/docs/examples/coupled_aircraft_mission_optimization-3.ipynb rename to aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb From 8ef61634a240a3519a5ac5510d1533d85d4b5ed7 Mon Sep 17 00:00:00 2001 From: jkirk5 Date: Wed, 22 Jan 2025 11:45:30 -0500 Subject: [PATCH 023/147] removed local-only filters --- aviary/docs/examples/.gitattributes | 1 - 1 file changed, 1 deletion(-) delete mode 100644 aviary/docs/examples/.gitattributes diff --git a/aviary/docs/examples/.gitattributes b/aviary/docs/examples/.gitattributes deleted file mode 100644 index 8425c58da..000000000 --- a/aviary/docs/examples/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -*.ipynb filter=strip-notebook-output From 31406d3f380e4905f106f4153252117b21b4d98a Mon Sep 17 00:00:00 2001 From: szoppelt Date: Tue, 4 Mar 2025 14:19:11 +0000 Subject: [PATCH 024/147] Testing adding this file for later use. --- aviary/docs/examples/wing.py | 492 +++++++++++++++++++++++++++++++++++ 1 file changed, 492 insertions(+) create mode 100644 aviary/docs/examples/wing.py diff --git a/aviary/docs/examples/wing.py b/aviary/docs/examples/wing.py new file mode 100644 index 000000000..10266d232 --- /dev/null +++ b/aviary/docs/examples/wing.py @@ -0,0 +1,492 @@ +import openmdao.api as om +import numpy as np +import matplotlib.pyplot as plt +import os +from scipy.interpolate import CubicSpline +from scipy.integrate import quad + +# Material densities (g/cm³ converted to kg/m³) -- these are just some random examples +MATERIAL_DENSITIES = { + 'wood': 130, # balsa wood + 'metal': 2700, # Aluminum + 'carbon_fiber': 1600 +} + + + +class WingMassAndCOG(om.ExplicitComponent): + def initialize(self): + self.options.declare('num_sections', + types=int, + default=1000) + + self.options.declare('airfoil_type', + types=str, + default='2412') # use 2412 as example for default + + self.options.declare('material', + default='metal', + values=list(MATERIAL_DENSITIES.keys())) + + self.options.declare('airfoil_data_file', + default=None, + types=str) # For user-provided airfoil data file + + def setup(self): + + # Inputs + self.add_input('span', + val=10.0, + units='m') # Full wingspan (adjustable) + + self.add_input('root_chord', + val=2.0, + units='m') # Root chord length + + self.add_input('tip_chord', + val=1.0, + units='m') # Tip chord length + + self.add_input('twist', + val=np.zeros(self.options['num_sections']), + units='deg') # Twist angles + + self.add_input('thickness_dist', + val=np.ones(self.options['num_sections']) * 0.1, + shape=(self.options['num_sections'],)) # Thickness distribution of the wing (height) + + + # Outputs + self.add_output('center_of_gravity_x', + val=0.0, + units='m') + + self.add_output('center_of_gravity_y', + val=0.0, + units='m') + + self.add_output('center_of_gravity_z', + val=0.0, + units='m') + + self.add_output('total_weight', + val=0.0, + units='kg') + + def setup_partials(self): + """ + Complex step is used for the derivatives for now as they are very complicated to calculate + analytically. Compute_partials function has the framework for analytical derivatives, but not + all of them match the check_partials. + """ + num_sections = self.options['num_sections'] + + self.declare_partials(['center_of_gravity_x', 'center_of_gravity_y', 'center_of_gravity_z'], + ['span', 'root_chord', 'tip_chord', 'thickness_dist', 'twist'], method='cs') + self.declare_partials('total_weight', ['span', 'root_chord', 'tip_chord', 'thickness_dist', 'twist'], method='cs') + + + def compute(self, inputs, outputs): + span = inputs['span'] + root_chord = inputs['root_chord'] + tip_chord = inputs['tip_chord'] + twist = np.radians(inputs['twist']) # Convert twist to radians + thickness_dist = inputs['thickness_dist'] + material = self.options['material'] # Material is taken from options + #num_sections = self.options['num_sections'] + airfoil_type = self.options['airfoil_type'] # NACA airfoil type + airfoil_data_file = self.options['airfoil_data_file'] + + # Input validation checks + if span <= 0: + raise ValueError("Span must be greater than zero.") + + if root_chord <= 0 or tip_chord <= 0: + raise ValueError("Root chord and tip chord must be greater than zero.") + + if tip_chord > root_chord: + raise ValueError("Tip chord cannot be larger than root chord.") + + if any(abs(twist)) > np.pi / 2: + raise ValueError("Twist angle is too extreme; must be within -90 to 90 degrees.") + + # Get material density + density = MATERIAL_DENSITIES[material] # in kg/m³ + + #x_points, dx = self.precompute_airfoil_geometry() + + if airfoil_data_file and os.path.exists(airfoil_data_file): + airfoil_data = np.loadtxt(airfoil_data_file) + x_coords = airfoil_data[:, 0] + y_coords = airfoil_data[:, 1] + + camber, camber_location, max_thickness, thickness, camber_line = self.extract_airfoil_features(x_coords, y_coords) + thickness_dist = thickness + num_sections = len(x_coords) + else: + # Parse the NACA airfoil type (4-digit) + camber = int(airfoil_type[0]) / 100.0 # Maximum camber + camber_location = int(airfoil_type[1]) / 10.0 # Location of max camber + max_thickness = int(airfoil_type[2:4]) / 100.0 # Max thickness + num_sections = self.options['num_sections'] + + # Wing spanwise distribution + span_locations = np.linspace(0, span, num_sections) + + #num_sections = self.options['num_sections'] + n_points = num_sections + x_points = np.linspace(0, 1, n_points) + dx = 1 / (n_points - 1) + + # Initialize total weight and moment accumulators + total_weight = 0 + total_moment_x = 0 + total_moment_y = 0 + total_moment_z = 0 + + # Arrays for storing 3D coordinates of the wing + x_coords = [] + y_coords = [] + z_coords = [] + + # Loop over each section along the span (3D wing approximation) + for i, location in enumerate(span_locations): + # Calculate the chord for this section -- note this is an approximation + chord = root_chord - (root_chord - tip_chord) * (location / span) # Assuming linear variation from root to tip + + # Apply twist + twist_angle = twist[i] + + section_area, centroid_x, centroid_z = self.compute_airfoil_geometry(chord, camber, camber_location, thickness_dist, x_points, dx) + centroid_y = i * span / num_sections + section_weight = density * section_area * (span / num_sections) + + rotated_x = centroid_x * np.cos(twist_angle) - centroid_z * np.sin(twist_angle) + rotated_z = centroid_x * np.sin(twist_angle) + centroid_z * np.cos(twist_angle) + + total_weight += section_weight + total_moment_x += rotated_x * section_weight + total_moment_y += centroid_y * section_weight + total_moment_z += rotated_z * section_weight + + + # Store the coordinates for plotting later + x_coords.append(rotated_x) + y_coords.append(centroid_y) + z_coords.append(rotated_z) + + # Calculate the overall center of gravity + outputs['center_of_gravity_x'] = total_moment_x / total_weight + outputs['center_of_gravity_y'] = total_moment_y / total_weight + outputs['center_of_gravity_z'] = total_moment_z / total_weight + outputs['total_weight'] = total_weight + + + def compute_partials(self, inputs, J): + span = inputs['span'] + root_chord = inputs['root_chord'] + tip_chord = inputs['tip_chord'] + thickness_dist = inputs['thickness_dist'] + twist=np.radians(inputs['twist']) + num_sections = self.options['num_sections'] + airfoil_type = self.options['airfoil_type'] # NACA airfoil type + airfoil_data_file = self.options['airfoil_data_file'] + material = self.options['material'] + + # Compute section locations along the span + span_locations = np.linspace(0, span, num_sections) + span_locations = span_locations / span + chord_lengths = tip_chord + (root_chord - tip_chord) * (1 - span_locations / span) + + # Compute section airfoil geometry + if airfoil_data_file and os.path.exists(airfoil_data_file): + airfoil_data = np.loadtxt(airfoil_data_file) + x_coords = airfoil_data[:, 0] + y_coords = airfoil_data[:, 1] + + camber, camber_location, max_thickness, thickness, camber_line = self.extract_airfoil_features(x_coords, y_coords) + thickness_dist = thickness + else: + # Parse the NACA airfoil type (4-digit) + camber = int(airfoil_type[0]) / 100.0 # Maximum camber + camber_location = int(airfoil_type[1]) / 10.0 # Location of max camber + max_thickness = int(airfoil_type[2:4]) / 100.0 # Max thickness + + # Compute section airfoil geometry + n_points = num_sections + x_points = np.linspace(0, 1, n_points) + dx = 1 / (num_sections - 1) + + #A_ref, err = quad(lambda x: np.interp(x, x_points, thickness_dist), 0, 1, limit=100) # \int_0^1 t(x) dx + A_ref = np.trapz(thickness_dist, x_points, dx=dx) + + density = MATERIAL_DENSITIES[material] + + total_moment_x = 0 + total_moment_y = 0 + total_moment_z = 0 + total_weight = 0 + + rotated_x_vals = np.zeros(num_sections) + rotated_z_vals = np.zeros(num_sections) + #section_weights = np.zeros(num_sections) + section_areas = np.zeros(num_sections) + dA_dspan = 0 + dA_droot_chord = 0 + dA_dtip_chord = 0 + dweight_dspan = 0 + dmoment_x_dtwist = np.zeros(num_sections) + dmoment_z_dtwist = np.zeros(num_sections) + dweight_dthickness = np.zeros(num_sections) + + for i, location in enumerate(span_locations): + # Calculate the chord for this section + chord = root_chord - (root_chord - tip_chord) * (location / span) # Assuming linear variation from root to tip + + # Apply twist + twist_angle = twist[i] + + section_area, centroid_x, centroid_z = self.compute_airfoil_geometry(chord, camber, camber_location, thickness_dist, x_points, dx) + section_weight = density * section_area * (span / num_sections) + centroid_y = location + + rotated_x_vals[i] = centroid_x * np.cos(twist_angle) - centroid_z * np.sin(twist_angle) + rotated_z_vals[i] = centroid_x * np.sin(twist_angle) + centroid_z * np.cos(twist_angle) + + total_weight += section_weight + total_moment_x += rotated_x_vals[i] * section_weight + total_moment_y += centroid_y * section_weight + total_moment_z += rotated_z_vals[i] * section_weight + + #section_weights[i] = section_weight + section_areas[i] = section_area + + # For dweight_dspan + dci_dspan = -(root_chord - tip_chord) * (location / span**2) + #dA_dspan, _ = quad(lambda x: np.interp(x, x_points, thickness_dist) * dci_dspan, 0, 1, limit=100) + dA_ds = np.trapz(thickness_dist * dci_dspan, x_points, dx=dx) + dA_dc_root = np.trapz(thickness_dist * (1 - i / num_sections), x_points, dx=dx) + dA_dc_tip = np.trapz(thickness_dist * i / num_sections, x_points, dx=dx) + dA_dspan += dA_ds + dA_droot_chord += dA_dc_root + dA_dtip_chord += dA_dc_tip + dweight_dspan += density * (section_area / num_sections - dA_ds * span / num_sections) + dmoment_x_dtwist[i] = -section_weight * (centroid_x * np.sin(twist_angle) + centroid_z * np.cos(twist_angle)) + dmoment_z_dtwist[i] = section_weight * (centroid_x * np.cos(twist_angle) - centroid_z * np.sin(twist_angle)) + dweight_dthickness[i] = density * span * chord / num_sections # dW_total / dthickness_dist -- vector value + + dweight_droot_chord = np.sum(density * A_ref * span / 2) # ((num_sections - 1) / (2 * num_sections)) ~ 1/2 for large N + dweight_dtip_chord = np.sum(density * A_ref * span / 2) # ((num_sections + 1) / (2 * num_sections)) ~ 1/2 for large N + + J['total_weight', 'span'] = dweight_dspan + J['total_weight', 'root_chord'] = dweight_droot_chord + J['total_weight', 'tip_chord'] = dweight_dtip_chord + J['total_weight', 'thickness_dist'] = dweight_dthickness + J['total_weight', 'twist'] = 0 + + dxcg_droot_chord = 0 + dzcg_droot_chord = 0 + dxcg_dtip_chord = 0 + dzcg_dtip_chord = 0 + for i, location in enumerate(span_locations): + dxcg_dcroot = np.sum( + np.trapz( + (x_points * thickness_dist * np.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * np.sin(twist)) * (1 - i / num_sections), x_points, dx=dx + ) + ) / np.sum(section_areas) - np.sum( + ( + np.trapz( + x_points * thickness_dist * chord_lengths * np.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * np.sin(twist), x_points, dx=dx + ) * np.trapz( + thickness_dist * (1 - i / num_sections), x_points, dx=dx + ) + ) + ) / np.sum(section_areas)**2 + dxcg_droot_chord += dxcg_dcroot + + dzcg_dcroot = np.sum( + np.trapz( + (x_points * thickness_dist * (1 - i / num_sections) * np.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist) * (1 - i / num_sections) * np.cos(twist), x_points, dx=dx + ) + ) / np.sum(section_areas) - np.sum( + np.trapz( + x_points * thickness_dist * chord_lengths * np.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * np.cos(twist), x_points, dx=dx + ) * dA_droot_chord + ) / np.sum(section_areas)**2 + dzcg_droot_chord += dzcg_dcroot + + dxcg_dctip = np.sum( + np.trapz( + (x_points * thickness_dist *np.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * np.sin(twist)) * (i / num_sections), x_points, dx=dx + ) / section_areas + ) - np.sum( + ( + np.trapz( + x_points * thickness_dist * chord_lengths * np.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * np.sin(twist), x_points, dx=dx + ) + ) * dA_dtip_chord + ) / np.sum(section_areas)**2 + dxcg_dtip_chord += dxcg_dctip + + dzcg_dctip = np.sum( + np.trapz( + x_points * thickness_dist * (i / num_sections) * np.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * (i / num_sections) * np.cos(twist), x_points, dx=dx + ) + ) / np.sum(section_areas) - np.sum( + np.trapz( + x_points * thickness_dist * chord_lengths * np.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * np.cos(twist), x_points, dx=dx + ) * dA_dtip_chord + ) / np.sum(section_areas)**2 + dzcg_dtip_chord += dzcg_dctip + + # partials of cog x + J['center_of_gravity_x', 'span'] = 0 + J['center_of_gravity_x', 'root_chord'] = dxcg_droot_chord + J['center_of_gravity_x', 'tip_chord'] = dxcg_dtip_chord + J['center_of_gravity_x', 'thickness_dist'] = np.sum( + np.trapz( + x_points * chord_lengths * np.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * chord_lengths * np.sin(twist), x_points, dx=dx + ) / section_areas + ) - ( + np.sum( + np.trapz(x_points * thickness_dist * chord_lengths * np.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * np.sin(twist), x_points, dx=dx) + ) * np.sum(chord_lengths) + ) / np.sum(section_areas)**2 + J['center_of_gravity_x', 'twist'] = dmoment_x_dtwist / total_weight + + # For center of gravity in y calculations + + sum_area_times_i = 0 + sum_darea_times_i = 0 + + for i in range(len(x_points)): + sum_area_times_i += i * section_areas[i] + sum_darea_times_i += i * dA_dspan # for cg_Y calculations + + dcg_y_dspan = np.sum(sum_area_times_i / (num_sections * section_areas)) #+ np.sum((span * sum_darea_times_i) / (num_sections * section_areas)) - np.sum((span * sum_area_times_i) / (num_sections * np.sum(section_areas)**2)) * dA_dspan + + # partials of cog y + J['center_of_gravity_y', 'span'] = dcg_y_dspan + J['center_of_gravity_y', 'root_chord'] = -total_moment_y / total_weight * dweight_droot_chord / total_weight + J['center_of_gravity_y', 'tip_chord'] = -total_moment_y / total_weight * dweight_dtip_chord / total_weight + J['center_of_gravity_y', 'thickness_dist'] = -total_moment_y / total_weight * dweight_dthickness / total_weight + J['center_of_gravity_y', 'twist'] = 0 + + # partials of cog z + J['center_of_gravity_z', 'span'] = 0 + J['center_of_gravity_z', 'root_chord'] = dzcg_droot_chord + J['center_of_gravity_z', 'tip_chord'] = dzcg_dtip_chord + J['center_of_gravity_z', 'thickness_dist'] = np.sum( + np.trapz( + x_points * chord_lengths * np.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * chord_lengths * np.cos(twist), x_points, dx=dx + ) + ) / np.sum( + section_areas + ) + J['center_of_gravity_z', 'twist'] = dmoment_z_dtwist / total_weight + + def precompute_airfoil_geometry(self): + num_sections = self.options['num_sections'] + n_points = num_sections + x_points = np.linspace(0, 1, n_points) + dx = 1 / (n_points - 1) + return x_points, dx + + def compute_airfoil_geometry(self, chord, camber, camber_location, thickness_dist, x_points, dx): + + #section_area, _ = quad(lambda x: np.interp(x, x_points, thickness_dist), 0, 1, limit=100) + section_area = np.trapz(thickness_dist, x_points, dx=dx) # trying np.trapz rather than quad to get rid of IntegrationWarning + section_area *= chord + + #centroid_x, _ = quad(lambda x: x * np.interp(x, x_points, thickness_dist), 0, 1, limit=100) + centroid_x = np.trapz(x_points * thickness_dist, x_points, dx=dx) + centroid_x = (centroid_x * chord) / section_area + + #centroid_z, _ = quad(lambda x: self.airfoil_camber_line(x, camber, camber_location) * np.interp(x, x_points, thickness_dist), 0, 1, limit=100) + centroid_z = np.trapz(self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist, x_points, dx=dx) + centroid_z = (centroid_z * chord) / section_area + return section_area, centroid_x, centroid_z + + def airfoil_thickness(self, x, max_thickness): + return 5 * max_thickness * (0.2969 * np.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) + + def airfoil_camber_line(self, x, camber, camber_location): + camber_location = max(camber_location, 1e-9) # Divide by zero check + return np.where( + x < camber_location, + (camber / camber_location**2) * (2 * camber_location * x - x**2), + (camber / (1 - camber_location)**2) * ((1 - 2 * camber_location) + 2 * camber_location * x - x**2) + ) + + def extract_airfoil_features(self, x_coords, y_coords): + """ + Extract camber, camber location, and max thickness from the given airfoil data. + This method assumes x_coords are normalized (ranging from 0 to 1). + """ + # Approximate the camber line and max thickness from the data + # Assume the camber line is the line of symmetry between the upper and lower surfaces + upper_surface = y_coords[:int(len(x_coords) // 2)] + lower_surface = y_coords[int(len(x_coords) // 2):] + x_upper = x_coords[:int(len(x_coords) // 2)] + x_lower = x_coords[int(len(x_coords) // 2):] + + upper_spline = CubicSpline(x_upper, upper_surface, bc_type='natural') + lower_spline = CubicSpline(x_lower, lower_surface, bc_type='natural') + + camber_line = (upper_spline(x_coords) + lower_spline(x_coords)) / 2.0 + + thickness = upper_spline(x_coords) - lower_spline(x_coords) + + max_thickness_index = np.argmax(thickness) + max_thickness_value = thickness[max_thickness_index] + + camber_slope = np.gradient(camber_line, x_coords) + camber_location_index = np.argmax(np.abs(camber_slope)) + camber_location = x_coords[camber_location_index] + + camber = camber_line[camber_location_index] + + return camber, camber_location, max_thickness_value, thickness, camber_line + + +# Build OpenMDAO problem +prob = om.Problem() + +# Add the center of gravity component +prob.model.add_subsystem('cog', WingMassAndCOG() , promotes_inputs=['span', 'root_chord', 'tip_chord', 'twist', 'thickness_dist']) + +n_points = 1000 # = num_sections +x = np.linspace(0, 1, n_points) +max_thickness_chord_ratio = 0.12 +thickness_dist = 5 * max_thickness_chord_ratio * (0.2969 * np.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) + +# Setup the problem +prob.setup() + +# Define some example inputs +prob.set_val('span', 2.438) +prob.set_val('root_chord', 0.3722) +prob.set_val('tip_chord', 0.2792) +prob.set_val('twist', np.linspace(0, 0, 1000)) +#prob.set_val('thickness_dist', thickness_dist) + + +prob.model.cog.options['airfoil_data_file'] = 'Clark_Y.dat' +prob.model.cog.options['material'] = 'wood' +#prob.model.cog.options['airfoil_type'] = '2412' + +# Run the model +prob.run_model() + +# Get the results +center_of_gravity_x = prob.get_val('cog.center_of_gravity_x') +center_of_gravity_y = prob.get_val('cog.center_of_gravity_y') +center_of_gravity_z = prob.get_val('cog.center_of_gravity_z') +total_weight = prob.get_val('cog.total_weight') + +#data = prob.check_partials(compact_print=True, method='cs') +#om.partial_deriv_plot(data) + +print(f"Center of gravity: X = {center_of_gravity_x} m, Y = {center_of_gravity_y} m, Z = {center_of_gravity_z} m") +print(f"Total weight of the wing: {total_weight} kg") + From 98ce5228e07725c05d77b5ee5664f12f5067be4c Mon Sep 17 00:00:00 2001 From: szoppelt Date: Tue, 4 Mar 2025 14:23:02 +0000 Subject: [PATCH 025/147] Another test. --- aviary/docs/examples/materials_database.py | 66 ++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 aviary/docs/examples/materials_database.py diff --git a/aviary/docs/examples/materials_database.py b/aviary/docs/examples/materials_database.py new file mode 100644 index 000000000..77b0fb5f4 --- /dev/null +++ b/aviary/docs/examples/materials_database.py @@ -0,0 +1,66 @@ +""" +Database for various material densities that are to be used for mass calculations for small aircraft in particular. + +This database will be expanded as needed. + +""" +from aviary.utils.named_values import NamedValues + +materials = NamedValues() + +""" +All densities below came from https://tpsx.arc.nasa.gov/MaterialsDatabase + +""" + +# Wood +materials.set_val('Balsa', 130, units='kg/m**3') +materials.set_val('Cypress', 460, units='kg/m**3') +materials.set_val('Mahogany', 540, units='kg/m**3') +materials.set_val('Maple', 710, units='kg/m**3') +materials.set_val('Teak', 640, units='kg/m**3') + +# Aluminum Compounds and Alloys +materials.set_val('Aluminum Oxide', 3400, units='kg/m**3') +materials.set_val('2024-T8XX', 2800, units='kg/m**3') # aircraft-grade strength Aluminum alloy +materials.set_val('2219-T8XX', 2810, units='kg/m**3') # Exceptionally strong Aluminum alloy +materials.set_val('2024-T6', 2770, units='kg/m**3') # Another Aluminum alloy +materials.set_val('Aluminum Foam', 1300, units='kg/m**3') + +# Steel +materials.set_val('Stainless Steel 17-4 PH', 7830, units='kg/m**3') # 17-4 PH stainless steel +materials.set_val('Stainless Steel-AISI 302', 8060, units='kg/m**3') # AISI 302 +materials.set_val('Stainless Steel-AISI 304', 7900, units='kg/m**3') # AISI 304 +materials.set_val('Steel Alloy Cast', 7830, units='kg/m**3') # General steel alloy cast +materials.set_val('Steel 321', 8030, units='kg/m**3') # Steel type 321 + +# Carbon Fibers / Carbon - Silicon Fibers +materials.set_val('Carbon/Silicon-Carbide', 2080, units='kg/m**3') # Carbon fiber reinforced SiC +materials.set_val('Silicon-Carbide/Silicon-Carbide', 2400, units='kg/m**3') # SiC fiber reinforced SiC matrix +materials.set_val('Advanced Carbon-Carbon Composite', 1600, units='kg/m**3') # ACC +materials.set_val('Reinfoced Carbon-Carbon', 1580, units='kg/m**3') +materials.set_val('Reinforced Carbon-Carbon Composite', 1580, units='kg/m**3') # Generally, ACC is better, but RCC is slightly cheaper + +""" +Below are miscellaneous values that could be of importance, particularly for small aircraft. + +These values were found from a variety of sources, and depending on the source/brand, the density +could be slightly different. For some cases, temperature of the material also matters (typically +the values are provided as a relative density). If there is a temperature dependence from the source, +it will be noted as a comment next to the line where the material value is set. Below are some sources +for various values. + +The values below were not explicity listed from the above source. + +Wood glue: https://www.gorillatough.com/wp-content/uploads/Gorilla-Wood-Glue-v1.2.pdf + +EPS Foam: https://www.abtfoam.com/wp-content/uploads/2020/05/EPS-Standard-Sheet-Sizes-Densities-and-R-values.pdf + Note that there is a density range given, along with different types. The density value used is for Type I, + and the value given is the average of the minimum and maximum within the range provided. The base unit in + this document is pcf for the density. It was converted to kg/m^3 for the actual value input. + +""" + +materials.set_val('Wood Glue', 1080, units='kg/m**3') # Relative density value -- corresponds to 25 C (77 F) +materials.set_val('EPS Foam', 16.3388, units='kg/m**3') + From 381f6622add1f11786e037906b5089778525787f Mon Sep 17 00:00:00 2001 From: szoppelt Date: Tue, 4 Mar 2025 14:24:54 +0000 Subject: [PATCH 026/147] Test. new file: aviary/docs/examples/fuselage.py new file: aviary/docs/examples/mass_builder.py new file: aviary/docs/examples/mass_premission.py new file: aviary/docs/examples/mass_summation.py new file: aviary/docs/examples/tail.py new file: aviary/docs/examples/test_wing.py --- aviary/docs/examples/fuselage.py | 303 ++++++++++++++++++++++++ aviary/docs/examples/mass_builder.py | 92 +++++++ aviary/docs/examples/mass_premission.py | 39 +++ aviary/docs/examples/mass_summation.py | 43 ++++ aviary/docs/examples/tail.py | 289 ++++++++++++++++++++++ aviary/docs/examples/test_wing.py | 17 ++ 6 files changed, 783 insertions(+) create mode 100644 aviary/docs/examples/fuselage.py create mode 100644 aviary/docs/examples/mass_builder.py create mode 100644 aviary/docs/examples/mass_premission.py create mode 100644 aviary/docs/examples/mass_summation.py create mode 100644 aviary/docs/examples/tail.py create mode 100644 aviary/docs/examples/test_wing.py diff --git a/aviary/docs/examples/fuselage.py b/aviary/docs/examples/fuselage.py new file mode 100644 index 000000000..3764a4eff --- /dev/null +++ b/aviary/docs/examples/fuselage.py @@ -0,0 +1,303 @@ +import openmdao.api as om +import numpy as np +from scipy.interpolate import interp1d +import logging + +# Configure logging +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +# Material densities (kg/m^3) +MATERIAL_DENSITIES = { + 'wood': 600, # Not any real wood density + 'metal': 2700, # Aluminum + 'carbon_fiber': 1600, + 'foam': 300 # Example density for foam (just for something lightweight) +} + +class FuselageMassAndCOG(om.ExplicitComponent): + def initialize(self): + self.options.declare('num_sections', + types=int, + default=1000) + + self.options.declare('material', + default='foam', + values=list(MATERIAL_DENSITIES.keys())) + + self.options.declare('custom_fuselage_data_file', + types=(str, type(None)), + default=None, + allow_none=True) + + self.custom_fuselage_function = None + + def setup(self): + + # Inputs + self.add_input('length', + val=2.0, + units='m') + + self.add_input('diameter', + val=0.4, + units='m') + + self.add_input('taper_ratio', + val=1.0, + units=None) # 1.0 means no taper + + self.add_input('curvature', + val=0.0, + units='m') # 0 for straight, positive for upward curve + + self.add_input('thickness', + val=0.05, + units='m') # Wall thickness of the fuselage + + # Allow for asymmetry in the y and z axes -- this value acts as a slope for linear variation along these axes + self.add_input('y_offset', + val=0.0, + units='m') + + self.add_input('z_offset', + val=0.0, + units='m') + + self.add_input('is_hollow', + val=True, + units=None) # Whether the fuselage is hollow or not (default is hollow) + + + # Outputs + self.add_output('center_of_gravity_x', + val=0.0, + units='m') + + self.add_output('center_of_gravity_y', + val=0.0, + units='m') + + self.add_output('center_of_gravity_z', + val=0.0, + units='m') + + self.add_output('total_weight', + val=0.0, + units='kg') + + def setup_partials(self): + """ + Complex step is used for the derivatives for now as they are very complicated to calculate + analytically. Compute_partials function has the framework for analytical derivatives, but not + all of them match the check_partials. + """ + self.declare_partials('center_of_gravity_x', ['length', 'diameter', 'taper_ratio', 'curvature', 'thickness'], method='cs') + self.declare_partials('center_of_gravity_y', ['length', 'y_offset', 'curvature'], method='cs') + self.declare_partials('total_weight', ['length', 'diameter', 'thickness'], method='cs') + + def compute_partials(self, inputs, partials): + length = inputs['length'] + diameter = inputs['diameter'] + taper_ratio = inputs['taper_ratio'] + curvature = inputs['curvature'] + thickness = inputs['thickness'] + y_offset = inputs['y_offset'] + z_offset = inputs['z_offset'] + is_hollow = inputs['is_hollow'] + + #custom_fuselage_function = getattr(self, 'custom_fuselage_function', None) # Custom fuselage model function -- if provided + + custom_fuselage_data_file = self.options['custom_fuselage_data_file'] + + material = self.options['material'] + num_sections = self.options['num_sections'] + + self.validate_inputs(length, diameter, thickness, taper_ratio, is_hollow) + + density = MATERIAL_DENSITIES[material] + + section_locations = np.linspace(0, length, num_sections).flatten() + dx = 1 / (num_sections - 1) + + total_weight = 0 + total_moment_x = 0 + total_moment_y = 0 + total_moment_z = 0 + + interpolate_diameter = self.load_fuselage_data(custom_fuselage_data_file) + + out_r = np.zeros(num_sections) + in_r = np.zeros(num_sections) + + + # Loop through each section + for i, location in enumerate(section_locations): + section_diameter = self.get_section_diameter(location, length, diameter, taper_ratio, interpolate_diameter) + outer_radius = section_diameter / 2.0 + inner_radius = max(0, outer_radius - thickness) if is_hollow else 0 + + out_r[i] = outer_radius + in_r[i] = inner_radius + + section_volume = np.pi * (outer_radius**2 - inner_radius**2) * (length / num_sections) + section_weight = density * section_volume + + centroid_x, centroid_y, centroid_z = self.compute_centroid(location, length, y_offset, z_offset, curvature, taper_ratio) + + total_weight += section_weight + total_moment_x += centroid_x * section_weight + total_moment_y += centroid_y * section_weight + total_moment_z += centroid_z * section_weight + + dzcg_dz_offset = np.sum( + np.trapz( + (1 - section_locations / length) * density * np.pi * (out_r**2 - in_r**2), section_locations, dx=dx + ) + ) / total_weight + + + partials['center_of_gravity_x', 'length'] = 3 / 4 if taper_ratio > 0 else 1 + partials['center_of_gravity_x', 'taper_ratio'] = - (3/4) * length if taper_ratio > 0 else 0 + partials['center_of_gravity_x', 'curvature'] = 0 + partials['center_of_gravity_x', 'thickness'] = 0 + + partials['center_of_gravity_y', 'length'] = -y_offset / length + partials['center_of_gravity_y', 'y_offset'] = 1 + + partials['center_of_gravity_z', 'length'] = -z_offset / length + partials['center_of_gravity_z', 'z_offset'] = dzcg_dz_offset + partials['center_of_gravity_z', 'curvature'] = length**2 / num_sections + + partials['total_weight', 'length'] = density * np.pi * (diameter**2 - (diameter - 2 * thickness)**2) / num_sections + partials['total_weight', 'diameter'] = 2 * density * np.pi * length * diameter / num_sections + partials['total_weight', 'thickness'] = -2 * density * np.pi * length * (diameter - thickness) / num_sections + + + def compute(self, inputs, outputs): + length = inputs['length'] + diameter = inputs['diameter'] + taper_ratio = inputs['taper_ratio'] + curvature = inputs['curvature'] + thickness = inputs['thickness'] + y_offset = inputs['y_offset'] + z_offset = inputs['z_offset'] + is_hollow = inputs['is_hollow'] + + # Input validation checks + if length <= 0: + raise ValueError("Length must be greater than zero.") + + if diameter <= 0: + raise ValueError("Diameter must be greater than zero.") + + custom_fuselage_function = getattr(self, 'custom_fuselage_function', None) # Custom fuselage model function -- if provided + + custom_fuselage_data_file = self.options['custom_fuselage_data_file'] + + material = self.options['material'] + num_sections = self.options['num_sections'] + + self.validate_inputs(length, diameter, thickness, taper_ratio, is_hollow) + + density = MATERIAL_DENSITIES[material] + + section_locations = np.linspace(0, length, num_sections) + + total_weight = 0 + total_moment_x = 0 + total_moment_y = 0 + total_moment_z = 0 + + interpolate_diameter = self.load_fuselage_data(custom_fuselage_data_file) + + # Loop through each section + for location in section_locations: + section_diameter = self.get_section_diameter(location, length, diameter, taper_ratio, interpolate_diameter) + outer_radius = section_diameter / 2.0 + inner_radius = max(0, outer_radius - thickness) if is_hollow else 0 + + section_volume = np.pi * (outer_radius**2 - inner_radius**2) * (length / num_sections) + section_weight = density * section_volume + + centroid_x, centroid_y, centroid_z = self.compute_centroid(location, length, y_offset, z_offset, curvature, taper_ratio) + + total_weight += section_weight + total_moment_x += centroid_x * section_weight + total_moment_y += centroid_y * section_weight + total_moment_z += centroid_z * section_weight + + outputs['center_of_gravity_x'] = total_moment_x / total_weight + outputs['center_of_gravity_y'] = total_moment_y / total_weight + outputs['center_of_gravity_z'] = total_moment_z / total_weight + outputs['total_weight'] = total_weight + + def validate_inputs(self, length, diameter, thickness, taper_ratio, is_hollow): + if length <= 0 or diameter <= 0 or thickness <= 0: + raise ValueError("Length, diameter, and thickness must be positive values.") + if taper_ratio < 0 or taper_ratio > 1: + raise ValueError("Taper ratio must be between 0 and 1.") + if is_hollow and thickness >= diameter / 2: + raise ValueError("Wall thickness is too large for a hollow fuselage.") + + def load_fuselage_data(self, custom_fuselage_data_file): + if custom_fuselage_data_file: + try: + # Load the file + custom_data = np.loadtxt(custom_fuselage_data_file) + fuselage_locations = custom_data[:, 0] + fuselage_diameters = custom_data[:, 1] + return interp1d(fuselage_locations, fuselage_diameters, kind='linear', fill_value='extrapolate') + except Exception as e: + raise ValueError(f"Error loading fuselage data file: {e}") + else: + return None + + def get_section_diameter(self, location, length, diameter, taper_ratio, interpolate_diameter): + if self.custom_fuselage_function: + return self.custom_fuselage_function(location) + elif self.load_fuselage_data: + return interpolate_diameter(location) if interpolate_diameter is not None else max(0.01, diameter * (1 - taper_ratio * (location / length))) + else: + return max(0.01, diameter * (1 - taper_ratio * (location / length))) + + def compute_centroid(self, location, length, y_offset, z_offset, curvature, taper_ratio): + centroid_x = (3/4) * location if taper_ratio > 0 else location # This is an approximation that could and should be better modeled in the future + centroid_y = y_offset * (1 - location / length) + centroid_z = z_offset * (1 - location / length) + curvature * location**2 / length + return centroid_x, centroid_y, centroid_z + +prob = om.Problem() + +prob.model.add_subsystem('fuselage_cg', FuselageMassAndCOG(), promotes_inputs=['length', 'diameter', 'taper_ratio', 'curvature', 'thickness', 'y_offset', 'z_offset', 'is_hollow']) + +prob.setup() + +prob.set_val('length', 2.5) +prob.set_val('diameter', 0.5) +prob.set_val('taper_ratio', 0.5) +prob.set_val('curvature', 0.0) +prob.set_val('thickness', 0.05) # Wall thickness of 5 cm +#prob.set_val('is_hollow', False) # Default is True, uncomment to use False -- for testing purposes + +# Example using custom function -- uncomment to run +#def custom_fuselage_model(location): +# return 0.5 * np.exp(-0.1 * location) + +#prob.model.fuselage_cg.custom_fuselage_function = custom_fuselage_model + +# Example for custom .dat file -- uncomment to run +#prob.model.fuselage_cg.options['custom_fuselage_data_file'] = 'Custom_Fuselage.dat' + +prob.run_model() + +center_of_gravity_x = prob.get_val('fuselage_cg.center_of_gravity_x') +center_of_gravity_y = prob.get_val('fuselage_cg.center_of_gravity_y') +center_of_gravity_z = prob.get_val('fuselage_cg.center_of_gravity_z') +total_weight = prob.get_val('fuselage_cg.total_weight') + +#data = prob.check_partials(compact_print=True, abs_err_tol=1e-04, rel_err_tol=1e-04, step=1e-8, step_calc='rel') + +logger.info(f"Center of gravity of the fuselage: X = {center_of_gravity_x} m, Y = {center_of_gravity_y} m, Z = {center_of_gravity_z} m") +logger.info(f"Total weight of the fuselage: {total_weight} kg") + diff --git a/aviary/docs/examples/mass_builder.py b/aviary/docs/examples/mass_builder.py new file mode 100644 index 000000000..050daf052 --- /dev/null +++ b/aviary/docs/examples/mass_builder.py @@ -0,0 +1,92 @@ +from aviary.interface.utils.markdown_utils import write_markdown_variable_table +from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase +from aviary.subsystems.mass.mass_builder import MassBuilderBase +from aviary.subsystems.mass.simple_mass.mass_premission import MassPremission # This will be the new folder in there \ +# along with flops_based and gasp_based folders. I just called it simple_mass for now. + +""" + +Define subsystem builder for Aviary core mass. + +Classes +-------------------------------------------------------------------------------------------------- + +MassBuilderBase: the interface for a mass subsystem builder. **Not sure how necessary this is for + my work right now, but wanted to include it as a just in case. I basically copied + it over from the mass_builder.py under the mass subsystems folder in Aviary github. + +StructureMassBuilder: the interface for Aviary's core mass builder -- in this case, + the core mass builder will work for wing and fuselage mass calculations + will be updated as more mass calculations are added + +""" + +_default_name = 'mass' + +#class MassBuilderBase(SubsystemBuilderBase): + #""" + #Base mass builder + # + #This class is basically copied line by line from the mass subsystems folder + #** Ask Jason if this is even necessary. + # + #""" + + #def __init__(self, name=None, meta_data=None): + # if name is None: + # name = _default_name + # + # super().__init__(name=name, meta_data=meta_data) + # + #def mission_inputs(self, **kwargs): + # return ['*'] + # + #def mission_outputs(self, **kwargs): + # return ['*'] + +class StructureMassBuilder(MassBuilderBase): + """ + Core mass subsystem builder + + Unlike the CoreMassBuilder on the github under the mass subsystems folder, + I am not including the __init__'s, since I don't have any FLOPS or GASP + dependence in my mass calculations at the moment; the math is essentially + hard coded from my calculations right now. + + """ + + def build_pre_mission(self, aviary_inputs): + return MassPremission # See the commented line above in the imports + + def build_mission(self, num_nodes, aviary_inputs, **kwargs): + super().build_mission(num_nodes, aviary_inputs) + + def report(self, prob, reports_folder, **kwargs): + """ + Generate the report for Aviary core mass + + Parameters + ---------- + prob : AviaryProblem + The AviaryProblem that will be used to generate the report + reports_folder : Path + Location of the subsystems_report folder this report will be placed in + + * This comment is copied from the mass subsystems folder * + + """ + + filename = self.name + '.md' + filepath = reports_folder / filename + + # Ask Jason about how I should format this + outputs = [ + + ] + + with open(filepath, mode='w') as f: + method = self.code_origin.value + '-derived relations' # Ask Jason about this too since I don't have FLOPS or GASP for code_origin_value + f.write(f'# Mass estimation: {method}') + write_markdown_variable_table(f, prob, outputs, self.meta_data) + + \ No newline at end of file diff --git a/aviary/docs/examples/mass_premission.py b/aviary/docs/examples/mass_premission.py new file mode 100644 index 000000000..cc2467139 --- /dev/null +++ b/aviary/docs/examples/mass_premission.py @@ -0,0 +1,39 @@ +import openmdao.api as om + +# Maybe some Aviary inputs as well? +from aviary.subsystems.mass.simple_mass.wing import WingMassAndCOG +from aviary.subsystems.mass.simple_mass.fuselage import FuselageMassAndCOG +from aviary.subsystems.mass.simple_mass.tail import TailMassAndCOG +from aviary.subsystems.mass.simple_mass.mass_summation import MassSummation + +class MassPremission(om.Group): + """ + Pre-mission group of top-level mass estimation groups and components for + the simple small-scale aircraft mass build-up. + """ + + def setup(self): + + self.add_subsystem( + 'Wing', + WingMassAndCOG(), + promotes_inputs=['*'], promotes_outputs=['*'] + ) + + self.add_subsystem( + 'Fuselage', + FuselageMassAndCOG(), + promotes_inputs=['*'], promotes_outputs=['*'] + ) + + self.add_subsystem( + 'Tail', + TailMassAndCOG(), + promotes_inputs=['*'], promotes_outputs=['*'] + ) + + self.add_subsystem( + 'total_mass', + MassSummation(), + promotes_inputs=['*'], promotes_outputs=['*'] + ) \ No newline at end of file diff --git a/aviary/docs/examples/mass_summation.py b/aviary/docs/examples/mass_summation.py new file mode 100644 index 000000000..2d040cf78 --- /dev/null +++ b/aviary/docs/examples/mass_summation.py @@ -0,0 +1,43 @@ +import numpy as np + +import openmdao.api as om + +# Maybe add some aviary inputs at some point here + +class MassSummation(om.Group): + """ + + Group to compute various design masses for this mass group. + + This group will be expanded greatly as more subsystems are created. + + """ + + def setup(self): + self.add_subsystem( + 'structure_mass', StructureMass(), + promotes_inputs=['*'], promotes_outputs=['*'] + ) + + +class StructureMass(om.ExplicitComponent): + + def setup(self): + # Maybe later change these to Aviary inputs? + self.add_input('wing_mass', val=0.0, units='kg') + self.add_input('fuse_mass', val=0.0, units='kg') + self.add_input('tail_mass', val=0.0, units='kg') + # More masses can be added, i.e., tail, spars, flaps, etc. as needed + + self.add_output('structure_mass', val=0.0, units='kg') + + def setup_partials(self): + # I'm not sure what else to put here at the moment + self.declare_partials('structure_mass', '*', val=1) + + def compute(self, inputs, outputs): + wing_mass = inputs['wing_mass'] + fuse_mass = inputs['fuse_mass'] + tail_mass = inputs['tail_mass'] + + outputs['structure_mass'] = wing_mass + fuse_mass + tail_mass \ No newline at end of file diff --git a/aviary/docs/examples/tail.py b/aviary/docs/examples/tail.py new file mode 100644 index 000000000..84d61f1ee --- /dev/null +++ b/aviary/docs/examples/tail.py @@ -0,0 +1,289 @@ +import openmdao.api as om +import numpy as np +import scipy.integrate as spi +from scipy.interpolate import interp1d +from scipy.interpolate import CubicSpline +import os + +# Material densities, all in kg/m^3 +MATERIALS = { + 'Aluminum': 2700, + 'Steel': 7850, + 'Titanium': 4500, + 'Carbon Fiber': 1600, + 'Wood': 600 +} + +class TailMassAndCOG(om.ExplicitComponent): + def initialize(self): + self.options.declare('tail_type', + default='horizontal', + values=['horizontal', 'vertical'], + desc="Type of tail: 'horizontal' or 'vertical'") + + self.options.declare('airfoil_type', + default='NACA', + values=['NACA', 'file'], + desc="Airfoil type: 'NACA' for 4-digit or 'file' for user-provided coordinates") + + if self.options['airfoil_type'] == 'NACA': + self.options.declare('NACA_digits', + default='2412', + desc="4 digit code for NACA airfoil, if that is given.") + + self.options.declare('material', + default='Aluminum', + values=list(MATERIALS.keys()), + desc="Material type") + + self.options.declare('airfoil_file', + default=None, + desc="File path for airfoil coordinates (if applicable)") + + self.options.declare('num_sections', + default=1000, + desc="Number of sections for enumeration") + + def setup(self): + # Inputs + self.add_input('span', + val=5.0, + units='m', + desc="Tail span") + + self.add_input('root_chord', + val=1.2, + units='m', + desc="Root chord length") + + self.add_input('tip_chord', + val=0.8, + units='m', + desc="Tip chord length") + + self.add_input('thickness_ratio', + val=0.12, + desc="Max thickness to chord ratio for NACA airfoil") + + self.add_input('skin_thickness', + val=0.002, + units='m', + desc="Skin panel thickness") + + self.add_input('twist', + val=np.zeros(self.options['num_sections']), + units='deg', + desc="Twist distribution") + + # Outputs + self.add_output('mass', + val=0.0, + units='kg', + desc="Total mass of the tail") + + self.add_output('cg_x', + val=0.0, + units='m', + desc="X location of the center of gravity") + + self.add_output('cg_y', + val=0.0, + units='m', + desc="Y location of the center of gravity") + + self.add_output('cg_z', + val=0.0, + units='m', + desc="Z location of the center of gravity") + + def compute(self, inputs, outputs): + tail_type = self.options["tail_type"] + airfoil_type = self.options["airfoil_type"] + material = self.options['material'] + span = inputs['span'] + root_chord = inputs['root_chord'] + tip_chord = inputs['tip_chord'] + thickness_ratio = inputs['thickness_ratio'] + density = MATERIALS[material] + airfoil_file = self.options['airfoil_file'] + skin_thickness = inputs['skin_thickness'] + num_sections = self.options['num_sections'] + twist = inputs['twist'] + NACA_digits = self.options['NACA_digits'] + + # File check + if airfoil_type == 'file': + if airfoil_type == 'file' and (airfoil_file is None or not os.path.isfile(airfoil_file)): + raise FileNotFoundError(f"Airfoil file '{airfoil_file}' not found or not provided.") + try: + airfoil_data = np.loadtxt(airfoil_file, skiprows=1) # Assume a header + x_coords, y_coords = airfoil_data[:, 0], airfoil_data[:, 1] + except Exception as e: + raise ValueError(f"Error reading airfoil file: {e}") + + # Compute section airfoil geometry + if airfoil_file and os.path.exists(airfoil_file): + airfoil_data = np.loadtxt(airfoil_file) + x_coords = airfoil_data[:, 0] + y_coords = airfoil_data[:, 1] + + camber, camber_location, max_thickness = self.extract_airfoil_features(x_coords, y_coords) + else: + # Parse the NACA airfoil type (4-digit) + camber = int(NACA_digits[0]) / 100.0 # Maximum camber + camber_location = int(NACA_digits[1]) / 10.0 # Location of max camber + max_thickness = int(NACA_digits[2:4]) / 100.0 # Max thickness + + # Tail type check + if tail_type not in ['horizontal', 'vertical']: + raise ValueError("Invalid tail_type. Must be 'horizontal' or 'vertical'.") + + # Input validation checks + if span <= 0: + raise ValueError("Span must be greater than zero.") + + if root_chord <= 0 or tip_chord <= 0: + raise ValueError("Root chord and tip chord must be greater than zero.") + + if tip_chord > root_chord: + raise ValueError("Tip chord cannot be larger than root chord.") + + if thickness_ratio <= 0: + raise ValueError("Thickness ratio must be greater than zero.") + + if skin_thickness <= 0: + raise ValueError("Skin thickness must be greater than zero.") + + if any(abs(twist)) > np.pi / 2: + raise ValueError("Twist angle is too extreme; must be within -90 to 90 degrees.") + + span_locations = np.linspace(0, span, num_sections) + + # Get x_points and dx for later + x_points, dx = self.precompute_airfoil_geometry() + + # Thickness distribution + thickness_dist = self.airfoil_thickness(x_points, max_thickness) + + total_mass = 0 + total_moment_x = 0 + total_moment_y = 0 + total_moment_z = 0 + + for i, y in enumerate(span_locations): + section_chord = root_chord - (root_chord - tip_chord) * (y / span) # Assume linear variation in chord + section_area, centroid_x, centroid_z = self.compute_airfoil_geometry(section_chord, + camber, + camber_location, + thickness_dist, + x_points, + dx) + + + section_mass = density * section_area * (span / num_sections) + + # Twist + twist_angle = twist[i] + rotated_x = centroid_x * np.cos(twist_angle) - centroid_z * np.sin(twist_angle) + rotated_z = centroid_x * np.sin(twist_angle) + centroid_z * np.cos(twist_angle) + + total_mass += section_mass + total_moment_x += rotated_x * section_mass + if tail_type == 'horizontal': + total_moment_y += y * section_mass + total_moment_z += rotated_z * section_mass + elif tail_type == 'vertical': + total_moment_y += rotated_z * section_mass + total_moment_z += y * section_mass + + # COG + outputs['mass'] = total_mass + outputs['cg_x'] = total_moment_x / total_mass + outputs['cg_y'] = total_moment_y / total_mass + outputs['cg_z'] = total_moment_z / total_mass + + def precompute_airfoil_geometry(self): + num_sections = self.options['num_sections'] + n_points = num_sections + x_points = np.linspace(0, 1, n_points) + dx = 1 / (n_points - 1) + return x_points, dx + + def compute_airfoil_geometry(self, chord, camber, camber_location, thickness_dist, x_points, dx): + + #section_area, _ = quad(lambda x: np.interp(x, x_points, thickness_dist), 0, 1, limit=100) + section_area = np.trapz(thickness_dist, x_points, dx=dx) + section_area *= chord + + #centroid_x, _ = quad(lambda x: x * np.interp(x, x_points, thickness_dist), 0, 1, limit=100) + centroid_x = np.trapz(x_points * thickness_dist, x_points, dx=dx) + centroid_x = (centroid_x * chord) / section_area + + #centroid_z, _ = quad(lambda x: self.airfoil_camber_line(x, camber, camber_location) * np.interp(x, x_points, thickness_dist), 0, 1, limit=100) + centroid_z = np.trapz(self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist, x_points, dx=dx) + centroid_z = (centroid_z * chord) / section_area + return section_area, centroid_x, centroid_z + + def airfoil_thickness(self, x, max_thickness): + return 5 * max_thickness * (0.2969 * np.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) + + def airfoil_camber_line(self, x, camber, camber_location): + camber_location = max(camber_location, 1e-9) # Divide by zero check + return np.where( + x < camber_location, + (camber / camber_location**2) * (2 * camber_location * x - x**2), + (camber / (1 - camber_location)**2) * ((1 - 2 * camber_location) + 2 * camber_location * x - x**2) + ) + + def extract_airfoil_features(self, x_coords, y_coords): + """ + Extract camber, camber location, and max thickness from the given airfoil data. + This method assumes x_coords are normalized (ranging from 0 to 1). + """ + # Approximate the camber line and max thickness from the data + # Assume the camber line is the line of symmetry between the upper and lower surfaces + upper_surface = y_coords[:int(len(x_coords) // 2)] + lower_surface = y_coords[int(len(x_coords) // 2):] + x_upper = x_coords[:int(len(x_coords) // 2)] + x_lower = x_coords[int(len(x_coords) // 2):] + + upper_spline = CubicSpline(x_upper, upper_surface, bc_type='natural') + lower_spline = CubicSpline(x_lower, lower_surface, bc_type='natural') + + camber_line = (upper_spline(x_coords) + lower_spline(x_coords)) / 2.0 + + thickness = upper_spline(x_coords) - lower_spline(x_coords) + + max_thickness_index = np.argmax(thickness) + max_thickness_value = thickness[max_thickness_index] + + camber_slope = np.gradient(camber_line, x_coords) + camber_location_index = np.argmax(np.abs(camber_slope)) + camber_location = x_coords[camber_location_index] + + camber = camber_line[camber_location_index] + + return camber, camber_location, max_thickness_value + + +prob = om.Problem() + +prob.model.add_subsystem('tail', TailMassAndCOG(), promotes_inputs=['*'], promotes_outputs=['*']) + +prob.setup() + +# Input values +prob.set_val('span', 0.3912) +prob.set_val('tip_chord', 0.15) +prob.set_val('root_chord', 0.26) +prob.set_val('thickness_ratio', 0.12) +prob.set_val('skin_thickness', 0.002) +prob.model.tail.options['tail_type'] = 'vertical' + +prob.model.tail.options['material'] = 'Carbon Fiber' + +prob.run_model() + +# Print +print(f"Mass: {prob.get_val('mass')} kg") +print(f"Center of gravity (X: {prob.get_val('cg_x')} m, Y: {prob.get_val('cg_y')} m, Z: {prob.get_val('cg_z')} m)") \ No newline at end of file diff --git a/aviary/docs/examples/test_wing.py b/aviary/docs/examples/test_wing.py new file mode 100644 index 000000000..ca9e2e14d --- /dev/null +++ b/aviary/docs/examples/test_wing.py @@ -0,0 +1,17 @@ +import unittest + +import openmdao.api as om +from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal + +from aviary.docs.examples.wing import WingMassAndCOG + +class WingMassTestCase(unittest.TestCase): + """ + Wing mass test case + + """ + + def setup(self): + + self.prob = om.Problem() + self.prob.model.add_subsystem("wing", WingMassAndCOG(), promotes=["*"]) \ No newline at end of file From 3164009377623c83e2eb6c0374d0c2f05a702489 Mon Sep 17 00:00:00 2001 From: szoppelt Date: Tue, 4 Mar 2025 14:27:05 +0000 Subject: [PATCH 027/147] Test modified: aviary/docs/examples/wing.py --- aviary/docs/examples/wing.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/aviary/docs/examples/wing.py b/aviary/docs/examples/wing.py index 10266d232..64a5815fa 100644 --- a/aviary/docs/examples/wing.py +++ b/aviary/docs/examples/wing.py @@ -1,9 +1,8 @@ import openmdao.api as om import numpy as np -import matplotlib.pyplot as plt import os from scipy.interpolate import CubicSpline -from scipy.integrate import quad + # Material densities (g/cm³ converted to kg/m³) -- these are just some random examples MATERIAL_DENSITIES = { From 9a67145f288bc4007404554be79a413dad0452df Mon Sep 17 00:00:00 2001 From: szoppelt Date: Tue, 4 Mar 2025 14:47:43 +0000 Subject: [PATCH 028/147] Test. new file: aviary/subsystems/mass/simple_mass/fuselage.py new file: aviary/subsystems/mass/simple_mass/mass_summation.py new file: aviary/subsystems/mass/simple_mass/materials_database.py new file: aviary/subsystems/mass/simple_mass/tail.py new file: aviary/subsystems/mass/simple_mass/wing.py --- .../subsystems/mass/simple_mass/fuselage.py | 303 +++++++++++ .../mass/simple_mass/mass_summation.py | 43 ++ .../mass/simple_mass/materials_database.py | 66 +++ aviary/subsystems/mass/simple_mass/tail.py | 289 +++++++++++ aviary/subsystems/mass/simple_mass/wing.py | 491 ++++++++++++++++++ 5 files changed, 1192 insertions(+) create mode 100644 aviary/subsystems/mass/simple_mass/fuselage.py create mode 100644 aviary/subsystems/mass/simple_mass/mass_summation.py create mode 100644 aviary/subsystems/mass/simple_mass/materials_database.py create mode 100644 aviary/subsystems/mass/simple_mass/tail.py create mode 100644 aviary/subsystems/mass/simple_mass/wing.py diff --git a/aviary/subsystems/mass/simple_mass/fuselage.py b/aviary/subsystems/mass/simple_mass/fuselage.py new file mode 100644 index 000000000..3764a4eff --- /dev/null +++ b/aviary/subsystems/mass/simple_mass/fuselage.py @@ -0,0 +1,303 @@ +import openmdao.api as om +import numpy as np +from scipy.interpolate import interp1d +import logging + +# Configure logging +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +# Material densities (kg/m^3) +MATERIAL_DENSITIES = { + 'wood': 600, # Not any real wood density + 'metal': 2700, # Aluminum + 'carbon_fiber': 1600, + 'foam': 300 # Example density for foam (just for something lightweight) +} + +class FuselageMassAndCOG(om.ExplicitComponent): + def initialize(self): + self.options.declare('num_sections', + types=int, + default=1000) + + self.options.declare('material', + default='foam', + values=list(MATERIAL_DENSITIES.keys())) + + self.options.declare('custom_fuselage_data_file', + types=(str, type(None)), + default=None, + allow_none=True) + + self.custom_fuselage_function = None + + def setup(self): + + # Inputs + self.add_input('length', + val=2.0, + units='m') + + self.add_input('diameter', + val=0.4, + units='m') + + self.add_input('taper_ratio', + val=1.0, + units=None) # 1.0 means no taper + + self.add_input('curvature', + val=0.0, + units='m') # 0 for straight, positive for upward curve + + self.add_input('thickness', + val=0.05, + units='m') # Wall thickness of the fuselage + + # Allow for asymmetry in the y and z axes -- this value acts as a slope for linear variation along these axes + self.add_input('y_offset', + val=0.0, + units='m') + + self.add_input('z_offset', + val=0.0, + units='m') + + self.add_input('is_hollow', + val=True, + units=None) # Whether the fuselage is hollow or not (default is hollow) + + + # Outputs + self.add_output('center_of_gravity_x', + val=0.0, + units='m') + + self.add_output('center_of_gravity_y', + val=0.0, + units='m') + + self.add_output('center_of_gravity_z', + val=0.0, + units='m') + + self.add_output('total_weight', + val=0.0, + units='kg') + + def setup_partials(self): + """ + Complex step is used for the derivatives for now as they are very complicated to calculate + analytically. Compute_partials function has the framework for analytical derivatives, but not + all of them match the check_partials. + """ + self.declare_partials('center_of_gravity_x', ['length', 'diameter', 'taper_ratio', 'curvature', 'thickness'], method='cs') + self.declare_partials('center_of_gravity_y', ['length', 'y_offset', 'curvature'], method='cs') + self.declare_partials('total_weight', ['length', 'diameter', 'thickness'], method='cs') + + def compute_partials(self, inputs, partials): + length = inputs['length'] + diameter = inputs['diameter'] + taper_ratio = inputs['taper_ratio'] + curvature = inputs['curvature'] + thickness = inputs['thickness'] + y_offset = inputs['y_offset'] + z_offset = inputs['z_offset'] + is_hollow = inputs['is_hollow'] + + #custom_fuselage_function = getattr(self, 'custom_fuselage_function', None) # Custom fuselage model function -- if provided + + custom_fuselage_data_file = self.options['custom_fuselage_data_file'] + + material = self.options['material'] + num_sections = self.options['num_sections'] + + self.validate_inputs(length, diameter, thickness, taper_ratio, is_hollow) + + density = MATERIAL_DENSITIES[material] + + section_locations = np.linspace(0, length, num_sections).flatten() + dx = 1 / (num_sections - 1) + + total_weight = 0 + total_moment_x = 0 + total_moment_y = 0 + total_moment_z = 0 + + interpolate_diameter = self.load_fuselage_data(custom_fuselage_data_file) + + out_r = np.zeros(num_sections) + in_r = np.zeros(num_sections) + + + # Loop through each section + for i, location in enumerate(section_locations): + section_diameter = self.get_section_diameter(location, length, diameter, taper_ratio, interpolate_diameter) + outer_radius = section_diameter / 2.0 + inner_radius = max(0, outer_radius - thickness) if is_hollow else 0 + + out_r[i] = outer_radius + in_r[i] = inner_radius + + section_volume = np.pi * (outer_radius**2 - inner_radius**2) * (length / num_sections) + section_weight = density * section_volume + + centroid_x, centroid_y, centroid_z = self.compute_centroid(location, length, y_offset, z_offset, curvature, taper_ratio) + + total_weight += section_weight + total_moment_x += centroid_x * section_weight + total_moment_y += centroid_y * section_weight + total_moment_z += centroid_z * section_weight + + dzcg_dz_offset = np.sum( + np.trapz( + (1 - section_locations / length) * density * np.pi * (out_r**2 - in_r**2), section_locations, dx=dx + ) + ) / total_weight + + + partials['center_of_gravity_x', 'length'] = 3 / 4 if taper_ratio > 0 else 1 + partials['center_of_gravity_x', 'taper_ratio'] = - (3/4) * length if taper_ratio > 0 else 0 + partials['center_of_gravity_x', 'curvature'] = 0 + partials['center_of_gravity_x', 'thickness'] = 0 + + partials['center_of_gravity_y', 'length'] = -y_offset / length + partials['center_of_gravity_y', 'y_offset'] = 1 + + partials['center_of_gravity_z', 'length'] = -z_offset / length + partials['center_of_gravity_z', 'z_offset'] = dzcg_dz_offset + partials['center_of_gravity_z', 'curvature'] = length**2 / num_sections + + partials['total_weight', 'length'] = density * np.pi * (diameter**2 - (diameter - 2 * thickness)**2) / num_sections + partials['total_weight', 'diameter'] = 2 * density * np.pi * length * diameter / num_sections + partials['total_weight', 'thickness'] = -2 * density * np.pi * length * (diameter - thickness) / num_sections + + + def compute(self, inputs, outputs): + length = inputs['length'] + diameter = inputs['diameter'] + taper_ratio = inputs['taper_ratio'] + curvature = inputs['curvature'] + thickness = inputs['thickness'] + y_offset = inputs['y_offset'] + z_offset = inputs['z_offset'] + is_hollow = inputs['is_hollow'] + + # Input validation checks + if length <= 0: + raise ValueError("Length must be greater than zero.") + + if diameter <= 0: + raise ValueError("Diameter must be greater than zero.") + + custom_fuselage_function = getattr(self, 'custom_fuselage_function', None) # Custom fuselage model function -- if provided + + custom_fuselage_data_file = self.options['custom_fuselage_data_file'] + + material = self.options['material'] + num_sections = self.options['num_sections'] + + self.validate_inputs(length, diameter, thickness, taper_ratio, is_hollow) + + density = MATERIAL_DENSITIES[material] + + section_locations = np.linspace(0, length, num_sections) + + total_weight = 0 + total_moment_x = 0 + total_moment_y = 0 + total_moment_z = 0 + + interpolate_diameter = self.load_fuselage_data(custom_fuselage_data_file) + + # Loop through each section + for location in section_locations: + section_diameter = self.get_section_diameter(location, length, diameter, taper_ratio, interpolate_diameter) + outer_radius = section_diameter / 2.0 + inner_radius = max(0, outer_radius - thickness) if is_hollow else 0 + + section_volume = np.pi * (outer_radius**2 - inner_radius**2) * (length / num_sections) + section_weight = density * section_volume + + centroid_x, centroid_y, centroid_z = self.compute_centroid(location, length, y_offset, z_offset, curvature, taper_ratio) + + total_weight += section_weight + total_moment_x += centroid_x * section_weight + total_moment_y += centroid_y * section_weight + total_moment_z += centroid_z * section_weight + + outputs['center_of_gravity_x'] = total_moment_x / total_weight + outputs['center_of_gravity_y'] = total_moment_y / total_weight + outputs['center_of_gravity_z'] = total_moment_z / total_weight + outputs['total_weight'] = total_weight + + def validate_inputs(self, length, diameter, thickness, taper_ratio, is_hollow): + if length <= 0 or diameter <= 0 or thickness <= 0: + raise ValueError("Length, diameter, and thickness must be positive values.") + if taper_ratio < 0 or taper_ratio > 1: + raise ValueError("Taper ratio must be between 0 and 1.") + if is_hollow and thickness >= diameter / 2: + raise ValueError("Wall thickness is too large for a hollow fuselage.") + + def load_fuselage_data(self, custom_fuselage_data_file): + if custom_fuselage_data_file: + try: + # Load the file + custom_data = np.loadtxt(custom_fuselage_data_file) + fuselage_locations = custom_data[:, 0] + fuselage_diameters = custom_data[:, 1] + return interp1d(fuselage_locations, fuselage_diameters, kind='linear', fill_value='extrapolate') + except Exception as e: + raise ValueError(f"Error loading fuselage data file: {e}") + else: + return None + + def get_section_diameter(self, location, length, diameter, taper_ratio, interpolate_diameter): + if self.custom_fuselage_function: + return self.custom_fuselage_function(location) + elif self.load_fuselage_data: + return interpolate_diameter(location) if interpolate_diameter is not None else max(0.01, diameter * (1 - taper_ratio * (location / length))) + else: + return max(0.01, diameter * (1 - taper_ratio * (location / length))) + + def compute_centroid(self, location, length, y_offset, z_offset, curvature, taper_ratio): + centroid_x = (3/4) * location if taper_ratio > 0 else location # This is an approximation that could and should be better modeled in the future + centroid_y = y_offset * (1 - location / length) + centroid_z = z_offset * (1 - location / length) + curvature * location**2 / length + return centroid_x, centroid_y, centroid_z + +prob = om.Problem() + +prob.model.add_subsystem('fuselage_cg', FuselageMassAndCOG(), promotes_inputs=['length', 'diameter', 'taper_ratio', 'curvature', 'thickness', 'y_offset', 'z_offset', 'is_hollow']) + +prob.setup() + +prob.set_val('length', 2.5) +prob.set_val('diameter', 0.5) +prob.set_val('taper_ratio', 0.5) +prob.set_val('curvature', 0.0) +prob.set_val('thickness', 0.05) # Wall thickness of 5 cm +#prob.set_val('is_hollow', False) # Default is True, uncomment to use False -- for testing purposes + +# Example using custom function -- uncomment to run +#def custom_fuselage_model(location): +# return 0.5 * np.exp(-0.1 * location) + +#prob.model.fuselage_cg.custom_fuselage_function = custom_fuselage_model + +# Example for custom .dat file -- uncomment to run +#prob.model.fuselage_cg.options['custom_fuselage_data_file'] = 'Custom_Fuselage.dat' + +prob.run_model() + +center_of_gravity_x = prob.get_val('fuselage_cg.center_of_gravity_x') +center_of_gravity_y = prob.get_val('fuselage_cg.center_of_gravity_y') +center_of_gravity_z = prob.get_val('fuselage_cg.center_of_gravity_z') +total_weight = prob.get_val('fuselage_cg.total_weight') + +#data = prob.check_partials(compact_print=True, abs_err_tol=1e-04, rel_err_tol=1e-04, step=1e-8, step_calc='rel') + +logger.info(f"Center of gravity of the fuselage: X = {center_of_gravity_x} m, Y = {center_of_gravity_y} m, Z = {center_of_gravity_z} m") +logger.info(f"Total weight of the fuselage: {total_weight} kg") + diff --git a/aviary/subsystems/mass/simple_mass/mass_summation.py b/aviary/subsystems/mass/simple_mass/mass_summation.py new file mode 100644 index 000000000..2d040cf78 --- /dev/null +++ b/aviary/subsystems/mass/simple_mass/mass_summation.py @@ -0,0 +1,43 @@ +import numpy as np + +import openmdao.api as om + +# Maybe add some aviary inputs at some point here + +class MassSummation(om.Group): + """ + + Group to compute various design masses for this mass group. + + This group will be expanded greatly as more subsystems are created. + + """ + + def setup(self): + self.add_subsystem( + 'structure_mass', StructureMass(), + promotes_inputs=['*'], promotes_outputs=['*'] + ) + + +class StructureMass(om.ExplicitComponent): + + def setup(self): + # Maybe later change these to Aviary inputs? + self.add_input('wing_mass', val=0.0, units='kg') + self.add_input('fuse_mass', val=0.0, units='kg') + self.add_input('tail_mass', val=0.0, units='kg') + # More masses can be added, i.e., tail, spars, flaps, etc. as needed + + self.add_output('structure_mass', val=0.0, units='kg') + + def setup_partials(self): + # I'm not sure what else to put here at the moment + self.declare_partials('structure_mass', '*', val=1) + + def compute(self, inputs, outputs): + wing_mass = inputs['wing_mass'] + fuse_mass = inputs['fuse_mass'] + tail_mass = inputs['tail_mass'] + + outputs['structure_mass'] = wing_mass + fuse_mass + tail_mass \ No newline at end of file diff --git a/aviary/subsystems/mass/simple_mass/materials_database.py b/aviary/subsystems/mass/simple_mass/materials_database.py new file mode 100644 index 000000000..77b0fb5f4 --- /dev/null +++ b/aviary/subsystems/mass/simple_mass/materials_database.py @@ -0,0 +1,66 @@ +""" +Database for various material densities that are to be used for mass calculations for small aircraft in particular. + +This database will be expanded as needed. + +""" +from aviary.utils.named_values import NamedValues + +materials = NamedValues() + +""" +All densities below came from https://tpsx.arc.nasa.gov/MaterialsDatabase + +""" + +# Wood +materials.set_val('Balsa', 130, units='kg/m**3') +materials.set_val('Cypress', 460, units='kg/m**3') +materials.set_val('Mahogany', 540, units='kg/m**3') +materials.set_val('Maple', 710, units='kg/m**3') +materials.set_val('Teak', 640, units='kg/m**3') + +# Aluminum Compounds and Alloys +materials.set_val('Aluminum Oxide', 3400, units='kg/m**3') +materials.set_val('2024-T8XX', 2800, units='kg/m**3') # aircraft-grade strength Aluminum alloy +materials.set_val('2219-T8XX', 2810, units='kg/m**3') # Exceptionally strong Aluminum alloy +materials.set_val('2024-T6', 2770, units='kg/m**3') # Another Aluminum alloy +materials.set_val('Aluminum Foam', 1300, units='kg/m**3') + +# Steel +materials.set_val('Stainless Steel 17-4 PH', 7830, units='kg/m**3') # 17-4 PH stainless steel +materials.set_val('Stainless Steel-AISI 302', 8060, units='kg/m**3') # AISI 302 +materials.set_val('Stainless Steel-AISI 304', 7900, units='kg/m**3') # AISI 304 +materials.set_val('Steel Alloy Cast', 7830, units='kg/m**3') # General steel alloy cast +materials.set_val('Steel 321', 8030, units='kg/m**3') # Steel type 321 + +# Carbon Fibers / Carbon - Silicon Fibers +materials.set_val('Carbon/Silicon-Carbide', 2080, units='kg/m**3') # Carbon fiber reinforced SiC +materials.set_val('Silicon-Carbide/Silicon-Carbide', 2400, units='kg/m**3') # SiC fiber reinforced SiC matrix +materials.set_val('Advanced Carbon-Carbon Composite', 1600, units='kg/m**3') # ACC +materials.set_val('Reinfoced Carbon-Carbon', 1580, units='kg/m**3') +materials.set_val('Reinforced Carbon-Carbon Composite', 1580, units='kg/m**3') # Generally, ACC is better, but RCC is slightly cheaper + +""" +Below are miscellaneous values that could be of importance, particularly for small aircraft. + +These values were found from a variety of sources, and depending on the source/brand, the density +could be slightly different. For some cases, temperature of the material also matters (typically +the values are provided as a relative density). If there is a temperature dependence from the source, +it will be noted as a comment next to the line where the material value is set. Below are some sources +for various values. + +The values below were not explicity listed from the above source. + +Wood glue: https://www.gorillatough.com/wp-content/uploads/Gorilla-Wood-Glue-v1.2.pdf + +EPS Foam: https://www.abtfoam.com/wp-content/uploads/2020/05/EPS-Standard-Sheet-Sizes-Densities-and-R-values.pdf + Note that there is a density range given, along with different types. The density value used is for Type I, + and the value given is the average of the minimum and maximum within the range provided. The base unit in + this document is pcf for the density. It was converted to kg/m^3 for the actual value input. + +""" + +materials.set_val('Wood Glue', 1080, units='kg/m**3') # Relative density value -- corresponds to 25 C (77 F) +materials.set_val('EPS Foam', 16.3388, units='kg/m**3') + diff --git a/aviary/subsystems/mass/simple_mass/tail.py b/aviary/subsystems/mass/simple_mass/tail.py new file mode 100644 index 000000000..84d61f1ee --- /dev/null +++ b/aviary/subsystems/mass/simple_mass/tail.py @@ -0,0 +1,289 @@ +import openmdao.api as om +import numpy as np +import scipy.integrate as spi +from scipy.interpolate import interp1d +from scipy.interpolate import CubicSpline +import os + +# Material densities, all in kg/m^3 +MATERIALS = { + 'Aluminum': 2700, + 'Steel': 7850, + 'Titanium': 4500, + 'Carbon Fiber': 1600, + 'Wood': 600 +} + +class TailMassAndCOG(om.ExplicitComponent): + def initialize(self): + self.options.declare('tail_type', + default='horizontal', + values=['horizontal', 'vertical'], + desc="Type of tail: 'horizontal' or 'vertical'") + + self.options.declare('airfoil_type', + default='NACA', + values=['NACA', 'file'], + desc="Airfoil type: 'NACA' for 4-digit or 'file' for user-provided coordinates") + + if self.options['airfoil_type'] == 'NACA': + self.options.declare('NACA_digits', + default='2412', + desc="4 digit code for NACA airfoil, if that is given.") + + self.options.declare('material', + default='Aluminum', + values=list(MATERIALS.keys()), + desc="Material type") + + self.options.declare('airfoil_file', + default=None, + desc="File path for airfoil coordinates (if applicable)") + + self.options.declare('num_sections', + default=1000, + desc="Number of sections for enumeration") + + def setup(self): + # Inputs + self.add_input('span', + val=5.0, + units='m', + desc="Tail span") + + self.add_input('root_chord', + val=1.2, + units='m', + desc="Root chord length") + + self.add_input('tip_chord', + val=0.8, + units='m', + desc="Tip chord length") + + self.add_input('thickness_ratio', + val=0.12, + desc="Max thickness to chord ratio for NACA airfoil") + + self.add_input('skin_thickness', + val=0.002, + units='m', + desc="Skin panel thickness") + + self.add_input('twist', + val=np.zeros(self.options['num_sections']), + units='deg', + desc="Twist distribution") + + # Outputs + self.add_output('mass', + val=0.0, + units='kg', + desc="Total mass of the tail") + + self.add_output('cg_x', + val=0.0, + units='m', + desc="X location of the center of gravity") + + self.add_output('cg_y', + val=0.0, + units='m', + desc="Y location of the center of gravity") + + self.add_output('cg_z', + val=0.0, + units='m', + desc="Z location of the center of gravity") + + def compute(self, inputs, outputs): + tail_type = self.options["tail_type"] + airfoil_type = self.options["airfoil_type"] + material = self.options['material'] + span = inputs['span'] + root_chord = inputs['root_chord'] + tip_chord = inputs['tip_chord'] + thickness_ratio = inputs['thickness_ratio'] + density = MATERIALS[material] + airfoil_file = self.options['airfoil_file'] + skin_thickness = inputs['skin_thickness'] + num_sections = self.options['num_sections'] + twist = inputs['twist'] + NACA_digits = self.options['NACA_digits'] + + # File check + if airfoil_type == 'file': + if airfoil_type == 'file' and (airfoil_file is None or not os.path.isfile(airfoil_file)): + raise FileNotFoundError(f"Airfoil file '{airfoil_file}' not found or not provided.") + try: + airfoil_data = np.loadtxt(airfoil_file, skiprows=1) # Assume a header + x_coords, y_coords = airfoil_data[:, 0], airfoil_data[:, 1] + except Exception as e: + raise ValueError(f"Error reading airfoil file: {e}") + + # Compute section airfoil geometry + if airfoil_file and os.path.exists(airfoil_file): + airfoil_data = np.loadtxt(airfoil_file) + x_coords = airfoil_data[:, 0] + y_coords = airfoil_data[:, 1] + + camber, camber_location, max_thickness = self.extract_airfoil_features(x_coords, y_coords) + else: + # Parse the NACA airfoil type (4-digit) + camber = int(NACA_digits[0]) / 100.0 # Maximum camber + camber_location = int(NACA_digits[1]) / 10.0 # Location of max camber + max_thickness = int(NACA_digits[2:4]) / 100.0 # Max thickness + + # Tail type check + if tail_type not in ['horizontal', 'vertical']: + raise ValueError("Invalid tail_type. Must be 'horizontal' or 'vertical'.") + + # Input validation checks + if span <= 0: + raise ValueError("Span must be greater than zero.") + + if root_chord <= 0 or tip_chord <= 0: + raise ValueError("Root chord and tip chord must be greater than zero.") + + if tip_chord > root_chord: + raise ValueError("Tip chord cannot be larger than root chord.") + + if thickness_ratio <= 0: + raise ValueError("Thickness ratio must be greater than zero.") + + if skin_thickness <= 0: + raise ValueError("Skin thickness must be greater than zero.") + + if any(abs(twist)) > np.pi / 2: + raise ValueError("Twist angle is too extreme; must be within -90 to 90 degrees.") + + span_locations = np.linspace(0, span, num_sections) + + # Get x_points and dx for later + x_points, dx = self.precompute_airfoil_geometry() + + # Thickness distribution + thickness_dist = self.airfoil_thickness(x_points, max_thickness) + + total_mass = 0 + total_moment_x = 0 + total_moment_y = 0 + total_moment_z = 0 + + for i, y in enumerate(span_locations): + section_chord = root_chord - (root_chord - tip_chord) * (y / span) # Assume linear variation in chord + section_area, centroid_x, centroid_z = self.compute_airfoil_geometry(section_chord, + camber, + camber_location, + thickness_dist, + x_points, + dx) + + + section_mass = density * section_area * (span / num_sections) + + # Twist + twist_angle = twist[i] + rotated_x = centroid_x * np.cos(twist_angle) - centroid_z * np.sin(twist_angle) + rotated_z = centroid_x * np.sin(twist_angle) + centroid_z * np.cos(twist_angle) + + total_mass += section_mass + total_moment_x += rotated_x * section_mass + if tail_type == 'horizontal': + total_moment_y += y * section_mass + total_moment_z += rotated_z * section_mass + elif tail_type == 'vertical': + total_moment_y += rotated_z * section_mass + total_moment_z += y * section_mass + + # COG + outputs['mass'] = total_mass + outputs['cg_x'] = total_moment_x / total_mass + outputs['cg_y'] = total_moment_y / total_mass + outputs['cg_z'] = total_moment_z / total_mass + + def precompute_airfoil_geometry(self): + num_sections = self.options['num_sections'] + n_points = num_sections + x_points = np.linspace(0, 1, n_points) + dx = 1 / (n_points - 1) + return x_points, dx + + def compute_airfoil_geometry(self, chord, camber, camber_location, thickness_dist, x_points, dx): + + #section_area, _ = quad(lambda x: np.interp(x, x_points, thickness_dist), 0, 1, limit=100) + section_area = np.trapz(thickness_dist, x_points, dx=dx) + section_area *= chord + + #centroid_x, _ = quad(lambda x: x * np.interp(x, x_points, thickness_dist), 0, 1, limit=100) + centroid_x = np.trapz(x_points * thickness_dist, x_points, dx=dx) + centroid_x = (centroid_x * chord) / section_area + + #centroid_z, _ = quad(lambda x: self.airfoil_camber_line(x, camber, camber_location) * np.interp(x, x_points, thickness_dist), 0, 1, limit=100) + centroid_z = np.trapz(self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist, x_points, dx=dx) + centroid_z = (centroid_z * chord) / section_area + return section_area, centroid_x, centroid_z + + def airfoil_thickness(self, x, max_thickness): + return 5 * max_thickness * (0.2969 * np.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) + + def airfoil_camber_line(self, x, camber, camber_location): + camber_location = max(camber_location, 1e-9) # Divide by zero check + return np.where( + x < camber_location, + (camber / camber_location**2) * (2 * camber_location * x - x**2), + (camber / (1 - camber_location)**2) * ((1 - 2 * camber_location) + 2 * camber_location * x - x**2) + ) + + def extract_airfoil_features(self, x_coords, y_coords): + """ + Extract camber, camber location, and max thickness from the given airfoil data. + This method assumes x_coords are normalized (ranging from 0 to 1). + """ + # Approximate the camber line and max thickness from the data + # Assume the camber line is the line of symmetry between the upper and lower surfaces + upper_surface = y_coords[:int(len(x_coords) // 2)] + lower_surface = y_coords[int(len(x_coords) // 2):] + x_upper = x_coords[:int(len(x_coords) // 2)] + x_lower = x_coords[int(len(x_coords) // 2):] + + upper_spline = CubicSpline(x_upper, upper_surface, bc_type='natural') + lower_spline = CubicSpline(x_lower, lower_surface, bc_type='natural') + + camber_line = (upper_spline(x_coords) + lower_spline(x_coords)) / 2.0 + + thickness = upper_spline(x_coords) - lower_spline(x_coords) + + max_thickness_index = np.argmax(thickness) + max_thickness_value = thickness[max_thickness_index] + + camber_slope = np.gradient(camber_line, x_coords) + camber_location_index = np.argmax(np.abs(camber_slope)) + camber_location = x_coords[camber_location_index] + + camber = camber_line[camber_location_index] + + return camber, camber_location, max_thickness_value + + +prob = om.Problem() + +prob.model.add_subsystem('tail', TailMassAndCOG(), promotes_inputs=['*'], promotes_outputs=['*']) + +prob.setup() + +# Input values +prob.set_val('span', 0.3912) +prob.set_val('tip_chord', 0.15) +prob.set_val('root_chord', 0.26) +prob.set_val('thickness_ratio', 0.12) +prob.set_val('skin_thickness', 0.002) +prob.model.tail.options['tail_type'] = 'vertical' + +prob.model.tail.options['material'] = 'Carbon Fiber' + +prob.run_model() + +# Print +print(f"Mass: {prob.get_val('mass')} kg") +print(f"Center of gravity (X: {prob.get_val('cg_x')} m, Y: {prob.get_val('cg_y')} m, Z: {prob.get_val('cg_z')} m)") \ No newline at end of file diff --git a/aviary/subsystems/mass/simple_mass/wing.py b/aviary/subsystems/mass/simple_mass/wing.py new file mode 100644 index 000000000..64a5815fa --- /dev/null +++ b/aviary/subsystems/mass/simple_mass/wing.py @@ -0,0 +1,491 @@ +import openmdao.api as om +import numpy as np +import os +from scipy.interpolate import CubicSpline + + +# Material densities (g/cm³ converted to kg/m³) -- these are just some random examples +MATERIAL_DENSITIES = { + 'wood': 130, # balsa wood + 'metal': 2700, # Aluminum + 'carbon_fiber': 1600 +} + + + +class WingMassAndCOG(om.ExplicitComponent): + def initialize(self): + self.options.declare('num_sections', + types=int, + default=1000) + + self.options.declare('airfoil_type', + types=str, + default='2412') # use 2412 as example for default + + self.options.declare('material', + default='metal', + values=list(MATERIAL_DENSITIES.keys())) + + self.options.declare('airfoil_data_file', + default=None, + types=str) # For user-provided airfoil data file + + def setup(self): + + # Inputs + self.add_input('span', + val=10.0, + units='m') # Full wingspan (adjustable) + + self.add_input('root_chord', + val=2.0, + units='m') # Root chord length + + self.add_input('tip_chord', + val=1.0, + units='m') # Tip chord length + + self.add_input('twist', + val=np.zeros(self.options['num_sections']), + units='deg') # Twist angles + + self.add_input('thickness_dist', + val=np.ones(self.options['num_sections']) * 0.1, + shape=(self.options['num_sections'],)) # Thickness distribution of the wing (height) + + + # Outputs + self.add_output('center_of_gravity_x', + val=0.0, + units='m') + + self.add_output('center_of_gravity_y', + val=0.0, + units='m') + + self.add_output('center_of_gravity_z', + val=0.0, + units='m') + + self.add_output('total_weight', + val=0.0, + units='kg') + + def setup_partials(self): + """ + Complex step is used for the derivatives for now as they are very complicated to calculate + analytically. Compute_partials function has the framework for analytical derivatives, but not + all of them match the check_partials. + """ + num_sections = self.options['num_sections'] + + self.declare_partials(['center_of_gravity_x', 'center_of_gravity_y', 'center_of_gravity_z'], + ['span', 'root_chord', 'tip_chord', 'thickness_dist', 'twist'], method='cs') + self.declare_partials('total_weight', ['span', 'root_chord', 'tip_chord', 'thickness_dist', 'twist'], method='cs') + + + def compute(self, inputs, outputs): + span = inputs['span'] + root_chord = inputs['root_chord'] + tip_chord = inputs['tip_chord'] + twist = np.radians(inputs['twist']) # Convert twist to radians + thickness_dist = inputs['thickness_dist'] + material = self.options['material'] # Material is taken from options + #num_sections = self.options['num_sections'] + airfoil_type = self.options['airfoil_type'] # NACA airfoil type + airfoil_data_file = self.options['airfoil_data_file'] + + # Input validation checks + if span <= 0: + raise ValueError("Span must be greater than zero.") + + if root_chord <= 0 or tip_chord <= 0: + raise ValueError("Root chord and tip chord must be greater than zero.") + + if tip_chord > root_chord: + raise ValueError("Tip chord cannot be larger than root chord.") + + if any(abs(twist)) > np.pi / 2: + raise ValueError("Twist angle is too extreme; must be within -90 to 90 degrees.") + + # Get material density + density = MATERIAL_DENSITIES[material] # in kg/m³ + + #x_points, dx = self.precompute_airfoil_geometry() + + if airfoil_data_file and os.path.exists(airfoil_data_file): + airfoil_data = np.loadtxt(airfoil_data_file) + x_coords = airfoil_data[:, 0] + y_coords = airfoil_data[:, 1] + + camber, camber_location, max_thickness, thickness, camber_line = self.extract_airfoil_features(x_coords, y_coords) + thickness_dist = thickness + num_sections = len(x_coords) + else: + # Parse the NACA airfoil type (4-digit) + camber = int(airfoil_type[0]) / 100.0 # Maximum camber + camber_location = int(airfoil_type[1]) / 10.0 # Location of max camber + max_thickness = int(airfoil_type[2:4]) / 100.0 # Max thickness + num_sections = self.options['num_sections'] + + # Wing spanwise distribution + span_locations = np.linspace(0, span, num_sections) + + #num_sections = self.options['num_sections'] + n_points = num_sections + x_points = np.linspace(0, 1, n_points) + dx = 1 / (n_points - 1) + + # Initialize total weight and moment accumulators + total_weight = 0 + total_moment_x = 0 + total_moment_y = 0 + total_moment_z = 0 + + # Arrays for storing 3D coordinates of the wing + x_coords = [] + y_coords = [] + z_coords = [] + + # Loop over each section along the span (3D wing approximation) + for i, location in enumerate(span_locations): + # Calculate the chord for this section -- note this is an approximation + chord = root_chord - (root_chord - tip_chord) * (location / span) # Assuming linear variation from root to tip + + # Apply twist + twist_angle = twist[i] + + section_area, centroid_x, centroid_z = self.compute_airfoil_geometry(chord, camber, camber_location, thickness_dist, x_points, dx) + centroid_y = i * span / num_sections + section_weight = density * section_area * (span / num_sections) + + rotated_x = centroid_x * np.cos(twist_angle) - centroid_z * np.sin(twist_angle) + rotated_z = centroid_x * np.sin(twist_angle) + centroid_z * np.cos(twist_angle) + + total_weight += section_weight + total_moment_x += rotated_x * section_weight + total_moment_y += centroid_y * section_weight + total_moment_z += rotated_z * section_weight + + + # Store the coordinates for plotting later + x_coords.append(rotated_x) + y_coords.append(centroid_y) + z_coords.append(rotated_z) + + # Calculate the overall center of gravity + outputs['center_of_gravity_x'] = total_moment_x / total_weight + outputs['center_of_gravity_y'] = total_moment_y / total_weight + outputs['center_of_gravity_z'] = total_moment_z / total_weight + outputs['total_weight'] = total_weight + + + def compute_partials(self, inputs, J): + span = inputs['span'] + root_chord = inputs['root_chord'] + tip_chord = inputs['tip_chord'] + thickness_dist = inputs['thickness_dist'] + twist=np.radians(inputs['twist']) + num_sections = self.options['num_sections'] + airfoil_type = self.options['airfoil_type'] # NACA airfoil type + airfoil_data_file = self.options['airfoil_data_file'] + material = self.options['material'] + + # Compute section locations along the span + span_locations = np.linspace(0, span, num_sections) + span_locations = span_locations / span + chord_lengths = tip_chord + (root_chord - tip_chord) * (1 - span_locations / span) + + # Compute section airfoil geometry + if airfoil_data_file and os.path.exists(airfoil_data_file): + airfoil_data = np.loadtxt(airfoil_data_file) + x_coords = airfoil_data[:, 0] + y_coords = airfoil_data[:, 1] + + camber, camber_location, max_thickness, thickness, camber_line = self.extract_airfoil_features(x_coords, y_coords) + thickness_dist = thickness + else: + # Parse the NACA airfoil type (4-digit) + camber = int(airfoil_type[0]) / 100.0 # Maximum camber + camber_location = int(airfoil_type[1]) / 10.0 # Location of max camber + max_thickness = int(airfoil_type[2:4]) / 100.0 # Max thickness + + # Compute section airfoil geometry + n_points = num_sections + x_points = np.linspace(0, 1, n_points) + dx = 1 / (num_sections - 1) + + #A_ref, err = quad(lambda x: np.interp(x, x_points, thickness_dist), 0, 1, limit=100) # \int_0^1 t(x) dx + A_ref = np.trapz(thickness_dist, x_points, dx=dx) + + density = MATERIAL_DENSITIES[material] + + total_moment_x = 0 + total_moment_y = 0 + total_moment_z = 0 + total_weight = 0 + + rotated_x_vals = np.zeros(num_sections) + rotated_z_vals = np.zeros(num_sections) + #section_weights = np.zeros(num_sections) + section_areas = np.zeros(num_sections) + dA_dspan = 0 + dA_droot_chord = 0 + dA_dtip_chord = 0 + dweight_dspan = 0 + dmoment_x_dtwist = np.zeros(num_sections) + dmoment_z_dtwist = np.zeros(num_sections) + dweight_dthickness = np.zeros(num_sections) + + for i, location in enumerate(span_locations): + # Calculate the chord for this section + chord = root_chord - (root_chord - tip_chord) * (location / span) # Assuming linear variation from root to tip + + # Apply twist + twist_angle = twist[i] + + section_area, centroid_x, centroid_z = self.compute_airfoil_geometry(chord, camber, camber_location, thickness_dist, x_points, dx) + section_weight = density * section_area * (span / num_sections) + centroid_y = location + + rotated_x_vals[i] = centroid_x * np.cos(twist_angle) - centroid_z * np.sin(twist_angle) + rotated_z_vals[i] = centroid_x * np.sin(twist_angle) + centroid_z * np.cos(twist_angle) + + total_weight += section_weight + total_moment_x += rotated_x_vals[i] * section_weight + total_moment_y += centroid_y * section_weight + total_moment_z += rotated_z_vals[i] * section_weight + + #section_weights[i] = section_weight + section_areas[i] = section_area + + # For dweight_dspan + dci_dspan = -(root_chord - tip_chord) * (location / span**2) + #dA_dspan, _ = quad(lambda x: np.interp(x, x_points, thickness_dist) * dci_dspan, 0, 1, limit=100) + dA_ds = np.trapz(thickness_dist * dci_dspan, x_points, dx=dx) + dA_dc_root = np.trapz(thickness_dist * (1 - i / num_sections), x_points, dx=dx) + dA_dc_tip = np.trapz(thickness_dist * i / num_sections, x_points, dx=dx) + dA_dspan += dA_ds + dA_droot_chord += dA_dc_root + dA_dtip_chord += dA_dc_tip + dweight_dspan += density * (section_area / num_sections - dA_ds * span / num_sections) + dmoment_x_dtwist[i] = -section_weight * (centroid_x * np.sin(twist_angle) + centroid_z * np.cos(twist_angle)) + dmoment_z_dtwist[i] = section_weight * (centroid_x * np.cos(twist_angle) - centroid_z * np.sin(twist_angle)) + dweight_dthickness[i] = density * span * chord / num_sections # dW_total / dthickness_dist -- vector value + + dweight_droot_chord = np.sum(density * A_ref * span / 2) # ((num_sections - 1) / (2 * num_sections)) ~ 1/2 for large N + dweight_dtip_chord = np.sum(density * A_ref * span / 2) # ((num_sections + 1) / (2 * num_sections)) ~ 1/2 for large N + + J['total_weight', 'span'] = dweight_dspan + J['total_weight', 'root_chord'] = dweight_droot_chord + J['total_weight', 'tip_chord'] = dweight_dtip_chord + J['total_weight', 'thickness_dist'] = dweight_dthickness + J['total_weight', 'twist'] = 0 + + dxcg_droot_chord = 0 + dzcg_droot_chord = 0 + dxcg_dtip_chord = 0 + dzcg_dtip_chord = 0 + for i, location in enumerate(span_locations): + dxcg_dcroot = np.sum( + np.trapz( + (x_points * thickness_dist * np.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * np.sin(twist)) * (1 - i / num_sections), x_points, dx=dx + ) + ) / np.sum(section_areas) - np.sum( + ( + np.trapz( + x_points * thickness_dist * chord_lengths * np.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * np.sin(twist), x_points, dx=dx + ) * np.trapz( + thickness_dist * (1 - i / num_sections), x_points, dx=dx + ) + ) + ) / np.sum(section_areas)**2 + dxcg_droot_chord += dxcg_dcroot + + dzcg_dcroot = np.sum( + np.trapz( + (x_points * thickness_dist * (1 - i / num_sections) * np.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist) * (1 - i / num_sections) * np.cos(twist), x_points, dx=dx + ) + ) / np.sum(section_areas) - np.sum( + np.trapz( + x_points * thickness_dist * chord_lengths * np.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * np.cos(twist), x_points, dx=dx + ) * dA_droot_chord + ) / np.sum(section_areas)**2 + dzcg_droot_chord += dzcg_dcroot + + dxcg_dctip = np.sum( + np.trapz( + (x_points * thickness_dist *np.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * np.sin(twist)) * (i / num_sections), x_points, dx=dx + ) / section_areas + ) - np.sum( + ( + np.trapz( + x_points * thickness_dist * chord_lengths * np.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * np.sin(twist), x_points, dx=dx + ) + ) * dA_dtip_chord + ) / np.sum(section_areas)**2 + dxcg_dtip_chord += dxcg_dctip + + dzcg_dctip = np.sum( + np.trapz( + x_points * thickness_dist * (i / num_sections) * np.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * (i / num_sections) * np.cos(twist), x_points, dx=dx + ) + ) / np.sum(section_areas) - np.sum( + np.trapz( + x_points * thickness_dist * chord_lengths * np.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * np.cos(twist), x_points, dx=dx + ) * dA_dtip_chord + ) / np.sum(section_areas)**2 + dzcg_dtip_chord += dzcg_dctip + + # partials of cog x + J['center_of_gravity_x', 'span'] = 0 + J['center_of_gravity_x', 'root_chord'] = dxcg_droot_chord + J['center_of_gravity_x', 'tip_chord'] = dxcg_dtip_chord + J['center_of_gravity_x', 'thickness_dist'] = np.sum( + np.trapz( + x_points * chord_lengths * np.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * chord_lengths * np.sin(twist), x_points, dx=dx + ) / section_areas + ) - ( + np.sum( + np.trapz(x_points * thickness_dist * chord_lengths * np.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * np.sin(twist), x_points, dx=dx) + ) * np.sum(chord_lengths) + ) / np.sum(section_areas)**2 + J['center_of_gravity_x', 'twist'] = dmoment_x_dtwist / total_weight + + # For center of gravity in y calculations + + sum_area_times_i = 0 + sum_darea_times_i = 0 + + for i in range(len(x_points)): + sum_area_times_i += i * section_areas[i] + sum_darea_times_i += i * dA_dspan # for cg_Y calculations + + dcg_y_dspan = np.sum(sum_area_times_i / (num_sections * section_areas)) #+ np.sum((span * sum_darea_times_i) / (num_sections * section_areas)) - np.sum((span * sum_area_times_i) / (num_sections * np.sum(section_areas)**2)) * dA_dspan + + # partials of cog y + J['center_of_gravity_y', 'span'] = dcg_y_dspan + J['center_of_gravity_y', 'root_chord'] = -total_moment_y / total_weight * dweight_droot_chord / total_weight + J['center_of_gravity_y', 'tip_chord'] = -total_moment_y / total_weight * dweight_dtip_chord / total_weight + J['center_of_gravity_y', 'thickness_dist'] = -total_moment_y / total_weight * dweight_dthickness / total_weight + J['center_of_gravity_y', 'twist'] = 0 + + # partials of cog z + J['center_of_gravity_z', 'span'] = 0 + J['center_of_gravity_z', 'root_chord'] = dzcg_droot_chord + J['center_of_gravity_z', 'tip_chord'] = dzcg_dtip_chord + J['center_of_gravity_z', 'thickness_dist'] = np.sum( + np.trapz( + x_points * chord_lengths * np.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * chord_lengths * np.cos(twist), x_points, dx=dx + ) + ) / np.sum( + section_areas + ) + J['center_of_gravity_z', 'twist'] = dmoment_z_dtwist / total_weight + + def precompute_airfoil_geometry(self): + num_sections = self.options['num_sections'] + n_points = num_sections + x_points = np.linspace(0, 1, n_points) + dx = 1 / (n_points - 1) + return x_points, dx + + def compute_airfoil_geometry(self, chord, camber, camber_location, thickness_dist, x_points, dx): + + #section_area, _ = quad(lambda x: np.interp(x, x_points, thickness_dist), 0, 1, limit=100) + section_area = np.trapz(thickness_dist, x_points, dx=dx) # trying np.trapz rather than quad to get rid of IntegrationWarning + section_area *= chord + + #centroid_x, _ = quad(lambda x: x * np.interp(x, x_points, thickness_dist), 0, 1, limit=100) + centroid_x = np.trapz(x_points * thickness_dist, x_points, dx=dx) + centroid_x = (centroid_x * chord) / section_area + + #centroid_z, _ = quad(lambda x: self.airfoil_camber_line(x, camber, camber_location) * np.interp(x, x_points, thickness_dist), 0, 1, limit=100) + centroid_z = np.trapz(self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist, x_points, dx=dx) + centroid_z = (centroid_z * chord) / section_area + return section_area, centroid_x, centroid_z + + def airfoil_thickness(self, x, max_thickness): + return 5 * max_thickness * (0.2969 * np.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) + + def airfoil_camber_line(self, x, camber, camber_location): + camber_location = max(camber_location, 1e-9) # Divide by zero check + return np.where( + x < camber_location, + (camber / camber_location**2) * (2 * camber_location * x - x**2), + (camber / (1 - camber_location)**2) * ((1 - 2 * camber_location) + 2 * camber_location * x - x**2) + ) + + def extract_airfoil_features(self, x_coords, y_coords): + """ + Extract camber, camber location, and max thickness from the given airfoil data. + This method assumes x_coords are normalized (ranging from 0 to 1). + """ + # Approximate the camber line and max thickness from the data + # Assume the camber line is the line of symmetry between the upper and lower surfaces + upper_surface = y_coords[:int(len(x_coords) // 2)] + lower_surface = y_coords[int(len(x_coords) // 2):] + x_upper = x_coords[:int(len(x_coords) // 2)] + x_lower = x_coords[int(len(x_coords) // 2):] + + upper_spline = CubicSpline(x_upper, upper_surface, bc_type='natural') + lower_spline = CubicSpline(x_lower, lower_surface, bc_type='natural') + + camber_line = (upper_spline(x_coords) + lower_spline(x_coords)) / 2.0 + + thickness = upper_spline(x_coords) - lower_spline(x_coords) + + max_thickness_index = np.argmax(thickness) + max_thickness_value = thickness[max_thickness_index] + + camber_slope = np.gradient(camber_line, x_coords) + camber_location_index = np.argmax(np.abs(camber_slope)) + camber_location = x_coords[camber_location_index] + + camber = camber_line[camber_location_index] + + return camber, camber_location, max_thickness_value, thickness, camber_line + + +# Build OpenMDAO problem +prob = om.Problem() + +# Add the center of gravity component +prob.model.add_subsystem('cog', WingMassAndCOG() , promotes_inputs=['span', 'root_chord', 'tip_chord', 'twist', 'thickness_dist']) + +n_points = 1000 # = num_sections +x = np.linspace(0, 1, n_points) +max_thickness_chord_ratio = 0.12 +thickness_dist = 5 * max_thickness_chord_ratio * (0.2969 * np.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) + +# Setup the problem +prob.setup() + +# Define some example inputs +prob.set_val('span', 2.438) +prob.set_val('root_chord', 0.3722) +prob.set_val('tip_chord', 0.2792) +prob.set_val('twist', np.linspace(0, 0, 1000)) +#prob.set_val('thickness_dist', thickness_dist) + + +prob.model.cog.options['airfoil_data_file'] = 'Clark_Y.dat' +prob.model.cog.options['material'] = 'wood' +#prob.model.cog.options['airfoil_type'] = '2412' + +# Run the model +prob.run_model() + +# Get the results +center_of_gravity_x = prob.get_val('cog.center_of_gravity_x') +center_of_gravity_y = prob.get_val('cog.center_of_gravity_y') +center_of_gravity_z = prob.get_val('cog.center_of_gravity_z') +total_weight = prob.get_val('cog.total_weight') + +#data = prob.check_partials(compact_print=True, method='cs') +#om.partial_deriv_plot(data) + +print(f"Center of gravity: X = {center_of_gravity_x} m, Y = {center_of_gravity_y} m, Z = {center_of_gravity_z} m") +print(f"Total weight of the wing: {total_weight} kg") + From dbdee9a97d42d6f95b41986fc83fe4dffe57418d Mon Sep 17 00:00:00 2001 From: szoppelt Date: Tue, 4 Mar 2025 16:03:13 +0000 Subject: [PATCH 029/147] test new file: aviary/subsystems/mass/simple_mass/Clark_Y.dat new file: aviary/subsystems/mass/simple_mass/Custom_Fuselage.dat new file: aviary/subsystems/mass/simple_mass/airfoil_data_test.dat new file: aviary/subsystems/mass/simple_mass/mass_builder.py new file: aviary/subsystems/mass/simple_mass/mass_premission.py new file: aviary/subsystems/mass/simple_mass/test_wing.py --- .../subsystems/mass/simple_mass/Clark_Y.dat | 122 ++++++++++++ .../mass/simple_mass/Custom_Fuselage.dat | 179 ++++++++++++++++++ .../mass/simple_mass/airfoil_data_test.dat | 124 ++++++++++++ .../mass/simple_mass/mass_builder.py | 92 +++++++++ .../mass/simple_mass/mass_premission.py | 39 ++++ .../subsystems/mass/simple_mass/test_wing.py | 42 ++++ 6 files changed, 598 insertions(+) create mode 100644 aviary/subsystems/mass/simple_mass/Clark_Y.dat create mode 100644 aviary/subsystems/mass/simple_mass/Custom_Fuselage.dat create mode 100644 aviary/subsystems/mass/simple_mass/airfoil_data_test.dat create mode 100644 aviary/subsystems/mass/simple_mass/mass_builder.py create mode 100644 aviary/subsystems/mass/simple_mass/mass_premission.py create mode 100644 aviary/subsystems/mass/simple_mass/test_wing.py diff --git a/aviary/subsystems/mass/simple_mass/Clark_Y.dat b/aviary/subsystems/mass/simple_mass/Clark_Y.dat new file mode 100644 index 000000000..3649ca4e2 --- /dev/null +++ b/aviary/subsystems/mass/simple_mass/Clark_Y.dat @@ -0,0 +1,122 @@ +0.0000000 0.0000000 +0.0005000 0.0023390 +0.0010000 0.0037271 +0.0020000 0.0058025 +0.0040000 0.0089238 +0.0080000 0.0137350 +0.0120000 0.0178581 +0.0200000 0.0253735 +0.0300000 0.0330215 +0.0400000 0.0391283 +0.0500000 0.0442753 +0.0600000 0.0487571 +0.0800000 0.0564308 +0.1000000 0.0629981 +0.1200000 0.0686204 +0.1400000 0.0734360 +0.1600000 0.0775707 +0.1800000 0.0810687 +0.2000000 0.0839202 +0.2200000 0.0861433 +0.2400000 0.0878308 +0.2600000 0.0890840 +0.2800000 0.0900016 +0.3000000 0.0906804 +0.3200000 0.0911857 +0.3400000 0.0915079 +0.3600000 0.0916266 +0.3800000 0.0915212 +0.4000000 0.0911712 +0.4200000 0.0905657 +0.4400000 0.0897175 +0.4600000 0.0886427 +0.4800000 0.0873572 +0.5000000 0.0858772 +0.5200000 0.0842145 +0.5400000 0.0823712 +0.5600000 0.0803480 +0.5800000 0.0781451 +0.6000000 0.0757633 +0.6200000 0.0732055 +0.6400000 0.0704822 +0.6600000 0.0676046 +0.6800000 0.0645843 +0.7000000 0.0614329 +0.7200000 0.0581599 +0.7400000 0.0547675 +0.7600000 0.0512565 +0.7800000 0.0476281 +0.8000000 0.0438836 +0.8200000 0.0400245 +0.8400000 0.0360536 +0.8600000 0.0319740 +0.8800000 0.0277891 +0.9000000 0.0235025 +0.9200000 0.0191156 +0.9400000 0.0146239 +0.9600000 0.0100232 +0.9700000 0.0076868 +0.9800000 0.0053335 +0.9900000 0.0029690 +1.0000000 0.0005993 +0.0000000 0.0000000 +0.0005000 -.0046700 +0.0010000 -.0059418 +0.0020000 -.0078113 +0.0040000 -.0105126 +0.0080000 -.0142862 +0.0120000 -.0169733 +0.0200000 -.0202723 +0.0300000 -.0226056 +0.0400000 -.0245211 +0.0500000 -.0260452 +0.0600000 -.0271277 +0.0800000 -.0284595 +0.1000000 -.0293786 +0.1200000 -.0299633 +0.1400000 -.0302404 +0.1600000 -.0302546 +0.1800000 -.0300490 +0.2000000 -.0296656 +0.2200000 -.0291445 +0.2400000 -.0285181 +0.2600000 -.0278164 +0.2800000 -.0270696 +0.3000000 -.0263079 +0.3200000 -.0255565 +0.3400000 -.0248176 +0.3600000 -.0240870 +0.3800000 -.0233606 +0.4000000 -.0226341 +0.4200000 -.0219042 +0.4400000 -.0211708 +0.4600000 -.0204353 +0.4800000 -.0196986 +0.5000000 -.0189619 +0.5200000 -.0182262 +0.5400000 -.0174914 +0.5600000 -.0167572 +0.5800000 -.0160232 +0.6000000 -.0152893 +0.6200000 -.0145551 +0.6400000 -.0138207 +0.6600000 -.0130862 +0.6800000 -.0123515 +0.7000000 -.0116169 +0.7200000 -.0108823 +0.7400000 -.0101478 +0.7600000 -.0094133 +0.7800000 -.0086788 +0.8000000 -.0079443 +0.8200000 -.0072098 +0.8400000 -.0064753 +0.8600000 -.0057408 +0.8800000 -.0050063 +0.9000000 -.0042718 +0.9200000 -.0035373 +0.9400000 -.0028028 +0.9600000 -.0020683 +0.9700000 -.0017011 +0.9800000 -.0013339 +0.9900000 -.0009666 +1.0000000 -.0005993 \ No newline at end of file diff --git a/aviary/subsystems/mass/simple_mass/Custom_Fuselage.dat b/aviary/subsystems/mass/simple_mass/Custom_Fuselage.dat new file mode 100644 index 000000000..ce85fe585 --- /dev/null +++ b/aviary/subsystems/mass/simple_mass/Custom_Fuselage.dat @@ -0,0 +1,179 @@ +0.0 0.5 +0.5 0.45 +1.0 0.4 +1.5 0.6 +2.0 0.3 +2.5 0.35 + +class CenterOfGravity3D(om.ExplicitComponent): + def initialize(self): + self.options.declare('num_sections', types=int, default=50) + self.options.declare('airfoil_type', types=str, default='2412') + self.options.declare('material', default='metal', values=['wood', 'metal', 'carbon_fiber']) + self.options.declare('airfoil_data_file', default=None, types=str) + + def setup(self): + num_sections = self.options['num_sections'] + + # Inputs + self.add_input('span', val=10.0, units='m') + self.add_input('root_chord', val=2.0, units='m') + self.add_input('tip_chord', val=1.0, units='m') + self.add_input('twist', val=np.zeros(num_sections), units='deg') + self.add_input('thickness', val=0.2, units='m') + + # Outputs + self.add_output('center_of_gravity_x', val=0.0, units='m') + self.add_output('center_of_gravity_y', val=0.0, units='m') + self.add_output('center_of_gravity_z', val=0.0, units='m') + self.add_output('total_weight', val=0.0, units='kg') + self.add_output('x_coords', val=np.zeros(num_sections), units='m') + self.add_output('y_coords', val=np.zeros(num_sections), units='m') + self.add_output('z_coords', val=np.zeros(num_sections), units='m') + + def setup_partials(self): + num_sections = self.options['num_sections'] + + self.declare_partials(of=['center_of_gravity_x', 'center_of_gravity_y', 'center_of_gravity_z'], + wrt=['span', 'root_chord', 'tip_chord', 'thickness']) + self.declare_partials(of='total_weight', wrt=['span', 'root_chord', 'tip_chord', 'thickness']) + self.declare_partials(of='x_coords', wrt=['twist'], rows=np.arange(num_sections), cols=np.arange(num_sections)) + self.declare_partials(of='y_coords', wrt=['span'], rows=np.arange(num_sections), cols=np.arange(num_sections)) + self.declare_partials(of='z_coords', wrt=['twist'], rows=np.arange(num_sections), cols=np.arange(num_sections)) + + def compute_partials(self, inputs, partials): + """Compute the analytical derivatives of outputs with respect to inputs.""" + span = inputs['span'] + root_chord = inputs['root_chord'] + tip_chord = inputs['tip_chord'] + thickness = inputs['thickness'] + num_sections = self.options['num_sections'] + + # Compute section locations along the span + span_locations = np.linspace(0, span, num_sections) + chord_lengths = root_chord - (root_chord - tip_chord) * (span_locations / span) + dchord_dspan = (tip_chord - root_chord) / span # Chord gradient w.r.t. span + + # Compute derivatives of total weight + total_weight = np.sum(chord_lengths * thickness * (span / num_sections)) + d_weight_dspan = np.sum(dchord_dspan * thickness * (span / num_sections)) + np.sum(chord_lengths * thickness / num_sections) + d_weight_droot_chord = np.sum(thickness * (span / num_sections)) + d_weight_dtip_chord = np.sum(thickness * (span / num_sections) * (span_locations / span)) + d_weight_dthickness = np.sum(chord_lengths * (span / num_sections)) + + partials['total_weight', 'span'] = d_weight_dspan + partials['total_weight', 'root_chord'] = d_weight_droot_chord + partials['total_weight', 'tip_chord'] = d_weight_dtip_chord + partials['total_weight', 'thickness'] = d_weight_dthickness + + # Compute derivatives of center of gravity coordinates + centroid_xs = chord_lengths / 4 # Approximate centroid of airfoil section + centroid_ys = span_locations + centroid_zs = np.zeros_like(span_locations) # Assuming zero camber + + total_moment_x = np.sum(centroid_xs * chord_lengths * thickness * (span / num_sections)) + total_moment_y = np.sum(centroid_ys * chord_lengths * thickness * (span / num_sections)) + total_moment_z = np.sum(centroid_zs * chord_lengths * thickness * (span / num_sections)) + + partials['center_of_gravity_x', 'span'] = (np.sum(dchord_dspan * centroid_xs * thickness * (span / num_sections)) - + total_moment_x / total_weight * d_weight_dspan) / total_weight + partials['center_of_gravity_x', 'root_chord'] = (np.sum(centroid_xs * thickness * (span / num_sections)) - + total_moment_x / total_weight * d_weight_droot_chord) / total_weight + partials['center_of_gravity_x', 'tip_chord'] = (np.sum(centroid_xs * thickness * (span / num_sections) * (span_locations / span)) - + total_moment_x / total_weight * d_weight_dtip_chord) / total_weight + partials['center_of_gravity_x', 'thickness'] = (np.sum(centroid_xs * chord_lengths * (span / num_sections)) - + total_moment_x / total_weight * d_weight_dthickness) / total_weight + + partials['center_of_gravity_y', 'span'] = (np.sum(dchord_dspan * centroid_ys * thickness * (span / num_sections)) - + total_moment_y / total_weight * d_weight_dspan) / total_weight + partials['center_of_gravity_y', 'root_chord'] = (np.sum(centroid_ys * thickness * (span / num_sections)) - + total_moment_y / total_weight * d_weight_droot_chord) / total_weight + partials['center_of_gravity_y', 'tip_chord'] = (np.sum(centroid_ys * thickness * (span / num_sections) * (span_locations / span)) - + total_moment_y / total_weight * d_weight_dtip_chord) / total_weight + partials['center_of_gravity_y', 'thickness'] = (np.sum(centroid_ys * chord_lengths * (span / num_sections)) - + total_moment_y / total_weight * d_weight_dthickness) / total_weight + + partials['center_of_gravity_z', 'span'] = 0 # No camber means no variation + partials['center_of_gravity_z', 'root_chord'] = 0 + partials['center_of_gravity_z', 'tip_chord'] = 0 + partials['center_of_gravity_z', 'thickness'] = 0 + + # Compute derivatives of x_coords and z_coords w.r.t. twist + twist = np.radians(inputs['twist']) + for i in range(num_sections): + partials['x_coords', 'twist'][i] = -centroid_xs[i] * np.sin(twist[i]) + partials['z_coords', 'twist'][i] = centroid_xs[i] * np.cos(twist[i]) + + +def compute_partials(self, inputs, partials): + """Compute the analytical derivatives of outputs with respect to inputs.""" + span = inputs['span'] + root_chord = inputs['root_chord'] + tip_chord = inputs['tip_chord'] + thickness = inputs['thickness'] + twist = np.radians(inputs['twist']) # Convert twist from degrees to radians + num_sections = self.options['num_sections'] + + # Spanwise locations + span_locations = np.linspace(0, span, num_sections) + + # Chord length variation (linear taper) + chord_lengths = root_chord - (root_chord - tip_chord) * (span_locations / span) + dchord_dspan = (tip_chord - root_chord) / span # Chord gradient w.r.t. span + + # Compute centroid locations + centroid_xs = chord_lengths / 4 # Approximate centroid X-location (quarter chord) + centroid_ys = span_locations # The spanwise locations + centroid_zs = np.zeros_like(span_locations) # Assume zero camber for now + + # Compute rotated centroid due to twist + rotated_xs = centroid_xs * np.cos(twist) - centroid_zs * np.sin(twist) + rotated_zs = centroid_xs * np.sin(twist) + centroid_zs * np.cos(twist) + + # Compute weight of each section + section_areas = chord_lengths * thickness # Simple approximation + section_volumes = section_areas * (span / num_sections) # Volume of each section + section_weights = section_volumes # Assuming uniform density + + # Compute total weight + total_weight = np.sum(section_weights) + + # Compute moments for CoG + total_moment_x = np.sum(rotated_xs * section_weights) + total_moment_y = np.sum(centroid_ys * section_weights) + total_moment_z = np.sum(rotated_zs * section_weights) + + # Compute derivatives of weight + d_weight_dspan = np.sum(dchord_dspan * thickness * (span / num_sections)) + np.sum(chord_lengths * thickness / num_sections) + d_weight_droot_chord = np.sum(thickness * (span / num_sections)) + d_weight_dtip_chord = np.sum(thickness * (span / num_sections) * (span_locations / span)) + d_weight_dthickness = np.sum(chord_lengths * (span / num_sections)) + + # Compute derivatives of moments + d_moment_x_dspan = np.sum((dchord_dspan / 4) * np.cos(twist) * section_weights) + d_moment_y_dspan = np.sum(centroid_ys * (section_weights / span)) # dY/dspan is straightforward + d_moment_z_dspan = np.sum((dchord_dspan / 4) * np.sin(twist) * section_weights) + + # Compute partials for CoG X + partials['center_of_gravity_x', 'span'] = (d_moment_x_dspan - total_moment_x / total_weight * d_weight_dspan) / total_weight + partials['center_of_gravity_x', 'root_chord'] = (np.sum(thickness * (span / num_sections) / 4) - total_moment_x / total_weight * d_weight_droot_chord) / total_weight + partials['center_of_gravity_x', 'tip_chord'] = (np.sum(thickness * (span / num_sections) * (span_locations / span) / 4) - total_moment_x / total_weight * d_weight_dtip_chord) / total_weight + partials['center_of_gravity_x', 'thickness'] = (np.sum(chord_lengths * (span / num_sections) / 4) - total_moment_x / total_weight * d_weight_dthickness) / total_weight + + # Compute partials for CoG Y + partials['center_of_gravity_y', 'span'] = (d_moment_y_dspan - total_moment_y / total_weight * d_weight_dspan) / total_weight + partials['center_of_gravity_y', 'root_chord'] = -total_moment_y / total_weight * d_weight_droot_chord / total_weight + partials['center_of_gravity_y', 'tip_chord'] = -total_moment_y / total_weight * d_weight_dtip_chord / total_weight + partials['center_of_gravity_y', 'thickness'] = -total_moment_y / total_weight * d_weight_dthickness / total_weight + + # Compute partials for CoG Z + partials['center_of_gravity_z', 'span'] = (d_moment_z_dspan - total_moment_z / total_weight * d_weight_dspan) / total_weight + partials['center_of_gravity_z', 'root_chord'] = (np.sum(thickness * (span / num_sections) / 4 * np.sin(twist)) - total_moment_z / total_weight * d_weight_droot_chord) / total_weight + partials['center_of_gravity_z', 'tip_chord'] = (np.sum(thickness * (span / num_sections) * (span_locations / span) / 4 * np.sin(twist)) - total_moment_z / total_weight * d_weight_dtip_chord) / total_weight + partials['center_of_gravity_z', 'thickness'] = (np.sum(chord_lengths * (span / num_sections) / 4 * np.sin(twist)) - total_moment_z / total_weight * d_weight_dthickness) / total_weight + + # Compute derivatives of x_coords and z_coords w.r.t. twist + for i in range(num_sections): + partials['x_coords', 'twist'][i] = -centroid_xs[i] * np.sin(twist[i]) # dx/dtwist + partials['z_coords', 'twist'][i] = centroid_xs[i] * np.cos(twist[i]) # dz/dtwist + diff --git a/aviary/subsystems/mass/simple_mass/airfoil_data_test.dat b/aviary/subsystems/mass/simple_mass/airfoil_data_test.dat new file mode 100644 index 000000000..2e2249c98 --- /dev/null +++ b/aviary/subsystems/mass/simple_mass/airfoil_data_test.dat @@ -0,0 +1,124 @@ + 0.00000 0.00001 + 0.00050 0.00430 + 0.00100 0.00600 + 0.00200 0.00903 + 0.00300 0.01127 + 0.00500 0.01490 + 0.00750 0.01861 + 0.01000 0.02180 + 0.02000 0.03186 + 0.03000 0.03967 + 0.04000 0.04688 + 0.05000 0.05192 + 0.06000 0.05698 + 0.07000 0.06110 + 0.08000 0.06562 + 0.09000 0.06937 + 0.10000 0.07280 + 0.12000 0.07886 + 0.14000 0.08401 + 0.16000 0.08839 + 0.18000 0.09211 + 0.20000 0.09525 + 0.22000 0.09786 + 0.24000 0.10000 + 0.26000 0.10173 + 0.28000 0.10313 + 0.30000 0.10418 + 0.34000 0.10542 + 0.36000 0.10632 + 0.38000 0.10687 + 0.40000 0.10700 + 0.44000 0.10656 + 0.46000 0.10600 + 0.48000 0.10526 + 0.50000 0.10423 + 0.54000 0.10154 + 0.56000 0.09965 + 0.58000 0.09795 + 0.60000 0.09587 + 0.64000 0.09125 + 0.66000 0.08872 + 0.68000 0.08605 + 0.70000 0.08322 + 0.74000 0.07789 + 0.76000 0.07477 + 0.78000 0.07028 + 0.80000 0.06668 + 0.82000 0.06262 + 0.84000 0.05834 + 0.86000 0.05368 + 0.88000 0.04856 + 0.90000 0.04299 + 0.91000 0.03997 + 0.92000 0.03686 + 0.93000 0.03364 + 0.94000 0.03032 + 0.95000 0.02689 + 0.96000 0.02335 + 0.97000 0.01968 + 0.98000 0.01570 + 0.99000 0.01171 + 1.00000 0.00720 + 0.00000 0.00000 + 0.00050 -0.00377 + 0.00100 -0.00519 + 0.00200 -0.00709 + 0.00300 -0.00842 + 0.00500 -0.01044 + 0.00750 -0.01230 + 0.01000 -0.01376 + 0.02000 -0.01767 + 0.03000 -0.02006 + 0.04000 -0.02109 + 0.05000 -0.02283 + 0.06000 -0.02353 + 0.07000 -0.02417 + 0.08000 -0.02450 + 0.09000 -0.02466 + 0.10000 -0.02469 + 0.12000 -0.02440 + 0.14000 -0.02374 + 0.16000 -0.02279 + 0.18000 -0.02159 + 0.20000 -0.02030 + 0.22000 -0.01901 + 0.24000 -0.01786 + 0.26000 -0.01688 + 0.28000 -0.01607 + 0.30000 -0.01536 + 0.34000 -0.01389 + 0.36000 -0.01344 + 0.38000 -0.01279 + 0.40000 -0.01216 + 0.44000 -0.01105 + 0.46000 -0.01060 + 0.48000 -0.01020 + 0.50000 -0.00985 + 0.54000 -0.00919 + 0.56000 -0.00888 + 0.58000 -0.00856 + 0.60000 -0.00824 + 0.64000 -0.00756 + 0.66000 -0.00721 + 0.68000 -0.00687 + 0.70000 -0.00658 + 0.74000 -0.00619 + 0.76000 -0.00611 + 0.78000 -0.00609 + 0.80000 -0.00611 + 0.82000 -0.00614 + 0.84000 -0.00621 + 0.86000 -0.00633 + 0.88000 -0.00653 + 0.90000 -0.00683 + 0.91000 -0.00701 + 0.92000 -0.00721 + 0.93000 -0.00742 + 0.94000 -0.00753 + 0.95000 -0.00785 + 0.96000 -0.00807 + 0.97000 -0.00829 + 0.98000 -0.00882 + 0.99000 -0.00976 + 1.00000 -0.01070 \ No newline at end of file diff --git a/aviary/subsystems/mass/simple_mass/mass_builder.py b/aviary/subsystems/mass/simple_mass/mass_builder.py new file mode 100644 index 000000000..050daf052 --- /dev/null +++ b/aviary/subsystems/mass/simple_mass/mass_builder.py @@ -0,0 +1,92 @@ +from aviary.interface.utils.markdown_utils import write_markdown_variable_table +from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase +from aviary.subsystems.mass.mass_builder import MassBuilderBase +from aviary.subsystems.mass.simple_mass.mass_premission import MassPremission # This will be the new folder in there \ +# along with flops_based and gasp_based folders. I just called it simple_mass for now. + +""" + +Define subsystem builder for Aviary core mass. + +Classes +-------------------------------------------------------------------------------------------------- + +MassBuilderBase: the interface for a mass subsystem builder. **Not sure how necessary this is for + my work right now, but wanted to include it as a just in case. I basically copied + it over from the mass_builder.py under the mass subsystems folder in Aviary github. + +StructureMassBuilder: the interface for Aviary's core mass builder -- in this case, + the core mass builder will work for wing and fuselage mass calculations + will be updated as more mass calculations are added + +""" + +_default_name = 'mass' + +#class MassBuilderBase(SubsystemBuilderBase): + #""" + #Base mass builder + # + #This class is basically copied line by line from the mass subsystems folder + #** Ask Jason if this is even necessary. + # + #""" + + #def __init__(self, name=None, meta_data=None): + # if name is None: + # name = _default_name + # + # super().__init__(name=name, meta_data=meta_data) + # + #def mission_inputs(self, **kwargs): + # return ['*'] + # + #def mission_outputs(self, **kwargs): + # return ['*'] + +class StructureMassBuilder(MassBuilderBase): + """ + Core mass subsystem builder + + Unlike the CoreMassBuilder on the github under the mass subsystems folder, + I am not including the __init__'s, since I don't have any FLOPS or GASP + dependence in my mass calculations at the moment; the math is essentially + hard coded from my calculations right now. + + """ + + def build_pre_mission(self, aviary_inputs): + return MassPremission # See the commented line above in the imports + + def build_mission(self, num_nodes, aviary_inputs, **kwargs): + super().build_mission(num_nodes, aviary_inputs) + + def report(self, prob, reports_folder, **kwargs): + """ + Generate the report for Aviary core mass + + Parameters + ---------- + prob : AviaryProblem + The AviaryProblem that will be used to generate the report + reports_folder : Path + Location of the subsystems_report folder this report will be placed in + + * This comment is copied from the mass subsystems folder * + + """ + + filename = self.name + '.md' + filepath = reports_folder / filename + + # Ask Jason about how I should format this + outputs = [ + + ] + + with open(filepath, mode='w') as f: + method = self.code_origin.value + '-derived relations' # Ask Jason about this too since I don't have FLOPS or GASP for code_origin_value + f.write(f'# Mass estimation: {method}') + write_markdown_variable_table(f, prob, outputs, self.meta_data) + + \ No newline at end of file diff --git a/aviary/subsystems/mass/simple_mass/mass_premission.py b/aviary/subsystems/mass/simple_mass/mass_premission.py new file mode 100644 index 000000000..cc2467139 --- /dev/null +++ b/aviary/subsystems/mass/simple_mass/mass_premission.py @@ -0,0 +1,39 @@ +import openmdao.api as om + +# Maybe some Aviary inputs as well? +from aviary.subsystems.mass.simple_mass.wing import WingMassAndCOG +from aviary.subsystems.mass.simple_mass.fuselage import FuselageMassAndCOG +from aviary.subsystems.mass.simple_mass.tail import TailMassAndCOG +from aviary.subsystems.mass.simple_mass.mass_summation import MassSummation + +class MassPremission(om.Group): + """ + Pre-mission group of top-level mass estimation groups and components for + the simple small-scale aircraft mass build-up. + """ + + def setup(self): + + self.add_subsystem( + 'Wing', + WingMassAndCOG(), + promotes_inputs=['*'], promotes_outputs=['*'] + ) + + self.add_subsystem( + 'Fuselage', + FuselageMassAndCOG(), + promotes_inputs=['*'], promotes_outputs=['*'] + ) + + self.add_subsystem( + 'Tail', + TailMassAndCOG(), + promotes_inputs=['*'], promotes_outputs=['*'] + ) + + self.add_subsystem( + 'total_mass', + MassSummation(), + promotes_inputs=['*'], promotes_outputs=['*'] + ) \ No newline at end of file diff --git a/aviary/subsystems/mass/simple_mass/test_wing.py b/aviary/subsystems/mass/simple_mass/test_wing.py new file mode 100644 index 000000000..61bdce86a --- /dev/null +++ b/aviary/subsystems/mass/simple_mass/test_wing.py @@ -0,0 +1,42 @@ +import unittest + +import openmdao.api as om +from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal + + + +class WingMassTestCase(unittest.TestCase): + """ + Wing mass test case + + """ + + def setUp(self): + + self.prob = om.Problem() + #self.prob.model.add_subsystem( + # "wing", + # WingMassAndCOG(), + # promotes_inputs=["*"], + # promotes_outputs=['*'], + #) + + self.prob.model.set_input_defaults( + "wing_mass", val=10, units="kg" + ) + + self.prob.setup(check=False, force_alloc_complex=True) + + def test_case(self): + + self.prob.run_model() + + tol = 1e-10 + assert_near_equal(self.prob["wing_mass"], 100, tol) # Need to calculate first -- filler value for now + + partial_data = self.prob.check_partials(out_stream=None, method="fd") # finite difference used because cs is used in wing.py calculation + assert_check_partials(partial_data, atol=1e-15, rtol=1e-15) + + +if __name__ == "__main__": + unittest.main() \ No newline at end of file From 50800657afb5650c0b4273d5b13df3cee6ccdf17 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 4 Mar 2025 11:14:46 -0500 Subject: [PATCH 030/147] Create __init__.py --- aviary/subsystems/mass/simple_mass/__init__.py | 1 + 1 file changed, 1 insertion(+) create mode 100644 aviary/subsystems/mass/simple_mass/__init__.py diff --git a/aviary/subsystems/mass/simple_mass/__init__.py b/aviary/subsystems/mass/simple_mass/__init__.py new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/aviary/subsystems/mass/simple_mass/__init__.py @@ -0,0 +1 @@ + From a6fe374a9f54d26fcbdd596ef78345d26e056003 Mon Sep 17 00:00:00 2001 From: szoppelt Date: Tue, 4 Mar 2025 16:21:37 +0000 Subject: [PATCH 031/147] new file: aviary/subsystems/mass/simple_mass/__init__.py --- aviary/subsystems/mass/simple_mass/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 aviary/subsystems/mass/simple_mass/__init__.py diff --git a/aviary/subsystems/mass/simple_mass/__init__.py b/aviary/subsystems/mass/simple_mass/__init__.py new file mode 100644 index 000000000..e69de29bb From 133de7b8e5e13c9c43fe795f71e59213c55ee4f9 Mon Sep 17 00:00:00 2001 From: szoppelt Date: Wed, 5 Mar 2025 14:21:49 +0000 Subject: [PATCH 032/147] new file: aviary/subsystems/mass/simple_mass/test_fuselage.py new file: aviary/subsystems/mass/simple_mass/test_tail.py modified: aviary/subsystems/mass/simple_mass/test_wing.py --- .../mass/simple_mass/test_fuselage.py | 54 +++++++++++++++++++ .../subsystems/mass/simple_mass/test_tail.py | 54 +++++++++++++++++++ .../subsystems/mass/simple_mass/test_wing.py | 36 ++++++++----- 3 files changed, 132 insertions(+), 12 deletions(-) create mode 100644 aviary/subsystems/mass/simple_mass/test_fuselage.py create mode 100644 aviary/subsystems/mass/simple_mass/test_tail.py diff --git a/aviary/subsystems/mass/simple_mass/test_fuselage.py b/aviary/subsystems/mass/simple_mass/test_fuselage.py new file mode 100644 index 000000000..99bff4b18 --- /dev/null +++ b/aviary/subsystems/mass/simple_mass/test_fuselage.py @@ -0,0 +1,54 @@ +import unittest + +import openmdao.api as om +from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal + +from aviary.subsystems.mass.simple_mass.fuselage import FuselageMassAndCOG + +class FuselageMassTestCase(unittest.TestCase): + """ + Fuselage mass test case. + + """ + + def setUp(self): + + self.prob = om.Problem() + self.prob.model.add_subsystem( + "fuselage", + FuselageMassAndCOG(), + promotes_inputs=["*"], + promotes_outputs=["*"], + ) + + self.prob.model.set_input_defaults( + "fuselage_mass", + val=10, + units="kg") + + self.prob.setup( + check=False, + force_alloc_complex=True) + + def test_case(self): + + self.prob.run_model() + + tol=1e-10 + + assert_near_equal( + self.prob["fuselage_mass"], + 100, # filler value for now + tol) + + partial_data = self.prob.check_partials( + out_stream=None, + method="fd") # fd for now since cs is used in the fuselage mass calculation right now + + assert_check_partials( + partial_data, + atol=1e-15, + rtol=1e-15) + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/aviary/subsystems/mass/simple_mass/test_tail.py b/aviary/subsystems/mass/simple_mass/test_tail.py new file mode 100644 index 000000000..c26183101 --- /dev/null +++ b/aviary/subsystems/mass/simple_mass/test_tail.py @@ -0,0 +1,54 @@ +import unittest + +import openmdao.api as om +from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal + +from aviary.subsystems.mass.simple_mass.tail import TailMassAndCOG + +class TailMassTestCase(unittest.TestCase): + """ + Tail mass test case. + + """ + + def setUp(self): + + self.prob = om.Problem() + self.prob.model.add_subsystem( + "Tail", + TailMassAndCOG(), + promotes_inputs=["*"], + promotes_outputs=["*"], + ) + + self.prob.model.set_input_defaults( + "tail_mass", + val=10, + units="kg") + + self.prob.setup( + check=False, + force_alloc_complex=True) + + def test_case(self): + + self.prob.run_model() + + tol = 1e-10 + + assert_near_equal( + self.prob["tail_mass"], + 100, # still need to calculate by hand + tol) + + partial_data = self.prob.check_partials( + out_stream=None, + method="fd") # Finite difference because cs is used in tail mass calculation right now + + assert_check_partials( + partial_data, + atol=1e-15, + rtol=1e-15) + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/aviary/subsystems/mass/simple_mass/test_wing.py b/aviary/subsystems/mass/simple_mass/test_wing.py index 61bdce86a..8edcbcc09 100644 --- a/aviary/subsystems/mass/simple_mass/test_wing.py +++ b/aviary/subsystems/mass/simple_mass/test_wing.py @@ -3,7 +3,7 @@ import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal - +from aviary.subsystems.mass.simple_mass.wing import WingMassAndCOG class WingMassTestCase(unittest.TestCase): """ @@ -14,28 +14,40 @@ class WingMassTestCase(unittest.TestCase): def setUp(self): self.prob = om.Problem() - #self.prob.model.add_subsystem( - # "wing", - # WingMassAndCOG(), - # promotes_inputs=["*"], - # promotes_outputs=['*'], - #) + self.prob.model.add_subsystem( + "wing", + WingMassAndCOG(), + promotes_inputs=["*"], + promotes_outputs=['*'], + ) self.prob.model.set_input_defaults( - "wing_mass", val=10, units="kg" + "wing_mass", + val=10, + units="kg" ) - self.prob.setup(check=False, force_alloc_complex=True) + self.prob.setup( + check=False, + force_alloc_complex=True + ) def test_case(self): self.prob.run_model() tol = 1e-10 - assert_near_equal(self.prob["wing_mass"], 100, tol) # Need to calculate first -- filler value for now + assert_near_equal(self.prob["wing_mass"], + 100, # Need to calculate first -- filler value for now + tol) - partial_data = self.prob.check_partials(out_stream=None, method="fd") # finite difference used because cs is used in wing.py calculation - assert_check_partials(partial_data, atol=1e-15, rtol=1e-15) + partial_data = self.prob.check_partials( + out_stream=None, + method="fd") # finite difference used because cs is used in wing.py calculation + assert_check_partials( + partial_data, + atol=1e-15, + rtol=1e-15) if __name__ == "__main__": From d0799305b6a4aba864beac214a1d3558253caf67 Mon Sep 17 00:00:00 2001 From: szoppelt Date: Wed, 5 Mar 2025 14:22:57 +0000 Subject: [PATCH 033/147] test modified: aviary/subsystems/mass/simple_mass/test_wing.py --- aviary/subsystems/mass/simple_mass/test_wing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aviary/subsystems/mass/simple_mass/test_wing.py b/aviary/subsystems/mass/simple_mass/test_wing.py index 8edcbcc09..45bbc9104 100644 --- a/aviary/subsystems/mass/simple_mass/test_wing.py +++ b/aviary/subsystems/mass/simple_mass/test_wing.py @@ -7,7 +7,7 @@ class WingMassTestCase(unittest.TestCase): """ - Wing mass test case + Wing mass test case. """ From 823228da59613f50c4695e896fa83cc49c00b2ec Mon Sep 17 00:00:00 2001 From: szoppelt Date: Wed, 5 Mar 2025 14:28:28 +0000 Subject: [PATCH 034/147] renamed: aviary/subsystems/mass/simple_mass/test_fuselage.py -> aviary/subsystems/mass/simple_mass/test/test_fuselage.py renamed: aviary/subsystems/mass/simple_mass/test_tail.py -> aviary/subsystems/mass/simple_mass/test/test_tail.py renamed: aviary/subsystems/mass/simple_mass/test_wing.py -> aviary/subsystems/mass/simple_mass/test/test_wing.py --- aviary/subsystems/mass/simple_mass/{ => test}/test_fuselage.py | 0 aviary/subsystems/mass/simple_mass/{ => test}/test_tail.py | 0 aviary/subsystems/mass/simple_mass/{ => test}/test_wing.py | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename aviary/subsystems/mass/simple_mass/{ => test}/test_fuselage.py (100%) rename aviary/subsystems/mass/simple_mass/{ => test}/test_tail.py (100%) rename aviary/subsystems/mass/simple_mass/{ => test}/test_wing.py (100%) diff --git a/aviary/subsystems/mass/simple_mass/test_fuselage.py b/aviary/subsystems/mass/simple_mass/test/test_fuselage.py similarity index 100% rename from aviary/subsystems/mass/simple_mass/test_fuselage.py rename to aviary/subsystems/mass/simple_mass/test/test_fuselage.py diff --git a/aviary/subsystems/mass/simple_mass/test_tail.py b/aviary/subsystems/mass/simple_mass/test/test_tail.py similarity index 100% rename from aviary/subsystems/mass/simple_mass/test_tail.py rename to aviary/subsystems/mass/simple_mass/test/test_tail.py diff --git a/aviary/subsystems/mass/simple_mass/test_wing.py b/aviary/subsystems/mass/simple_mass/test/test_wing.py similarity index 100% rename from aviary/subsystems/mass/simple_mass/test_wing.py rename to aviary/subsystems/mass/simple_mass/test/test_wing.py From 5b5405357827e98a4491e60699779a2753fec501 Mon Sep 17 00:00:00 2001 From: szoppelt Date: Wed, 5 Mar 2025 14:31:30 +0000 Subject: [PATCH 035/147] new file: aviary/subsystems/mass/simple_mass/test/__init__.py --- aviary/subsystems/mass/simple_mass/test/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 aviary/subsystems/mass/simple_mass/test/__init__.py diff --git a/aviary/subsystems/mass/simple_mass/test/__init__.py b/aviary/subsystems/mass/simple_mass/test/__init__.py new file mode 100644 index 000000000..e69de29bb From a25a59fa1efeffeef169a0f8351147d8eff3dec1 Mon Sep 17 00:00:00 2001 From: szoppelt Date: Tue, 1 Apr 2025 17:14:31 +0000 Subject: [PATCH 036/147] Commit. modified: aviary/docs/examples/mass_premission.py modified: aviary/docs/examples/mass_summation.py modified: aviary/docs/examples/test_wing.py modified: aviary/subsystems/mass/simple_mass/fuselage.py modified: aviary/subsystems/mass/simple_mass/materials_database.py modified: aviary/subsystems/mass/simple_mass/tail.py modified: aviary/subsystems/mass/simple_mass/test/test_fuselage.py modified: aviary/subsystems/mass/simple_mass/test/test_tail.py modified: aviary/subsystems/mass/simple_mass/test/test_wing.py modified: aviary/subsystems/mass/simple_mass/wing.py --- aviary/docs/examples/C:UsersszoppeltDesktop | 231 + .../examples/C:UsersszoppeltDesktoptest.py | 231 + aviary/docs/examples/Clark_Y.dat | 122 + aviary/docs/examples/Clark_Y.yaml | 122 + aviary/docs/examples/Custom_Fuselage.dat | 179 + aviary/docs/examples/airfoil_data_test.dat | 124 + .../docs/examples/fuselage_out/.openmdao_out | 0 aviary/docs/examples/mass_premission.py | 15 + aviary/docs/examples/mass_summation.py | 12 +- aviary/docs/examples/tail_out/.openmdao_out | 0 .../examples/test_fuselage2_out/.openmdao_out | 0 .../test_fuselage_dbf_out/.openmdao_out | 0 .../examples/test_fuselage_out/.openmdao_out | 0 aviary/docs/examples/test_out/.openmdao_out | 0 .../examples/test_tail2_out/.openmdao_out | 0 .../docs/examples/test_tail_out/.openmdao_out | 0 aviary/docs/examples/test_wing.py | 33 +- .../examples/test_wing2_out/.openmdao_out | 0 .../docs/examples/test_wing_out/.openmdao_out | 0 aviary/docs/examples/wingN2.html | 14805 ++++++++++++++++ aviary/docs/examples/wing_out/.openmdao_out | 0 ... New lump sum payments: $10,000 in 2025.py | 64 + .../simple_mass/C:UsersszoppeltDesktopwingN2 | 14805 ++++++++++++++++ .../subsystems/mass/simple_mass/fuselage.py | 205 +- .../mass/simple_mass/import numpy as np.py | 120 + .../mass/simple_mass/materials_database.py | 2 + aviary/subsystems/mass/simple_mass/tail.py | 208 +- .../mass/simple_mass/test/import os.py | 2 + .../subsystems/mass/simple_mass/test/test.py | 3 + .../mass/simple_mass/test/test_fuselage.py | 68 +- .../mass/simple_mass/test/test_tail.py | 63 +- .../mass/simple_mass/test/test_wing.py | 74 +- .../subsystems/mass/simple_mass/test_quad.py | 642 + aviary/subsystems/mass/simple_mass/wing.py | 486 +- aviary/subsystems/mass/simple_mass/wingN2 | 14805 ++++++++++++++++ 35 files changed, 46869 insertions(+), 552 deletions(-) create mode 100644 aviary/docs/examples/C:UsersszoppeltDesktop create mode 100644 aviary/docs/examples/C:UsersszoppeltDesktoptest.py create mode 100644 aviary/docs/examples/Clark_Y.dat create mode 100644 aviary/docs/examples/Clark_Y.yaml create mode 100644 aviary/docs/examples/Custom_Fuselage.dat create mode 100644 aviary/docs/examples/airfoil_data_test.dat create mode 100644 aviary/docs/examples/fuselage_out/.openmdao_out create mode 100644 aviary/docs/examples/tail_out/.openmdao_out create mode 100644 aviary/docs/examples/test_fuselage2_out/.openmdao_out create mode 100644 aviary/docs/examples/test_fuselage_dbf_out/.openmdao_out create mode 100644 aviary/docs/examples/test_fuselage_out/.openmdao_out create mode 100644 aviary/docs/examples/test_out/.openmdao_out create mode 100644 aviary/docs/examples/test_tail2_out/.openmdao_out create mode 100644 aviary/docs/examples/test_tail_out/.openmdao_out create mode 100644 aviary/docs/examples/test_wing2_out/.openmdao_out create mode 100644 aviary/docs/examples/test_wing_out/.openmdao_out create mode 100644 aviary/docs/examples/wingN2.html create mode 100644 aviary/docs/examples/wing_out/.openmdao_out create mode 100644 aviary/subsystems/mass/simple_mass/# New lump sum payments: $10,000 in 2025.py create mode 100644 aviary/subsystems/mass/simple_mass/C:UsersszoppeltDesktopwingN2 create mode 100644 aviary/subsystems/mass/simple_mass/import numpy as np.py create mode 100644 aviary/subsystems/mass/simple_mass/test/import os.py create mode 100644 aviary/subsystems/mass/simple_mass/test/test.py create mode 100644 aviary/subsystems/mass/simple_mass/test_quad.py create mode 100644 aviary/subsystems/mass/simple_mass/wingN2 diff --git a/aviary/docs/examples/C:UsersszoppeltDesktop b/aviary/docs/examples/C:UsersszoppeltDesktop new file mode 100644 index 000000000..383c06e15 --- /dev/null +++ b/aviary/docs/examples/C:UsersszoppeltDesktop @@ -0,0 +1,231 @@ +import openmdao.api as om +import numpy as np +import matplotlib.pyplot as plt +import os +from scipy.interpolate import CubicSpline + +# Material densities (g/cm³ converted to kg/m³) -- these are just some random examples +MATERIAL_DENSITIES = { + 'wood': 600, # This isn't even a real wood density that I'm aware of, I just made it up for the sake of debugging + 'metal': 2700, # Aluminum + 'carbon_fiber': 1600 +} + + + +class CenterOfGravity3D(om.ExplicitComponent): + def initialize(self): + self.options.declare('num_sections', types=int, default=50) + self.options.declare('airfoil_type', types=str, default='2412') # use 2412 as example for default + self.options.declare('material', default='metal', values=['wood', 'metal', 'carbon_fiber']) + self.options.declare('airfoil_data_file', default=None, types=str) # For user-provided airfoil data file + + def setup(self): + # Inputs + self.add_input('span', val=10.0, units='m') # Full wingspan (adjustable) + self.add_input('root_chord', val=2.0, units='m') # Root chord length + self.add_input('tip_chord', val=1.0, units='m') # Tip chord length + self.add_input('twist', val=np.zeros(self.options['num_sections']), units='deg') # Twist angles + self.add_input('thickness', val=0.2, units='m') # Thickness of the wing (height) + + + # Outputs + self.add_output('center_of_gravity_x', val=0.0, units='m') + self.add_output('center_of_gravity_y', val=0.0, units='m') + self.add_output('center_of_gravity_z', val=0.0, units='m') + self.add_output('total_weight', val=0.0, units='kg') + self.add_output('x_coords', val=np.zeros(self.options['num_sections']), units='m') + self.add_output('y_coords', val=np.zeros(self.options['num_sections']), units='m') + self.add_output('z_coords', val=np.zeros(self.options['num_sections']), units='m') + + + def compute(self, inputs, outputs): + span = inputs['span'] + root_chord = inputs['root_chord'] + tip_chord = inputs['tip_chord'] + twist = np.radians(inputs['twist']) # Convert twist to radians + thickness = inputs['thickness'] + material = self.options['material'] # Material is taken from options + num_sections = self.options['num_sections'] + airfoil_type = self.options['airfoil_type'] # NACA airfoil type + airfoil_data_file = self.options['airfoil_data_file'] + + # Get material density + density = MATERIAL_DENSITIES[material] # in kg/m³ + + if airfoil_data_file: + airfoil_data = np.loadtxt(airfoil_data_file) + x_coords = airfoil_data[:, 0] + y_coords = airfoil_data[:, 1] + + camber, camber_location, max_thickness = self.extract_airfoil_features(x_coords, y_coords) + else: + # Parse the NACA airfoil type (4-digit) + camber = int(airfoil_type[0]) / 100.0 # Maximum camber + camber_location = int(airfoil_type[1]) / 10.0 # Location of max camber + max_thickness = int(airfoil_type[2:4]) / 100.0 # Max thickness + + # Wing spanwise distribution + span_locations = np.linspace(0, span, num_sections) + + # Initialize total weight and moment accumulators + total_weight = 0 + total_moment_x = 0 + total_moment_y = 0 + total_moment_z = 0 + + # Arrays for storing 3D coordinates of the wing + x_coords = [] + y_coords = [] + z_coords = [] + top_coords = [] + bottom_coords = [] + + # Loop over each section along the span (3D wing approximation) + for i, location in enumerate(span_locations): + # Calculate the chord for this section + chord = root_chord - (root_chord - tip_chord) * (location / span) # Assuming linear variation from root to tip + + # Apply twist + twist_angle = twist[i] + + # Calculate the camber and thickness distribution + # Airfoil thickness distribution using the NACA Equation + def airfoil_thickness(x): + return 5 * max_thickness * (0.2969 * np.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) + + # Airfoil camber line (NACA 4-digit) + def airfoil_camber_line(x, camber, camber_location): + if x < camber_location: + return (camber / camber_location**2) * (2 * camber_location * x - x**2) + else: + return (camber / (1 - camber_location)**2) * ((1 - 2 * camber_location) + 2 * camber_location * x - x**2) + + # Numerical integration: sum up the areas using small segments along the chord + n_points = 100 + x_points = np.linspace(0, 1, n_points) + dx = 1 / (n_points - 1) + + area = 0 # Cross-sectional area of the wing section + centroid_x = 0 + centroid_z = 0 + + for x in x_points: + # Thickness at each point along the chord + thickness_at_x = airfoil_thickness(x) * chord + # Camber at each point (for z-coordinate) + camber_at_x = airfoil_camber_line(x, camber, camber_location) * chord + + # Area of small rectangle at x + area += thickness_at_x * dx + + centroid_x += (x * thickness_at_x) * dx + centroid_z += (camber_at_x * thickness_at_x) * dx + # Weight of this section (density * area * thickness) + section_weight = density * area * thickness # Volume approximation + + # Normalize + if area > 0: + centroid_x /= area + centroid_z /= area + else: + centroid_x = 0 + centroid_z = 0 + # Centroid of this section (assuming centroid is at half chord) + centroid_y = location + + # Debug print line + #print("Section " + str(i+1) + ", Location: " + str(location) + " m, Weight: " + str(section_weight) + " kg, Centroid Z: " + str(centroid_z)) + + # Apply twist + rotated_z = centroid_z * np.cos(twist_angle) - centroid_x * np.sin(twist_angle) + rotated_x = centroid_z * np.sin(twist_angle) + centroid_x * np.cos(twist_angle) + + # Add the section's contributions + total_weight += section_weight + total_moment_x += rotated_x * section_weight + total_moment_y += centroid_y * section_weight + total_moment_z += rotated_z * section_weight + + # Store the coordinates for plotting later + x_coords.append(rotated_x) + y_coords.append(centroid_y) + z_coords.append(rotated_z) + + # Calculate the overall center of gravity + outputs['center_of_gravity_x'] = total_moment_x / total_weight + outputs['center_of_gravity_y'] = total_moment_y / total_weight + outputs['center_of_gravity_z'] = total_moment_z / total_weight + outputs['total_weight'] = total_weight + + # Store the x, y, and z coordinates for the entire wing + outputs['x_coords'] = np.array(x_coords) + outputs['y_coords'] = np.array(y_coords) + outputs['z_coords'] = np.array(z_coords) + + def extract_airfoil_features(self, x_coords, y_coords): + """ + Extract camber, camber location, and max thickness from the given airfoil data. + This method assumes x_coords are normalized (ranging from 0 to 1). + """ + # Approximate the camber line and max thickness from the data + # Assume the camber line is the line of symmetry between the upper and lower surfaces + upper_surface = y_coords[:int(len(x_coords) / 2)] + lower_surface = y_coords[int(len(x_coords) / 2):] + x_upper = x_coords[:int(len(x_coords) / 2)] + x_lower = x_coords[int(len(x_coords) / 2):] + + upper_spline = CubicSpline(x_upper, upper_surface, bc_type='natural') + lower_spline = CubicSpline(x_lower, lower_surface, bc_type='natural') + + camber_line = (upper_spline(x_coords) + lower_spline(x_coords)) / 2.0 + + thickness = upper_spline(x_coords) - lower_spline(x_coords) + + max_thickness_index = np.argmax(thickness) + max_thickness_value = thickness[max_thickness_index] + + camber_slope = np.gradient(camber_line, x_coords) + camber_location_index = np.argmax(np.abs(camber_slope)) + camber_location = x_coords[camber_location_index] + + camber = camber_line[camber_location_index] + + return camber, camber_location, max_thickness_value + + +# Build OpenMDAO problem +prob = om.Problem() + +# Add the center of gravity component +prob.model.add_subsystem('cog', CenterOfGravity3D() , promotes_inputs=['span', 'root_chord', 'tip_chord', 'twist', 'thickness']) + +# Setup the problem +prob.setup() + +# Define some example inputs +prob.set_val('span', 11.0) +prob.set_val('root_chord', 1.9) +prob.set_val('tip_chord', 0.5) +#prob.set_val('twist', np.linspace(0, 0, 50)) +prob.set_val('thickness', 0.2) + +prob.model.cog.options['airfoil_data_file'] = 'airfoil_data_test.dat' + +# Run the model +prob.run_model() + +# Get the results +center_of_gravity_x = prob.get_val('cog.center_of_gravity_x') +center_of_gravity_y = prob.get_val('cog.center_of_gravity_y') +center_of_gravity_z = prob.get_val('cog.center_of_gravity_z') +total_weight = prob.get_val('cog.total_weight') + +# Get the 3D coordinates for the entire wing +x_coords = prob.get_val('cog.x_coords') +y_coords = prob.get_val('cog.y_coords') +z_coords = prob.get_val('cog.z_coords') + +print(f"Center of gravity: X = {center_of_gravity_x} m, Y = {center_of_gravity_y} m, Z = {center_of_gravity_z} m") +print(f"Total weight of the wing: {total_weight} kg") + diff --git a/aviary/docs/examples/C:UsersszoppeltDesktoptest.py b/aviary/docs/examples/C:UsersszoppeltDesktoptest.py new file mode 100644 index 000000000..383c06e15 --- /dev/null +++ b/aviary/docs/examples/C:UsersszoppeltDesktoptest.py @@ -0,0 +1,231 @@ +import openmdao.api as om +import numpy as np +import matplotlib.pyplot as plt +import os +from scipy.interpolate import CubicSpline + +# Material densities (g/cm³ converted to kg/m³) -- these are just some random examples +MATERIAL_DENSITIES = { + 'wood': 600, # This isn't even a real wood density that I'm aware of, I just made it up for the sake of debugging + 'metal': 2700, # Aluminum + 'carbon_fiber': 1600 +} + + + +class CenterOfGravity3D(om.ExplicitComponent): + def initialize(self): + self.options.declare('num_sections', types=int, default=50) + self.options.declare('airfoil_type', types=str, default='2412') # use 2412 as example for default + self.options.declare('material', default='metal', values=['wood', 'metal', 'carbon_fiber']) + self.options.declare('airfoil_data_file', default=None, types=str) # For user-provided airfoil data file + + def setup(self): + # Inputs + self.add_input('span', val=10.0, units='m') # Full wingspan (adjustable) + self.add_input('root_chord', val=2.0, units='m') # Root chord length + self.add_input('tip_chord', val=1.0, units='m') # Tip chord length + self.add_input('twist', val=np.zeros(self.options['num_sections']), units='deg') # Twist angles + self.add_input('thickness', val=0.2, units='m') # Thickness of the wing (height) + + + # Outputs + self.add_output('center_of_gravity_x', val=0.0, units='m') + self.add_output('center_of_gravity_y', val=0.0, units='m') + self.add_output('center_of_gravity_z', val=0.0, units='m') + self.add_output('total_weight', val=0.0, units='kg') + self.add_output('x_coords', val=np.zeros(self.options['num_sections']), units='m') + self.add_output('y_coords', val=np.zeros(self.options['num_sections']), units='m') + self.add_output('z_coords', val=np.zeros(self.options['num_sections']), units='m') + + + def compute(self, inputs, outputs): + span = inputs['span'] + root_chord = inputs['root_chord'] + tip_chord = inputs['tip_chord'] + twist = np.radians(inputs['twist']) # Convert twist to radians + thickness = inputs['thickness'] + material = self.options['material'] # Material is taken from options + num_sections = self.options['num_sections'] + airfoil_type = self.options['airfoil_type'] # NACA airfoil type + airfoil_data_file = self.options['airfoil_data_file'] + + # Get material density + density = MATERIAL_DENSITIES[material] # in kg/m³ + + if airfoil_data_file: + airfoil_data = np.loadtxt(airfoil_data_file) + x_coords = airfoil_data[:, 0] + y_coords = airfoil_data[:, 1] + + camber, camber_location, max_thickness = self.extract_airfoil_features(x_coords, y_coords) + else: + # Parse the NACA airfoil type (4-digit) + camber = int(airfoil_type[0]) / 100.0 # Maximum camber + camber_location = int(airfoil_type[1]) / 10.0 # Location of max camber + max_thickness = int(airfoil_type[2:4]) / 100.0 # Max thickness + + # Wing spanwise distribution + span_locations = np.linspace(0, span, num_sections) + + # Initialize total weight and moment accumulators + total_weight = 0 + total_moment_x = 0 + total_moment_y = 0 + total_moment_z = 0 + + # Arrays for storing 3D coordinates of the wing + x_coords = [] + y_coords = [] + z_coords = [] + top_coords = [] + bottom_coords = [] + + # Loop over each section along the span (3D wing approximation) + for i, location in enumerate(span_locations): + # Calculate the chord for this section + chord = root_chord - (root_chord - tip_chord) * (location / span) # Assuming linear variation from root to tip + + # Apply twist + twist_angle = twist[i] + + # Calculate the camber and thickness distribution + # Airfoil thickness distribution using the NACA Equation + def airfoil_thickness(x): + return 5 * max_thickness * (0.2969 * np.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) + + # Airfoil camber line (NACA 4-digit) + def airfoil_camber_line(x, camber, camber_location): + if x < camber_location: + return (camber / camber_location**2) * (2 * camber_location * x - x**2) + else: + return (camber / (1 - camber_location)**2) * ((1 - 2 * camber_location) + 2 * camber_location * x - x**2) + + # Numerical integration: sum up the areas using small segments along the chord + n_points = 100 + x_points = np.linspace(0, 1, n_points) + dx = 1 / (n_points - 1) + + area = 0 # Cross-sectional area of the wing section + centroid_x = 0 + centroid_z = 0 + + for x in x_points: + # Thickness at each point along the chord + thickness_at_x = airfoil_thickness(x) * chord + # Camber at each point (for z-coordinate) + camber_at_x = airfoil_camber_line(x, camber, camber_location) * chord + + # Area of small rectangle at x + area += thickness_at_x * dx + + centroid_x += (x * thickness_at_x) * dx + centroid_z += (camber_at_x * thickness_at_x) * dx + # Weight of this section (density * area * thickness) + section_weight = density * area * thickness # Volume approximation + + # Normalize + if area > 0: + centroid_x /= area + centroid_z /= area + else: + centroid_x = 0 + centroid_z = 0 + # Centroid of this section (assuming centroid is at half chord) + centroid_y = location + + # Debug print line + #print("Section " + str(i+1) + ", Location: " + str(location) + " m, Weight: " + str(section_weight) + " kg, Centroid Z: " + str(centroid_z)) + + # Apply twist + rotated_z = centroid_z * np.cos(twist_angle) - centroid_x * np.sin(twist_angle) + rotated_x = centroid_z * np.sin(twist_angle) + centroid_x * np.cos(twist_angle) + + # Add the section's contributions + total_weight += section_weight + total_moment_x += rotated_x * section_weight + total_moment_y += centroid_y * section_weight + total_moment_z += rotated_z * section_weight + + # Store the coordinates for plotting later + x_coords.append(rotated_x) + y_coords.append(centroid_y) + z_coords.append(rotated_z) + + # Calculate the overall center of gravity + outputs['center_of_gravity_x'] = total_moment_x / total_weight + outputs['center_of_gravity_y'] = total_moment_y / total_weight + outputs['center_of_gravity_z'] = total_moment_z / total_weight + outputs['total_weight'] = total_weight + + # Store the x, y, and z coordinates for the entire wing + outputs['x_coords'] = np.array(x_coords) + outputs['y_coords'] = np.array(y_coords) + outputs['z_coords'] = np.array(z_coords) + + def extract_airfoil_features(self, x_coords, y_coords): + """ + Extract camber, camber location, and max thickness from the given airfoil data. + This method assumes x_coords are normalized (ranging from 0 to 1). + """ + # Approximate the camber line and max thickness from the data + # Assume the camber line is the line of symmetry between the upper and lower surfaces + upper_surface = y_coords[:int(len(x_coords) / 2)] + lower_surface = y_coords[int(len(x_coords) / 2):] + x_upper = x_coords[:int(len(x_coords) / 2)] + x_lower = x_coords[int(len(x_coords) / 2):] + + upper_spline = CubicSpline(x_upper, upper_surface, bc_type='natural') + lower_spline = CubicSpline(x_lower, lower_surface, bc_type='natural') + + camber_line = (upper_spline(x_coords) + lower_spline(x_coords)) / 2.0 + + thickness = upper_spline(x_coords) - lower_spline(x_coords) + + max_thickness_index = np.argmax(thickness) + max_thickness_value = thickness[max_thickness_index] + + camber_slope = np.gradient(camber_line, x_coords) + camber_location_index = np.argmax(np.abs(camber_slope)) + camber_location = x_coords[camber_location_index] + + camber = camber_line[camber_location_index] + + return camber, camber_location, max_thickness_value + + +# Build OpenMDAO problem +prob = om.Problem() + +# Add the center of gravity component +prob.model.add_subsystem('cog', CenterOfGravity3D() , promotes_inputs=['span', 'root_chord', 'tip_chord', 'twist', 'thickness']) + +# Setup the problem +prob.setup() + +# Define some example inputs +prob.set_val('span', 11.0) +prob.set_val('root_chord', 1.9) +prob.set_val('tip_chord', 0.5) +#prob.set_val('twist', np.linspace(0, 0, 50)) +prob.set_val('thickness', 0.2) + +prob.model.cog.options['airfoil_data_file'] = 'airfoil_data_test.dat' + +# Run the model +prob.run_model() + +# Get the results +center_of_gravity_x = prob.get_val('cog.center_of_gravity_x') +center_of_gravity_y = prob.get_val('cog.center_of_gravity_y') +center_of_gravity_z = prob.get_val('cog.center_of_gravity_z') +total_weight = prob.get_val('cog.total_weight') + +# Get the 3D coordinates for the entire wing +x_coords = prob.get_val('cog.x_coords') +y_coords = prob.get_val('cog.y_coords') +z_coords = prob.get_val('cog.z_coords') + +print(f"Center of gravity: X = {center_of_gravity_x} m, Y = {center_of_gravity_y} m, Z = {center_of_gravity_z} m") +print(f"Total weight of the wing: {total_weight} kg") + diff --git a/aviary/docs/examples/Clark_Y.dat b/aviary/docs/examples/Clark_Y.dat new file mode 100644 index 000000000..3649ca4e2 --- /dev/null +++ b/aviary/docs/examples/Clark_Y.dat @@ -0,0 +1,122 @@ +0.0000000 0.0000000 +0.0005000 0.0023390 +0.0010000 0.0037271 +0.0020000 0.0058025 +0.0040000 0.0089238 +0.0080000 0.0137350 +0.0120000 0.0178581 +0.0200000 0.0253735 +0.0300000 0.0330215 +0.0400000 0.0391283 +0.0500000 0.0442753 +0.0600000 0.0487571 +0.0800000 0.0564308 +0.1000000 0.0629981 +0.1200000 0.0686204 +0.1400000 0.0734360 +0.1600000 0.0775707 +0.1800000 0.0810687 +0.2000000 0.0839202 +0.2200000 0.0861433 +0.2400000 0.0878308 +0.2600000 0.0890840 +0.2800000 0.0900016 +0.3000000 0.0906804 +0.3200000 0.0911857 +0.3400000 0.0915079 +0.3600000 0.0916266 +0.3800000 0.0915212 +0.4000000 0.0911712 +0.4200000 0.0905657 +0.4400000 0.0897175 +0.4600000 0.0886427 +0.4800000 0.0873572 +0.5000000 0.0858772 +0.5200000 0.0842145 +0.5400000 0.0823712 +0.5600000 0.0803480 +0.5800000 0.0781451 +0.6000000 0.0757633 +0.6200000 0.0732055 +0.6400000 0.0704822 +0.6600000 0.0676046 +0.6800000 0.0645843 +0.7000000 0.0614329 +0.7200000 0.0581599 +0.7400000 0.0547675 +0.7600000 0.0512565 +0.7800000 0.0476281 +0.8000000 0.0438836 +0.8200000 0.0400245 +0.8400000 0.0360536 +0.8600000 0.0319740 +0.8800000 0.0277891 +0.9000000 0.0235025 +0.9200000 0.0191156 +0.9400000 0.0146239 +0.9600000 0.0100232 +0.9700000 0.0076868 +0.9800000 0.0053335 +0.9900000 0.0029690 +1.0000000 0.0005993 +0.0000000 0.0000000 +0.0005000 -.0046700 +0.0010000 -.0059418 +0.0020000 -.0078113 +0.0040000 -.0105126 +0.0080000 -.0142862 +0.0120000 -.0169733 +0.0200000 -.0202723 +0.0300000 -.0226056 +0.0400000 -.0245211 +0.0500000 -.0260452 +0.0600000 -.0271277 +0.0800000 -.0284595 +0.1000000 -.0293786 +0.1200000 -.0299633 +0.1400000 -.0302404 +0.1600000 -.0302546 +0.1800000 -.0300490 +0.2000000 -.0296656 +0.2200000 -.0291445 +0.2400000 -.0285181 +0.2600000 -.0278164 +0.2800000 -.0270696 +0.3000000 -.0263079 +0.3200000 -.0255565 +0.3400000 -.0248176 +0.3600000 -.0240870 +0.3800000 -.0233606 +0.4000000 -.0226341 +0.4200000 -.0219042 +0.4400000 -.0211708 +0.4600000 -.0204353 +0.4800000 -.0196986 +0.5000000 -.0189619 +0.5200000 -.0182262 +0.5400000 -.0174914 +0.5600000 -.0167572 +0.5800000 -.0160232 +0.6000000 -.0152893 +0.6200000 -.0145551 +0.6400000 -.0138207 +0.6600000 -.0130862 +0.6800000 -.0123515 +0.7000000 -.0116169 +0.7200000 -.0108823 +0.7400000 -.0101478 +0.7600000 -.0094133 +0.7800000 -.0086788 +0.8000000 -.0079443 +0.8200000 -.0072098 +0.8400000 -.0064753 +0.8600000 -.0057408 +0.8800000 -.0050063 +0.9000000 -.0042718 +0.9200000 -.0035373 +0.9400000 -.0028028 +0.9600000 -.0020683 +0.9700000 -.0017011 +0.9800000 -.0013339 +0.9900000 -.0009666 +1.0000000 -.0005993 \ No newline at end of file diff --git a/aviary/docs/examples/Clark_Y.yaml b/aviary/docs/examples/Clark_Y.yaml new file mode 100644 index 000000000..3649ca4e2 --- /dev/null +++ b/aviary/docs/examples/Clark_Y.yaml @@ -0,0 +1,122 @@ +0.0000000 0.0000000 +0.0005000 0.0023390 +0.0010000 0.0037271 +0.0020000 0.0058025 +0.0040000 0.0089238 +0.0080000 0.0137350 +0.0120000 0.0178581 +0.0200000 0.0253735 +0.0300000 0.0330215 +0.0400000 0.0391283 +0.0500000 0.0442753 +0.0600000 0.0487571 +0.0800000 0.0564308 +0.1000000 0.0629981 +0.1200000 0.0686204 +0.1400000 0.0734360 +0.1600000 0.0775707 +0.1800000 0.0810687 +0.2000000 0.0839202 +0.2200000 0.0861433 +0.2400000 0.0878308 +0.2600000 0.0890840 +0.2800000 0.0900016 +0.3000000 0.0906804 +0.3200000 0.0911857 +0.3400000 0.0915079 +0.3600000 0.0916266 +0.3800000 0.0915212 +0.4000000 0.0911712 +0.4200000 0.0905657 +0.4400000 0.0897175 +0.4600000 0.0886427 +0.4800000 0.0873572 +0.5000000 0.0858772 +0.5200000 0.0842145 +0.5400000 0.0823712 +0.5600000 0.0803480 +0.5800000 0.0781451 +0.6000000 0.0757633 +0.6200000 0.0732055 +0.6400000 0.0704822 +0.6600000 0.0676046 +0.6800000 0.0645843 +0.7000000 0.0614329 +0.7200000 0.0581599 +0.7400000 0.0547675 +0.7600000 0.0512565 +0.7800000 0.0476281 +0.8000000 0.0438836 +0.8200000 0.0400245 +0.8400000 0.0360536 +0.8600000 0.0319740 +0.8800000 0.0277891 +0.9000000 0.0235025 +0.9200000 0.0191156 +0.9400000 0.0146239 +0.9600000 0.0100232 +0.9700000 0.0076868 +0.9800000 0.0053335 +0.9900000 0.0029690 +1.0000000 0.0005993 +0.0000000 0.0000000 +0.0005000 -.0046700 +0.0010000 -.0059418 +0.0020000 -.0078113 +0.0040000 -.0105126 +0.0080000 -.0142862 +0.0120000 -.0169733 +0.0200000 -.0202723 +0.0300000 -.0226056 +0.0400000 -.0245211 +0.0500000 -.0260452 +0.0600000 -.0271277 +0.0800000 -.0284595 +0.1000000 -.0293786 +0.1200000 -.0299633 +0.1400000 -.0302404 +0.1600000 -.0302546 +0.1800000 -.0300490 +0.2000000 -.0296656 +0.2200000 -.0291445 +0.2400000 -.0285181 +0.2600000 -.0278164 +0.2800000 -.0270696 +0.3000000 -.0263079 +0.3200000 -.0255565 +0.3400000 -.0248176 +0.3600000 -.0240870 +0.3800000 -.0233606 +0.4000000 -.0226341 +0.4200000 -.0219042 +0.4400000 -.0211708 +0.4600000 -.0204353 +0.4800000 -.0196986 +0.5000000 -.0189619 +0.5200000 -.0182262 +0.5400000 -.0174914 +0.5600000 -.0167572 +0.5800000 -.0160232 +0.6000000 -.0152893 +0.6200000 -.0145551 +0.6400000 -.0138207 +0.6600000 -.0130862 +0.6800000 -.0123515 +0.7000000 -.0116169 +0.7200000 -.0108823 +0.7400000 -.0101478 +0.7600000 -.0094133 +0.7800000 -.0086788 +0.8000000 -.0079443 +0.8200000 -.0072098 +0.8400000 -.0064753 +0.8600000 -.0057408 +0.8800000 -.0050063 +0.9000000 -.0042718 +0.9200000 -.0035373 +0.9400000 -.0028028 +0.9600000 -.0020683 +0.9700000 -.0017011 +0.9800000 -.0013339 +0.9900000 -.0009666 +1.0000000 -.0005993 \ No newline at end of file diff --git a/aviary/docs/examples/Custom_Fuselage.dat b/aviary/docs/examples/Custom_Fuselage.dat new file mode 100644 index 000000000..ce85fe585 --- /dev/null +++ b/aviary/docs/examples/Custom_Fuselage.dat @@ -0,0 +1,179 @@ +0.0 0.5 +0.5 0.45 +1.0 0.4 +1.5 0.6 +2.0 0.3 +2.5 0.35 + +class CenterOfGravity3D(om.ExplicitComponent): + def initialize(self): + self.options.declare('num_sections', types=int, default=50) + self.options.declare('airfoil_type', types=str, default='2412') + self.options.declare('material', default='metal', values=['wood', 'metal', 'carbon_fiber']) + self.options.declare('airfoil_data_file', default=None, types=str) + + def setup(self): + num_sections = self.options['num_sections'] + + # Inputs + self.add_input('span', val=10.0, units='m') + self.add_input('root_chord', val=2.0, units='m') + self.add_input('tip_chord', val=1.0, units='m') + self.add_input('twist', val=np.zeros(num_sections), units='deg') + self.add_input('thickness', val=0.2, units='m') + + # Outputs + self.add_output('center_of_gravity_x', val=0.0, units='m') + self.add_output('center_of_gravity_y', val=0.0, units='m') + self.add_output('center_of_gravity_z', val=0.0, units='m') + self.add_output('total_weight', val=0.0, units='kg') + self.add_output('x_coords', val=np.zeros(num_sections), units='m') + self.add_output('y_coords', val=np.zeros(num_sections), units='m') + self.add_output('z_coords', val=np.zeros(num_sections), units='m') + + def setup_partials(self): + num_sections = self.options['num_sections'] + + self.declare_partials(of=['center_of_gravity_x', 'center_of_gravity_y', 'center_of_gravity_z'], + wrt=['span', 'root_chord', 'tip_chord', 'thickness']) + self.declare_partials(of='total_weight', wrt=['span', 'root_chord', 'tip_chord', 'thickness']) + self.declare_partials(of='x_coords', wrt=['twist'], rows=np.arange(num_sections), cols=np.arange(num_sections)) + self.declare_partials(of='y_coords', wrt=['span'], rows=np.arange(num_sections), cols=np.arange(num_sections)) + self.declare_partials(of='z_coords', wrt=['twist'], rows=np.arange(num_sections), cols=np.arange(num_sections)) + + def compute_partials(self, inputs, partials): + """Compute the analytical derivatives of outputs with respect to inputs.""" + span = inputs['span'] + root_chord = inputs['root_chord'] + tip_chord = inputs['tip_chord'] + thickness = inputs['thickness'] + num_sections = self.options['num_sections'] + + # Compute section locations along the span + span_locations = np.linspace(0, span, num_sections) + chord_lengths = root_chord - (root_chord - tip_chord) * (span_locations / span) + dchord_dspan = (tip_chord - root_chord) / span # Chord gradient w.r.t. span + + # Compute derivatives of total weight + total_weight = np.sum(chord_lengths * thickness * (span / num_sections)) + d_weight_dspan = np.sum(dchord_dspan * thickness * (span / num_sections)) + np.sum(chord_lengths * thickness / num_sections) + d_weight_droot_chord = np.sum(thickness * (span / num_sections)) + d_weight_dtip_chord = np.sum(thickness * (span / num_sections) * (span_locations / span)) + d_weight_dthickness = np.sum(chord_lengths * (span / num_sections)) + + partials['total_weight', 'span'] = d_weight_dspan + partials['total_weight', 'root_chord'] = d_weight_droot_chord + partials['total_weight', 'tip_chord'] = d_weight_dtip_chord + partials['total_weight', 'thickness'] = d_weight_dthickness + + # Compute derivatives of center of gravity coordinates + centroid_xs = chord_lengths / 4 # Approximate centroid of airfoil section + centroid_ys = span_locations + centroid_zs = np.zeros_like(span_locations) # Assuming zero camber + + total_moment_x = np.sum(centroid_xs * chord_lengths * thickness * (span / num_sections)) + total_moment_y = np.sum(centroid_ys * chord_lengths * thickness * (span / num_sections)) + total_moment_z = np.sum(centroid_zs * chord_lengths * thickness * (span / num_sections)) + + partials['center_of_gravity_x', 'span'] = (np.sum(dchord_dspan * centroid_xs * thickness * (span / num_sections)) - + total_moment_x / total_weight * d_weight_dspan) / total_weight + partials['center_of_gravity_x', 'root_chord'] = (np.sum(centroid_xs * thickness * (span / num_sections)) - + total_moment_x / total_weight * d_weight_droot_chord) / total_weight + partials['center_of_gravity_x', 'tip_chord'] = (np.sum(centroid_xs * thickness * (span / num_sections) * (span_locations / span)) - + total_moment_x / total_weight * d_weight_dtip_chord) / total_weight + partials['center_of_gravity_x', 'thickness'] = (np.sum(centroid_xs * chord_lengths * (span / num_sections)) - + total_moment_x / total_weight * d_weight_dthickness) / total_weight + + partials['center_of_gravity_y', 'span'] = (np.sum(dchord_dspan * centroid_ys * thickness * (span / num_sections)) - + total_moment_y / total_weight * d_weight_dspan) / total_weight + partials['center_of_gravity_y', 'root_chord'] = (np.sum(centroid_ys * thickness * (span / num_sections)) - + total_moment_y / total_weight * d_weight_droot_chord) / total_weight + partials['center_of_gravity_y', 'tip_chord'] = (np.sum(centroid_ys * thickness * (span / num_sections) * (span_locations / span)) - + total_moment_y / total_weight * d_weight_dtip_chord) / total_weight + partials['center_of_gravity_y', 'thickness'] = (np.sum(centroid_ys * chord_lengths * (span / num_sections)) - + total_moment_y / total_weight * d_weight_dthickness) / total_weight + + partials['center_of_gravity_z', 'span'] = 0 # No camber means no variation + partials['center_of_gravity_z', 'root_chord'] = 0 + partials['center_of_gravity_z', 'tip_chord'] = 0 + partials['center_of_gravity_z', 'thickness'] = 0 + + # Compute derivatives of x_coords and z_coords w.r.t. twist + twist = np.radians(inputs['twist']) + for i in range(num_sections): + partials['x_coords', 'twist'][i] = -centroid_xs[i] * np.sin(twist[i]) + partials['z_coords', 'twist'][i] = centroid_xs[i] * np.cos(twist[i]) + + +def compute_partials(self, inputs, partials): + """Compute the analytical derivatives of outputs with respect to inputs.""" + span = inputs['span'] + root_chord = inputs['root_chord'] + tip_chord = inputs['tip_chord'] + thickness = inputs['thickness'] + twist = np.radians(inputs['twist']) # Convert twist from degrees to radians + num_sections = self.options['num_sections'] + + # Spanwise locations + span_locations = np.linspace(0, span, num_sections) + + # Chord length variation (linear taper) + chord_lengths = root_chord - (root_chord - tip_chord) * (span_locations / span) + dchord_dspan = (tip_chord - root_chord) / span # Chord gradient w.r.t. span + + # Compute centroid locations + centroid_xs = chord_lengths / 4 # Approximate centroid X-location (quarter chord) + centroid_ys = span_locations # The spanwise locations + centroid_zs = np.zeros_like(span_locations) # Assume zero camber for now + + # Compute rotated centroid due to twist + rotated_xs = centroid_xs * np.cos(twist) - centroid_zs * np.sin(twist) + rotated_zs = centroid_xs * np.sin(twist) + centroid_zs * np.cos(twist) + + # Compute weight of each section + section_areas = chord_lengths * thickness # Simple approximation + section_volumes = section_areas * (span / num_sections) # Volume of each section + section_weights = section_volumes # Assuming uniform density + + # Compute total weight + total_weight = np.sum(section_weights) + + # Compute moments for CoG + total_moment_x = np.sum(rotated_xs * section_weights) + total_moment_y = np.sum(centroid_ys * section_weights) + total_moment_z = np.sum(rotated_zs * section_weights) + + # Compute derivatives of weight + d_weight_dspan = np.sum(dchord_dspan * thickness * (span / num_sections)) + np.sum(chord_lengths * thickness / num_sections) + d_weight_droot_chord = np.sum(thickness * (span / num_sections)) + d_weight_dtip_chord = np.sum(thickness * (span / num_sections) * (span_locations / span)) + d_weight_dthickness = np.sum(chord_lengths * (span / num_sections)) + + # Compute derivatives of moments + d_moment_x_dspan = np.sum((dchord_dspan / 4) * np.cos(twist) * section_weights) + d_moment_y_dspan = np.sum(centroid_ys * (section_weights / span)) # dY/dspan is straightforward + d_moment_z_dspan = np.sum((dchord_dspan / 4) * np.sin(twist) * section_weights) + + # Compute partials for CoG X + partials['center_of_gravity_x', 'span'] = (d_moment_x_dspan - total_moment_x / total_weight * d_weight_dspan) / total_weight + partials['center_of_gravity_x', 'root_chord'] = (np.sum(thickness * (span / num_sections) / 4) - total_moment_x / total_weight * d_weight_droot_chord) / total_weight + partials['center_of_gravity_x', 'tip_chord'] = (np.sum(thickness * (span / num_sections) * (span_locations / span) / 4) - total_moment_x / total_weight * d_weight_dtip_chord) / total_weight + partials['center_of_gravity_x', 'thickness'] = (np.sum(chord_lengths * (span / num_sections) / 4) - total_moment_x / total_weight * d_weight_dthickness) / total_weight + + # Compute partials for CoG Y + partials['center_of_gravity_y', 'span'] = (d_moment_y_dspan - total_moment_y / total_weight * d_weight_dspan) / total_weight + partials['center_of_gravity_y', 'root_chord'] = -total_moment_y / total_weight * d_weight_droot_chord / total_weight + partials['center_of_gravity_y', 'tip_chord'] = -total_moment_y / total_weight * d_weight_dtip_chord / total_weight + partials['center_of_gravity_y', 'thickness'] = -total_moment_y / total_weight * d_weight_dthickness / total_weight + + # Compute partials for CoG Z + partials['center_of_gravity_z', 'span'] = (d_moment_z_dspan - total_moment_z / total_weight * d_weight_dspan) / total_weight + partials['center_of_gravity_z', 'root_chord'] = (np.sum(thickness * (span / num_sections) / 4 * np.sin(twist)) - total_moment_z / total_weight * d_weight_droot_chord) / total_weight + partials['center_of_gravity_z', 'tip_chord'] = (np.sum(thickness * (span / num_sections) * (span_locations / span) / 4 * np.sin(twist)) - total_moment_z / total_weight * d_weight_dtip_chord) / total_weight + partials['center_of_gravity_z', 'thickness'] = (np.sum(chord_lengths * (span / num_sections) / 4 * np.sin(twist)) - total_moment_z / total_weight * d_weight_dthickness) / total_weight + + # Compute derivatives of x_coords and z_coords w.r.t. twist + for i in range(num_sections): + partials['x_coords', 'twist'][i] = -centroid_xs[i] * np.sin(twist[i]) # dx/dtwist + partials['z_coords', 'twist'][i] = centroid_xs[i] * np.cos(twist[i]) # dz/dtwist + diff --git a/aviary/docs/examples/airfoil_data_test.dat b/aviary/docs/examples/airfoil_data_test.dat new file mode 100644 index 000000000..2e2249c98 --- /dev/null +++ b/aviary/docs/examples/airfoil_data_test.dat @@ -0,0 +1,124 @@ + 0.00000 0.00001 + 0.00050 0.00430 + 0.00100 0.00600 + 0.00200 0.00903 + 0.00300 0.01127 + 0.00500 0.01490 + 0.00750 0.01861 + 0.01000 0.02180 + 0.02000 0.03186 + 0.03000 0.03967 + 0.04000 0.04688 + 0.05000 0.05192 + 0.06000 0.05698 + 0.07000 0.06110 + 0.08000 0.06562 + 0.09000 0.06937 + 0.10000 0.07280 + 0.12000 0.07886 + 0.14000 0.08401 + 0.16000 0.08839 + 0.18000 0.09211 + 0.20000 0.09525 + 0.22000 0.09786 + 0.24000 0.10000 + 0.26000 0.10173 + 0.28000 0.10313 + 0.30000 0.10418 + 0.34000 0.10542 + 0.36000 0.10632 + 0.38000 0.10687 + 0.40000 0.10700 + 0.44000 0.10656 + 0.46000 0.10600 + 0.48000 0.10526 + 0.50000 0.10423 + 0.54000 0.10154 + 0.56000 0.09965 + 0.58000 0.09795 + 0.60000 0.09587 + 0.64000 0.09125 + 0.66000 0.08872 + 0.68000 0.08605 + 0.70000 0.08322 + 0.74000 0.07789 + 0.76000 0.07477 + 0.78000 0.07028 + 0.80000 0.06668 + 0.82000 0.06262 + 0.84000 0.05834 + 0.86000 0.05368 + 0.88000 0.04856 + 0.90000 0.04299 + 0.91000 0.03997 + 0.92000 0.03686 + 0.93000 0.03364 + 0.94000 0.03032 + 0.95000 0.02689 + 0.96000 0.02335 + 0.97000 0.01968 + 0.98000 0.01570 + 0.99000 0.01171 + 1.00000 0.00720 + 0.00000 0.00000 + 0.00050 -0.00377 + 0.00100 -0.00519 + 0.00200 -0.00709 + 0.00300 -0.00842 + 0.00500 -0.01044 + 0.00750 -0.01230 + 0.01000 -0.01376 + 0.02000 -0.01767 + 0.03000 -0.02006 + 0.04000 -0.02109 + 0.05000 -0.02283 + 0.06000 -0.02353 + 0.07000 -0.02417 + 0.08000 -0.02450 + 0.09000 -0.02466 + 0.10000 -0.02469 + 0.12000 -0.02440 + 0.14000 -0.02374 + 0.16000 -0.02279 + 0.18000 -0.02159 + 0.20000 -0.02030 + 0.22000 -0.01901 + 0.24000 -0.01786 + 0.26000 -0.01688 + 0.28000 -0.01607 + 0.30000 -0.01536 + 0.34000 -0.01389 + 0.36000 -0.01344 + 0.38000 -0.01279 + 0.40000 -0.01216 + 0.44000 -0.01105 + 0.46000 -0.01060 + 0.48000 -0.01020 + 0.50000 -0.00985 + 0.54000 -0.00919 + 0.56000 -0.00888 + 0.58000 -0.00856 + 0.60000 -0.00824 + 0.64000 -0.00756 + 0.66000 -0.00721 + 0.68000 -0.00687 + 0.70000 -0.00658 + 0.74000 -0.00619 + 0.76000 -0.00611 + 0.78000 -0.00609 + 0.80000 -0.00611 + 0.82000 -0.00614 + 0.84000 -0.00621 + 0.86000 -0.00633 + 0.88000 -0.00653 + 0.90000 -0.00683 + 0.91000 -0.00701 + 0.92000 -0.00721 + 0.93000 -0.00742 + 0.94000 -0.00753 + 0.95000 -0.00785 + 0.96000 -0.00807 + 0.97000 -0.00829 + 0.98000 -0.00882 + 0.99000 -0.00976 + 1.00000 -0.01070 \ No newline at end of file diff --git a/aviary/docs/examples/fuselage_out/.openmdao_out b/aviary/docs/examples/fuselage_out/.openmdao_out new file mode 100644 index 000000000..e69de29bb diff --git a/aviary/docs/examples/mass_premission.py b/aviary/docs/examples/mass_premission.py index cc2467139..31a98c778 100644 --- a/aviary/docs/examples/mass_premission.py +++ b/aviary/docs/examples/mass_premission.py @@ -1,5 +1,20 @@ import openmdao.api as om +""" +The little bit of path code below is not important overall. This is for me to test +within the Docker container and VS Code before I push everything fully to the Github +repository. These lines can be deleted as things are updated further. + +""" + +import sys +import os + + +module_path = os.path.abspath("/home/omdao/Aviary/aviary/subsystems/mass") +if module_path not in sys.path: + sys.path.append(module_path) + # Maybe some Aviary inputs as well? from aviary.subsystems.mass.simple_mass.wing import WingMassAndCOG from aviary.subsystems.mass.simple_mass.fuselage import FuselageMassAndCOG diff --git a/aviary/docs/examples/mass_summation.py b/aviary/docs/examples/mass_summation.py index 2d040cf78..040351e9f 100644 --- a/aviary/docs/examples/mass_summation.py +++ b/aviary/docs/examples/mass_summation.py @@ -1,6 +1,7 @@ import numpy as np import openmdao.api as om +import openmdao.jax as omj # Maybe add some aviary inputs at some point here @@ -20,7 +21,7 @@ def setup(self): ) -class StructureMass(om.ExplicitComponent): +class StructureMass(om.JaxExplicitComponent): def setup(self): # Maybe later change these to Aviary inputs? @@ -35,9 +36,8 @@ def setup_partials(self): # I'm not sure what else to put here at the moment self.declare_partials('structure_mass', '*', val=1) - def compute(self, inputs, outputs): - wing_mass = inputs['wing_mass'] - fuse_mass = inputs['fuse_mass'] - tail_mass = inputs['tail_mass'] + def compute_primal(self, wing_mass, fuse_mass, tail_mass): - outputs['structure_mass'] = wing_mass + fuse_mass + tail_mass \ No newline at end of file + structure_mass = wing_mass + fuse_mass + tail_mass + + return structure_mass \ No newline at end of file diff --git a/aviary/docs/examples/tail_out/.openmdao_out b/aviary/docs/examples/tail_out/.openmdao_out new file mode 100644 index 000000000..e69de29bb diff --git a/aviary/docs/examples/test_fuselage2_out/.openmdao_out b/aviary/docs/examples/test_fuselage2_out/.openmdao_out new file mode 100644 index 000000000..e69de29bb diff --git a/aviary/docs/examples/test_fuselage_dbf_out/.openmdao_out b/aviary/docs/examples/test_fuselage_dbf_out/.openmdao_out new file mode 100644 index 000000000..e69de29bb diff --git a/aviary/docs/examples/test_fuselage_out/.openmdao_out b/aviary/docs/examples/test_fuselage_out/.openmdao_out new file mode 100644 index 000000000..e69de29bb diff --git a/aviary/docs/examples/test_out/.openmdao_out b/aviary/docs/examples/test_out/.openmdao_out new file mode 100644 index 000000000..e69de29bb diff --git a/aviary/docs/examples/test_tail2_out/.openmdao_out b/aviary/docs/examples/test_tail2_out/.openmdao_out new file mode 100644 index 000000000..e69de29bb diff --git a/aviary/docs/examples/test_tail_out/.openmdao_out b/aviary/docs/examples/test_tail_out/.openmdao_out new file mode 100644 index 000000000..e69de29bb diff --git a/aviary/docs/examples/test_wing.py b/aviary/docs/examples/test_wing.py index ca9e2e14d..7ec5f07ff 100644 --- a/aviary/docs/examples/test_wing.py +++ b/aviary/docs/examples/test_wing.py @@ -3,7 +3,7 @@ import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal -from aviary.docs.examples.wing import WingMassAndCOG + class WingMassTestCase(unittest.TestCase): """ @@ -11,7 +11,32 @@ class WingMassTestCase(unittest.TestCase): """ - def setup(self): + def setUp(self): + + #self.prob = om.Problem() + #self.prob.model.add_subsystem( + # "wing", + # WingMassAndCOG(), + # promotes_inputs=["*"], + # promotes_outputs=['*'], + #) + + self.prob.model.set_input_defaults( + "wing_mass", val=10, units="kg" + ) + + self.prob.setup(check=False, force_alloc_complex=True) + + def test_case(self): + + self.prob.run_model() - self.prob = om.Problem() - self.prob.model.add_subsystem("wing", WingMassAndCOG(), promotes=["*"]) \ No newline at end of file + tol = 1e-10 + assert_near_equal(self.prob["wing_mass"], 100, tol) # Need to calculate first -- filler value for now + + partial_data = self.prob.check_partials(out_stream=None, method="fd") # finite difference used because cs is used in wing.py calculation + assert_check_partials(partial_data, atol=1e-15, rtol=1e-15) + + +if __name__ == "__main__": + unittest.main() \ No newline at end of file diff --git a/aviary/docs/examples/test_wing2_out/.openmdao_out b/aviary/docs/examples/test_wing2_out/.openmdao_out new file mode 100644 index 000000000..e69de29bb diff --git a/aviary/docs/examples/test_wing_out/.openmdao_out b/aviary/docs/examples/test_wing_out/.openmdao_out new file mode 100644 index 000000000..e69de29bb diff --git a/aviary/docs/examples/wingN2.html b/aviary/docs/examples/wingN2.html new file mode 100644 index 000000000..5c5691589 --- /dev/null +++ b/aviary/docs/examples/wingN2.html @@ -0,0 +1,14805 @@ + + + +OpenMDAO Model Hierarchy and N2 diagram + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ + +
+
+
+
+ + + +
+
+ + +
+
+ + + + + +
+
+ + + + +
+
+ +
+
+ +
+ +
+
+ +
+ +
+
+ Processing... +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+
+
+ + + +
+ +
+ +
+
+ +
+
+
+
+ N2 Information +
+ + +
+ +
+
+
+
+
+ + + + + + + + + + +
+ +
+ +
+ +
+ +
+

Left-click on a node in the model hierarchy to navigate to that node.
+ Right-click on a node to collapse/expand it. + Alt-right-click on a node with variables to select which ones to hide.
+ Note: Right-click in Firefox displays a browser menu. To disable that, + visit about:config and set dom.event.contextmenu.enabled + to true.
+ Hover over any cell in the matrix to display its connections + as arrows. Click that cell to make those arrows persistent. +

+

Toolbar Help

+
+ Snapshot of toolbar buttons + +
+
+ +
+ + + + + + +
Variable NameVisible
+
+ + +
+
+
+ Search + +
+
+ + + +
+
+
+ + + + + + + diff --git a/aviary/docs/examples/wing_out/.openmdao_out b/aviary/docs/examples/wing_out/.openmdao_out new file mode 100644 index 000000000..e69de29bb diff --git a/aviary/subsystems/mass/simple_mass/# New lump sum payments: $10,000 in 2025.py b/aviary/subsystems/mass/simple_mass/# New lump sum payments: $10,000 in 2025.py new file mode 100644 index 000000000..f098ddac7 --- /dev/null +++ b/aviary/subsystems/mass/simple_mass/# New lump sum payments: $10,000 in 2025.py @@ -0,0 +1,64 @@ +# New lump sum payments: $10,000 in 2025, $4,000 in 2026 and 2027 +lump_sum_payments = {0: 10000, 12: 4000, 24: 4000} # Months from now when lump sums occur + +# Reset loan balances +private_loan_balance = 58000 +gov_loan_balance = 28760.60 + +# Reset months counter +months = 0 + +private_interest_rate = 0.05 / 12 # Monthly interest rate for private loans (5% annually) +gov_interest_rate = 0.04 / 12 # Monthly interest rate for government loans (4% annually) + +# Payment schedule +initial_months = (2028 - 2025) * 12 # Number of months until January 2028 +private_payment_initial = 360 +gov_payment_initial = 0 # Government loans in forbearance + +private_payment_after = 1500 +gov_payment_after = 1000 + +# Payments until January 2028 with updated lump sum payments +for month in range(initial_months): + if private_loan_balance > 0: + interest = private_loan_balance * private_interest_rate + private_loan_balance += interest - private_payment_initial + private_loan_balance = max(private_loan_balance, 0) # Ensure no negative balance + + # Government loan accrues interest, but lump sum payments occur at specified months + if gov_loan_balance > 0: + interest = gov_loan_balance * gov_interest_rate + gov_loan_balance += interest + + if month in lump_sum_payments: + gov_loan_balance -= lump_sum_payments[month] + gov_loan_balance = max(gov_loan_balance, 0) + + months += 1 + +# Payments starting January 2028 +while private_loan_balance > 0 or gov_loan_balance > 0: + if private_loan_balance > 0: + interest = private_loan_balance * private_interest_rate + private_loan_balance += interest - private_payment_after + private_loan_balance = max(private_loan_balance, 0) + + if gov_loan_balance > 0: + interest = gov_loan_balance * gov_interest_rate + gov_loan_balance += interest - gov_payment_after + gov_loan_balance = max(gov_loan_balance, 0) + + months += 1 + + # If private loans are paid off, redirect full payment to government loans + if private_loan_balance == 0 and gov_loan_balance > 0: + gov_payment_after += private_payment_after + private_payment_after = 0 + + # If government loans are paid off, redirect full payment to private loans + if gov_loan_balance == 0 and private_loan_balance > 0: + private_payment_after += gov_payment_after + gov_payment_after = 0 + +months diff --git a/aviary/subsystems/mass/simple_mass/C:UsersszoppeltDesktopwingN2 b/aviary/subsystems/mass/simple_mass/C:UsersszoppeltDesktopwingN2 new file mode 100644 index 000000000..9819364ac --- /dev/null +++ b/aviary/subsystems/mass/simple_mass/C:UsersszoppeltDesktopwingN2 @@ -0,0 +1,14805 @@ + + + +OpenMDAO Model Hierarchy and N2 diagram + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ + +
+
+
+
+ + + +
+
+ + +
+
+ + + + + +
+
+ + + + +
+
+ +
+
+ +
+ +
+
+ +
+ +
+
+ Processing... +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+
+
+ + + +
+ +
+ +
+
+ +
+
+
+
+ N2 Information +
+ + +
+ +
+
+
+
+
+ + + + + + + + + + +
+ +
+ +
+ +
+ +
+

Left-click on a node in the model hierarchy to navigate to that node.
+ Right-click on a node to collapse/expand it. + Alt-right-click on a node with variables to select which ones to hide.
+ Note: Right-click in Firefox displays a browser menu. To disable that, + visit about:config and set dom.event.contextmenu.enabled + to true.
+ Hover over any cell in the matrix to display its connections + as arrows. Click that cell to make those arrows persistent. +

+

Toolbar Help

+
+ Snapshot of toolbar buttons + +
+
+ +
+ + + + + + +
Variable NameVisible
+
+ + +
+
+
+ Search + +
+
+ + + +
+
+
+ + + + + + + diff --git a/aviary/subsystems/mass/simple_mass/fuselage.py b/aviary/subsystems/mass/simple_mass/fuselage.py index 3764a4eff..4f200ee2f 100644 --- a/aviary/subsystems/mass/simple_mass/fuselage.py +++ b/aviary/subsystems/mass/simple_mass/fuselage.py @@ -1,29 +1,48 @@ import openmdao.api as om import numpy as np from scipy.interpolate import interp1d -import logging -# Configure logging -logging.basicConfig(level=logging.INFO) -logger = logging.getLogger(__name__) +import jax.numpy as jnp +import openmdao.jax as omj +import jax.scipy.interpolate as jinterp -# Material densities (kg/m^3) -MATERIAL_DENSITIES = { - 'wood': 600, # Not any real wood density - 'metal': 2700, # Aluminum - 'carbon_fiber': 1600, - 'foam': 300 # Example density for foam (just for something lightweight) -} +try: + from quadax import quadgk +except ImportError: + raise ImportError( + "quadax package not found. You can install it by running 'pip install quadax'." + ) -class FuselageMassAndCOG(om.ExplicitComponent): +""" +The little bit of path code below is not important overall. This is for me to test +within the Docker container and VS Code before I push everything fully to the Github +repository. These lines can be deleted as things are updated further. + +""" + +import sys +import os + + +module_path = os.path.abspath("/home/omdao/Aviary/aviary/subsystems/mass") +if module_path not in sys.path: + sys.path.append(module_path) + +from simple_mass.materials_database import materials + +from aviary.utils.named_values import get_keys + +Debug = True + +class FuselageMassAndCOG(om.JaxExplicitComponent): def initialize(self): self.options.declare('num_sections', types=int, - default=1000) + default=10) self.options.declare('material', - default='foam', - values=list(MATERIAL_DENSITIES.keys())) + default='Aluminum Oxide', + values=list(get_keys(materials))) self.options.declare('custom_fuselage_data_file', types=(str, type(None)), @@ -33,6 +52,7 @@ def initialize(self): self.custom_fuselage_function = None def setup(self): + self.options['use_jit'] = not(Debug) # Inputs self.add_input('length', @@ -86,104 +106,7 @@ def setup(self): val=0.0, units='kg') - def setup_partials(self): - """ - Complex step is used for the derivatives for now as they are very complicated to calculate - analytically. Compute_partials function has the framework for analytical derivatives, but not - all of them match the check_partials. - """ - self.declare_partials('center_of_gravity_x', ['length', 'diameter', 'taper_ratio', 'curvature', 'thickness'], method='cs') - self.declare_partials('center_of_gravity_y', ['length', 'y_offset', 'curvature'], method='cs') - self.declare_partials('total_weight', ['length', 'diameter', 'thickness'], method='cs') - - def compute_partials(self, inputs, partials): - length = inputs['length'] - diameter = inputs['diameter'] - taper_ratio = inputs['taper_ratio'] - curvature = inputs['curvature'] - thickness = inputs['thickness'] - y_offset = inputs['y_offset'] - z_offset = inputs['z_offset'] - is_hollow = inputs['is_hollow'] - - #custom_fuselage_function = getattr(self, 'custom_fuselage_function', None) # Custom fuselage model function -- if provided - - custom_fuselage_data_file = self.options['custom_fuselage_data_file'] - - material = self.options['material'] - num_sections = self.options['num_sections'] - - self.validate_inputs(length, diameter, thickness, taper_ratio, is_hollow) - - density = MATERIAL_DENSITIES[material] - - section_locations = np.linspace(0, length, num_sections).flatten() - dx = 1 / (num_sections - 1) - - total_weight = 0 - total_moment_x = 0 - total_moment_y = 0 - total_moment_z = 0 - - interpolate_diameter = self.load_fuselage_data(custom_fuselage_data_file) - - out_r = np.zeros(num_sections) - in_r = np.zeros(num_sections) - - - # Loop through each section - for i, location in enumerate(section_locations): - section_diameter = self.get_section_diameter(location, length, diameter, taper_ratio, interpolate_diameter) - outer_radius = section_diameter / 2.0 - inner_radius = max(0, outer_radius - thickness) if is_hollow else 0 - - out_r[i] = outer_radius - in_r[i] = inner_radius - - section_volume = np.pi * (outer_radius**2 - inner_radius**2) * (length / num_sections) - section_weight = density * section_volume - - centroid_x, centroid_y, centroid_z = self.compute_centroid(location, length, y_offset, z_offset, curvature, taper_ratio) - - total_weight += section_weight - total_moment_x += centroid_x * section_weight - total_moment_y += centroid_y * section_weight - total_moment_z += centroid_z * section_weight - - dzcg_dz_offset = np.sum( - np.trapz( - (1 - section_locations / length) * density * np.pi * (out_r**2 - in_r**2), section_locations, dx=dx - ) - ) / total_weight - - - partials['center_of_gravity_x', 'length'] = 3 / 4 if taper_ratio > 0 else 1 - partials['center_of_gravity_x', 'taper_ratio'] = - (3/4) * length if taper_ratio > 0 else 0 - partials['center_of_gravity_x', 'curvature'] = 0 - partials['center_of_gravity_x', 'thickness'] = 0 - - partials['center_of_gravity_y', 'length'] = -y_offset / length - partials['center_of_gravity_y', 'y_offset'] = 1 - - partials['center_of_gravity_z', 'length'] = -z_offset / length - partials['center_of_gravity_z', 'z_offset'] = dzcg_dz_offset - partials['center_of_gravity_z', 'curvature'] = length**2 / num_sections - - partials['total_weight', 'length'] = density * np.pi * (diameter**2 - (diameter - 2 * thickness)**2) / num_sections - partials['total_weight', 'diameter'] = 2 * density * np.pi * length * diameter / num_sections - partials['total_weight', 'thickness'] = -2 * density * np.pi * length * (diameter - thickness) / num_sections - - - def compute(self, inputs, outputs): - length = inputs['length'] - diameter = inputs['diameter'] - taper_ratio = inputs['taper_ratio'] - curvature = inputs['curvature'] - thickness = inputs['thickness'] - y_offset = inputs['y_offset'] - z_offset = inputs['z_offset'] - is_hollow = inputs['is_hollow'] - + def compute_primal(self, length, diameter, taper_ratio, curvature, thickness, y_offset, z_offset, is_hollow): # Input validation checks if length <= 0: raise ValueError("Length must be greater than zero.") @@ -200,9 +123,9 @@ def compute(self, inputs, outputs): self.validate_inputs(length, diameter, thickness, taper_ratio, is_hollow) - density = MATERIAL_DENSITIES[material] + density, _ = materials.get_item(material) - section_locations = np.linspace(0, length, num_sections) + section_locations = jnp.linspace(0, length, num_sections) total_weight = 0 total_moment_x = 0 @@ -215,9 +138,9 @@ def compute(self, inputs, outputs): for location in section_locations: section_diameter = self.get_section_diameter(location, length, diameter, taper_ratio, interpolate_diameter) outer_radius = section_diameter / 2.0 - inner_radius = max(0, outer_radius - thickness) if is_hollow else 0 + inner_radius = jnp.where(is_hollow, omj.smooth_max(0, outer_radius - thickness), 0) - section_volume = np.pi * (outer_radius**2 - inner_radius**2) * (length / num_sections) + section_volume = jnp.pi * (outer_radius**2 - inner_radius**2) * (length / num_sections) section_weight = density * section_volume centroid_x, centroid_y, centroid_z = self.compute_centroid(location, length, y_offset, z_offset, curvature, taper_ratio) @@ -226,11 +149,35 @@ def compute(self, inputs, outputs): total_moment_x += centroid_x * section_weight total_moment_y += centroid_y * section_weight total_moment_z += centroid_z * section_weight + + center_of_gravity_x = total_moment_x / total_weight + center_of_gravity_y = total_moment_y / total_weight + center_of_gravity_z = total_moment_z / total_weight + + # outer_radius = lambda x: 0.5 * (1 - taper_ratio * (x / length)) + + # if is_hollow: + # inner_radius = lambda x: 0.5 * (1 - taper_ratio * (x / length)) - thickness + # inner_radius_squared = lambda x: (0.5 - thickness)**2 - 2 * (0.5 - thickness) * (taper_ratio / 2) * (x / length) + (taper_ratio**2 / 4) * (x / length)**2 + # else: + # inner_radius = lambda x: 0 * x # 0 + # inner_radius_squared = lambda x: 0 * x # 0 + + # outer_radius_squared = lambda x: (1 / 4) - (taper_ratio / 2) * (x / length) + taper_ratio**2 * (x / length)**2 / 4 + + # if is_hollow: + # outer_minus_inner_squared = lambda x: ((1 / 4) - (taper_ratio / 2) * (x / length) + taper_ratio**2 * (x / length)**2 / 4) - ( + # (0.5 - thickness)**2 - 2 * (0.5 - thickness) * (taper_ratio / 2) * (x / length) + (taper_ratio**2 / 4) * (x / length)**2) + # else: + # outer_minus_inner_squared = lambda x: (1 / 4) - (taper_ratio / 2) * (x / length) + taper_ratio**2 * (x / length)**2 / 4 - outputs['center_of_gravity_x'] = total_moment_x / total_weight - outputs['center_of_gravity_y'] = total_moment_y / total_weight - outputs['center_of_gravity_z'] = total_moment_z / total_weight - outputs['total_weight'] = total_weight + # if is_hollow: + # total_weight, _ = quadgk(lambda x: (length * jnp.pi * density) * (((1 / 4) - (taper_ratio / 2) * (x / length) + taper_ratio**2 * (x / length)**2 / 4) - ( + # (0.5 - thickness)**2 - 2 * (0.5 - thickness) * (taper_ratio / 2) * (x / length) + (taper_ratio**2 / 4) * (x / length)**2)), [0, length]) + # else: + # total_weight, _ = quadgk(lambda x: (length * jnp.pi * density) * ((1 / 4) - (taper_ratio / 2) * (x / length) + taper_ratio**2 * (x / length)**2 / 4), [0, length]) + + return center_of_gravity_x, center_of_gravity_y, center_of_gravity_z, total_weight def validate_inputs(self, length, diameter, thickness, taper_ratio, is_hollow): if length <= 0 or diameter <= 0 or thickness <= 0: @@ -247,7 +194,7 @@ def load_fuselage_data(self, custom_fuselage_data_file): custom_data = np.loadtxt(custom_fuselage_data_file) fuselage_locations = custom_data[:, 0] fuselage_diameters = custom_data[:, 1] - return interp1d(fuselage_locations, fuselage_diameters, kind='linear', fill_value='extrapolate') + return jinterp.RegularGridInterpolator(fuselage_locations, fuselage_diameters, kind='linear', fill_value='extrapolate') except Exception as e: raise ValueError(f"Error loading fuselage data file: {e}") else: @@ -257,12 +204,14 @@ def get_section_diameter(self, location, length, diameter, taper_ratio, interpol if self.custom_fuselage_function: return self.custom_fuselage_function(location) elif self.load_fuselage_data: - return interpolate_diameter(location) if interpolate_diameter is not None else max(0.01, diameter * (1 - taper_ratio * (location / length))) + return interpolate_diameter(location) if interpolate_diameter is not None else omj.smooth_max(0.01, diameter * (1 - taper_ratio * (location / length))) + #return jnp.where(interpolate_diameter is not None, interpolate_diameter(location), omj.smooth_max(0.01, diameter * (1 - taper_ratio * (location / length)))) else: - return max(0.01, diameter * (1 - taper_ratio * (location / length))) + return omj.smooth_max(0.01, diameter * (1 - taper_ratio * (location / length))) def compute_centroid(self, location, length, y_offset, z_offset, curvature, taper_ratio): - centroid_x = (3/4) * location if taper_ratio > 0 else location # This is an approximation that could and should be better modeled in the future + #centroid_x = (3/4) * location if taper_ratio > 0 else location # This is an approximation that could and should be better modeled in the future + centroid_x = jnp.where(taper_ratio > 0, (3/4) * location, location) centroid_y = y_offset * (1 - location / length) centroid_z = z_offset * (1 - location / length) + curvature * location**2 / length return centroid_x, centroid_y, centroid_z @@ -282,7 +231,7 @@ def compute_centroid(self, location, length, y_offset, z_offset, curvature, tape # Example using custom function -- uncomment to run #def custom_fuselage_model(location): -# return 0.5 * np.exp(-0.1 * location) +# return 0.5 * jnp.exp(-0.1 * location) #prob.model.fuselage_cg.custom_fuselage_function = custom_fuselage_model @@ -298,6 +247,6 @@ def compute_centroid(self, location, length, y_offset, z_offset, curvature, tape #data = prob.check_partials(compact_print=True, abs_err_tol=1e-04, rel_err_tol=1e-04, step=1e-8, step_calc='rel') -logger.info(f"Center of gravity of the fuselage: X = {center_of_gravity_x} m, Y = {center_of_gravity_y} m, Z = {center_of_gravity_z} m") -logger.info(f"Total weight of the fuselage: {total_weight} kg") +print(f"Center of gravity of the fuselage: X = {center_of_gravity_x} m, Y = {center_of_gravity_y} m, Z = {center_of_gravity_z} m") +print(f"Total weight of the fuselage: {total_weight} kg") diff --git a/aviary/subsystems/mass/simple_mass/import numpy as np.py b/aviary/subsystems/mass/simple_mass/import numpy as np.py new file mode 100644 index 000000000..782b420e4 --- /dev/null +++ b/aviary/subsystems/mass/simple_mass/import numpy as np.py @@ -0,0 +1,120 @@ +import numpy as np + +# Initial salary values +salary_user = 125000 +salary_partner = 150000 +salary_growth = 0.03 # 3% raise per year + +# Retirement contribution (pre-tax) +retirement_contribution = 0.15 # 15% of salary + +# Tax parameters (approximate federal tax brackets for married filing jointly, 2024) +standard_deduction = 29200 # Standard deduction for married filing jointly +tax_brackets = [(0.10, 23000), (0.12, 94300), (0.22, 201050), (0.24, 383900)] # Simplified brackets + +# Initial loan balances +private_loan_user = 58000 # User's private loans (6% interest) +gov_loan_user = 30000 # User's government loans (4% interest) + +private_loan_partner = 60000 # Partner's private loans (7% interest) +gov_loan_partner = 60000 # Partner's government loans (4% interest) + +# Loan payments per month +private_payment_user = 1500 +gov_payment_user = 1000 +private_payment_partner = 1600 +gov_payment_partner = 900 + +# Monthly expenses +rent = 2000 # Rent & utilities +rent_increase = 100 # Rent increase per year + +groceries = 500 # Groceries & gas +groceries_increase = 0.02 # 2% increase per year + +fixed_expenses = 500 # Fixed subscriptions, car insurance, etc. + +# Simulation for 10 years +years = 10 +net_income_per_year = [] + +# Function to calculate taxes owed +def calculate_taxes(income): + taxable_income = max(income - standard_deduction, 0) # Apply standard deduction + taxes_owed = 0 + for rate, bracket in tax_brackets: + if taxable_income > bracket: + taxes_owed += bracket * rate + taxable_income -= bracket + else: + taxes_owed += taxable_income * rate + break + return taxes_owed + +# Loan repayment tracking +user_private_paid = False +partner_private_paid = False + +for year in range(years): + # Salary growth + salary_user *= (1 + salary_growth) + salary_partner *= (1 + salary_growth) + total_salary = salary_user + salary_partner + + # Pre-tax retirement contributions + retirement_user = salary_user * retirement_contribution + retirement_partner = salary_partner * retirement_contribution + taxable_income = total_salary - (retirement_user + retirement_partner) + + # Calculate taxes + taxes = calculate_taxes(taxable_income) + + # Loan payments (pay extra to government loans after private loans are paid) + total_private_payment = 0 + total_gov_payment = 0 + + if not user_private_paid: + if private_loan_user > 0: + total_private_payment += private_payment_user * 12 + private_loan_user *= (1 + 0.06 / 12) ** 12 # Apply interest + private_loan_user -= private_payment_user * 12 + if private_loan_user <= 0: + user_private_paid = True + + if not partner_private_paid: + if private_loan_partner > 0: + total_private_payment += private_payment_partner * 12 + private_loan_partner *= (1 + 0.07 / 12) ** 12 # Apply interest + private_loan_partner -= private_payment_partner * 12 + if private_loan_partner <= 0: + partner_private_paid = True + + # After private loans are paid, extra payment goes to government loans + if user_private_paid: + gov_payment_user += private_payment_user + + if partner_private_paid: + gov_payment_partner += private_payment_partner + + if gov_loan_user > 0: + total_gov_payment += gov_payment_user * 12 + gov_loan_user *= (1 + 0.04 / 12) ** 12 # Apply interest + gov_loan_user -= gov_payment_user * 12 + + if gov_loan_partner > 0: + total_gov_payment += gov_payment_partner * 12 + gov_loan_partner *= (1 + 0.04 / 12) ** 12 # Apply interest + gov_loan_partner -= gov_payment_partner * 12 + + # Adjust expenses + rent += rent_increase # Increase rent yearly + groceries *= (1 + groceries_increase) # Increase groceries yearly + + # Calculate net income + total_expenses = (rent * 12) + (groceries * 12) + (fixed_expenses * 12) + total_loan_payments = total_private_payment + total_gov_payment + + net_income = taxable_income - taxes - total_expenses - total_loan_payments + net_income_per_year.append(net_income) + +net_income_per_year diff --git a/aviary/subsystems/mass/simple_mass/materials_database.py b/aviary/subsystems/mass/simple_mass/materials_database.py index 77b0fb5f4..7fcb8f8b8 100644 --- a/aviary/subsystems/mass/simple_mass/materials_database.py +++ b/aviary/subsystems/mass/simple_mass/materials_database.py @@ -5,6 +5,7 @@ """ from aviary.utils.named_values import NamedValues +from aviary.utils.named_values import get_keys, get_values, get_items materials = NamedValues() @@ -64,3 +65,4 @@ materials.set_val('Wood Glue', 1080, units='kg/m**3') # Relative density value -- corresponds to 25 C (77 F) materials.set_val('EPS Foam', 16.3388, units='kg/m**3') + diff --git a/aviary/subsystems/mass/simple_mass/tail.py b/aviary/subsystems/mass/simple_mass/tail.py index 84d61f1ee..d249c8c4b 100644 --- a/aviary/subsystems/mass/simple_mass/tail.py +++ b/aviary/subsystems/mass/simple_mass/tail.py @@ -1,21 +1,44 @@ import openmdao.api as om +import openmdao.jax as omj +import jax.numpy as jnp +from jax.scipy.integrate import trapezoid as jtrapz import numpy as np -import scipy.integrate as spi from scipy.interpolate import interp1d from scipy.interpolate import CubicSpline +import os + +try: + from quadax import quadgk +except ImportError: + raise ImportError( + "quadax package not found. You can install it by running 'pip install quadax'." + ) + +""" +The little bit of path code below is not important overall. This is for me to test +within the Docker container and VS Code before I push everything fully to the Github +repository. These lines can be deleted as things are updated further. + +""" + +import sys import os -# Material densities, all in kg/m^3 -MATERIALS = { - 'Aluminum': 2700, - 'Steel': 7850, - 'Titanium': 4500, - 'Carbon Fiber': 1600, - 'Wood': 600 -} -class TailMassAndCOG(om.ExplicitComponent): +module_path = os.path.abspath("/home/omdao/Aviary/aviary/subsystems/mass") +if module_path not in sys.path: + sys.path.append(module_path) + +from simple_mass.materials_database import materials + +from aviary.utils.named_values import get_keys, get_values + +Debug = True # set to enable printing + +class TailMassAndCOG(om.JaxExplicitComponent): def initialize(self): + #self.options['default_shape'] = () # Sets the default shape to scalar + self.options.declare('tail_type', default='horizontal', values=['horizontal', 'vertical'], @@ -32,8 +55,8 @@ def initialize(self): desc="4 digit code for NACA airfoil, if that is given.") self.options.declare('material', - default='Aluminum', - values=list(MATERIALS.keys()), + default='Balsa', + values=list(get_keys(materials)), desc="Material type") self.options.declare('airfoil_file', @@ -41,10 +64,12 @@ def initialize(self): desc="File path for airfoil coordinates (if applicable)") self.options.declare('num_sections', - default=1000, + default=10, desc="Number of sections for enumeration") def setup(self): + self.options['use_jit'] = not(Debug) + # Inputs self.add_input('span', val=5.0, @@ -71,7 +96,7 @@ def setup(self): desc="Skin panel thickness") self.add_input('twist', - val=np.zeros(self.options['num_sections']), + val=jnp.zeros(self.options['num_sections']), units='deg', desc="Twist distribution") @@ -96,19 +121,19 @@ def setup(self): units='m', desc="Z location of the center of gravity") - def compute(self, inputs, outputs): + def compute_primal(self, span, root_chord, tip_chord, thickness_ratio, skin_thickness, twist): tail_type = self.options["tail_type"] airfoil_type = self.options["airfoil_type"] material = self.options['material'] - span = inputs['span'] - root_chord = inputs['root_chord'] - tip_chord = inputs['tip_chord'] - thickness_ratio = inputs['thickness_ratio'] - density = MATERIALS[material] + # span = inputs['span'] + # root_chord = inputs['root_chord'] + # tip_chord = inputs['tip_chord'] + # thickness_ratio = inputs['thickness_ratio'] + density, _ = materials.get_item(material) airfoil_file = self.options['airfoil_file'] - skin_thickness = inputs['skin_thickness'] + # skin_thickness = inputs['skin_thickness'] num_sections = self.options['num_sections'] - twist = inputs['twist'] + # twist = inputs['twist'] NACA_digits = self.options['NACA_digits'] # File check @@ -154,10 +179,10 @@ def compute(self, inputs, outputs): if skin_thickness <= 0: raise ValueError("Skin thickness must be greater than zero.") - if any(abs(twist)) > np.pi / 2: + if any(omj.smooth_abs(twist)) > jnp.pi / 2: raise ValueError("Twist angle is too extreme; must be within -90 to 90 degrees.") - span_locations = np.linspace(0, span, num_sections) + span_locations = jnp.linspace(0, span, num_sections) # Get x_points and dx for later x_points, dx = self.precompute_airfoil_geometry() @@ -165,71 +190,105 @@ def compute(self, inputs, outputs): # Thickness distribution thickness_dist = self.airfoil_thickness(x_points, max_thickness) - total_mass = 0 - total_moment_x = 0 - total_moment_y = 0 - total_moment_z = 0 + # total_mass = 0 + # total_moment_x = 0 + # total_moment_y = 0 + # total_moment_z = 0 - for i, y in enumerate(span_locations): - section_chord = root_chord - (root_chord - tip_chord) * (y / span) # Assume linear variation in chord - section_area, centroid_x, centroid_z = self.compute_airfoil_geometry(section_chord, - camber, - camber_location, - thickness_dist, - x_points, - dx) + # for i, y in enumerate(span_locations): + # section_chord = root_chord - (root_chord - tip_chord) * (y / span) # Assume linear variation in chord + # section_area, centroid_x, centroid_z = self.compute_airfoil_geometry(section_chord, + # camber, + # camber_location, + # thickness_dist, + # x_points, + # dx) - section_mass = density * section_area * (span / num_sections) + # section_mass = density * thickness_dist[i] * section_chord * (span / num_sections) + + # # Twist + # twist_angle = twist[i] + # rotated_x = centroid_x * jnp.cos(twist_angle) - centroid_z * jnp.sin(twist_angle) + # rotated_z = centroid_x * jnp.sin(twist_angle) + centroid_z * jnp.cos(twist_angle) + + # total_mass += section_mass + # total_moment_x += rotated_x * section_mass + # # if tail_type == 'horizontal': + # # total_moment_y += y * section_mass + # # total_moment_z += rotated_z * section_mass + # # elif tail_type == 'vertical': + # # total_moment_y += rotated_z * section_mass + # # total_moment_z += y * section_mass - # Twist - twist_angle = twist[i] - rotated_x = centroid_x * np.cos(twist_angle) - centroid_z * np.sin(twist_angle) - rotated_z = centroid_x * np.sin(twist_angle) + centroid_z * np.cos(twist_angle) - - total_mass += section_mass - total_moment_x += rotated_x * section_mass - if tail_type == 'horizontal': - total_moment_y += y * section_mass - total_moment_z += rotated_z * section_mass - elif tail_type == 'vertical': - total_moment_y += rotated_z * section_mass - total_moment_z += y * section_mass - - # COG - outputs['mass'] = total_mass - outputs['cg_x'] = total_moment_x / total_mass - outputs['cg_y'] = total_moment_y / total_mass - outputs['cg_z'] = total_moment_z / total_mass + # total_moment_y += jnp.where(tail_type == 'horizontal', y * section_mass, rotated_z * section_mass) + # total_moment_z += jnp.where(tail_type == 'horizontal', rotated_z * section_mass, y * section_mass) + + + #total_mass = jtrapz(density * self.airfoil_thickness(x_points, max_thickness) * (root_chord - (root_chord - tip_chord) * (x_points / span)) * span, x_points) + total_mass, _ = quadgk(lambda x: density * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span)) * span, [0, 1], epsabs=1e-9, epsrel=1e-9) + + #cgz_function = jnp.where(tail_type == 'horizontal', lambda x: (x * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span))) * jnp.sin(twist) + (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span))) * jnp.cos(twist), lambda x: x * span) + #cgy_function = jnp.where(tail_type == 'horizontal', lambda x: x * span, lambda x: (x * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span))) * jnp.sin(twist) + (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span))) * jnp.cos(twist)) + if tail_type == 'horizontal': + cgz_function = lambda x: (x * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span))) * jnp.sin(twist) + (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span))) * jnp.cos(twist) + cgy_function = lambda x: x * span + else: + cgz_function = lambda x: x * span + cgy_function = lambda x: (x * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span))) * jnp.sin(twist) + (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span))) * jnp.cos(twist) + + area, _ = quadgk(lambda x: self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span)), [0, 1], epsabs=1e-9, epsrel=1e-9) + + cg_x_num, _ = quadgk(lambda x: (x * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span)) * jnp.cos(twist)) - + (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span))) * jnp.sin(twist), + [0, 1], epsabs=1e-9, epsrel=1e-9) + + cg_x = cg_x_num / area + cg_x = cg_x[0] + + + cg_y, _ = quadgk(cgy_function, [0, 1], epsabs=1e-9, epsrel=1e-9) + + cg_z_num, _ = quadgk(cgz_function, [0, 1], epsabs=1e-9, epsrel=1e-9) + + cg_z = cg_z_num / area + cg_z = cg_z[0] + + mass = total_mass + #cg_x = total_moment_x / total_mass + #cg_y = total_moment_y / total_mass + #cg_z = total_moment_z / total_mass + + return mass, cg_x, cg_y, cg_z def precompute_airfoil_geometry(self): num_sections = self.options['num_sections'] n_points = num_sections - x_points = np.linspace(0, 1, n_points) + x_points = jnp.linspace(0, 1, n_points) dx = 1 / (n_points - 1) return x_points, dx def compute_airfoil_geometry(self, chord, camber, camber_location, thickness_dist, x_points, dx): - #section_area, _ = quad(lambda x: np.interp(x, x_points, thickness_dist), 0, 1, limit=100) - section_area = np.trapz(thickness_dist, x_points, dx=dx) + #section_area, _ = quad(lambda x: jnp.interp(x, x_points, thickness_dist), 0, 1, limit=100) + section_area = jnp.trapezoid(thickness_dist, x_points, dx=dx) section_area *= chord - #centroid_x, _ = quad(lambda x: x * np.interp(x, x_points, thickness_dist), 0, 1, limit=100) - centroid_x = np.trapz(x_points * thickness_dist, x_points, dx=dx) + #centroid_x, _ = quad(lambda x: x * jnp.interp(x, x_points, thickness_dist), 0, 1, limit=100) + centroid_x = jnp.trapezoid(x_points * thickness_dist, x_points, dx=dx) centroid_x = (centroid_x * chord) / section_area - #centroid_z, _ = quad(lambda x: self.airfoil_camber_line(x, camber, camber_location) * np.interp(x, x_points, thickness_dist), 0, 1, limit=100) - centroid_z = np.trapz(self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist, x_points, dx=dx) + #centroid_z, _ = quad(lambda x: self.airfoil_camber_line(x, camber, camber_location) * jnp.interp(x, x_points, thickness_dist), 0, 1, limit=100) + centroid_z = jnp.trapezoid(self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist, x_points, dx=dx) centroid_z = (centroid_z * chord) / section_area return section_area, centroid_x, centroid_z def airfoil_thickness(self, x, max_thickness): - return 5 * max_thickness * (0.2969 * np.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) + return 5 * max_thickness * (0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) def airfoil_camber_line(self, x, camber, camber_location): - camber_location = max(camber_location, 1e-9) # Divide by zero check - return np.where( + camber_location = omj.ks_max(camber_location, 1e-9) # Divide by zero check + return jnp.where( x < camber_location, (camber / camber_location**2) * (2 * camber_location * x - x**2), (camber / (1 - camber_location)**2) * ((1 - 2 * camber_location) + 2 * camber_location * x - x**2) @@ -254,18 +313,17 @@ def extract_airfoil_features(self, x_coords, y_coords): thickness = upper_spline(x_coords) - lower_spline(x_coords) - max_thickness_index = np.argmax(thickness) + max_thickness_index = omj.ks_max(thickness) max_thickness_value = thickness[max_thickness_index] - camber_slope = np.gradient(camber_line, x_coords) - camber_location_index = np.argmax(np.abs(camber_slope)) + camber_slope = jnp.gradient(camber_line, x_coords) + camber_location_index = omj.ks_max(omj.smooth_abs(camber_slope)) camber_location = x_coords[camber_location_index] camber = camber_line[camber_location_index] return camber, camber_location, max_thickness_value - prob = om.Problem() prob.model.add_subsystem('tail', TailMassAndCOG(), promotes_inputs=['*'], promotes_outputs=['*']) @@ -273,14 +331,14 @@ def extract_airfoil_features(self, x_coords, y_coords): prob.setup() # Input values -prob.set_val('span', 0.3912) -prob.set_val('tip_chord', 0.15) -prob.set_val('root_chord', 0.26) +prob.set_val('span', 1) +prob.set_val('tip_chord', 0.5) +prob.set_val('root_chord', 1) prob.set_val('thickness_ratio', 0.12) prob.set_val('skin_thickness', 0.002) -prob.model.tail.options['tail_type'] = 'vertical' +prob.model.tail.options['tail_type'] = 'horizontal' -prob.model.tail.options['material'] = 'Carbon Fiber' +prob.model.tail.options['material'] = 'Balsa' prob.run_model() diff --git a/aviary/subsystems/mass/simple_mass/test/import os.py b/aviary/subsystems/mass/simple_mass/test/import os.py new file mode 100644 index 000000000..5d4713452 --- /dev/null +++ b/aviary/subsystems/mass/simple_mass/test/import os.py @@ -0,0 +1,2 @@ +import os +print(os.getcwd()) \ No newline at end of file diff --git a/aviary/subsystems/mass/simple_mass/test/test.py b/aviary/subsystems/mass/simple_mass/test/test.py new file mode 100644 index 000000000..58b9244da --- /dev/null +++ b/aviary/subsystems/mass/simple_mass/test/test.py @@ -0,0 +1,3 @@ +import os +print('path = '+ str(os.getcwd())) + diff --git a/aviary/subsystems/mass/simple_mass/test/test_fuselage.py b/aviary/subsystems/mass/simple_mass/test/test_fuselage.py index 99bff4b18..553720f21 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_fuselage.py +++ b/aviary/subsystems/mass/simple_mass/test/test_fuselage.py @@ -3,7 +3,22 @@ import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal -from aviary.subsystems.mass.simple_mass.fuselage import FuselageMassAndCOG +""" +The little bit of path code below is not important overall. This is for me to test +within the Docker container and VS Code before I push everything fully to the Github +repository. These lines can be deleted as things are updated further. + +""" + +import sys +import os + + +module_path = os.path.abspath("/home/omdao/Aviary/aviary/subsystems/mass") +if module_path not in sys.path: + sys.path.append(module_path) + +from simple_mass.fuselage import FuselageMassAndCOG class FuselageMassTestCase(unittest.TestCase): """ @@ -22,9 +37,43 @@ def setUp(self): ) self.prob.model.set_input_defaults( - "fuselage_mass", - val=10, - units="kg") + "length", + val=2.0, + units="m") + + self.prob.model.set_input_defaults( + "diameter", + val=0.4, + units="m" + ) + + self.prob.model.set_input_defaults( + "taper_ratio", + val=0.9999999999 + ) + + self.prob.model.set_input_defaults( + "curvature", + val=0.0, + units="m" + ) + + self.prob.model.set_input_defaults( + "y_offset", + val=0.0, + units="m" + ) + + self.prob.model.set_input_defaults( + "z_offset", + val=0.0, + units="m" + ) + + self.prob.model.set_input_defaults( + "is_hollow", + val=True + ) self.prob.setup( check=False, @@ -34,16 +83,19 @@ def test_case(self): self.prob.run_model() - tol=1e-10 + tol=1e-3 assert_near_equal( - self.prob["fuselage_mass"], - 100, # filler value for now + self.prob["total_weight"], + 167.35489, tol) partial_data = self.prob.check_partials( out_stream=None, - method="fd") # fd for now since cs is used in the fuselage mass calculation right now + method="cs") + + from pprint import pprint + pprint(partial_data) assert_check_partials( partial_data, diff --git a/aviary/subsystems/mass/simple_mass/test/test_tail.py b/aviary/subsystems/mass/simple_mass/test/test_tail.py index c26183101..b4e1939cd 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_tail.py +++ b/aviary/subsystems/mass/simple_mass/test/test_tail.py @@ -3,7 +3,24 @@ import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal -from aviary.subsystems.mass.simple_mass.tail import TailMassAndCOG +import numpy as np + +""" +The little bit of path code below is not important overall. This is for me to test +within the Docker container and VS Code before I push everything fully to the Github +repository. These lines can be deleted as things are updated further. + +""" + +import sys +import os + + +module_path = os.path.abspath("/home/omdao/Aviary/aviary/subsystems/mass") +if module_path not in sys.path: + sys.path.append(module_path) + +from simple_mass.tail import TailMassAndCOG class TailMassTestCase(unittest.TestCase): """ @@ -22,9 +39,39 @@ def setUp(self): ) self.prob.model.set_input_defaults( - "tail_mass", - val=10, - units="kg") + "span", + val=1, + units="m" + ) + + self.prob.model.set_input_defaults( + "root_chord", + val=1, + units="m" + ) + + self.prob.model.set_input_defaults( + "tip_chord", + val=0.5, + units="m" + ) + + self.prob.model.set_input_defaults( + "thickness_ratio", + val=0.12 + ) + + self.prob.model.set_input_defaults( + "skin_thickness", + val=0.002, + units="m" + ) + + self.prob.model.set_input_defaults( + "twist", + val=np.zeros(10), + units="deg" + ) self.prob.setup( check=False, @@ -34,16 +81,16 @@ def test_case(self): self.prob.run_model() - tol = 1e-10 + tol = 1e-4 assert_near_equal( - self.prob["tail_mass"], - 100, # still need to calculate by hand + self.prob["mass"], + 4.22032, # still need to calculate by hand tol) partial_data = self.prob.check_partials( out_stream=None, - method="fd") # Finite difference because cs is used in tail mass calculation right now + method="cs") # Finite difference because cs is used in tail mass calculation right now assert_check_partials( partial_data, diff --git a/aviary/subsystems/mass/simple_mass/test/test_wing.py b/aviary/subsystems/mass/simple_mass/test/test_wing.py index 45bbc9104..87fdd9d2b 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_wing.py +++ b/aviary/subsystems/mass/simple_mass/test/test_wing.py @@ -2,9 +2,29 @@ import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal +import aviary.api as av -from aviary.subsystems.mass.simple_mass.wing import WingMassAndCOG +import numpy as np +import jax.numpy as jnp +""" +The little bit of path code below is not important overall. This is for me to test +within the Docker container and VS Code before I push everything fully to the Github +repository. These lines can be deleted as things are updated further. + +""" + +import sys +import os + + +module_path = os.path.abspath("/home/omdao/Aviary/aviary/subsystems/mass") +if module_path not in sys.path: + sys.path.append(module_path) + +from simple_mass.wing import WingMassAndCOG + +#@av.skipIfMissingDependencies(WingMassAndCOG) class WingMassTestCase(unittest.TestCase): """ Wing mass test case. @@ -15,16 +35,47 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( - "wing", + "wing_mass", WingMassAndCOG(), promotes_inputs=["*"], promotes_outputs=['*'], ) self.prob.model.set_input_defaults( - "wing_mass", - val=10, - units="kg" + "span", + val=1, + units="m" + ) + + self.prob.model.set_input_defaults( + "root_chord", + val=1, + units="m" + ) + + self.prob.model.set_input_defaults( + "tip_chord", + val=0.5, + units="m" + ) + + self.prob.model.set_input_defaults( + "twist", + val=jnp.zeros(10), + units="deg" + ) + + + + n_points = 10 # = num_sections + x = jnp.linspace(0, 1, n_points) + max_thickness_chord_ratio = 0.12 + thickness_dist = 5 * max_thickness_chord_ratio * (0.2969 * np.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) + + self.prob.model.set_input_defaults( + "thickness_dist", + val=thickness_dist, + units="m" ) self.prob.setup( @@ -36,18 +87,17 @@ def test_case(self): self.prob.run_model() - tol = 1e-10 - assert_near_equal(self.prob["wing_mass"], - 100, # Need to calculate first -- filler value for now + tol = 1e-10 + assert_near_equal(self.prob["total_weight"], + 4.22032, tol) partial_data = self.prob.check_partials( out_stream=None, - method="fd") # finite difference used because cs is used in wing.py calculation + method="cs") assert_check_partials( - partial_data, - atol=1e-15, - rtol=1e-15) + partial_data) + if __name__ == "__main__": diff --git a/aviary/subsystems/mass/simple_mass/test_quad.py b/aviary/subsystems/mass/simple_mass/test_quad.py new file mode 100644 index 000000000..0b9fb26c5 --- /dev/null +++ b/aviary/subsystems/mass/simple_mass/test_quad.py @@ -0,0 +1,642 @@ +import jax.numpy as jnp +from jax.scipy.linalg import eigh +import jax.scipy as jsp +import jax +from jax import jit, lax +from scipy.integrate import quad +import quadax +""" +Website: https://rosettacode.org/wiki/Numerical_integration/Gauss-Legendre_Quadrature#Python + +""" + +# def legendre_poly_and_deriv(n, x): +# """ +# Compute the Legendre polynomial P_n(x) and its derivative P_n'(x) using +# recurrence relations. + +# Parameters: + +# n : int +# Degree of the Legendre polynomial. +# x : jnp.ndarray +# Points at which to evalulate the polynomial. + +# Returns: + +# P_n : jnp.ndarray +# Value of the Legendre polynomial P_n(x). +# P_n_prime : jnp.ndarray +# Value of the derivative P_n'(x). + +# """ + +# if n == 0: +# return jnp.ones_like(x), jnp.zeros_like(x) +# elif n == 1: +# return x, jnp.ones_like(x) + +# # initialize P_0(x) and P_1(x) +# P0 = jnp.ones_like(x) +# P1 = x + +# for k in range(2, n+1): +# P2 = ((2 * k - 1) * x * P1 - (k - 1) * P0) / k +# P0, P1 = P1, P2 # Shift P_k-1 to P_k, and P_k to P_k+1 + +# # Compute derivative using recurrence relation +# P_n = P1 +# P_n_prime = n * (x * P_n - P0) / (x**2 - 1) + +# return P_n, P_n_prime + +# def legendre_roots_and_weights(n, tol=1e-15, max_iter=10): +# """ +# Compute the Gauss-Legendre quadrature nodes (roots) and weights using the +# Newton method. + +# Parameters: + +# n : int +# Number of quadrature points. +# tol : float, optional +# Convergence tolerance for Newton's method. + +# Returns: + +# roots : jnp.ndarray +# Legendre polynomial roots (Gauss-Legendre nodes). +# weights : jnp.ndarray +# Gauss-Legendre quadrature weights. + +# """ + +# # Initial guess for roots: use Chebyshev approximation +# roots = jnp.cos(jnp.pi * (4 * jnp.arange(1, n + 1) - 1) / (4 * n + 2)) + +# # Newton's method +# for _ in range(max_iter): +# P_n, P_n_prime = legendre_poly_and_deriv(n, roots) +# roots -= P_n / P_n_prime + +# # Compute weights +# _, P_n_prime = legendre_poly_and_deriv(n, roots) +# weights = 2 / ((1 - roots**2) * P_n_prime**2) + +# return roots, weights + + + + +# def gauss_quad(f, n, a, b): +# """ +# Computes the integral of f(x) over [a, b] using Gaussian quadrature with n points. + +# Parameters: + +# f : function +# The function to integrate. + +# n : int +# The number of quadrature points. + +# a, b : float +# Integration limits. + +# Returns: +# float +# The approximated integral of f(x) over [a, b]. + +# """ +# x, w = legendre_roots_and_weights(n) + +# x_mapped = 0.5 * (b - a) * x + 0.5 * (b + a) +# w_mapped = 0.5 * (b - a) * w +# integral = jnp.sum(w_mapped * f(x_mapped)) # Compute weighted sum +# return integral.astype(jnp.float64) + +# def legendre_roots_and_weights(n): +# """ +# Compute nodes and weights for Legendre-Gauss quadrature using JAX. + +# Parameters: + +# beta: +# coefficient coming form Gram-Schmidt process, derived from recursive relation +# of Legendre polynomials. + +# T: +# symmetric, tri-diagonal Jacobi matrix derived using Golub-Welsch theorem. Eigenvalues +# of T correspond to roots of Legendre polynomials + +# Eigenvalues, Eigenvectors: +# The eigenvalues of T and their respective eigenvectors, calculated using +# jax.scipy.special.eigh function. + +# weights: +# Weights used for Gaussian-Legendre quadrature, calculated using the first +# component of the normalized eigenvector, derived from Golub & Welsch (1969). +# Coefficient 2 comes from an application of Rodrigues' formula for Legendre +# polynomials and applying the orthonormality property for Legendre polynomials +# over the interval [-1, 1] with weight = 1. + +# Returns: + +# float +# Roots of the Legendre polynomials (eigenvalues of T) +# float +# weights used for G-L quadrature (formula from Golub & Welsch 1969) + +# References: + +# [1] Golub, Gene H., and John H. Welsch. "Calculation of Gauss quadrature rules." +# Mathematics of computation 23.106 (1969): 221-230. + +# [2] André Ronveaux, Jean Mawhin, Rediscovering the contributions of Rodrigues on +# the representation of special functions, Expositiones Mathematicae, Volume 23, +# Issue 4, 2005, Pages 361-369, ISSN 0723-0869, +# https://doi.org/10.1016/j.exmath.2005.05.001. + +# """ + +# i = jnp.arange(1, n) +# beta = i / jnp.sqrt(4 * i**2 - 1) +# T = jnp.diag(beta, k=1) + jnp.diag(beta, k=-1) # Tridiagonal matrix +# eigenvalues, eigenvectors = jax.jit(jnp.linalg.eigh)(T) # Compute eigenvalues (roots) and eigenvectors +# roots = eigenvalues +# weights = 2 * (eigenvectors[0, :] ** 2) # Compute weights from first row of eigenvectors + +# return roots, weights + + +# def gauss_quad(f, n, a, b): +# """ +# Computes the integral of f(x) over [a, b] using Gaussian quadrature with n points. + +# Parameters: + +# f : function +# The function to integrate. + +# n : int +# The number of quadrature points. + +# a, b : float +# Integration limits. + +# Returns: + +# float +# The approximated integral of f(x) over [a, b]. + +# """ +# x, w = legendre_roots_and_weights(n) + +# x_mapped = 0.5 * (b - a) * x + 0.5 * (b + a) + +# integral = jnp.sum(w * f(x_mapped)) * ((b - a) / 2) # Compute weighted sum +# return integral.astype(jnp.float64) + + +# span = 1 +# root_chord = 1 +# tip_chord = 0.5 +# density = 130 +# max_thickness = 0.12 +# n = 1000 + +# test_f = lambda x: density * (5 * max_thickness * (0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4)) * (root_chord - (root_chord - tip_chord) * (x / span)) * span +# integral_value = gauss_quad(test_f, n, 0, 1) +# scipy_int, _ = quad(test_f, 0, 1) +# print(f"Gauss-Legendre Quadrature Result (n={n}): {integral_value:.10f}") +# print("Expected: 4.22032, Computed with scipy.integrate.quad: ", scipy_int) + +def Legendre(n, x): + x = jnp.array(x) + if n == 0: + return x * 0 + 1.0 + elif n == 1: + return x + else: + return ((2.0 * n - 1.0) * x * Legendre(n-1, x) - (n - 1) * Legendre(n-2, x)) / n + +def DLegendre(n, x): + x = jnp.array(x) + if n == 0: + return x * 0 + elif n == 1: + return x * 0 + 1.0 + else: + return (n / (x**2 - 1.0)) * (x * Legendre(n, x) - Legendre(n-1, x)) + +def LegendreRoots(polyorder, tolerance=1e-20): + if polyorder < 2: + err = 1 + else: + roots = [] + for i in range(1, jnp.int_(polyorder / 2 + 1)): + x = jnp.cos(jnp.pi * (i - 0.25) / polyorder + 0.5) + error = 10 * tolerance + iters = 0 + while (error > tolerance) and (iters < 1000): + dx = -Legendre(polyorder, x) / DLegendre(polyorder, x) + x += dx + iters += 1 + error = jnp.abs(dx) + roots.append(x) + roots = jnp.asarray(roots) + if (polyorder % 2 == 0): + roots = jnp.concatenate([-1.0 * roots, roots[::-1]]) + else: + roots = jnp.concatenate([-1.0 * roots, jnp.array([0.0]), roots[::-1]]) + err = 0 + return [roots, err] + +def GaussLegendreWeights(polyorder): + W = [] + [xis, err] = LegendreRoots(polyorder) + if err == 0: + W = 2.0 / ((1.0 - xis**2) * (DLegendre(polyorder, xis)**2)) + else: + err = 1 + return [W, xis, err] + +def GaussLegendreQuadrature(func, polyorder, a, b): + [Ws, xs, err] = GaussLegendreWeights(polyorder) + if err == 0: + ans = (b-a) * 0.5 * jnp.sum(Ws * func((b - a) * 0.5 * xs + (b + a) * 0.5)) + else: + err = 1 + ans = None + + return [ans, err] + +span = 1 +root_chord = 1 +tip_chord = 0.5 +density = 130 +max_thickness = 0.12 + +test_f = lambda x: density * (5 * max_thickness * (0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4)) * (root_chord - (root_chord - tip_chord) * (x / span)) * span + +order = 3 +[Ws, xs, err] = GaussLegendreWeights(order) + +if err == 0: + print("Order : ", order) + print("Roots : ", xs) + print("Weights : ", Ws) +else: + print("Roots/Weights evaluation failed") + +[ans, err] = GaussLegendreQuadrature(test_f, order, 0, 1) +if err == 0: + print("Integral : ", ans) +else: + print("Integral evaluation failed") + +epsabs = epsrel = 1e-9 + +integral, _ = quadax.quadgk(test_f, [0, 1], epsabs=epsabs, epsrel=epsrel) +print("Result using quadax: ", integral) + +# Throw away code from wing.py file that I don't want to let go of + +# def compute_partials(self, inputs, J): + # span = inputs['span'] + # root_chord = inputs['root_chord'] + # tip_chord = inputs['tip_chord'] + # thickness_dist = inputs['thickness_dist'] + # twist=jnp.radians(inputs['twist']) + # num_sections = self.options['num_sections'] + # airfoil_type = self.options['airfoil_type'] # NACA airfoil type + # airfoil_data_file = self.options['airfoil_data_file'] + # material = self.options['material'] + + # # Compute section locations along the span + # span_locations = jnp.linspace(0, span, num_sections) + # span_locations = span_locations / span + # chord_lengths = tip_chord + (root_chord - tip_chord) * (1 - span_locations / span) + + # # Compute section airfoil geometry + # if airfoil_data_file and os.path.exists(airfoil_data_file): + # airfoil_data = jnp.loadtxt(airfoil_data_file) + # x_coords = airfoil_data[:, 0] + # y_coords = airfoil_data[:, 1] + + # camber, camber_location, max_thickness, thickness, camber_line = self.extract_airfoil_features(x_coords, y_coords) + # thickness_dist = thickness + # else: + # # Parse the NACA airfoil type (4-digit) + # camber = int(airfoil_type[0]) / 100.0 # Maximum camber + # camber_location = int(airfoil_type[1]) / 10.0 # Location of max camber + # max_thickness = int(airfoil_type[2:4]) / 100.0 # Max thickness + + # # Compute section airfoil geometry + # n_points = num_sections + # x_points = jnp.linspace(0, 1, n_points) + # dx = 1 / (num_sections - 1) + + # #A_ref, err = quad(lambda x: jnp.interp(x, x_points, thickness_dist), 0, 1, limit=100) # \int_0^1 t(x) dx + # A_ref, _ = quad(lambda x: self.airfoil_thickness(x, max_thickness), 0, 1) + + # density, _ = materials.get_item(material) + + # total_moment_x = 0 + # total_moment_y = 0 + # total_moment_z = 0 + # total_weight = 0 + + # rotated_x_vals = jnp.zeros(num_sections) + # rotated_z_vals = jnp.zeros(num_sections) + # #section_weights = jnp.zeros(num_sections) + # section_areas = jnp.zeros(num_sections) + # dA_dspan = 0 + # dA_droot_chord = 0 + # dA_dtip_chord = 0 + # dweight_dspan = 0 + # dmoment_x_dtwist = jnp.zeros(num_sections) + # dmoment_z_dtwist = jnp.zeros(num_sections) + # dweight_dthickness = jnp.zeros(num_sections) + + # for i, location in enumerate(span_locations): + # # Calculate the chord for this section + # chord = root_chord - (root_chord - tip_chord) * (location / span) # Assuming linear variation from root to tip + + # # Apply twist + # twist_angle = twist[i] + + # section_area, centroid_x, centroid_z = self.compute_airfoil_geometry(chord, camber, camber_location, thickness_dist, x_points, dx) + # #section_weight = density * section_area * (span / num_sections) + # section_weight = density * thickness_dist[i] * chord * (span / num_sections) + # centroid_y = location + + # rotated_x_vals[i] = centroid_x * jnp.cos(twist_angle) - centroid_z * jnp.sin(twist_angle) + # rotated_z_vals[i] = centroid_x * jnp.sin(twist_angle) + centroid_z * jnp.cos(twist_angle) + + # total_weight += section_weight + # total_moment_x += rotated_x_vals[i] * section_weight + # total_moment_y += centroid_y * section_weight + # total_moment_z += rotated_z_vals[i] * section_weight + + # #section_weights[i] = section_weight + # section_areas[i] = section_area + + # # For dweight_dspan + # #dci_dspan = -(root_chord - tip_chord) * (location / span**2) + # #dA_dspan, _ = quad(lambda x: jnp.interp(x, x_points, thickness_dist) * dci_dspan, 0, 1, limit=100) + # #dA_ds = jnp.trapz(thickness_dist * dci_dspan, x_points, dx=dx) + # dA_dc_root = jnp.trapz(thickness_dist * (1 - i / num_sections), x_points, dx=dx) + # dA_dc_tip = jnp.trapz(thickness_dist * i / num_sections, x_points, dx=dx) + # #dA_dspan += dA_ds + # dA_droot_chord += dA_dc_root + # dA_dtip_chord += dA_dc_tip + # #dweight_dspan += density * (section_area / num_sections - dA_ds * span / num_sections) + # dmoment_x_dtwist[i] = -section_weight * (centroid_x * jnp.sin(twist_angle) + centroid_z * jnp.cos(twist_angle)) + # dmoment_z_dtwist[i] = section_weight * (centroid_x * jnp.cos(twist_angle) - centroid_z * jnp.sin(twist_angle)) + # dweight_dthickness[i] = density * span * chord / num_sections # dW_total / dthickness_dist -- vector value + + # dweight_droot_chord = jnp.sum(density * A_ref * span * ((num_sections - 1) / (2 * num_sections))) # ~ 1/2 for large N + # dweight_dtip_chord = jnp.sum(density * A_ref * span * ((num_sections + 1) / (2 * num_sections))) # ~ 1/2 for large N + + # dweight_dspan, _ = (density / span) * dblquad(lambda y, x: self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (y / span)), 0, 1, 0, span) + + # J['total_weight', 'span'] = dweight_dspan + # J['total_weight', 'root_chord'] = dweight_droot_chord + # J['total_weight', 'tip_chord'] = dweight_dtip_chord + # J['total_weight', 'thickness_dist'] = dweight_dthickness + # J['total_weight', 'twist'] = 0 + + # dxcg_droot_chord = 0 + # dzcg_droot_chord = 0 + # dxcg_dtip_chord = 0 + # dzcg_dtip_chord = 0 + # for i, location in enumerate(span_locations): + # dxcg_dcroot = jnp.sum( + # jnp.trapz( + # (x_points * thickness_dist * jnp.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * jnp.sin(twist)) * (1 - i / num_sections), x_points, dx=dx + # ) + # ) / jnp.sum(section_areas) - jnp.sum( + # ( + # jnp.trapz( + # x_points * thickness_dist * chord_lengths * jnp.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * jnp.sin(twist), x_points, dx=dx + # ) * jnp.trapz( + # thickness_dist * (1 - i / num_sections), x_points, dx=dx + # ) + # ) + # ) / jnp.sum(section_areas)**2 + # dxcg_droot_chord += dxcg_dcroot + + # dzcg_dcroot = jnp.sum( + # jnp.trapz( + # (x_points * thickness_dist * (1 - i / num_sections) * jnp.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist) * (1 - i / num_sections) * jnp.cos(twist), x_points, dx=dx + # ) + # ) / jnp.sum(section_areas) - jnp.sum( + # jnp.trapz( + # x_points * thickness_dist * chord_lengths * jnp.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * jnp.cos(twist), x_points, dx=dx + # ) * dA_droot_chord + # ) / jnp.sum(section_areas)**2 + # dzcg_droot_chord += dzcg_dcroot + + # dxcg_dctip = jnp.sum( + # jnp.trapz( + # (x_points * thickness_dist *jnp.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * jnp.sin(twist)) * (i / num_sections), x_points, dx=dx + # ) / section_areas + # ) - jnp.sum( + # ( + # jnp.trapz( + # x_points * thickness_dist * chord_lengths * jnp.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * jnp.sin(twist), x_points, dx=dx + # ) + # ) * dA_dtip_chord + # ) / jnp.sum(section_areas)**2 + # dxcg_dtip_chord += dxcg_dctip + + # dzcg_dctip = jnp.sum( + # jnp.trapz( + # x_points * thickness_dist * (i / num_sections) * jnp.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * (i / num_sections) * jnp.cos(twist), x_points, dx=dx + # ) + # ) / jnp.sum(section_areas) - jnp.sum( + # jnp.trapz( + # x_points * thickness_dist * chord_lengths * jnp.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * jnp.cos(twist), x_points, dx=dx + # ) * dA_dtip_chord + # ) / jnp.sum(section_areas)**2 + # dzcg_dtip_chord += dzcg_dctip + + # # partials of cog x + # J['center_of_gravity_x', 'span'] = 0 + # J['center_of_gravity_x', 'root_chord'] = dxcg_droot_chord + # J['center_of_gravity_x', 'tip_chord'] = dxcg_dtip_chord + # J['center_of_gravity_x', 'thickness_dist'] = jnp.sum( + # jnp.trapz( + # x_points * chord_lengths * jnp.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * chord_lengths * jnp.sin(twist), x_points, dx=dx + # ) / section_areas + # ) - ( + # jnp.sum( + # jnp.trapz(x_points * thickness_dist * chord_lengths * jnp.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * jnp.sin(twist), x_points, dx=dx) + # ) * jnp.sum(chord_lengths) + # ) / jnp.sum(section_areas)**2 + # J['center_of_gravity_x', 'twist'] = dmoment_x_dtwist / total_weight + + # # For center of gravity in y calculations + + # sum_area_times_i = 0 + # sum_darea_times_i = 0 + + # for i in range(len(x_points)): + # sum_area_times_i += i * section_areas[i] + # sum_darea_times_i += i * dA_dspan # for cg_Y calculations + + # dcg_y_dspan = jnp.sum(sum_area_times_i / (num_sections * section_areas)) #+ jnp.sum((span * sum_darea_times_i) / (num_sections * section_areas)) - jnp.sum((span * sum_area_times_i) / (num_sections * jnp.sum(section_areas)**2)) * dA_dspan + + # # partials of cog y + # J['center_of_gravity_y', 'span'] = dcg_y_dspan + # J['center_of_gravity_y', 'root_chord'] = -total_moment_y / total_weight * dweight_droot_chord / total_weight + # J['center_of_gravity_y', 'tip_chord'] = -total_moment_y / total_weight * dweight_dtip_chord / total_weight + # J['center_of_gravity_y', 'thickness_dist'] = -total_moment_y / total_weight * dweight_dthickness / total_weight + # J['center_of_gravity_y', 'twist'] = 0 + + # # partials of cog z + # J['center_of_gravity_z', 'span'] = 0 + # J['center_of_gravity_z', 'root_chord'] = dzcg_droot_chord + # J['center_of_gravity_z', 'tip_chord'] = dzcg_dtip_chord + # J['center_of_gravity_z', 'thickness_dist'] = jnp.sum( + # jnp.trapz( + # x_points * chord_lengths * jnp.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * chord_lengths * jnp.cos(twist), x_points, dx=dx + # ) + # ) / jnp.sum( + # section_areas + # ) + # J['center_of_gravity_z', 'twist'] = dmoment_z_dtwist / total_weight + + + # def compute_airfoil_geometry(self, chord, camber, camber_location, thickness_dist, x_points, dx): + + # #section_area, _ = quad(lambda x: jnp.interp(x, x_points, thickness_dist), 0, 1, limit=100) + # section_area = jint.trapezoid(thickness_dist, x_points) # trying jnp.trapz rather than quad to get rid of IntegrationWarning + # section_area *= chord + + # #centroid_x, _ = quad(lambda x: x * jnp.interp(x, x_points, thickness_dist), 0, 1, limit=100) + # centroid_x = jint.trapezoid(x_points * thickness_dist, x_points) + # centroid_x = (centroid_x * chord) / section_area + + # #centroid_z, _ = quad(lambda x: self.airfoil_camber_line(x, camber, camber_location) * jnp.interp(x, x_points, thickness_dist), 0, 1, limit=100) + # centroid_z = jint.trapezoid(self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist, x_points) + # centroid_z = (centroid_z * chord) / section_area + # return section_area, centroid_x, centroid_z + + + # Loop over each section along the span (3D wing approximation) + # for i, location in enumerate(span_locations): + # # Calculate the chord for this section -- note this is an approximation + # chord = root_chord - (root_chord - tip_chord) * (location / span) # Assuming linear variation from root to tip + + # # Apply twist + # twist_angle = twist[i] + + # section_area, centroid_x, centroid_z = self.compute_airfoil_geometry(chord, camber, camber_location, thickness_dist, x_points, dx) + # centroid_y = i * span / num_sections + # #section_weight = density * section_area * (span / num_sections) + # section_weight = density * thickness_dist[i] * chord * (span / num_sections) + + # rotated_x = centroid_x * jnp.cos(twist_angle) - centroid_z * jnp.sin(twist_angle) + # rotated_z = centroid_x * jnp.sin(twist_angle) + centroid_z * jnp.cos(twist_angle) + + # total_weight += section_weight + # total_moment_x += rotated_x * section_weight + # total_moment_y += centroid_y * section_weight + # total_moment_z += rotated_z * section_weight + + + # # Store the coordinates for plotting later + # x_coords.append(rotated_x) + # y_coords.append(centroid_y) + # z_coords.append(rotated_z) + +# Throw away code from fuselage.py + + # def setup_partials(self): + # """ + # Complex step is used for the derivatives for now as they are very complicated to calculate + # analytically. Compute_partials function has the framework for analytical derivatives, but not + # all of them match the check_partials. + # """ + # self.declare_partials('center_of_gravity_x', ['length', 'diameter', 'taper_ratio', 'curvature', 'thickness'], method='cs') + # self.declare_partials('center_of_gravity_y', ['length', 'y_offset', 'curvature'], method='cs') + # self.declare_partials('total_weight', ['length', 'diameter', 'thickness'], method='cs') + + # def compute_partials(self, inputs, partials): + # length = inputs['length'] + # diameter = inputs['diameter'] + # taper_ratio = inputs['taper_ratio'] + # curvature = inputs['curvature'] + # thickness = inputs['thickness'] + # y_offset = inputs['y_offset'] + # z_offset = inputs['z_offset'] + # is_hollow = inputs['is_hollow'] + + # #custom_fuselage_function = getattr(self, 'custom_fuselage_function', None) # Custom fuselage model function -- if provided + + # custom_fuselage_data_file = self.options['custom_fuselage_data_file'] + + # material = self.options['material'] + # num_sections = self.options['num_sections'] + + # self.validate_inputs(length, diameter, thickness, taper_ratio, is_hollow) + + # density, _ = materials.get_item(material) + + # section_locations = jnp.linspace(0, length, num_sections).flatten() + # dx = 1 / (num_sections - 1) + + # total_weight = 0 + # total_moment_x = 0 + # total_moment_y = 0 + # total_moment_z = 0 + + # interpolate_diameter = self.load_fuselage_data(custom_fuselage_data_file) + + # out_r = jnp.zeros(num_sections) + # in_r = jnp.zeros(num_sections) + + + # # Loop through each section + # for i, location in enumerate(section_locations): + # section_diameter = self.get_section_diameter(location, length, diameter, taper_ratio, interpolate_diameter) + # outer_radius = section_diameter / 2.0 + # inner_radius = max(0, outer_radius - thickness) if is_hollow else 0 + + # out_r[i] = outer_radius + # in_r[i] = inner_radius + + # section_volume = jnp.pi * (outer_radius**2 - inner_radius**2) * (length / num_sections) + # section_weight = density * section_volume + + # centroid_x, centroid_y, centroid_z = self.compute_centroid(location, length, y_offset, z_offset, curvature, taper_ratio) + + # total_weight += section_weight + # total_moment_x += centroid_x * section_weight + # total_moment_y += centroid_y * section_weight + # total_moment_z += centroid_z * section_weight + + # dzcg_dz_offset = jnp.sum( + # jnp.trapz( + # (1 - section_locations / length) * density * jnp.pi * (out_r**2 - in_r**2), section_locations, dx=dx + # ) + # ) / total_weight + + + # partials['center_of_gravity_x', 'length'] = 3 / 4 if taper_ratio > 0 else 1 + # partials['center_of_gravity_x', 'taper_ratio'] = - (3/4) * length if taper_ratio > 0 else 0 + # partials['center_of_gravity_x', 'curvature'] = 0 + # partials['center_of_gravity_x', 'thickness'] = 0 + + # partials['center_of_gravity_y', 'length'] = -y_offset / length + # partials['center_of_gravity_y', 'y_offset'] = 1 + + # partials['center_of_gravity_z', 'length'] = -z_offset / length + # partials['center_of_gravity_z', 'z_offset'] = dzcg_dz_offset + # partials['center_of_gravity_z', 'curvature'] = length**2 / num_sections + + # partials['total_weight', 'length'] = density * jnp.pi * (diameter**2 - (diameter - 2 * thickness)**2) / num_sections + # partials['total_weight', 'diameter'] = 2 * density * jnp.pi * length * diameter / num_sections + # partials['total_weight', 'thickness'] = -2 * density * jnp.pi * length * (diameter - thickness) / num_sections \ No newline at end of file diff --git a/aviary/subsystems/mass/simple_mass/wing.py b/aviary/subsystems/mass/simple_mass/wing.py index 64a5815fa..cd3137a92 100644 --- a/aviary/subsystems/mass/simple_mass/wing.py +++ b/aviary/subsystems/mass/simple_mass/wing.py @@ -1,37 +1,60 @@ import openmdao.api as om +import openmdao.jax as omj import numpy as np +import jax.numpy as jnp +import jax import os from scipy.interpolate import CubicSpline +import jax.scipy.integrate as jint +try: + from quadax import quadgk +except ImportError: + raise ImportError( + "quadax package not found. You can install it by running 'pip install quadax'." + ) -# Material densities (g/cm³ converted to kg/m³) -- these are just some random examples -MATERIAL_DENSITIES = { - 'wood': 130, # balsa wood - 'metal': 2700, # Aluminum - 'carbon_fiber': 1600 -} +""" +The little bit of path code below is not important overall. This is for me to test +within the Docker container and VS Code before I push everything fully to the Github +repository. These lines can be deleted as things are updated further. +""" +import sys +import os + + +module_path = os.path.abspath("/home/omdao/Aviary/aviary/subsystems/mass") +if module_path not in sys.path: + sys.path.append(module_path) + +from simple_mass.materials_database import materials + +from aviary.utils.named_values import get_keys -class WingMassAndCOG(om.ExplicitComponent): +Debug = False + +class WingMassAndCOG(om.JaxExplicitComponent): def initialize(self): self.options.declare('num_sections', types=int, - default=1000) + default=10) self.options.declare('airfoil_type', types=str, default='2412') # use 2412 as example for default self.options.declare('material', - default='metal', - values=list(MATERIAL_DENSITIES.keys())) + default='Balsa', + values=list(get_keys(materials))) self.options.declare('airfoil_data_file', default=None, types=str) # For user-provided airfoil data file def setup(self): + self.options['use_jit'] = not(Debug) # Inputs self.add_input('span', @@ -47,12 +70,13 @@ def setup(self): units='m') # Tip chord length self.add_input('twist', - val=np.zeros(self.options['num_sections']), + val=jnp.zeros(self.options['num_sections']), units='deg') # Twist angles self.add_input('thickness_dist', - val=np.ones(self.options['num_sections']) * 0.1, - shape=(self.options['num_sections'],)) # Thickness distribution of the wing (height) + val=jnp.ones(self.options['num_sections']) * 0.1, + shape=(self.options['num_sections'],), + units='m') # Thickness distribution of the wing (height) # Outputs @@ -72,27 +96,8 @@ def setup(self): val=0.0, units='kg') - def setup_partials(self): - """ - Complex step is used for the derivatives for now as they are very complicated to calculate - analytically. Compute_partials function has the framework for analytical derivatives, but not - all of them match the check_partials. - """ - num_sections = self.options['num_sections'] - - self.declare_partials(['center_of_gravity_x', 'center_of_gravity_y', 'center_of_gravity_z'], - ['span', 'root_chord', 'tip_chord', 'thickness_dist', 'twist'], method='cs') - self.declare_partials('total_weight', ['span', 'root_chord', 'tip_chord', 'thickness_dist', 'twist'], method='cs') - - - def compute(self, inputs, outputs): - span = inputs['span'] - root_chord = inputs['root_chord'] - tip_chord = inputs['tip_chord'] - twist = np.radians(inputs['twist']) # Convert twist to radians - thickness_dist = inputs['thickness_dist'] + def compute_primal(self, span, root_chord, tip_chord, twist, thickness_dist): material = self.options['material'] # Material is taken from options - #num_sections = self.options['num_sections'] airfoil_type = self.options['airfoil_type'] # NACA airfoil type airfoil_data_file = self.options['airfoil_data_file'] @@ -106,11 +111,11 @@ def compute(self, inputs, outputs): if tip_chord > root_chord: raise ValueError("Tip chord cannot be larger than root chord.") - if any(abs(twist)) > np.pi / 2: + if any(omj.smooth_abs(twist)) > jnp.pi / 2: raise ValueError("Twist angle is too extreme; must be within -90 to 90 degrees.") # Get material density - density = MATERIAL_DENSITIES[material] # in kg/m³ + density, _ = materials.get_item(material) # in kg/m³ #x_points, dx = self.precompute_airfoil_geometry() @@ -130,288 +135,64 @@ def compute(self, inputs, outputs): num_sections = self.options['num_sections'] # Wing spanwise distribution - span_locations = np.linspace(0, span, num_sections) + span_locations = jnp.linspace(0, span, num_sections) #num_sections = self.options['num_sections'] n_points = num_sections - x_points = np.linspace(0, 1, n_points) + x_points = jnp.linspace(0, 1, n_points) dx = 1 / (n_points - 1) - # Initialize total weight and moment accumulators - total_weight = 0 - total_moment_x = 0 - total_moment_y = 0 - total_moment_z = 0 - - # Arrays for storing 3D coordinates of the wing - x_coords = [] - y_coords = [] - z_coords = [] - - # Loop over each section along the span (3D wing approximation) - for i, location in enumerate(span_locations): - # Calculate the chord for this section -- note this is an approximation - chord = root_chord - (root_chord - tip_chord) * (location / span) # Assuming linear variation from root to tip - - # Apply twist - twist_angle = twist[i] - - section_area, centroid_x, centroid_z = self.compute_airfoil_geometry(chord, camber, camber_location, thickness_dist, x_points, dx) - centroid_y = i * span / num_sections - section_weight = density * section_area * (span / num_sections) - - rotated_x = centroid_x * np.cos(twist_angle) - centroid_z * np.sin(twist_angle) - rotated_z = centroid_x * np.sin(twist_angle) + centroid_z * np.cos(twist_angle) - - total_weight += section_weight - total_moment_x += rotated_x * section_weight - total_moment_y += centroid_y * section_weight - total_moment_z += rotated_z * section_weight - - - # Store the coordinates for plotting later - x_coords.append(rotated_x) - y_coords.append(centroid_y) - z_coords.append(rotated_z) - - # Calculate the overall center of gravity - outputs['center_of_gravity_x'] = total_moment_x / total_weight - outputs['center_of_gravity_y'] = total_moment_y / total_weight - outputs['center_of_gravity_z'] = total_moment_z / total_weight - outputs['total_weight'] = total_weight - - - def compute_partials(self, inputs, J): - span = inputs['span'] - root_chord = inputs['root_chord'] - tip_chord = inputs['tip_chord'] - thickness_dist = inputs['thickness_dist'] - twist=np.radians(inputs['twist']) - num_sections = self.options['num_sections'] - airfoil_type = self.options['airfoil_type'] # NACA airfoil type - airfoil_data_file = self.options['airfoil_data_file'] - material = self.options['material'] - - # Compute section locations along the span - span_locations = np.linspace(0, span, num_sections) - span_locations = span_locations / span - chord_lengths = tip_chord + (root_chord - tip_chord) * (1 - span_locations / span) + weight_function = lambda x: density * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span)) * span + + #total_weight = jint.trapezoid(density * self.airfoil_thickness(x_points, max_thickness) * (root_chord - (root_chord - tip_chord) * (x_points / span)) * span, x_points) - # Compute section airfoil geometry - if airfoil_data_file and os.path.exists(airfoil_data_file): - airfoil_data = np.loadtxt(airfoil_data_file) - x_coords = airfoil_data[:, 0] - y_coords = airfoil_data[:, 1] + #total_weight = self.gauss_quad(weight_function, num_sections, 0, 1) + total_weight, _ = quadgk(weight_function, [0, 1], epsabs=1e-9, epsrel=1e-9) - camber, camber_location, max_thickness, thickness, camber_line = self.extract_airfoil_features(x_coords, y_coords) - thickness_dist = thickness - else: - # Parse the NACA airfoil type (4-digit) - camber = int(airfoil_type[0]) / 100.0 # Maximum camber - camber_location = int(airfoil_type[1]) / 10.0 # Location of max camber - max_thickness = int(airfoil_type[2:4]) / 100.0 # Max thickness + #center_of_gravity_x = jint.trapezoid(x_points * self.airfoil_thickness(x_points, max_thickness) * (root_chord - (root_chord - tip_chord) * (x_points / span) * jnp.cos(twist)) - + # self.airfoil_camber_line(x_points, camber, camber_location) * self.airfoil_thickness(x_points, max_thickness) * (root_chord - (root_chord - tip_chord) * (x_points / span)) * jnp.sin(twist), + # x_points) / jint.trapezoid(self.airfoil_thickness(x_points, max_thickness) * (root_chord - (root_chord - tip_chord) * (x_points / span)), x_points) + + center_of_gravity_x_num, _ = quadgk(lambda x: x * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span) * jnp.cos(twist)) - + self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span)) * jnp.sin(twist), + [0, 1], epsabs=1e-9, epsrel=1e-9) + center_of_gravity_x_denom, _ = quadgk(lambda x: self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span)), [0, 1], epsabs=1e-9, epsrel=1e-9) - # Compute section airfoil geometry - n_points = num_sections - x_points = np.linspace(0, 1, n_points) - dx = 1 / (num_sections - 1) - - #A_ref, err = quad(lambda x: np.interp(x, x_points, thickness_dist), 0, 1, limit=100) # \int_0^1 t(x) dx - A_ref = np.trapz(thickness_dist, x_points, dx=dx) - - density = MATERIAL_DENSITIES[material] - - total_moment_x = 0 - total_moment_y = 0 - total_moment_z = 0 - total_weight = 0 - - rotated_x_vals = np.zeros(num_sections) - rotated_z_vals = np.zeros(num_sections) - #section_weights = np.zeros(num_sections) - section_areas = np.zeros(num_sections) - dA_dspan = 0 - dA_droot_chord = 0 - dA_dtip_chord = 0 - dweight_dspan = 0 - dmoment_x_dtwist = np.zeros(num_sections) - dmoment_z_dtwist = np.zeros(num_sections) - dweight_dthickness = np.zeros(num_sections) - - for i, location in enumerate(span_locations): - # Calculate the chord for this section - chord = root_chord - (root_chord - tip_chord) * (location / span) # Assuming linear variation from root to tip - - # Apply twist - twist_angle = twist[i] - - section_area, centroid_x, centroid_z = self.compute_airfoil_geometry(chord, camber, camber_location, thickness_dist, x_points, dx) - section_weight = density * section_area * (span / num_sections) - centroid_y = location - - rotated_x_vals[i] = centroid_x * np.cos(twist_angle) - centroid_z * np.sin(twist_angle) - rotated_z_vals[i] = centroid_x * np.sin(twist_angle) + centroid_z * np.cos(twist_angle) - - total_weight += section_weight - total_moment_x += rotated_x_vals[i] * section_weight - total_moment_y += centroid_y * section_weight - total_moment_z += rotated_z_vals[i] * section_weight - - #section_weights[i] = section_weight - section_areas[i] = section_area - - # For dweight_dspan - dci_dspan = -(root_chord - tip_chord) * (location / span**2) - #dA_dspan, _ = quad(lambda x: np.interp(x, x_points, thickness_dist) * dci_dspan, 0, 1, limit=100) - dA_ds = np.trapz(thickness_dist * dci_dspan, x_points, dx=dx) - dA_dc_root = np.trapz(thickness_dist * (1 - i / num_sections), x_points, dx=dx) - dA_dc_tip = np.trapz(thickness_dist * i / num_sections, x_points, dx=dx) - dA_dspan += dA_ds - dA_droot_chord += dA_dc_root - dA_dtip_chord += dA_dc_tip - dweight_dspan += density * (section_area / num_sections - dA_ds * span / num_sections) - dmoment_x_dtwist[i] = -section_weight * (centroid_x * np.sin(twist_angle) + centroid_z * np.cos(twist_angle)) - dmoment_z_dtwist[i] = section_weight * (centroid_x * np.cos(twist_angle) - centroid_z * np.sin(twist_angle)) - dweight_dthickness[i] = density * span * chord / num_sections # dW_total / dthickness_dist -- vector value - - dweight_droot_chord = np.sum(density * A_ref * span / 2) # ((num_sections - 1) / (2 * num_sections)) ~ 1/2 for large N - dweight_dtip_chord = np.sum(density * A_ref * span / 2) # ((num_sections + 1) / (2 * num_sections)) ~ 1/2 for large N - - J['total_weight', 'span'] = dweight_dspan - J['total_weight', 'root_chord'] = dweight_droot_chord - J['total_weight', 'tip_chord'] = dweight_dtip_chord - J['total_weight', 'thickness_dist'] = dweight_dthickness - J['total_weight', 'twist'] = 0 - - dxcg_droot_chord = 0 - dzcg_droot_chord = 0 - dxcg_dtip_chord = 0 - dzcg_dtip_chord = 0 - for i, location in enumerate(span_locations): - dxcg_dcroot = np.sum( - np.trapz( - (x_points * thickness_dist * np.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * np.sin(twist)) * (1 - i / num_sections), x_points, dx=dx - ) - ) / np.sum(section_areas) - np.sum( - ( - np.trapz( - x_points * thickness_dist * chord_lengths * np.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * np.sin(twist), x_points, dx=dx - ) * np.trapz( - thickness_dist * (1 - i / num_sections), x_points, dx=dx - ) - ) - ) / np.sum(section_areas)**2 - dxcg_droot_chord += dxcg_dcroot - - dzcg_dcroot = np.sum( - np.trapz( - (x_points * thickness_dist * (1 - i / num_sections) * np.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist) * (1 - i / num_sections) * np.cos(twist), x_points, dx=dx - ) - ) / np.sum(section_areas) - np.sum( - np.trapz( - x_points * thickness_dist * chord_lengths * np.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * np.cos(twist), x_points, dx=dx - ) * dA_droot_chord - ) / np.sum(section_areas)**2 - dzcg_droot_chord += dzcg_dcroot - - dxcg_dctip = np.sum( - np.trapz( - (x_points * thickness_dist *np.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * np.sin(twist)) * (i / num_sections), x_points, dx=dx - ) / section_areas - ) - np.sum( - ( - np.trapz( - x_points * thickness_dist * chord_lengths * np.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * np.sin(twist), x_points, dx=dx - ) - ) * dA_dtip_chord - ) / np.sum(section_areas)**2 - dxcg_dtip_chord += dxcg_dctip - - dzcg_dctip = np.sum( - np.trapz( - x_points * thickness_dist * (i / num_sections) * np.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * (i / num_sections) * np.cos(twist), x_points, dx=dx - ) - ) / np.sum(section_areas) - np.sum( - np.trapz( - x_points * thickness_dist * chord_lengths * np.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * np.cos(twist), x_points, dx=dx - ) * dA_dtip_chord - ) / np.sum(section_areas)**2 - dzcg_dtip_chord += dzcg_dctip - - # partials of cog x - J['center_of_gravity_x', 'span'] = 0 - J['center_of_gravity_x', 'root_chord'] = dxcg_droot_chord - J['center_of_gravity_x', 'tip_chord'] = dxcg_dtip_chord - J['center_of_gravity_x', 'thickness_dist'] = np.sum( - np.trapz( - x_points * chord_lengths * np.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * chord_lengths * np.sin(twist), x_points, dx=dx - ) / section_areas - ) - ( - np.sum( - np.trapz(x_points * thickness_dist * chord_lengths * np.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * np.sin(twist), x_points, dx=dx) - ) * np.sum(chord_lengths) - ) / np.sum(section_areas)**2 - J['center_of_gravity_x', 'twist'] = dmoment_x_dtwist / total_weight + center_of_gravity_x = center_of_gravity_x_num / center_of_gravity_x_denom + center_of_gravity_x = center_of_gravity_x[0] - # For center of gravity in y calculations + #center_of_gravity_z = jint.trapezoid(x_points * self.airfoil_thickness(x_points, max_thickness) * (root_chord - (root_chord - tip_chord) * (x_points / span) * jnp.sin(twist)) + + # self.airfoil_camber_line(x_points, camber, camber_location) * self.airfoil_thickness(x_points, max_thickness) * (root_chord - (root_chord - tip_chord) * (x_points / span)) * jnp.cos(twist), + # x_points) / jint.trapezoid(self.airfoil_thickness(x_points, max_thickness) * (root_chord - (root_chord - tip_chord) * (x_points / span)), x_points) + + center_of_gravity_z_num, _ = quadgk(lambda x: x * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span) * jnp.sin(twist)) + + self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span)) * jnp.cos(twist), + [0, 1], epsabs=1e-9, epsrel=1e-9) + + center_of_gravity_z_denom, _ = quadgk(lambda x: self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span)), [0, 1], epsabs=1e-9, epsrel=1e-9) - sum_area_times_i = 0 - sum_darea_times_i = 0 + center_of_gravity_z = center_of_gravity_z_num / center_of_gravity_z_denom + center_of_gravity_z = center_of_gravity_z[0] - for i in range(len(x_points)): - sum_area_times_i += i * section_areas[i] - sum_darea_times_i += i * dA_dspan # for cg_Y calculations - - dcg_y_dspan = np.sum(sum_area_times_i / (num_sections * section_areas)) #+ np.sum((span * sum_darea_times_i) / (num_sections * section_areas)) - np.sum((span * sum_area_times_i) / (num_sections * np.sum(section_areas)**2)) * dA_dspan - - # partials of cog y - J['center_of_gravity_y', 'span'] = dcg_y_dspan - J['center_of_gravity_y', 'root_chord'] = -total_moment_y / total_weight * dweight_droot_chord / total_weight - J['center_of_gravity_y', 'tip_chord'] = -total_moment_y / total_weight * dweight_dtip_chord / total_weight - J['center_of_gravity_y', 'thickness_dist'] = -total_moment_y / total_weight * dweight_dthickness / total_weight - J['center_of_gravity_y', 'twist'] = 0 - - # partials of cog z - J['center_of_gravity_z', 'span'] = 0 - J['center_of_gravity_z', 'root_chord'] = dzcg_droot_chord - J['center_of_gravity_z', 'tip_chord'] = dzcg_dtip_chord - J['center_of_gravity_z', 'thickness_dist'] = np.sum( - np.trapz( - x_points * chord_lengths * np.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * chord_lengths * np.cos(twist), x_points, dx=dx - ) - ) / np.sum( - section_areas - ) - J['center_of_gravity_z', 'twist'] = dmoment_z_dtwist / total_weight + #center_of_gravity_y = jint.trapezoid(x_points * span, x_points) + + center_of_gravity_y, _ = quadgk(lambda x: x * span, [0, 1], epsabs=1e-9, epsrel=1e-9) + + return center_of_gravity_x, center_of_gravity_y, center_of_gravity_z, total_weight def precompute_airfoil_geometry(self): num_sections = self.options['num_sections'] n_points = num_sections - x_points = np.linspace(0, 1, n_points) + x_points = jnp.linspace(0, 1, n_points) dx = 1 / (n_points - 1) return x_points, dx - def compute_airfoil_geometry(self, chord, camber, camber_location, thickness_dist, x_points, dx): - - #section_area, _ = quad(lambda x: np.interp(x, x_points, thickness_dist), 0, 1, limit=100) - section_area = np.trapz(thickness_dist, x_points, dx=dx) # trying np.trapz rather than quad to get rid of IntegrationWarning - section_area *= chord - - #centroid_x, _ = quad(lambda x: x * np.interp(x, x_points, thickness_dist), 0, 1, limit=100) - centroid_x = np.trapz(x_points * thickness_dist, x_points, dx=dx) - centroid_x = (centroid_x * chord) / section_area - - #centroid_z, _ = quad(lambda x: self.airfoil_camber_line(x, camber, camber_location) * np.interp(x, x_points, thickness_dist), 0, 1, limit=100) - centroid_z = np.trapz(self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist, x_points, dx=dx) - centroid_z = (centroid_z * chord) / section_area - return section_area, centroid_x, centroid_z - def airfoil_thickness(self, x, max_thickness): - return 5 * max_thickness * (0.2969 * np.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) + return 5 * max_thickness * (0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) def airfoil_camber_line(self, x, camber, camber_location): - camber_location = max(camber_location, 1e-9) # Divide by zero check - return np.where( + camber_location = omj.smooth_max(camber_location, 1e-9) # Divide by zero check + return jnp.where( x < camber_location, (camber / camber_location**2) * (2 * camber_location * x - x**2), (camber / (1 - camber_location)**2) * ((1 - 2 * camber_location) + 2 * camber_location * x - x**2) @@ -436,43 +217,125 @@ def extract_airfoil_features(self, x_coords, y_coords): thickness = upper_spline(x_coords) - lower_spline(x_coords) - max_thickness_index = np.argmax(thickness) + max_thickness_index = jnp.argmax(thickness) max_thickness_value = thickness[max_thickness_index] - camber_slope = np.gradient(camber_line, x_coords) - camber_location_index = np.argmax(np.abs(camber_slope)) + camber_slope = jnp.gradient(camber_line, x_coords) + camber_location_index = jnp.argmax(omj.smooth_abs(camber_slope)) camber_location = x_coords[camber_location_index] camber = camber_line[camber_location_index] return camber, camber_location, max_thickness_value, thickness, camber_line + # def legendre_roots_and_weights(self, n): + # """ + # Compute nodes and weights for Legendre-Gauss quadrature using JAX. + + # Parameters: + + # beta: + # coefficient coming form Gram-Schmidt process, derived from recursive relation + # of Legendre polynomials. + + # T: + # symmetric, tri-diagonal Jacobi matrix derived using Golub-Welsch theorem. Eigenvalues + # of T correspond to roots of Legendre polynomials + + # Eigenvalues, Eigenvectors: + # The eigenvalues of T and their respective eigenvectors, calculated using + # jax.scipy.special.eigh function. + + # weights: + # Weights used for Gaussian-Legendre quadrature, calculated using the first + # component of the normalized eigenvector, derived from Golub & Welsch (1969). + # Coefficient 2 comes from an application of Rodrigues' formula for Legendre + # polynomials and applying the orthonormality property for Legendre polynomials + # over the interval [-1, 1] with weight = 1. + + # Returns: + + # float + # Roots of the Legendre polynomials (eigenvalues of T) + # float + # weights used for G-L quadrature (formula from Golub & Welsch 1969) + + # References: + + # [1] Golub, Gene H., and John H. Welsch. "Calculation of Gauss quadrature rules." + # Mathematics of computation 23.106 (1969): 221-230. + + # [2] André Ronveaux, Jean Mawhin, Rediscovering the contributions of Rodrigues on + # the representation of special functions, Expositiones Mathematicae, Volume 23, + # Issue 4, 2005, Pages 361-369, ISSN 0723-0869, + # https://doi.org/10.1016/j.exmath.2005.05.001. + + # """ + + # i = jnp.arange(1, n) + # beta = i / jnp.sqrt(4 * i**2 - 1) + # T = jnp.diag(beta, k=1) + jnp.diag(beta, k=-1) # Tridiagonal matrix + # eigenvalues, eigenvectors = jax.jit(jnp.linalg.eigh)(T) # Compute eigenvalues (roots) and eigenvectors + # roots = eigenvalues + # weights = 2 * (eigenvectors[0, :] ** 2) # Compute weights from first row of eigenvectors + + # return roots, weights + + + # def gauss_quad(self, f, n, a, b): + # """ + # Computes the integral of f(x) over [a, b] using Gaussian quadrature with n points. + + # Parameters: + + # f : function + # The function to integrate. + + # n : int + # The number of quadrature points. + + # a, b : float + # Integration limits. + + # Returns: + + # float + # The approximated integral of f(x) over [a, b]. + + # """ + # x, w = self.legendre_roots_and_weights(n) + + # x_mapped = 0.5 * (b - a) * x + 0.5 * (b + a) + # w_mapped = 0.5 * (b - a) * w + + # integral = jnp.sum(w_mapped * f(x_mapped)) # Compute weighted sum + # return integral.astype(jnp.float64) # Build OpenMDAO problem prob = om.Problem() # Add the center of gravity component -prob.model.add_subsystem('cog', WingMassAndCOG() , promotes_inputs=['span', 'root_chord', 'tip_chord', 'twist', 'thickness_dist']) +prob.model.add_subsystem('cog', WingMassAndCOG() , promotes_inputs=['*'], promotes_outputs=['*']) -n_points = 1000 # = num_sections -x = np.linspace(0, 1, n_points) +n_points = 10 # = num_sections +x = jnp.linspace(0, 1, n_points) max_thickness_chord_ratio = 0.12 -thickness_dist = 5 * max_thickness_chord_ratio * (0.2969 * np.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) +thickness_dist = 5 * max_thickness_chord_ratio * (0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) # Setup the problem prob.setup() # Define some example inputs -prob.set_val('span', 2.438) -prob.set_val('root_chord', 0.3722) -prob.set_val('tip_chord', 0.2792) -prob.set_val('twist', np.linspace(0, 0, 1000)) -#prob.set_val('thickness_dist', thickness_dist) +prob.set_val('span', 1) +prob.set_val('root_chord', 1) +prob.set_val('tip_chord', 0.5) +prob.set_val('twist', jnp.linspace(0, 0, 10)) +prob.set_val('thickness_dist', thickness_dist) -prob.model.cog.options['airfoil_data_file'] = 'Clark_Y.dat' -prob.model.cog.options['material'] = 'wood' -#prob.model.cog.options['airfoil_type'] = '2412' +#prob.model.cog.options['airfoil_data_file'] = 'Clark_Y.dat' +prob.model.cog.options['material'] = 'Balsa' +prob.model.cog.options['airfoil_type'] = '2412' # Run the model prob.run_model() @@ -489,3 +352,4 @@ def extract_airfoil_features(self, x_coords, y_coords): print(f"Center of gravity: X = {center_of_gravity_x} m, Y = {center_of_gravity_y} m, Z = {center_of_gravity_z} m") print(f"Total weight of the wing: {total_weight} kg") + diff --git a/aviary/subsystems/mass/simple_mass/wingN2 b/aviary/subsystems/mass/simple_mass/wingN2 new file mode 100644 index 000000000..a73b55aa8 --- /dev/null +++ b/aviary/subsystems/mass/simple_mass/wingN2 @@ -0,0 +1,14805 @@ + + + +OpenMDAO Model Hierarchy and N2 diagram + + + + + + + + + + + + + + + + + +
+
+ +
+
+ +
+ + +
+
+
+
+ + + +
+
+ + +
+
+ + + + + +
+
+ + + + +
+
+ +
+
+ +
+ +
+
+ +
+ +
+
+ Processing... +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

+
+
+ + + +
+ +
+ +
+
+ +
+
+
+
+ N2 Information +
+ + +
+ +
+
+
+
+
+ + + + + + + + + + +
+ +
+ +
+ +
+ +
+

Left-click on a node in the model hierarchy to navigate to that node.
+ Right-click on a node to collapse/expand it. + Alt-right-click on a node with variables to select which ones to hide.
+ Note: Right-click in Firefox displays a browser menu. To disable that, + visit about:config and set dom.event.contextmenu.enabled + to true.
+ Hover over any cell in the matrix to display its connections + as arrows. Click that cell to make those arrows persistent. +

+

Toolbar Help

+
+ Snapshot of toolbar buttons + +
+
+ +
+ + + + + + +
Variable NameVisible
+
+ + +
+
+
+ Search + +
+
+ + + +
+
+
+ + + + + + + From 0f2bf51295df80632ae5506405745fc327b71f22 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 1 Apr 2025 13:18:34 -0400 Subject: [PATCH 037/147] Delete aviary/subsystems/mass/simple_mass/C:UsersszoppeltDesktopwingN2 --- .../simple_mass/C:UsersszoppeltDesktopwingN2 | 14805 ---------------- 1 file changed, 14805 deletions(-) delete mode 100644 aviary/subsystems/mass/simple_mass/C:UsersszoppeltDesktopwingN2 diff --git a/aviary/subsystems/mass/simple_mass/C:UsersszoppeltDesktopwingN2 b/aviary/subsystems/mass/simple_mass/C:UsersszoppeltDesktopwingN2 deleted file mode 100644 index 9819364ac..000000000 --- a/aviary/subsystems/mass/simple_mass/C:UsersszoppeltDesktopwingN2 +++ /dev/null @@ -1,14805 +0,0 @@ - - - -OpenMDAO Model Hierarchy and N2 diagram - - - - - - - - - - - - - - - - - -
-
- -
-
- -
- - -
-
-
-
- - - -
-
- - -
-
- - - - - -
-
- - - - -
-
- -
-
- -
- -
-
- -
- -
-
- Processing... -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

-
-
- - - -
- -
- -
-
- -
-
-
-
- N2 Information -
- - -
- -
-
-
-
-
- - - - - - - - - - -
- -
- -
- -
- -
-

Left-click on a node in the model hierarchy to navigate to that node.
- Right-click on a node to collapse/expand it. - Alt-right-click on a node with variables to select which ones to hide.
- Note: Right-click in Firefox displays a browser menu. To disable that, - visit about:config and set dom.event.contextmenu.enabled - to true.
- Hover over any cell in the matrix to display its connections - as arrows. Click that cell to make those arrows persistent. -

-

Toolbar Help

-
- Snapshot of toolbar buttons - -
-
- -
- - - - - - -
Variable NameVisible
-
- - -
-
-
- Search - -
-
- - - -
-
-
- - - - - - - From f694d354fd6f71725b55dd55e1504c8170ed5d37 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 1 Apr 2025 13:18:43 -0400 Subject: [PATCH 038/147] Delete aviary/subsystems/mass/simple_mass/# New lump sum payments: $10,000 in 2025.py --- ... New lump sum payments: $10,000 in 2025.py | 64 ------------------- 1 file changed, 64 deletions(-) delete mode 100644 aviary/subsystems/mass/simple_mass/# New lump sum payments: $10,000 in 2025.py diff --git a/aviary/subsystems/mass/simple_mass/# New lump sum payments: $10,000 in 2025.py b/aviary/subsystems/mass/simple_mass/# New lump sum payments: $10,000 in 2025.py deleted file mode 100644 index f098ddac7..000000000 --- a/aviary/subsystems/mass/simple_mass/# New lump sum payments: $10,000 in 2025.py +++ /dev/null @@ -1,64 +0,0 @@ -# New lump sum payments: $10,000 in 2025, $4,000 in 2026 and 2027 -lump_sum_payments = {0: 10000, 12: 4000, 24: 4000} # Months from now when lump sums occur - -# Reset loan balances -private_loan_balance = 58000 -gov_loan_balance = 28760.60 - -# Reset months counter -months = 0 - -private_interest_rate = 0.05 / 12 # Monthly interest rate for private loans (5% annually) -gov_interest_rate = 0.04 / 12 # Monthly interest rate for government loans (4% annually) - -# Payment schedule -initial_months = (2028 - 2025) * 12 # Number of months until January 2028 -private_payment_initial = 360 -gov_payment_initial = 0 # Government loans in forbearance - -private_payment_after = 1500 -gov_payment_after = 1000 - -# Payments until January 2028 with updated lump sum payments -for month in range(initial_months): - if private_loan_balance > 0: - interest = private_loan_balance * private_interest_rate - private_loan_balance += interest - private_payment_initial - private_loan_balance = max(private_loan_balance, 0) # Ensure no negative balance - - # Government loan accrues interest, but lump sum payments occur at specified months - if gov_loan_balance > 0: - interest = gov_loan_balance * gov_interest_rate - gov_loan_balance += interest - - if month in lump_sum_payments: - gov_loan_balance -= lump_sum_payments[month] - gov_loan_balance = max(gov_loan_balance, 0) - - months += 1 - -# Payments starting January 2028 -while private_loan_balance > 0 or gov_loan_balance > 0: - if private_loan_balance > 0: - interest = private_loan_balance * private_interest_rate - private_loan_balance += interest - private_payment_after - private_loan_balance = max(private_loan_balance, 0) - - if gov_loan_balance > 0: - interest = gov_loan_balance * gov_interest_rate - gov_loan_balance += interest - gov_payment_after - gov_loan_balance = max(gov_loan_balance, 0) - - months += 1 - - # If private loans are paid off, redirect full payment to government loans - if private_loan_balance == 0 and gov_loan_balance > 0: - gov_payment_after += private_payment_after - private_payment_after = 0 - - # If government loans are paid off, redirect full payment to private loans - if gov_loan_balance == 0 and private_loan_balance > 0: - private_payment_after += gov_payment_after - gov_payment_after = 0 - -months From 3bcfdf032d1248d887d3cc1a8f00d3a960c55131 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 1 Apr 2025 13:18:57 -0400 Subject: [PATCH 039/147] Delete aviary/subsystems/mass/simple_mass/import numpy as np.py --- .../mass/simple_mass/import numpy as np.py | 120 ------------------ 1 file changed, 120 deletions(-) delete mode 100644 aviary/subsystems/mass/simple_mass/import numpy as np.py diff --git a/aviary/subsystems/mass/simple_mass/import numpy as np.py b/aviary/subsystems/mass/simple_mass/import numpy as np.py deleted file mode 100644 index 782b420e4..000000000 --- a/aviary/subsystems/mass/simple_mass/import numpy as np.py +++ /dev/null @@ -1,120 +0,0 @@ -import numpy as np - -# Initial salary values -salary_user = 125000 -salary_partner = 150000 -salary_growth = 0.03 # 3% raise per year - -# Retirement contribution (pre-tax) -retirement_contribution = 0.15 # 15% of salary - -# Tax parameters (approximate federal tax brackets for married filing jointly, 2024) -standard_deduction = 29200 # Standard deduction for married filing jointly -tax_brackets = [(0.10, 23000), (0.12, 94300), (0.22, 201050), (0.24, 383900)] # Simplified brackets - -# Initial loan balances -private_loan_user = 58000 # User's private loans (6% interest) -gov_loan_user = 30000 # User's government loans (4% interest) - -private_loan_partner = 60000 # Partner's private loans (7% interest) -gov_loan_partner = 60000 # Partner's government loans (4% interest) - -# Loan payments per month -private_payment_user = 1500 -gov_payment_user = 1000 -private_payment_partner = 1600 -gov_payment_partner = 900 - -# Monthly expenses -rent = 2000 # Rent & utilities -rent_increase = 100 # Rent increase per year - -groceries = 500 # Groceries & gas -groceries_increase = 0.02 # 2% increase per year - -fixed_expenses = 500 # Fixed subscriptions, car insurance, etc. - -# Simulation for 10 years -years = 10 -net_income_per_year = [] - -# Function to calculate taxes owed -def calculate_taxes(income): - taxable_income = max(income - standard_deduction, 0) # Apply standard deduction - taxes_owed = 0 - for rate, bracket in tax_brackets: - if taxable_income > bracket: - taxes_owed += bracket * rate - taxable_income -= bracket - else: - taxes_owed += taxable_income * rate - break - return taxes_owed - -# Loan repayment tracking -user_private_paid = False -partner_private_paid = False - -for year in range(years): - # Salary growth - salary_user *= (1 + salary_growth) - salary_partner *= (1 + salary_growth) - total_salary = salary_user + salary_partner - - # Pre-tax retirement contributions - retirement_user = salary_user * retirement_contribution - retirement_partner = salary_partner * retirement_contribution - taxable_income = total_salary - (retirement_user + retirement_partner) - - # Calculate taxes - taxes = calculate_taxes(taxable_income) - - # Loan payments (pay extra to government loans after private loans are paid) - total_private_payment = 0 - total_gov_payment = 0 - - if not user_private_paid: - if private_loan_user > 0: - total_private_payment += private_payment_user * 12 - private_loan_user *= (1 + 0.06 / 12) ** 12 # Apply interest - private_loan_user -= private_payment_user * 12 - if private_loan_user <= 0: - user_private_paid = True - - if not partner_private_paid: - if private_loan_partner > 0: - total_private_payment += private_payment_partner * 12 - private_loan_partner *= (1 + 0.07 / 12) ** 12 # Apply interest - private_loan_partner -= private_payment_partner * 12 - if private_loan_partner <= 0: - partner_private_paid = True - - # After private loans are paid, extra payment goes to government loans - if user_private_paid: - gov_payment_user += private_payment_user - - if partner_private_paid: - gov_payment_partner += private_payment_partner - - if gov_loan_user > 0: - total_gov_payment += gov_payment_user * 12 - gov_loan_user *= (1 + 0.04 / 12) ** 12 # Apply interest - gov_loan_user -= gov_payment_user * 12 - - if gov_loan_partner > 0: - total_gov_payment += gov_payment_partner * 12 - gov_loan_partner *= (1 + 0.04 / 12) ** 12 # Apply interest - gov_loan_partner -= gov_payment_partner * 12 - - # Adjust expenses - rent += rent_increase # Increase rent yearly - groceries *= (1 + groceries_increase) # Increase groceries yearly - - # Calculate net income - total_expenses = (rent * 12) + (groceries * 12) + (fixed_expenses * 12) - total_loan_payments = total_private_payment + total_gov_payment - - net_income = taxable_income - taxes - total_expenses - total_loan_payments - net_income_per_year.append(net_income) - -net_income_per_year From f89307c2f12437fcab5bf2514a6b9d70d3d4d5f0 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 1 Apr 2025 13:19:08 -0400 Subject: [PATCH 040/147] Delete aviary/subsystems/mass/simple_mass/test_quad.py --- .../subsystems/mass/simple_mass/test_quad.py | 642 ------------------ 1 file changed, 642 deletions(-) delete mode 100644 aviary/subsystems/mass/simple_mass/test_quad.py diff --git a/aviary/subsystems/mass/simple_mass/test_quad.py b/aviary/subsystems/mass/simple_mass/test_quad.py deleted file mode 100644 index 0b9fb26c5..000000000 --- a/aviary/subsystems/mass/simple_mass/test_quad.py +++ /dev/null @@ -1,642 +0,0 @@ -import jax.numpy as jnp -from jax.scipy.linalg import eigh -import jax.scipy as jsp -import jax -from jax import jit, lax -from scipy.integrate import quad -import quadax -""" -Website: https://rosettacode.org/wiki/Numerical_integration/Gauss-Legendre_Quadrature#Python - -""" - -# def legendre_poly_and_deriv(n, x): -# """ -# Compute the Legendre polynomial P_n(x) and its derivative P_n'(x) using -# recurrence relations. - -# Parameters: - -# n : int -# Degree of the Legendre polynomial. -# x : jnp.ndarray -# Points at which to evalulate the polynomial. - -# Returns: - -# P_n : jnp.ndarray -# Value of the Legendre polynomial P_n(x). -# P_n_prime : jnp.ndarray -# Value of the derivative P_n'(x). - -# """ - -# if n == 0: -# return jnp.ones_like(x), jnp.zeros_like(x) -# elif n == 1: -# return x, jnp.ones_like(x) - -# # initialize P_0(x) and P_1(x) -# P0 = jnp.ones_like(x) -# P1 = x - -# for k in range(2, n+1): -# P2 = ((2 * k - 1) * x * P1 - (k - 1) * P0) / k -# P0, P1 = P1, P2 # Shift P_k-1 to P_k, and P_k to P_k+1 - -# # Compute derivative using recurrence relation -# P_n = P1 -# P_n_prime = n * (x * P_n - P0) / (x**2 - 1) - -# return P_n, P_n_prime - -# def legendre_roots_and_weights(n, tol=1e-15, max_iter=10): -# """ -# Compute the Gauss-Legendre quadrature nodes (roots) and weights using the -# Newton method. - -# Parameters: - -# n : int -# Number of quadrature points. -# tol : float, optional -# Convergence tolerance for Newton's method. - -# Returns: - -# roots : jnp.ndarray -# Legendre polynomial roots (Gauss-Legendre nodes). -# weights : jnp.ndarray -# Gauss-Legendre quadrature weights. - -# """ - -# # Initial guess for roots: use Chebyshev approximation -# roots = jnp.cos(jnp.pi * (4 * jnp.arange(1, n + 1) - 1) / (4 * n + 2)) - -# # Newton's method -# for _ in range(max_iter): -# P_n, P_n_prime = legendre_poly_and_deriv(n, roots) -# roots -= P_n / P_n_prime - -# # Compute weights -# _, P_n_prime = legendre_poly_and_deriv(n, roots) -# weights = 2 / ((1 - roots**2) * P_n_prime**2) - -# return roots, weights - - - - -# def gauss_quad(f, n, a, b): -# """ -# Computes the integral of f(x) over [a, b] using Gaussian quadrature with n points. - -# Parameters: - -# f : function -# The function to integrate. - -# n : int -# The number of quadrature points. - -# a, b : float -# Integration limits. - -# Returns: -# float -# The approximated integral of f(x) over [a, b]. - -# """ -# x, w = legendre_roots_and_weights(n) - -# x_mapped = 0.5 * (b - a) * x + 0.5 * (b + a) -# w_mapped = 0.5 * (b - a) * w -# integral = jnp.sum(w_mapped * f(x_mapped)) # Compute weighted sum -# return integral.astype(jnp.float64) - -# def legendre_roots_and_weights(n): -# """ -# Compute nodes and weights for Legendre-Gauss quadrature using JAX. - -# Parameters: - -# beta: -# coefficient coming form Gram-Schmidt process, derived from recursive relation -# of Legendre polynomials. - -# T: -# symmetric, tri-diagonal Jacobi matrix derived using Golub-Welsch theorem. Eigenvalues -# of T correspond to roots of Legendre polynomials - -# Eigenvalues, Eigenvectors: -# The eigenvalues of T and their respective eigenvectors, calculated using -# jax.scipy.special.eigh function. - -# weights: -# Weights used for Gaussian-Legendre quadrature, calculated using the first -# component of the normalized eigenvector, derived from Golub & Welsch (1969). -# Coefficient 2 comes from an application of Rodrigues' formula for Legendre -# polynomials and applying the orthonormality property for Legendre polynomials -# over the interval [-1, 1] with weight = 1. - -# Returns: - -# float -# Roots of the Legendre polynomials (eigenvalues of T) -# float -# weights used for G-L quadrature (formula from Golub & Welsch 1969) - -# References: - -# [1] Golub, Gene H., and John H. Welsch. "Calculation of Gauss quadrature rules." -# Mathematics of computation 23.106 (1969): 221-230. - -# [2] André Ronveaux, Jean Mawhin, Rediscovering the contributions of Rodrigues on -# the representation of special functions, Expositiones Mathematicae, Volume 23, -# Issue 4, 2005, Pages 361-369, ISSN 0723-0869, -# https://doi.org/10.1016/j.exmath.2005.05.001. - -# """ - -# i = jnp.arange(1, n) -# beta = i / jnp.sqrt(4 * i**2 - 1) -# T = jnp.diag(beta, k=1) + jnp.diag(beta, k=-1) # Tridiagonal matrix -# eigenvalues, eigenvectors = jax.jit(jnp.linalg.eigh)(T) # Compute eigenvalues (roots) and eigenvectors -# roots = eigenvalues -# weights = 2 * (eigenvectors[0, :] ** 2) # Compute weights from first row of eigenvectors - -# return roots, weights - - -# def gauss_quad(f, n, a, b): -# """ -# Computes the integral of f(x) over [a, b] using Gaussian quadrature with n points. - -# Parameters: - -# f : function -# The function to integrate. - -# n : int -# The number of quadrature points. - -# a, b : float -# Integration limits. - -# Returns: - -# float -# The approximated integral of f(x) over [a, b]. - -# """ -# x, w = legendre_roots_and_weights(n) - -# x_mapped = 0.5 * (b - a) * x + 0.5 * (b + a) - -# integral = jnp.sum(w * f(x_mapped)) * ((b - a) / 2) # Compute weighted sum -# return integral.astype(jnp.float64) - - -# span = 1 -# root_chord = 1 -# tip_chord = 0.5 -# density = 130 -# max_thickness = 0.12 -# n = 1000 - -# test_f = lambda x: density * (5 * max_thickness * (0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4)) * (root_chord - (root_chord - tip_chord) * (x / span)) * span -# integral_value = gauss_quad(test_f, n, 0, 1) -# scipy_int, _ = quad(test_f, 0, 1) -# print(f"Gauss-Legendre Quadrature Result (n={n}): {integral_value:.10f}") -# print("Expected: 4.22032, Computed with scipy.integrate.quad: ", scipy_int) - -def Legendre(n, x): - x = jnp.array(x) - if n == 0: - return x * 0 + 1.0 - elif n == 1: - return x - else: - return ((2.0 * n - 1.0) * x * Legendre(n-1, x) - (n - 1) * Legendre(n-2, x)) / n - -def DLegendre(n, x): - x = jnp.array(x) - if n == 0: - return x * 0 - elif n == 1: - return x * 0 + 1.0 - else: - return (n / (x**2 - 1.0)) * (x * Legendre(n, x) - Legendre(n-1, x)) - -def LegendreRoots(polyorder, tolerance=1e-20): - if polyorder < 2: - err = 1 - else: - roots = [] - for i in range(1, jnp.int_(polyorder / 2 + 1)): - x = jnp.cos(jnp.pi * (i - 0.25) / polyorder + 0.5) - error = 10 * tolerance - iters = 0 - while (error > tolerance) and (iters < 1000): - dx = -Legendre(polyorder, x) / DLegendre(polyorder, x) - x += dx - iters += 1 - error = jnp.abs(dx) - roots.append(x) - roots = jnp.asarray(roots) - if (polyorder % 2 == 0): - roots = jnp.concatenate([-1.0 * roots, roots[::-1]]) - else: - roots = jnp.concatenate([-1.0 * roots, jnp.array([0.0]), roots[::-1]]) - err = 0 - return [roots, err] - -def GaussLegendreWeights(polyorder): - W = [] - [xis, err] = LegendreRoots(polyorder) - if err == 0: - W = 2.0 / ((1.0 - xis**2) * (DLegendre(polyorder, xis)**2)) - else: - err = 1 - return [W, xis, err] - -def GaussLegendreQuadrature(func, polyorder, a, b): - [Ws, xs, err] = GaussLegendreWeights(polyorder) - if err == 0: - ans = (b-a) * 0.5 * jnp.sum(Ws * func((b - a) * 0.5 * xs + (b + a) * 0.5)) - else: - err = 1 - ans = None - - return [ans, err] - -span = 1 -root_chord = 1 -tip_chord = 0.5 -density = 130 -max_thickness = 0.12 - -test_f = lambda x: density * (5 * max_thickness * (0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4)) * (root_chord - (root_chord - tip_chord) * (x / span)) * span - -order = 3 -[Ws, xs, err] = GaussLegendreWeights(order) - -if err == 0: - print("Order : ", order) - print("Roots : ", xs) - print("Weights : ", Ws) -else: - print("Roots/Weights evaluation failed") - -[ans, err] = GaussLegendreQuadrature(test_f, order, 0, 1) -if err == 0: - print("Integral : ", ans) -else: - print("Integral evaluation failed") - -epsabs = epsrel = 1e-9 - -integral, _ = quadax.quadgk(test_f, [0, 1], epsabs=epsabs, epsrel=epsrel) -print("Result using quadax: ", integral) - -# Throw away code from wing.py file that I don't want to let go of - -# def compute_partials(self, inputs, J): - # span = inputs['span'] - # root_chord = inputs['root_chord'] - # tip_chord = inputs['tip_chord'] - # thickness_dist = inputs['thickness_dist'] - # twist=jnp.radians(inputs['twist']) - # num_sections = self.options['num_sections'] - # airfoil_type = self.options['airfoil_type'] # NACA airfoil type - # airfoil_data_file = self.options['airfoil_data_file'] - # material = self.options['material'] - - # # Compute section locations along the span - # span_locations = jnp.linspace(0, span, num_sections) - # span_locations = span_locations / span - # chord_lengths = tip_chord + (root_chord - tip_chord) * (1 - span_locations / span) - - # # Compute section airfoil geometry - # if airfoil_data_file and os.path.exists(airfoil_data_file): - # airfoil_data = jnp.loadtxt(airfoil_data_file) - # x_coords = airfoil_data[:, 0] - # y_coords = airfoil_data[:, 1] - - # camber, camber_location, max_thickness, thickness, camber_line = self.extract_airfoil_features(x_coords, y_coords) - # thickness_dist = thickness - # else: - # # Parse the NACA airfoil type (4-digit) - # camber = int(airfoil_type[0]) / 100.0 # Maximum camber - # camber_location = int(airfoil_type[1]) / 10.0 # Location of max camber - # max_thickness = int(airfoil_type[2:4]) / 100.0 # Max thickness - - # # Compute section airfoil geometry - # n_points = num_sections - # x_points = jnp.linspace(0, 1, n_points) - # dx = 1 / (num_sections - 1) - - # #A_ref, err = quad(lambda x: jnp.interp(x, x_points, thickness_dist), 0, 1, limit=100) # \int_0^1 t(x) dx - # A_ref, _ = quad(lambda x: self.airfoil_thickness(x, max_thickness), 0, 1) - - # density, _ = materials.get_item(material) - - # total_moment_x = 0 - # total_moment_y = 0 - # total_moment_z = 0 - # total_weight = 0 - - # rotated_x_vals = jnp.zeros(num_sections) - # rotated_z_vals = jnp.zeros(num_sections) - # #section_weights = jnp.zeros(num_sections) - # section_areas = jnp.zeros(num_sections) - # dA_dspan = 0 - # dA_droot_chord = 0 - # dA_dtip_chord = 0 - # dweight_dspan = 0 - # dmoment_x_dtwist = jnp.zeros(num_sections) - # dmoment_z_dtwist = jnp.zeros(num_sections) - # dweight_dthickness = jnp.zeros(num_sections) - - # for i, location in enumerate(span_locations): - # # Calculate the chord for this section - # chord = root_chord - (root_chord - tip_chord) * (location / span) # Assuming linear variation from root to tip - - # # Apply twist - # twist_angle = twist[i] - - # section_area, centroid_x, centroid_z = self.compute_airfoil_geometry(chord, camber, camber_location, thickness_dist, x_points, dx) - # #section_weight = density * section_area * (span / num_sections) - # section_weight = density * thickness_dist[i] * chord * (span / num_sections) - # centroid_y = location - - # rotated_x_vals[i] = centroid_x * jnp.cos(twist_angle) - centroid_z * jnp.sin(twist_angle) - # rotated_z_vals[i] = centroid_x * jnp.sin(twist_angle) + centroid_z * jnp.cos(twist_angle) - - # total_weight += section_weight - # total_moment_x += rotated_x_vals[i] * section_weight - # total_moment_y += centroid_y * section_weight - # total_moment_z += rotated_z_vals[i] * section_weight - - # #section_weights[i] = section_weight - # section_areas[i] = section_area - - # # For dweight_dspan - # #dci_dspan = -(root_chord - tip_chord) * (location / span**2) - # #dA_dspan, _ = quad(lambda x: jnp.interp(x, x_points, thickness_dist) * dci_dspan, 0, 1, limit=100) - # #dA_ds = jnp.trapz(thickness_dist * dci_dspan, x_points, dx=dx) - # dA_dc_root = jnp.trapz(thickness_dist * (1 - i / num_sections), x_points, dx=dx) - # dA_dc_tip = jnp.trapz(thickness_dist * i / num_sections, x_points, dx=dx) - # #dA_dspan += dA_ds - # dA_droot_chord += dA_dc_root - # dA_dtip_chord += dA_dc_tip - # #dweight_dspan += density * (section_area / num_sections - dA_ds * span / num_sections) - # dmoment_x_dtwist[i] = -section_weight * (centroid_x * jnp.sin(twist_angle) + centroid_z * jnp.cos(twist_angle)) - # dmoment_z_dtwist[i] = section_weight * (centroid_x * jnp.cos(twist_angle) - centroid_z * jnp.sin(twist_angle)) - # dweight_dthickness[i] = density * span * chord / num_sections # dW_total / dthickness_dist -- vector value - - # dweight_droot_chord = jnp.sum(density * A_ref * span * ((num_sections - 1) / (2 * num_sections))) # ~ 1/2 for large N - # dweight_dtip_chord = jnp.sum(density * A_ref * span * ((num_sections + 1) / (2 * num_sections))) # ~ 1/2 for large N - - # dweight_dspan, _ = (density / span) * dblquad(lambda y, x: self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (y / span)), 0, 1, 0, span) - - # J['total_weight', 'span'] = dweight_dspan - # J['total_weight', 'root_chord'] = dweight_droot_chord - # J['total_weight', 'tip_chord'] = dweight_dtip_chord - # J['total_weight', 'thickness_dist'] = dweight_dthickness - # J['total_weight', 'twist'] = 0 - - # dxcg_droot_chord = 0 - # dzcg_droot_chord = 0 - # dxcg_dtip_chord = 0 - # dzcg_dtip_chord = 0 - # for i, location in enumerate(span_locations): - # dxcg_dcroot = jnp.sum( - # jnp.trapz( - # (x_points * thickness_dist * jnp.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * jnp.sin(twist)) * (1 - i / num_sections), x_points, dx=dx - # ) - # ) / jnp.sum(section_areas) - jnp.sum( - # ( - # jnp.trapz( - # x_points * thickness_dist * chord_lengths * jnp.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * jnp.sin(twist), x_points, dx=dx - # ) * jnp.trapz( - # thickness_dist * (1 - i / num_sections), x_points, dx=dx - # ) - # ) - # ) / jnp.sum(section_areas)**2 - # dxcg_droot_chord += dxcg_dcroot - - # dzcg_dcroot = jnp.sum( - # jnp.trapz( - # (x_points * thickness_dist * (1 - i / num_sections) * jnp.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist) * (1 - i / num_sections) * jnp.cos(twist), x_points, dx=dx - # ) - # ) / jnp.sum(section_areas) - jnp.sum( - # jnp.trapz( - # x_points * thickness_dist * chord_lengths * jnp.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * jnp.cos(twist), x_points, dx=dx - # ) * dA_droot_chord - # ) / jnp.sum(section_areas)**2 - # dzcg_droot_chord += dzcg_dcroot - - # dxcg_dctip = jnp.sum( - # jnp.trapz( - # (x_points * thickness_dist *jnp.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * jnp.sin(twist)) * (i / num_sections), x_points, dx=dx - # ) / section_areas - # ) - jnp.sum( - # ( - # jnp.trapz( - # x_points * thickness_dist * chord_lengths * jnp.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * jnp.sin(twist), x_points, dx=dx - # ) - # ) * dA_dtip_chord - # ) / jnp.sum(section_areas)**2 - # dxcg_dtip_chord += dxcg_dctip - - # dzcg_dctip = jnp.sum( - # jnp.trapz( - # x_points * thickness_dist * (i / num_sections) * jnp.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * (i / num_sections) * jnp.cos(twist), x_points, dx=dx - # ) - # ) / jnp.sum(section_areas) - jnp.sum( - # jnp.trapz( - # x_points * thickness_dist * chord_lengths * jnp.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * jnp.cos(twist), x_points, dx=dx - # ) * dA_dtip_chord - # ) / jnp.sum(section_areas)**2 - # dzcg_dtip_chord += dzcg_dctip - - # # partials of cog x - # J['center_of_gravity_x', 'span'] = 0 - # J['center_of_gravity_x', 'root_chord'] = dxcg_droot_chord - # J['center_of_gravity_x', 'tip_chord'] = dxcg_dtip_chord - # J['center_of_gravity_x', 'thickness_dist'] = jnp.sum( - # jnp.trapz( - # x_points * chord_lengths * jnp.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * chord_lengths * jnp.sin(twist), x_points, dx=dx - # ) / section_areas - # ) - ( - # jnp.sum( - # jnp.trapz(x_points * thickness_dist * chord_lengths * jnp.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * jnp.sin(twist), x_points, dx=dx) - # ) * jnp.sum(chord_lengths) - # ) / jnp.sum(section_areas)**2 - # J['center_of_gravity_x', 'twist'] = dmoment_x_dtwist / total_weight - - # # For center of gravity in y calculations - - # sum_area_times_i = 0 - # sum_darea_times_i = 0 - - # for i in range(len(x_points)): - # sum_area_times_i += i * section_areas[i] - # sum_darea_times_i += i * dA_dspan # for cg_Y calculations - - # dcg_y_dspan = jnp.sum(sum_area_times_i / (num_sections * section_areas)) #+ jnp.sum((span * sum_darea_times_i) / (num_sections * section_areas)) - jnp.sum((span * sum_area_times_i) / (num_sections * jnp.sum(section_areas)**2)) * dA_dspan - - # # partials of cog y - # J['center_of_gravity_y', 'span'] = dcg_y_dspan - # J['center_of_gravity_y', 'root_chord'] = -total_moment_y / total_weight * dweight_droot_chord / total_weight - # J['center_of_gravity_y', 'tip_chord'] = -total_moment_y / total_weight * dweight_dtip_chord / total_weight - # J['center_of_gravity_y', 'thickness_dist'] = -total_moment_y / total_weight * dweight_dthickness / total_weight - # J['center_of_gravity_y', 'twist'] = 0 - - # # partials of cog z - # J['center_of_gravity_z', 'span'] = 0 - # J['center_of_gravity_z', 'root_chord'] = dzcg_droot_chord - # J['center_of_gravity_z', 'tip_chord'] = dzcg_dtip_chord - # J['center_of_gravity_z', 'thickness_dist'] = jnp.sum( - # jnp.trapz( - # x_points * chord_lengths * jnp.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * chord_lengths * jnp.cos(twist), x_points, dx=dx - # ) - # ) / jnp.sum( - # section_areas - # ) - # J['center_of_gravity_z', 'twist'] = dmoment_z_dtwist / total_weight - - - # def compute_airfoil_geometry(self, chord, camber, camber_location, thickness_dist, x_points, dx): - - # #section_area, _ = quad(lambda x: jnp.interp(x, x_points, thickness_dist), 0, 1, limit=100) - # section_area = jint.trapezoid(thickness_dist, x_points) # trying jnp.trapz rather than quad to get rid of IntegrationWarning - # section_area *= chord - - # #centroid_x, _ = quad(lambda x: x * jnp.interp(x, x_points, thickness_dist), 0, 1, limit=100) - # centroid_x = jint.trapezoid(x_points * thickness_dist, x_points) - # centroid_x = (centroid_x * chord) / section_area - - # #centroid_z, _ = quad(lambda x: self.airfoil_camber_line(x, camber, camber_location) * jnp.interp(x, x_points, thickness_dist), 0, 1, limit=100) - # centroid_z = jint.trapezoid(self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist, x_points) - # centroid_z = (centroid_z * chord) / section_area - # return section_area, centroid_x, centroid_z - - - # Loop over each section along the span (3D wing approximation) - # for i, location in enumerate(span_locations): - # # Calculate the chord for this section -- note this is an approximation - # chord = root_chord - (root_chord - tip_chord) * (location / span) # Assuming linear variation from root to tip - - # # Apply twist - # twist_angle = twist[i] - - # section_area, centroid_x, centroid_z = self.compute_airfoil_geometry(chord, camber, camber_location, thickness_dist, x_points, dx) - # centroid_y = i * span / num_sections - # #section_weight = density * section_area * (span / num_sections) - # section_weight = density * thickness_dist[i] * chord * (span / num_sections) - - # rotated_x = centroid_x * jnp.cos(twist_angle) - centroid_z * jnp.sin(twist_angle) - # rotated_z = centroid_x * jnp.sin(twist_angle) + centroid_z * jnp.cos(twist_angle) - - # total_weight += section_weight - # total_moment_x += rotated_x * section_weight - # total_moment_y += centroid_y * section_weight - # total_moment_z += rotated_z * section_weight - - - # # Store the coordinates for plotting later - # x_coords.append(rotated_x) - # y_coords.append(centroid_y) - # z_coords.append(rotated_z) - -# Throw away code from fuselage.py - - # def setup_partials(self): - # """ - # Complex step is used for the derivatives for now as they are very complicated to calculate - # analytically. Compute_partials function has the framework for analytical derivatives, but not - # all of them match the check_partials. - # """ - # self.declare_partials('center_of_gravity_x', ['length', 'diameter', 'taper_ratio', 'curvature', 'thickness'], method='cs') - # self.declare_partials('center_of_gravity_y', ['length', 'y_offset', 'curvature'], method='cs') - # self.declare_partials('total_weight', ['length', 'diameter', 'thickness'], method='cs') - - # def compute_partials(self, inputs, partials): - # length = inputs['length'] - # diameter = inputs['diameter'] - # taper_ratio = inputs['taper_ratio'] - # curvature = inputs['curvature'] - # thickness = inputs['thickness'] - # y_offset = inputs['y_offset'] - # z_offset = inputs['z_offset'] - # is_hollow = inputs['is_hollow'] - - # #custom_fuselage_function = getattr(self, 'custom_fuselage_function', None) # Custom fuselage model function -- if provided - - # custom_fuselage_data_file = self.options['custom_fuselage_data_file'] - - # material = self.options['material'] - # num_sections = self.options['num_sections'] - - # self.validate_inputs(length, diameter, thickness, taper_ratio, is_hollow) - - # density, _ = materials.get_item(material) - - # section_locations = jnp.linspace(0, length, num_sections).flatten() - # dx = 1 / (num_sections - 1) - - # total_weight = 0 - # total_moment_x = 0 - # total_moment_y = 0 - # total_moment_z = 0 - - # interpolate_diameter = self.load_fuselage_data(custom_fuselage_data_file) - - # out_r = jnp.zeros(num_sections) - # in_r = jnp.zeros(num_sections) - - - # # Loop through each section - # for i, location in enumerate(section_locations): - # section_diameter = self.get_section_diameter(location, length, diameter, taper_ratio, interpolate_diameter) - # outer_radius = section_diameter / 2.0 - # inner_radius = max(0, outer_radius - thickness) if is_hollow else 0 - - # out_r[i] = outer_radius - # in_r[i] = inner_radius - - # section_volume = jnp.pi * (outer_radius**2 - inner_radius**2) * (length / num_sections) - # section_weight = density * section_volume - - # centroid_x, centroid_y, centroid_z = self.compute_centroid(location, length, y_offset, z_offset, curvature, taper_ratio) - - # total_weight += section_weight - # total_moment_x += centroid_x * section_weight - # total_moment_y += centroid_y * section_weight - # total_moment_z += centroid_z * section_weight - - # dzcg_dz_offset = jnp.sum( - # jnp.trapz( - # (1 - section_locations / length) * density * jnp.pi * (out_r**2 - in_r**2), section_locations, dx=dx - # ) - # ) / total_weight - - - # partials['center_of_gravity_x', 'length'] = 3 / 4 if taper_ratio > 0 else 1 - # partials['center_of_gravity_x', 'taper_ratio'] = - (3/4) * length if taper_ratio > 0 else 0 - # partials['center_of_gravity_x', 'curvature'] = 0 - # partials['center_of_gravity_x', 'thickness'] = 0 - - # partials['center_of_gravity_y', 'length'] = -y_offset / length - # partials['center_of_gravity_y', 'y_offset'] = 1 - - # partials['center_of_gravity_z', 'length'] = -z_offset / length - # partials['center_of_gravity_z', 'z_offset'] = dzcg_dz_offset - # partials['center_of_gravity_z', 'curvature'] = length**2 / num_sections - - # partials['total_weight', 'length'] = density * jnp.pi * (diameter**2 - (diameter - 2 * thickness)**2) / num_sections - # partials['total_weight', 'diameter'] = 2 * density * jnp.pi * length * diameter / num_sections - # partials['total_weight', 'thickness'] = -2 * density * jnp.pi * length * (diameter - thickness) / num_sections \ No newline at end of file From ca8d07d00d6815962bc1dd57f85d70cad3f46730 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 1 Apr 2025 13:19:21 -0400 Subject: [PATCH 041/147] Delete aviary/subsystems/mass/simple_mass/wingN2 --- aviary/subsystems/mass/simple_mass/wingN2 | 14805 -------------------- 1 file changed, 14805 deletions(-) delete mode 100644 aviary/subsystems/mass/simple_mass/wingN2 diff --git a/aviary/subsystems/mass/simple_mass/wingN2 b/aviary/subsystems/mass/simple_mass/wingN2 deleted file mode 100644 index a73b55aa8..000000000 --- a/aviary/subsystems/mass/simple_mass/wingN2 +++ /dev/null @@ -1,14805 +0,0 @@ - - - -OpenMDAO Model Hierarchy and N2 diagram - - - - - - - - - - - - - - - - - -
-
- -
-
- -
- - -
-
-
-
- - - -
-
- - -
-
- - - - - -
-
- - - - -
-
- -
-
- -
- -
-
- -
- -
-
- Processing... -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

-
-
- - - -
- -
- -
-
- -
-
-
-
- N2 Information -
- - -
- -
-
-
-
-
- - - - - - - - - - -
- -
- -
- -
- -
-

Left-click on a node in the model hierarchy to navigate to that node.
- Right-click on a node to collapse/expand it. - Alt-right-click on a node with variables to select which ones to hide.
- Note: Right-click in Firefox displays a browser menu. To disable that, - visit about:config and set dom.event.contextmenu.enabled - to true.
- Hover over any cell in the matrix to display its connections - as arrows. Click that cell to make those arrows persistent. -

-

Toolbar Help

-
- Snapshot of toolbar buttons - -
-
- -
- - - - - - -
Variable NameVisible
-
- - -
-
-
- Search - -
-
- - - -
-
-
- - - - - - - From fabc45bc3124078334efa6413a5c4918729b4e28 Mon Sep 17 00:00:00 2001 From: szoppelt Date: Mon, 12 May 2025 18:20:42 +0000 Subject: [PATCH 042/147] commit. --- aviary/docs/examples/mass_summation.py | 63 ++- aviary/docs/examples/six_dof_ODE.py | 110 +++++ .../subsystems/mass/simple_mass/fuselage.py | 95 ++-- .../mass/simple_mass/six_dof_EOM.py | 405 ++++++++++++++++++ aviary/subsystems/mass/simple_mass/tail.py | 127 ++---- .../mass/simple_mass/test/test_tail.py | 12 +- .../mass/simple_mass/test/test_wing.py | 2 +- aviary/subsystems/mass/simple_mass/wing.py | 194 ++------- 8 files changed, 679 insertions(+), 329 deletions(-) create mode 100644 aviary/docs/examples/six_dof_ODE.py create mode 100644 aviary/subsystems/mass/simple_mass/six_dof_EOM.py diff --git a/aviary/docs/examples/mass_summation.py b/aviary/docs/examples/mass_summation.py index 040351e9f..7546ec87b 100644 --- a/aviary/docs/examples/mass_summation.py +++ b/aviary/docs/examples/mass_summation.py @@ -5,6 +5,25 @@ # Maybe add some aviary inputs at some point here +""" +The little bit of path code below is not important overall. This is for me to test +within the Docker container and VS Code before I push everything fully to the Github +repository. These lines can be deleted as things are updated further. + +""" + +import sys +import os + + +module_path = os.path.abspath("/home/omdao/Aviary/aviary/subsystems/mass") +if module_path not in sys.path: + sys.path.append(module_path) + +from simple_mass.fuselage import FuselageMassAndCOG +from simple_mass.wing import WingMassAndCOG +from simple_mass.tail import TailMassAndCOG + class MassSummation(om.Group): """ @@ -15,9 +34,33 @@ class MassSummation(om.Group): """ def setup(self): + + self.add_subsystem( + 'fuse_mass', + FuselageMassAndCOG(), + promotes_inputs=['*'], + promotes_outputs=['total_weight_fuse'] + ) + self.add_subsystem( - 'structure_mass', StructureMass(), - promotes_inputs=['*'], promotes_outputs=['*'] + 'wing_mass', + WingMassAndCOG(), + promotes_inputs=['*'], + promotes_outputs=['total_weight_wing'] + ) + + self.add_subsystem( + 'tail_mass', + TailMassAndCOG(), + promotes_inputs=['*'], + promotes_outputs=['mass'] + ) + + self.add_subsystem( + 'structure_mass', + StructureMass(), + promotes_inputs=['*'], + promotes_outputs=['*'] ) @@ -25,19 +68,15 @@ class StructureMass(om.JaxExplicitComponent): def setup(self): # Maybe later change these to Aviary inputs? - self.add_input('wing_mass', val=0.0, units='kg') - self.add_input('fuse_mass', val=0.0, units='kg') - self.add_input('tail_mass', val=0.0, units='kg') + self.add_input('total_weight_wing', val=0.0, units='kg') + self.add_input('total_weight_fuse', val=0.0, units='kg') + self.add_input('mass', val=0.0, units='kg') # More masses can be added, i.e., tail, spars, flaps, etc. as needed self.add_output('structure_mass', val=0.0, units='kg') - def setup_partials(self): - # I'm not sure what else to put here at the moment - self.declare_partials('structure_mass', '*', val=1) - - def compute_primal(self, wing_mass, fuse_mass, tail_mass): - - structure_mass = wing_mass + fuse_mass + tail_mass + def compute_primal(self, total_weight_wing, total_weight_fuse, mass): + + structure_mass = total_weight_wing + total_weight_fuse + mass return structure_mass \ No newline at end of file diff --git a/aviary/docs/examples/six_dof_ODE.py b/aviary/docs/examples/six_dof_ODE.py new file mode 100644 index 000000000..b9a2a60fc --- /dev/null +++ b/aviary/docs/examples/six_dof_ODE.py @@ -0,0 +1,110 @@ +import numpy as np +import openmdao.api as om + +# Here will import the 6dof equations of motion + +from aviary.mission.base_ode import BaseODE as _BaseODE + +from aviary.variable_info.enums import AnalysisScheme, SpeedType, ThrottleAllocation +from aviary.variable_info.variables import Aircraft, Dynamic, Mission + +class SixDOF_ODE(_BaseODE): + + def initialize(self): + super().initialize() + + def setup(self): + options = self.options + nn = options['num_nodes'] + analysis_scheme = options['analysis_scheme'] + self.add_atmosphere(input_speed_type=SpeedType.MACH) + + self.add_subsystem( + name='veclocity_rate_comp', + subsys=om.ExecComp( + 'velocity_rate = mach_rate * sos', + mach_rate = {'units': 'unitless/s', 'shape': (nn,)}, + sos={'units': 'm/s', 'shape': (nn,)}, + velocity_rate={'units': 'm/s**2', 'shape': (nn,)}, + has_diag_partials=True, + ), + promotes_inputs=[ + ('mach_rate', Dynamic.Atmosphere.MACH_RATE), + ('sos', Dynamic.Atmosphere.SPEED_OF_SOUND), + ], + promotes_outputs=[ + 'velocity_rate', Dynamic.Mission.VELOCITY_RATE + ], + ) + + sub1 = self.add_subsystem( + 'solver_sub', + om.Group(), + promotes=['*'] + ) + + self.add_core_subsystems(solver_group=sub1) + + self.add_external_subsystems(solver_group=sub1) + + sub1.add_subsystem( + name='SixDOF_EOM', + subsys=SixDOF_EOM(num_nodes=nn), + promotes_inputs=[ + 'mass', + 'axial_vel', + 'lat_vel', + 'vert_vel', + 'roll_ang_vel', + 'pitch_ang_vel', + 'yaw_ang_vel', + 'roll', + 'pitch', + 'yaw', + 'g', + 'Fx_ext', + 'Fy_ext', + 'Fz_ext', + 'lx_ext', + 'ly_ext', + 'lz_ext', + 'J_xz', + 'J_xx', + 'J_yy', + 'J_zz', + ], + promotes_outputs=[ + 'dx_accel', + 'dy_accel', + 'dz_accel', + 'roll_accel', + 'pitch_accel', + 'yaw_accel', + 'roll_angle_rate_eq', + 'pitch_angle_rate_eq', + 'yaw_angle_rate_eq', + 'dx_dt', + 'dy_dt', + 'dz_dt', + ] + ) + + self.set_input_defaults(Dynamic.Atmosphere.MACH, val=np.ones(nn), units='unitless') + self.set_input_defaults(Dynamic.Vehicle.MASS, val=np.ones(nn), units='kg') + self.set_input_defaults(Dynamic.Mission.VELOCITY, val=np.ones(nn), units='m/s') + self.set_input_defaults(Dynamic.Mission.ALTITUDE, val=np.ones(nn), units='m') + self.set_input_defaults(Dynamic.Mission.ALTITUDE_RATE, val=np.ones(nn), units='m/s') + + print_level = 0 if analysis_scheme is AnalysisScheme.SHOOTING else 2 + + sub1.nonlinear_solver = om.NewtonSolver( + solve_subsystems=True, + atol=1.0e-10, + rtol=1.0e-10, + ) + sub1.nonlinear_solver.linesearch = om.BoundsEnforceLS() + sub1.linear_solver = om.DirectSolver(assemble_jac=True) + sub1.nonlinear_solver.options['err_on_non_converge'] = True + sub1.nonlinear_solver.options['iprint'] = print_level + + self.options['auto_order'] = True \ No newline at end of file diff --git a/aviary/subsystems/mass/simple_mass/fuselage.py b/aviary/subsystems/mass/simple_mass/fuselage.py index 4f200ee2f..9f50d0067 100644 --- a/aviary/subsystems/mass/simple_mass/fuselage.py +++ b/aviary/subsystems/mass/simple_mass/fuselage.py @@ -90,19 +90,19 @@ def setup(self): # Outputs - self.add_output('center_of_gravity_x', + self.add_output('center_of_gravity_x_fuse', val=0.0, units='m') - self.add_output('center_of_gravity_y', + self.add_output('center_of_gravity_y_fuse', val=0.0, units='m') - self.add_output('center_of_gravity_z', + self.add_output('center_of_gravity_z_fuse', val=0.0, units='m') - self.add_output('total_weight', + self.add_output('total_weight_fuse', val=0.0, units='kg') @@ -127,7 +127,7 @@ def compute_primal(self, length, diameter, taper_ratio, curvature, thickness, y_ section_locations = jnp.linspace(0, length, num_sections) - total_weight = 0 + total_weight_fuse = 0 total_moment_x = 0 total_moment_y = 0 total_moment_z = 0 @@ -145,39 +145,16 @@ def compute_primal(self, length, diameter, taper_ratio, curvature, thickness, y_ centroid_x, centroid_y, centroid_z = self.compute_centroid(location, length, y_offset, z_offset, curvature, taper_ratio) - total_weight += section_weight + total_weight_fuse += section_weight total_moment_x += centroid_x * section_weight total_moment_y += centroid_y * section_weight total_moment_z += centroid_z * section_weight - center_of_gravity_x = total_moment_x / total_weight - center_of_gravity_y = total_moment_y / total_weight - center_of_gravity_z = total_moment_z / total_weight + center_of_gravity_x_fuse = total_moment_x / total_weight_fuse + center_of_gravity_y_fuse = total_moment_y / total_weight_fuse + center_of_gravity_z_fuse = total_moment_z / total_weight_fuse - # outer_radius = lambda x: 0.5 * (1 - taper_ratio * (x / length)) - - # if is_hollow: - # inner_radius = lambda x: 0.5 * (1 - taper_ratio * (x / length)) - thickness - # inner_radius_squared = lambda x: (0.5 - thickness)**2 - 2 * (0.5 - thickness) * (taper_ratio / 2) * (x / length) + (taper_ratio**2 / 4) * (x / length)**2 - # else: - # inner_radius = lambda x: 0 * x # 0 - # inner_radius_squared = lambda x: 0 * x # 0 - - # outer_radius_squared = lambda x: (1 / 4) - (taper_ratio / 2) * (x / length) + taper_ratio**2 * (x / length)**2 / 4 - - # if is_hollow: - # outer_minus_inner_squared = lambda x: ((1 / 4) - (taper_ratio / 2) * (x / length) + taper_ratio**2 * (x / length)**2 / 4) - ( - # (0.5 - thickness)**2 - 2 * (0.5 - thickness) * (taper_ratio / 2) * (x / length) + (taper_ratio**2 / 4) * (x / length)**2) - # else: - # outer_minus_inner_squared = lambda x: (1 / 4) - (taper_ratio / 2) * (x / length) + taper_ratio**2 * (x / length)**2 / 4 - - # if is_hollow: - # total_weight, _ = quadgk(lambda x: (length * jnp.pi * density) * (((1 / 4) - (taper_ratio / 2) * (x / length) + taper_ratio**2 * (x / length)**2 / 4) - ( - # (0.5 - thickness)**2 - 2 * (0.5 - thickness) * (taper_ratio / 2) * (x / length) + (taper_ratio**2 / 4) * (x / length)**2)), [0, length]) - # else: - # total_weight, _ = quadgk(lambda x: (length * jnp.pi * density) * ((1 / 4) - (taper_ratio / 2) * (x / length) + taper_ratio**2 * (x / length)**2 / 4), [0, length]) - - return center_of_gravity_x, center_of_gravity_y, center_of_gravity_z, total_weight + return center_of_gravity_x_fuse, center_of_gravity_y_fuse, center_of_gravity_z_fuse, total_weight_fuse def validate_inputs(self, length, diameter, thickness, taper_ratio, is_hollow): if length <= 0 or diameter <= 0 or thickness <= 0: @@ -205,48 +182,48 @@ def get_section_diameter(self, location, length, diameter, taper_ratio, interpol return self.custom_fuselage_function(location) elif self.load_fuselage_data: return interpolate_diameter(location) if interpolate_diameter is not None else omj.smooth_max(0.01, diameter * (1 - taper_ratio * (location / length))) - #return jnp.where(interpolate_diameter is not None, interpolate_diameter(location), omj.smooth_max(0.01, diameter * (1 - taper_ratio * (location / length)))) else: return omj.smooth_max(0.01, diameter * (1 - taper_ratio * (location / length))) def compute_centroid(self, location, length, y_offset, z_offset, curvature, taper_ratio): - #centroid_x = (3/4) * location if taper_ratio > 0 else location # This is an approximation that could and should be better modeled in the future centroid_x = jnp.where(taper_ratio > 0, (3/4) * location, location) centroid_y = y_offset * (1 - location / length) centroid_z = z_offset * (1 - location / length) + curvature * location**2 / length return centroid_x, centroid_y, centroid_z - -prob = om.Problem() -prob.model.add_subsystem('fuselage_cg', FuselageMassAndCOG(), promotes_inputs=['length', 'diameter', 'taper_ratio', 'curvature', 'thickness', 'y_offset', 'z_offset', 'is_hollow']) -prob.setup() +if __name__ == "__main__": + prob = om.Problem() + + prob.model.add_subsystem('fuselage_cg', FuselageMassAndCOG(), promotes_inputs=['length', 'diameter', 'taper_ratio', 'curvature', 'thickness', 'y_offset', 'z_offset', 'is_hollow']) + + prob.setup() -prob.set_val('length', 2.5) -prob.set_val('diameter', 0.5) -prob.set_val('taper_ratio', 0.5) -prob.set_val('curvature', 0.0) -prob.set_val('thickness', 0.05) # Wall thickness of 5 cm -#prob.set_val('is_hollow', False) # Default is True, uncomment to use False -- for testing purposes + prob.set_val('length', 2.5) + prob.set_val('diameter', 0.5) + prob.set_val('taper_ratio', 0.5) + prob.set_val('curvature', 0.0) + prob.set_val('thickness', 0.05) # Wall thickness of 5 cm + #prob.set_val('is_hollow', False) # Default is True, uncomment to use False -- for testing purposes -# Example using custom function -- uncomment to run -#def custom_fuselage_model(location): -# return 0.5 * jnp.exp(-0.1 * location) + # Example using custom function -- uncomment to run + #def custom_fuselage_model(location): + # return 0.5 * jnp.exp(-0.1 * location) -#prob.model.fuselage_cg.custom_fuselage_function = custom_fuselage_model + #prob.model.fuselage_cg.custom_fuselage_function = custom_fuselage_model -# Example for custom .dat file -- uncomment to run -#prob.model.fuselage_cg.options['custom_fuselage_data_file'] = 'Custom_Fuselage.dat' + # Example for custom .dat file -- uncomment to run + #prob.model.fuselage_cg.options['custom_fuselage_data_file'] = 'Custom_Fuselage.dat' -prob.run_model() + prob.run_model() -center_of_gravity_x = prob.get_val('fuselage_cg.center_of_gravity_x') -center_of_gravity_y = prob.get_val('fuselage_cg.center_of_gravity_y') -center_of_gravity_z = prob.get_val('fuselage_cg.center_of_gravity_z') -total_weight = prob.get_val('fuselage_cg.total_weight') + center_of_gravity_x = prob.get_val('fuselage_cg.center_of_gravity_x_fuse') + center_of_gravity_y = prob.get_val('fuselage_cg.center_of_gravity_y_fuse') + center_of_gravity_z = prob.get_val('fuselage_cg.center_of_gravity_z_fuse') + total_weight = prob.get_val('fuselage_cg.total_weight_fuse') -#data = prob.check_partials(compact_print=True, abs_err_tol=1e-04, rel_err_tol=1e-04, step=1e-8, step_calc='rel') + #data = prob.check_partials(compact_print=True, abs_err_tol=1e-04, rel_err_tol=1e-04, step=1e-8, step_calc='rel') -print(f"Center of gravity of the fuselage: X = {center_of_gravity_x} m, Y = {center_of_gravity_y} m, Z = {center_of_gravity_z} m") -print(f"Total weight of the fuselage: {total_weight} kg") + print(f"Center of gravity of the fuselage: X = {center_of_gravity_x} m, Y = {center_of_gravity_y} m, Z = {center_of_gravity_z} m") + print(f"Total mass of the fuselage: {total_weight} kg") diff --git a/aviary/subsystems/mass/simple_mass/six_dof_EOM.py b/aviary/subsystems/mass/simple_mass/six_dof_EOM.py new file mode 100644 index 000000000..735d140fc --- /dev/null +++ b/aviary/subsystems/mass/simple_mass/six_dof_EOM.py @@ -0,0 +1,405 @@ +import numpy as np +import openmdao.api as om + +class SixDOF_EOM(om.ExplicitComponent): + """ + Six DOF EOM component, with particular emphasis for rotorcraft. + ASSUMPTIONS: + - Assume Flat Earth model (particularly for rotorcraft) + - Earth is the internal f.o.r. + - Gravity is constant and normal to the tangent plane (Earth's surface) -- g = (0 0 G)^T + - (aircraft) mass is constant + - aircraft is a rigid body + - Symmetry in the xz plane (for moment of inertia matrix -- J_xy = J_yx = J_zy = J_yz = 0) + + Reference: https://youtu.be/hr_PqdkG6XY?si=_hFAZZMnk58eV9GJ + + """ + + def setup(self): + self.add_input( + 'mass', + val=0.0, + units='kg', + desc="mass -- assume constant" + ) + + self.add_input( + 'axial_vel', + val=0.0, + units='m/s', # meters per second + desc="axial velocity of CM wrt inertial CS resolved in aircraft body fixed CS" + ) + + self.add_input( + 'lat_vel', + val=0.0, + units='m/s', + desc="lateral velocity of CM wrt inertial CS resolved in aircraft body fixed CS" + ) + + self.add_input( + 'vert_vel', + val=0.0, + units='m/s', + desc="vertical velocity of CM wrt inertial CS resolved in aircraft body fixed CS" + ) + + self.add_input( + 'roll_ang_vel', + val=0.0, + units='rad/s', # radians per second + desc="roll angular velocity of body fixed CS wrt intertial CS" + ) + + self.add_input( + 'pitch_ang_vel', + val=0.0, + units='rad/s', + desc="pitch angular velocity of body fixed CS wrt intertial CS" + ) + + self.add_input( + 'yaw_ang_vel', + val=0.0, + units='rad/s', + desc="yaw angular velocity of body fixed CS wrt intertial CS" + ) + + self.add_input( + 'roll', + val=0.0, + units='rad', # radians + desc="roll angle" + ) + + self.add_input( + 'pitch', + val=0.0, + units='rad', + desc="pitch angle" + ) + + self.add_input( + 'yaw', + val=0.0, + units='rad', + desc="yaw angle" + ) + + self.add_input( + 'x', + val=0.0, + units='m', + desc="x-axis position of aircraft resolved in North-East-Down (NED) CS" + ) + + self.add_input( + 'y', + val=0.0, + units='m', + desc="y-axis position of aircraft resolved in NED CS" + ) + + self.add_input( + 'z', + val=0.0, + units='m', + desc="z-axis position of aircraft resolved in NED CS" + ) + + self.add_input( + 'time', + val=0.0, + desc="scalar time in seconds" + ) + + self.add_input( + 'g', + val=9.81, + units='m/s**2', + desc="acceleration due to gravity" + ) + + self.add_input( + 'Fx_ext', + val=0.0, + units='N', + desc="external forces in the x direciton" + ) + + self.add_input( + 'Fy_ext', + val=0.0, + units='N', + desc="external forces in the y direction" + ) + + self.add_input( + 'Fz_ext', + val=0.0, + units='N', + desc="external forces in the z direction" + ) + + self.add_input( + 'lx_ext', + val=0.0, + units='kg*m**2/s**2', # kg times m^2 / s^2 + desc="external moments in the x direction" + ) + + self.add_input( + 'ly_ext', + val=0.0, + units='kg*m**2/s**2', + desc="external moments in the y direction" + ) + + self.add_input( + 'lz_ext', + val=0.0, + units='kg*m**2/s**2', + desc="external moments in the z direction" + ) + + # Below are the necessary components for the moment of inertia matrix (J) + # Only xx, yy, zz, and xz are needed (xy and yz are 0 with assumptions) + # For now, these are separated. + # TODO: Rewrite J and EOM in matrix form + + self.add_input( + 'J_xz', + val=0.0, + units='kg*m**2', + desc="x-z (top right and bottom left corner of 3x3 matrix, assuming symmetry) " \ + "component" + ) + + self.add_input( + 'J_xx', + val=0.0, + units='kg*m**2', + desc="first diag component" + ) + + self.add_input( + 'J_yy', + val=0.0, + units='kg*m**2', + desc="second diag component" + ) + + self.add_input( + 'J_zz', + val=0.0, + units='kg*m**2', + desc="third diag component" + ) + + # Outputs + + self.add_output( + 'dx_accel', + val=0.0, + units='m/s**2', # meters per seconds squared + desc="x-axis (roll-axis) velocity equation, " \ + "state: axial_vel" + ) + + self.add_output( + 'dy_accel', + val=0.0, + units='m/s**2', + desc="y-axis (pitch axis) velocity equation, " \ + "state: lat_vel" + ) + + self.add_output( + 'dz_accel', + val=0.0, + units='m/s**2', + desc="z-axis (yaw axis) velocity equation, " \ + "state: vert_vel" + ) + + self.add_output( + 'roll_accel', + val=0.0, + units='rad/s**2', # radians per second squared + desc="roll equation, " \ + "state: roll_ang_vel" + ) + + self.add_output( + 'pitch_accel', + val=0.0, + units='rad/s**2', + desc="pitch equation, " \ + "state: pitch_ang_vel" + ) + + self.add_output( + 'yaw_accel', + val=0.0, + units='rad/s**2', + desc="yaw equation, " \ + "state: yaw_ang_vel" + ) + + self.add_output( + 'roll_angle_rate_eq', + val=0.0, + units='rad/s', + desc="Euler angular roll rate" + ) + + self.add_output( + 'pitch_angle_rate_eq', + val=0.0, + units='rad/s', + desc="Euler angular pitch rate" + ) + + self.add_output( + 'yaw_angle_rate_eq', + val=0.0, + units='rad/s', + desc="Euler angular yaw rate" + ) + + self.add_output( + 'dx_dt', + val=0.0, + units='m/s', + desc="x-position derivative of aircraft COM wrt point in NED CS" + ) + + self.add_output( + 'dy_dt', + val=0.0, + units='m/s', + desc="y-position derivative of aircraft COM wrt point in NED CS" + ) + + self.add_output( + 'dz_dt', + val=0.0, + units='m/s', + desc="z-position derivative of aircraft COM wrt point in NED CS" + ) + + def compute(self, inputs, outputs): + """ + Compute function for EOM. + TODO: Same as above, potentially rewrite equations for \ + matrix form, and add potential assymetry to moment \ + of inertia matrix. + + """ + + # inputs + + mass = inputs['mass'] + axial_vel = inputs['axial_vel'] # u + lat_vel = inputs['lat_vel'] # v + vert_vel = inputs['vert_vel'] # w + roll_ang_vel = inputs['roll_ang_vel'] # p + pitch_ang_vel = inputs['pitch_ang_vel'] # q + yaw_ang_vel = inputs['yaw_ang_vel'] # r + roll = inputs['roll'] # phi + pitch = inputs['pitch'] # theta + yaw = inputs['yaw'] # psi + x = inputs['x'] # p1 + y = inputs['y'] # p2 + z = inputs['z'] # p3 + time = inputs['time'] + g = inputs['g'] + Fx_ext = inputs['Fx_ext'] + Fy_ext = inputs['Fy_ext'] + Fz_ext = inputs['Fz_ext'] + lx_ext = inputs['lx_ext'] # l + ly_ext = inputs['ly_ext'] # m + lz_ext = inputs['lz_ext'] # n + J_xz = inputs['J_xz'] + J_xx = inputs['J_xx'] + J_yy = inputs['J_yy'] + J_zz = inputs['J_zz'] + + # Resolve gravity in body coordinate system -- denoted with subscript 'b' + gx_b = -np.sin(pitch) * g + gy_b = np.sin(roll) * np.cos(pitch) * g + gz_b = np.cos(roll) * np.cos(pitch) * g + + # TODO: could add external forces and moments here if needed + + # Denominator for roll and yaw rate equations + Den = J_xx * J_zz - J_xz**2 + + # roll-axis velocity equation + + dx_accel = 1 / mass * Fx_ext + gx_b - vert_vel * pitch_ang_vel + lat_vel * yaw_ang_vel + + # pitch-axis velocity equation + + dy_accel = 1 / mass * Fy_ext + gy_b - axial_vel * yaw_ang_vel + vert_vel * roll_ang_vel + + # yaw-axis velocity equation + + dz_accel = 1 / mass * Fz_ext + gz_b - lat_vel * roll_ang_vel + axial_vel * pitch_ang_vel + + # Roll equation + + roll_accel = (J_xz * (J_xx - J_yy + J_zz) * roll_ang_vel * pitch_ang_vel - + (J_zz * (J_zz - J_yy) + J_xz**2) * pitch_ang_vel * yaw_ang_vel + + J_zz * lx_ext + + J_xz * lz_ext) / Den + + # Pitch equation + + pitch_accel = ((J_zz - J_xx) * roll_ang_vel * yaw_ang_vel - + J_xz * (roll_ang_vel**2 - yaw_ang_vel**2) + ly_ext) / J_yy + + # Yaw equation + + yaw_accel = ((J_xx * (J_xx - J_yy) + J_xz**2) * roll_ang_vel * pitch_ang_vel + + J_xz * (J_xx - J_yy + J_zz) * pitch_ang_vel * yaw_ang_vel + + J_xz * lx_ext + + J_xz * lz_ext) / Den + + # Kinematic equations + + roll_angle_rate_eq = roll_ang_vel + np.sin(roll) * np.tan(pitch) * pitch_ang_vel + \ + np.cos(roll) * np.tan(pitch) * yaw_ang_vel + + pitch_angle_rate_eq = np.cos(roll) * pitch_ang_vel - np.sin(roll) * yaw_ang_vel + + yaw_angle_rate_eq = np.sin(roll) / np.cos(pitch) * pitch_ang_vel + \ + np.cos(roll) / np.cos(pitch) * yaw_ang_vel + + # Position equations + + dx_dt = np.cos(pitch) * np.cos(yaw) * axial_vel + \ + (-np.cos(roll) * np.sin(yaw) + np.sin(roll) * np.sin(pitch) * np.cos(yaw)) * lat_vel + \ + (np.sin(roll) * np.sin(yaw) + np.cos(roll) * np.sin(pitch) * np.cos(yaw)) * vert_vel + + dy_dt = np.cos(pitch) * np.sin(yaw) * axial_vel + \ + (np.cos(roll) * np.cos(yaw) + np.sin(roll) * np.sin(pitch) * np.sin(yaw)) * lat_vel + \ + (-np.sin(roll) * np.cos(yaw) + np.cos(roll) * np.sin(pitch) * np.sin(yaw)) * vert_vel + + dz_dt = -np.sin(pitch) * axial_vel + \ + np.sin(roll) * np.cos(pitch) * lat_vel + \ + np.cos(roll) * np.cos(pitch) * vert_vel + + outputs['dx_accel'] = dx_accel + outputs['dy_accel'] = dy_accel + outputs['dz_accel'] = dz_accel + outputs['roll_accel'] = roll_accel + outputs['pitch_accel'] = pitch_accel + outputs['yaw_accel'] = yaw_accel + outputs['roll_angle_rate_eq'] = roll_angle_rate_eq + outputs['pitch_angle_rate_eq'] = pitch_angle_rate_eq + outputs['yaw_angle_rate_eq'] = yaw_angle_rate_eq + outputs['dx_dt'] = dx_dt + outputs['dy_dt'] = dy_dt + outputs['dz_dt'] = dz_dt \ No newline at end of file diff --git a/aviary/subsystems/mass/simple_mass/tail.py b/aviary/subsystems/mass/simple_mass/tail.py index d249c8c4b..28e8d52cd 100644 --- a/aviary/subsystems/mass/simple_mass/tail.py +++ b/aviary/subsystems/mass/simple_mass/tail.py @@ -71,17 +71,17 @@ def setup(self): self.options['use_jit'] = not(Debug) # Inputs - self.add_input('span', + self.add_input('span_tail', val=5.0, units='m', desc="Tail span") - self.add_input('root_chord', + self.add_input('root_chord_tail', val=1.2, units='m', desc="Root chord length") - self.add_input('tip_chord', + self.add_input('tip_chord_tail', val=0.8, units='m', desc="Tip chord length") @@ -95,7 +95,7 @@ def setup(self): units='m', desc="Skin panel thickness") - self.add_input('twist', + self.add_input('twist_tail', val=jnp.zeros(self.options['num_sections']), units='deg', desc="Twist distribution") @@ -121,19 +121,13 @@ def setup(self): units='m', desc="Z location of the center of gravity") - def compute_primal(self, span, root_chord, tip_chord, thickness_ratio, skin_thickness, twist): + def compute_primal(self, span_tail, root_chord_tail, tip_chord_tail, thickness_ratio, skin_thickness, twist_tail): tail_type = self.options["tail_type"] airfoil_type = self.options["airfoil_type"] material = self.options['material'] - # span = inputs['span'] - # root_chord = inputs['root_chord'] - # tip_chord = inputs['tip_chord'] - # thickness_ratio = inputs['thickness_ratio'] density, _ = materials.get_item(material) airfoil_file = self.options['airfoil_file'] - # skin_thickness = inputs['skin_thickness'] num_sections = self.options['num_sections'] - # twist = inputs['twist'] NACA_digits = self.options['NACA_digits'] # File check @@ -162,27 +156,8 @@ def compute_primal(self, span, root_chord, tip_chord, thickness_ratio, skin_thic # Tail type check if tail_type not in ['horizontal', 'vertical']: raise ValueError("Invalid tail_type. Must be 'horizontal' or 'vertical'.") - - # Input validation checks - if span <= 0: - raise ValueError("Span must be greater than zero.") - - if root_chord <= 0 or tip_chord <= 0: - raise ValueError("Root chord and tip chord must be greater than zero.") - - if tip_chord > root_chord: - raise ValueError("Tip chord cannot be larger than root chord.") - - if thickness_ratio <= 0: - raise ValueError("Thickness ratio must be greater than zero.") - - if skin_thickness <= 0: - raise ValueError("Skin thickness must be greater than zero.") - - if any(omj.smooth_abs(twist)) > jnp.pi / 2: - raise ValueError("Twist angle is too extreme; must be within -90 to 90 degrees.") - span_locations = jnp.linspace(0, span, num_sections) + span_locations = jnp.linspace(0, span_tail, num_sections) # Get x_points and dx for later x_points, dx = self.precompute_airfoil_geometry() @@ -190,57 +165,20 @@ def compute_primal(self, span, root_chord, tip_chord, thickness_ratio, skin_thic # Thickness distribution thickness_dist = self.airfoil_thickness(x_points, max_thickness) - # total_mass = 0 - # total_moment_x = 0 - # total_moment_y = 0 - # total_moment_z = 0 - - # for i, y in enumerate(span_locations): - # section_chord = root_chord - (root_chord - tip_chord) * (y / span) # Assume linear variation in chord - # section_area, centroid_x, centroid_z = self.compute_airfoil_geometry(section_chord, - # camber, - # camber_location, - # thickness_dist, - # x_points, - # dx) - - - # section_mass = density * thickness_dist[i] * section_chord * (span / num_sections) - - # # Twist - # twist_angle = twist[i] - # rotated_x = centroid_x * jnp.cos(twist_angle) - centroid_z * jnp.sin(twist_angle) - # rotated_z = centroid_x * jnp.sin(twist_angle) + centroid_z * jnp.cos(twist_angle) - - # total_mass += section_mass - # total_moment_x += rotated_x * section_mass - # # if tail_type == 'horizontal': - # # total_moment_y += y * section_mass - # # total_moment_z += rotated_z * section_mass - # # elif tail_type == 'vertical': - # # total_moment_y += rotated_z * section_mass - # # total_moment_z += y * section_mass - - # total_moment_y += jnp.where(tail_type == 'horizontal', y * section_mass, rotated_z * section_mass) - # total_moment_z += jnp.where(tail_type == 'horizontal', rotated_z * section_mass, y * section_mass) - - #total_mass = jtrapz(density * self.airfoil_thickness(x_points, max_thickness) * (root_chord - (root_chord - tip_chord) * (x_points / span)) * span, x_points) - total_mass, _ = quadgk(lambda x: density * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span)) * span, [0, 1], epsabs=1e-9, epsrel=1e-9) + total_mass, _ = quadgk(lambda x: density * self.airfoil_thickness(x, max_thickness) * (root_chord_tail - (root_chord_tail - tip_chord_tail) * (x / span_tail)) * span_tail, [0, 1], epsabs=1e-9, epsrel=1e-9) - #cgz_function = jnp.where(tail_type == 'horizontal', lambda x: (x * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span))) * jnp.sin(twist) + (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span))) * jnp.cos(twist), lambda x: x * span) - #cgy_function = jnp.where(tail_type == 'horizontal', lambda x: x * span, lambda x: (x * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span))) * jnp.sin(twist) + (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span))) * jnp.cos(twist)) if tail_type == 'horizontal': - cgz_function = lambda x: (x * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span))) * jnp.sin(twist) + (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span))) * jnp.cos(twist) - cgy_function = lambda x: x * span + cgz_function = lambda x: (x * self.airfoil_thickness(x, max_thickness) * (root_chord_tail - (root_chord_tail - tip_chord_tail) * (x / span_tail))) * jnp.sin(twist_tail) + (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (root_chord_tail - (root_chord_tail - tip_chord_tail) * (x / span_tail))) * jnp.cos(twist_tail) + cgy_function = lambda x: x * span_tail else: - cgz_function = lambda x: x * span - cgy_function = lambda x: (x * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span))) * jnp.sin(twist) + (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span))) * jnp.cos(twist) + cgz_function = lambda x: x * span_tail + cgy_function = lambda x: (x * self.airfoil_thickness(x, max_thickness) * (root_chord_tail - (root_chord_tail - tip_chord_tail) * (x / span_tail))) * jnp.sin(twist_tail) + (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (root_chord_tail - (root_chord_tail - tip_chord_tail) * (x / span_tail))) * jnp.cos(twist_tail) - area, _ = quadgk(lambda x: self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span)), [0, 1], epsabs=1e-9, epsrel=1e-9) + area, _ = quadgk(lambda x: self.airfoil_thickness(x, max_thickness) * (root_chord_tail- (root_chord_tail - tip_chord_tail) * (x / span_tail)), [0, 1], epsabs=1e-9, epsrel=1e-9) - cg_x_num, _ = quadgk(lambda x: (x * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span)) * jnp.cos(twist)) - - (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span))) * jnp.sin(twist), + cg_x_num, _ = quadgk(lambda x: (x * self.airfoil_thickness(x, max_thickness) * (root_chord_tail - (root_chord_tail - tip_chord_tail) * (x / span_tail)) * jnp.cos(twist_tail)) - + (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (root_chord_tail - (root_chord_tail - tip_chord_tail) * (x / span_tail))) * jnp.sin(twist_tail), [0, 1], epsabs=1e-9, epsrel=1e-9) cg_x = cg_x_num / area @@ -255,9 +193,6 @@ def compute_primal(self, span, root_chord, tip_chord, thickness_ratio, skin_thic cg_z = cg_z[0] mass = total_mass - #cg_x = total_moment_x / total_mass - #cg_y = total_moment_y / total_mass - #cg_z = total_moment_z / total_mass return mass, cg_x, cg_y, cg_z @@ -270,15 +205,12 @@ def precompute_airfoil_geometry(self): def compute_airfoil_geometry(self, chord, camber, camber_location, thickness_dist, x_points, dx): - #section_area, _ = quad(lambda x: jnp.interp(x, x_points, thickness_dist), 0, 1, limit=100) section_area = jnp.trapezoid(thickness_dist, x_points, dx=dx) section_area *= chord - #centroid_x, _ = quad(lambda x: x * jnp.interp(x, x_points, thickness_dist), 0, 1, limit=100) centroid_x = jnp.trapezoid(x_points * thickness_dist, x_points, dx=dx) centroid_x = (centroid_x * chord) / section_area - #centroid_z, _ = quad(lambda x: self.airfoil_camber_line(x, camber, camber_location) * jnp.interp(x, x_points, thickness_dist), 0, 1, limit=100) centroid_z = jnp.trapezoid(self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist, x_points, dx=dx) centroid_z = (centroid_z * chord) / section_area return section_area, centroid_x, centroid_z @@ -324,24 +256,25 @@ def extract_airfoil_features(self, x_coords, y_coords): return camber, camber_location, max_thickness_value -prob = om.Problem() +if __name__ == "__main__": + prob = om.Problem() -prob.model.add_subsystem('tail', TailMassAndCOG(), promotes_inputs=['*'], promotes_outputs=['*']) + prob.model.add_subsystem('tail', TailMassAndCOG(), promotes_inputs=['*'], promotes_outputs=['*']) -prob.setup() + prob.setup() -# Input values -prob.set_val('span', 1) -prob.set_val('tip_chord', 0.5) -prob.set_val('root_chord', 1) -prob.set_val('thickness_ratio', 0.12) -prob.set_val('skin_thickness', 0.002) -prob.model.tail.options['tail_type'] = 'horizontal' + # Input values + prob.set_val('span', 1) + prob.set_val('tip_chord', 0.5) + prob.set_val('root_chord', 1) + prob.set_val('thickness_ratio', 0.12) + prob.set_val('skin_thickness', 0.002) + prob.model.tail.options['tail_type'] = 'horizontal' -prob.model.tail.options['material'] = 'Balsa' + prob.model.tail.options['material'] = 'Balsa' -prob.run_model() + prob.run_model() -# Print -print(f"Mass: {prob.get_val('mass')} kg") -print(f"Center of gravity (X: {prob.get_val('cg_x')} m, Y: {prob.get_val('cg_y')} m, Z: {prob.get_val('cg_z')} m)") \ No newline at end of file + # Print + print(f"Total mass of the tail: {prob.get_val('mass')} kg") + print(f"Center of gravity (X: {prob.get_val('cg_x')} m, Y: {prob.get_val('cg_y')} m, Z: {prob.get_val('cg_z')} m)") \ No newline at end of file diff --git a/aviary/subsystems/mass/simple_mass/test/test_tail.py b/aviary/subsystems/mass/simple_mass/test/test_tail.py index b4e1939cd..372928553 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_tail.py +++ b/aviary/subsystems/mass/simple_mass/test/test_tail.py @@ -39,19 +39,19 @@ def setUp(self): ) self.prob.model.set_input_defaults( - "span", + "span_tail", val=1, units="m" ) self.prob.model.set_input_defaults( - "root_chord", + "root_chord_tail", val=1, units="m" ) self.prob.model.set_input_defaults( - "tip_chord", + "tip_chord_tail", val=0.5, units="m" ) @@ -68,7 +68,7 @@ def setUp(self): ) self.prob.model.set_input_defaults( - "twist", + "twist_tail", val=np.zeros(10), units="deg" ) @@ -85,12 +85,12 @@ def test_case(self): assert_near_equal( self.prob["mass"], - 4.22032, # still need to calculate by hand + 4.22032, tol) partial_data = self.prob.check_partials( out_stream=None, - method="cs") # Finite difference because cs is used in tail mass calculation right now + method="cs") assert_check_partials( partial_data, diff --git a/aviary/subsystems/mass/simple_mass/test/test_wing.py b/aviary/subsystems/mass/simple_mass/test/test_wing.py index 87fdd9d2b..fe4524ee5 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_wing.py +++ b/aviary/subsystems/mass/simple_mass/test/test_wing.py @@ -88,7 +88,7 @@ def test_case(self): self.prob.run_model() tol = 1e-10 - assert_near_equal(self.prob["total_weight"], + assert_near_equal(self.prob["total_weight_wing"], 4.22032, tol) diff --git a/aviary/subsystems/mass/simple_mass/wing.py b/aviary/subsystems/mass/simple_mass/wing.py index cd3137a92..832339ea9 100644 --- a/aviary/subsystems/mass/simple_mass/wing.py +++ b/aviary/subsystems/mass/simple_mass/wing.py @@ -80,19 +80,19 @@ def setup(self): # Outputs - self.add_output('center_of_gravity_x', + self.add_output('center_of_gravity_x_wing', val=0.0, units='m') - self.add_output('center_of_gravity_y', + self.add_output('center_of_gravity_y_wing', val=0.0, units='m') - self.add_output('center_of_gravity_z', + self.add_output('center_of_gravity_z_wing', val=0.0, units='m') - self.add_output('total_weight', + self.add_output('total_weight_wing', val=0.0, units='kg') @@ -100,24 +100,9 @@ def compute_primal(self, span, root_chord, tip_chord, twist, thickness_dist): material = self.options['material'] # Material is taken from options airfoil_type = self.options['airfoil_type'] # NACA airfoil type airfoil_data_file = self.options['airfoil_data_file'] - - # Input validation checks - if span <= 0: - raise ValueError("Span must be greater than zero.") - - if root_chord <= 0 or tip_chord <= 0: - raise ValueError("Root chord and tip chord must be greater than zero.") - - if tip_chord > root_chord: - raise ValueError("Tip chord cannot be larger than root chord.") - - if any(omj.smooth_abs(twist)) > jnp.pi / 2: - raise ValueError("Twist angle is too extreme; must be within -90 to 90 degrees.") # Get material density - density, _ = materials.get_item(material) # in kg/m³ - - #x_points, dx = self.precompute_airfoil_geometry() + density, _ = materials.get_item(material) # in kg/m^3 if airfoil_data_file and os.path.exists(airfoil_data_file): airfoil_data = np.loadtxt(airfoil_data_file) @@ -137,21 +122,13 @@ def compute_primal(self, span, root_chord, tip_chord, twist, thickness_dist): # Wing spanwise distribution span_locations = jnp.linspace(0, span, num_sections) - #num_sections = self.options['num_sections'] n_points = num_sections x_points = jnp.linspace(0, 1, n_points) dx = 1 / (n_points - 1) weight_function = lambda x: density * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span)) * span - - #total_weight = jint.trapezoid(density * self.airfoil_thickness(x_points, max_thickness) * (root_chord - (root_chord - tip_chord) * (x_points / span)) * span, x_points) - - #total_weight = self.gauss_quad(weight_function, num_sections, 0, 1) - total_weight, _ = quadgk(weight_function, [0, 1], epsabs=1e-9, epsrel=1e-9) - - #center_of_gravity_x = jint.trapezoid(x_points * self.airfoil_thickness(x_points, max_thickness) * (root_chord - (root_chord - tip_chord) * (x_points / span) * jnp.cos(twist)) - - # self.airfoil_camber_line(x_points, camber, camber_location) * self.airfoil_thickness(x_points, max_thickness) * (root_chord - (root_chord - tip_chord) * (x_points / span)) * jnp.sin(twist), - # x_points) / jint.trapezoid(self.airfoil_thickness(x_points, max_thickness) * (root_chord - (root_chord - tip_chord) * (x_points / span)), x_points) + + total_weight_wing, _ = quadgk(weight_function, [0, 1], epsabs=1e-9, epsrel=1e-9) center_of_gravity_x_num, _ = quadgk(lambda x: x * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span) * jnp.cos(twist)) - self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span)) * jnp.sin(twist), @@ -159,11 +136,7 @@ def compute_primal(self, span, root_chord, tip_chord, twist, thickness_dist): center_of_gravity_x_denom, _ = quadgk(lambda x: self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span)), [0, 1], epsabs=1e-9, epsrel=1e-9) center_of_gravity_x = center_of_gravity_x_num / center_of_gravity_x_denom - center_of_gravity_x = center_of_gravity_x[0] - - #center_of_gravity_z = jint.trapezoid(x_points * self.airfoil_thickness(x_points, max_thickness) * (root_chord - (root_chord - tip_chord) * (x_points / span) * jnp.sin(twist)) + - # self.airfoil_camber_line(x_points, camber, camber_location) * self.airfoil_thickness(x_points, max_thickness) * (root_chord - (root_chord - tip_chord) * (x_points / span)) * jnp.cos(twist), - # x_points) / jint.trapezoid(self.airfoil_thickness(x_points, max_thickness) * (root_chord - (root_chord - tip_chord) * (x_points / span)), x_points) + center_of_gravity_x_wing = center_of_gravity_x[0] center_of_gravity_z_num, _ = quadgk(lambda x: x * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span) * jnp.sin(twist)) + self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span)) * jnp.cos(twist), @@ -172,13 +145,10 @@ def compute_primal(self, span, root_chord, tip_chord, twist, thickness_dist): center_of_gravity_z_denom, _ = quadgk(lambda x: self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span)), [0, 1], epsabs=1e-9, epsrel=1e-9) center_of_gravity_z = center_of_gravity_z_num / center_of_gravity_z_denom - center_of_gravity_z = center_of_gravity_z[0] - - #center_of_gravity_y = jint.trapezoid(x_points * span, x_points) - - center_of_gravity_y, _ = quadgk(lambda x: x * span, [0, 1], epsabs=1e-9, epsrel=1e-9) + center_of_gravity_z_wing = center_of_gravity_z[0] + center_of_gravity_y_wing, _ = quadgk(lambda x: x * span, [0, 1], epsabs=1e-9, epsrel=1e-9) - return center_of_gravity_x, center_of_gravity_y, center_of_gravity_z, total_weight + return center_of_gravity_x_wing, center_of_gravity_y_wing, center_of_gravity_z_wing, total_weight_wing def precompute_airfoil_geometry(self): num_sections = self.options['num_sections'] @@ -228,128 +198,44 @@ def extract_airfoil_features(self, x_coords, y_coords): return camber, camber_location, max_thickness_value, thickness, camber_line - # def legendre_roots_and_weights(self, n): - # """ - # Compute nodes and weights for Legendre-Gauss quadrature using JAX. - - # Parameters: - - # beta: - # coefficient coming form Gram-Schmidt process, derived from recursive relation - # of Legendre polynomials. - - # T: - # symmetric, tri-diagonal Jacobi matrix derived using Golub-Welsch theorem. Eigenvalues - # of T correspond to roots of Legendre polynomials - - # Eigenvalues, Eigenvectors: - # The eigenvalues of T and their respective eigenvectors, calculated using - # jax.scipy.special.eigh function. - - # weights: - # Weights used for Gaussian-Legendre quadrature, calculated using the first - # component of the normalized eigenvector, derived from Golub & Welsch (1969). - # Coefficient 2 comes from an application of Rodrigues' formula for Legendre - # polynomials and applying the orthonormality property for Legendre polynomials - # over the interval [-1, 1] with weight = 1. - - # Returns: - - # float - # Roots of the Legendre polynomials (eigenvalues of T) - # float - # weights used for G-L quadrature (formula from Golub & Welsch 1969) - - # References: - - # [1] Golub, Gene H., and John H. Welsch. "Calculation of Gauss quadrature rules." - # Mathematics of computation 23.106 (1969): 221-230. - - # [2] André Ronveaux, Jean Mawhin, Rediscovering the contributions of Rodrigues on - # the representation of special functions, Expositiones Mathematicae, Volume 23, - # Issue 4, 2005, Pages 361-369, ISSN 0723-0869, - # https://doi.org/10.1016/j.exmath.2005.05.001. - - # """ - - # i = jnp.arange(1, n) - # beta = i / jnp.sqrt(4 * i**2 - 1) - # T = jnp.diag(beta, k=1) + jnp.diag(beta, k=-1) # Tridiagonal matrix - # eigenvalues, eigenvectors = jax.jit(jnp.linalg.eigh)(T) # Compute eigenvalues (roots) and eigenvectors - # roots = eigenvalues - # weights = 2 * (eigenvectors[0, :] ** 2) # Compute weights from first row of eigenvectors - - # return roots, weights - - - # def gauss_quad(self, f, n, a, b): - # """ - # Computes the integral of f(x) over [a, b] using Gaussian quadrature with n points. - - # Parameters: - - # f : function - # The function to integrate. - - # n : int - # The number of quadrature points. - - # a, b : float - # Integration limits. - - # Returns: - - # float - # The approximated integral of f(x) over [a, b]. - - # """ - # x, w = self.legendre_roots_and_weights(n) - - # x_mapped = 0.5 * (b - a) * x + 0.5 * (b + a) - # w_mapped = 0.5 * (b - a) * w - - # integral = jnp.sum(w_mapped * f(x_mapped)) # Compute weighted sum - # return integral.astype(jnp.float64) - -# Build OpenMDAO problem -prob = om.Problem() +if __name__ == '__main__': -# Add the center of gravity component -prob.model.add_subsystem('cog', WingMassAndCOG() , promotes_inputs=['*'], promotes_outputs=['*']) + # Build OpenMDAO problem + prob = om.Problem() -n_points = 10 # = num_sections -x = jnp.linspace(0, 1, n_points) -max_thickness_chord_ratio = 0.12 -thickness_dist = 5 * max_thickness_chord_ratio * (0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) + # Add the center of gravity component + prob.model.add_subsystem('cog', WingMassAndCOG() , promotes_inputs=['*'], promotes_outputs=['*']) -# Setup the problem -prob.setup() + n_points = 10 # = num_sections + x = jnp.linspace(0, 1, n_points) + max_thickness_chord_ratio = 0.12 + thickness_dist = 5 * max_thickness_chord_ratio * (0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) -# Define some example inputs -prob.set_val('span', 1) -prob.set_val('root_chord', 1) -prob.set_val('tip_chord', 0.5) -prob.set_val('twist', jnp.linspace(0, 0, 10)) -prob.set_val('thickness_dist', thickness_dist) + # Setup the problem + prob.setup() + # Define some example inputs + prob.set_val('span', 1) + prob.set_val('root_chord', 1) + prob.set_val('tip_chord', 0.5) + prob.set_val('twist', jnp.linspace(0, 0, 10)) + prob.set_val('thickness_dist', thickness_dist) -#prob.model.cog.options['airfoil_data_file'] = 'Clark_Y.dat' -prob.model.cog.options['material'] = 'Balsa' -prob.model.cog.options['airfoil_type'] = '2412' -# Run the model -prob.run_model() + #prob.model.cog.options['airfoil_data_file'] = 'Clark_Y.dat' + prob.model.cog.options['material'] = 'Balsa' + prob.model.cog.options['airfoil_type'] = '2412' -# Get the results -center_of_gravity_x = prob.get_val('cog.center_of_gravity_x') -center_of_gravity_y = prob.get_val('cog.center_of_gravity_y') -center_of_gravity_z = prob.get_val('cog.center_of_gravity_z') -total_weight = prob.get_val('cog.total_weight') + # Run the model + prob.run_model() -#data = prob.check_partials(compact_print=True, method='cs') -#om.partial_deriv_plot(data) + # Get the results + center_of_gravity_x = prob.get_val('cog.center_of_gravity_x_wing') + center_of_gravity_y = prob.get_val('cog.center_of_gravity_y_wing') + center_of_gravity_z = prob.get_val('cog.center_of_gravity_z_wing') + total_weight = prob.get_val('cog.total_weight_wing') -print(f"Center of gravity: X = {center_of_gravity_x} m, Y = {center_of_gravity_y} m, Z = {center_of_gravity_z} m") -print(f"Total weight of the wing: {total_weight} kg") + print(f"Center of gravity: X = {center_of_gravity_x} m, Y = {center_of_gravity_y} m, Z = {center_of_gravity_z} m") + print(f"Total mass of the wing: {total_weight} kg") From 5b08b4f5cffd54c302083b11bfe23e895dec68aa Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Mon, 12 May 2025 14:35:35 -0400 Subject: [PATCH 043/147] Delete aviary/subsystems/mass/simple_mass/test/import os.py --- aviary/subsystems/mass/simple_mass/test/import os.py | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 aviary/subsystems/mass/simple_mass/test/import os.py diff --git a/aviary/subsystems/mass/simple_mass/test/import os.py b/aviary/subsystems/mass/simple_mass/test/import os.py deleted file mode 100644 index 5d4713452..000000000 --- a/aviary/subsystems/mass/simple_mass/test/import os.py +++ /dev/null @@ -1,2 +0,0 @@ -import os -print(os.getcwd()) \ No newline at end of file From a752575178edc86fa3aadb1dd6d956472f11a1d3 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Mon, 12 May 2025 14:36:26 -0400 Subject: [PATCH 044/147] Delete aviary/docs/examples/wingN2.html --- aviary/docs/examples/wingN2.html | 14805 ----------------------------- 1 file changed, 14805 deletions(-) delete mode 100644 aviary/docs/examples/wingN2.html diff --git a/aviary/docs/examples/wingN2.html b/aviary/docs/examples/wingN2.html deleted file mode 100644 index 5c5691589..000000000 --- a/aviary/docs/examples/wingN2.html +++ /dev/null @@ -1,14805 +0,0 @@ - - - -OpenMDAO Model Hierarchy and N2 diagram - - - - - - - - - - - - - - - - - -
-
- -
-
- -
- - -
-
-
-
- - - -
-
- - -
-
- - - - - -
-
- - - - -
-
- -
-
- -
- -
-
- -
- -
-
- Processing... -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

-
-
- - - -
- -
- -
-
- -
-
-
-
- N2 Information -
- - -
- -
-
-
-
-
- - - - - - - - - - -
- -
- -
- -
- -
-

Left-click on a node in the model hierarchy to navigate to that node.
- Right-click on a node to collapse/expand it. - Alt-right-click on a node with variables to select which ones to hide.
- Note: Right-click in Firefox displays a browser menu. To disable that, - visit about:config and set dom.event.contextmenu.enabled - to true.
- Hover over any cell in the matrix to display its connections - as arrows. Click that cell to make those arrows persistent. -

-

Toolbar Help

-
- Snapshot of toolbar buttons - -
-
- -
- - - - - - -
Variable NameVisible
-
- - -
-
-
- Search - -
-
- - - -
-
-
- - - - - - - From 8d5d6c7a8b3844e1e0cf117cbfe0da02559c735a Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Mon, 12 May 2025 14:36:36 -0400 Subject: [PATCH 045/147] Delete aviary/docs/examples/wing.py --- aviary/docs/examples/wing.py | 491 ----------------------------------- 1 file changed, 491 deletions(-) delete mode 100644 aviary/docs/examples/wing.py diff --git a/aviary/docs/examples/wing.py b/aviary/docs/examples/wing.py deleted file mode 100644 index 64a5815fa..000000000 --- a/aviary/docs/examples/wing.py +++ /dev/null @@ -1,491 +0,0 @@ -import openmdao.api as om -import numpy as np -import os -from scipy.interpolate import CubicSpline - - -# Material densities (g/cm³ converted to kg/m³) -- these are just some random examples -MATERIAL_DENSITIES = { - 'wood': 130, # balsa wood - 'metal': 2700, # Aluminum - 'carbon_fiber': 1600 -} - - - -class WingMassAndCOG(om.ExplicitComponent): - def initialize(self): - self.options.declare('num_sections', - types=int, - default=1000) - - self.options.declare('airfoil_type', - types=str, - default='2412') # use 2412 as example for default - - self.options.declare('material', - default='metal', - values=list(MATERIAL_DENSITIES.keys())) - - self.options.declare('airfoil_data_file', - default=None, - types=str) # For user-provided airfoil data file - - def setup(self): - - # Inputs - self.add_input('span', - val=10.0, - units='m') # Full wingspan (adjustable) - - self.add_input('root_chord', - val=2.0, - units='m') # Root chord length - - self.add_input('tip_chord', - val=1.0, - units='m') # Tip chord length - - self.add_input('twist', - val=np.zeros(self.options['num_sections']), - units='deg') # Twist angles - - self.add_input('thickness_dist', - val=np.ones(self.options['num_sections']) * 0.1, - shape=(self.options['num_sections'],)) # Thickness distribution of the wing (height) - - - # Outputs - self.add_output('center_of_gravity_x', - val=0.0, - units='m') - - self.add_output('center_of_gravity_y', - val=0.0, - units='m') - - self.add_output('center_of_gravity_z', - val=0.0, - units='m') - - self.add_output('total_weight', - val=0.0, - units='kg') - - def setup_partials(self): - """ - Complex step is used for the derivatives for now as they are very complicated to calculate - analytically. Compute_partials function has the framework for analytical derivatives, but not - all of them match the check_partials. - """ - num_sections = self.options['num_sections'] - - self.declare_partials(['center_of_gravity_x', 'center_of_gravity_y', 'center_of_gravity_z'], - ['span', 'root_chord', 'tip_chord', 'thickness_dist', 'twist'], method='cs') - self.declare_partials('total_weight', ['span', 'root_chord', 'tip_chord', 'thickness_dist', 'twist'], method='cs') - - - def compute(self, inputs, outputs): - span = inputs['span'] - root_chord = inputs['root_chord'] - tip_chord = inputs['tip_chord'] - twist = np.radians(inputs['twist']) # Convert twist to radians - thickness_dist = inputs['thickness_dist'] - material = self.options['material'] # Material is taken from options - #num_sections = self.options['num_sections'] - airfoil_type = self.options['airfoil_type'] # NACA airfoil type - airfoil_data_file = self.options['airfoil_data_file'] - - # Input validation checks - if span <= 0: - raise ValueError("Span must be greater than zero.") - - if root_chord <= 0 or tip_chord <= 0: - raise ValueError("Root chord and tip chord must be greater than zero.") - - if tip_chord > root_chord: - raise ValueError("Tip chord cannot be larger than root chord.") - - if any(abs(twist)) > np.pi / 2: - raise ValueError("Twist angle is too extreme; must be within -90 to 90 degrees.") - - # Get material density - density = MATERIAL_DENSITIES[material] # in kg/m³ - - #x_points, dx = self.precompute_airfoil_geometry() - - if airfoil_data_file and os.path.exists(airfoil_data_file): - airfoil_data = np.loadtxt(airfoil_data_file) - x_coords = airfoil_data[:, 0] - y_coords = airfoil_data[:, 1] - - camber, camber_location, max_thickness, thickness, camber_line = self.extract_airfoil_features(x_coords, y_coords) - thickness_dist = thickness - num_sections = len(x_coords) - else: - # Parse the NACA airfoil type (4-digit) - camber = int(airfoil_type[0]) / 100.0 # Maximum camber - camber_location = int(airfoil_type[1]) / 10.0 # Location of max camber - max_thickness = int(airfoil_type[2:4]) / 100.0 # Max thickness - num_sections = self.options['num_sections'] - - # Wing spanwise distribution - span_locations = np.linspace(0, span, num_sections) - - #num_sections = self.options['num_sections'] - n_points = num_sections - x_points = np.linspace(0, 1, n_points) - dx = 1 / (n_points - 1) - - # Initialize total weight and moment accumulators - total_weight = 0 - total_moment_x = 0 - total_moment_y = 0 - total_moment_z = 0 - - # Arrays for storing 3D coordinates of the wing - x_coords = [] - y_coords = [] - z_coords = [] - - # Loop over each section along the span (3D wing approximation) - for i, location in enumerate(span_locations): - # Calculate the chord for this section -- note this is an approximation - chord = root_chord - (root_chord - tip_chord) * (location / span) # Assuming linear variation from root to tip - - # Apply twist - twist_angle = twist[i] - - section_area, centroid_x, centroid_z = self.compute_airfoil_geometry(chord, camber, camber_location, thickness_dist, x_points, dx) - centroid_y = i * span / num_sections - section_weight = density * section_area * (span / num_sections) - - rotated_x = centroid_x * np.cos(twist_angle) - centroid_z * np.sin(twist_angle) - rotated_z = centroid_x * np.sin(twist_angle) + centroid_z * np.cos(twist_angle) - - total_weight += section_weight - total_moment_x += rotated_x * section_weight - total_moment_y += centroid_y * section_weight - total_moment_z += rotated_z * section_weight - - - # Store the coordinates for plotting later - x_coords.append(rotated_x) - y_coords.append(centroid_y) - z_coords.append(rotated_z) - - # Calculate the overall center of gravity - outputs['center_of_gravity_x'] = total_moment_x / total_weight - outputs['center_of_gravity_y'] = total_moment_y / total_weight - outputs['center_of_gravity_z'] = total_moment_z / total_weight - outputs['total_weight'] = total_weight - - - def compute_partials(self, inputs, J): - span = inputs['span'] - root_chord = inputs['root_chord'] - tip_chord = inputs['tip_chord'] - thickness_dist = inputs['thickness_dist'] - twist=np.radians(inputs['twist']) - num_sections = self.options['num_sections'] - airfoil_type = self.options['airfoil_type'] # NACA airfoil type - airfoil_data_file = self.options['airfoil_data_file'] - material = self.options['material'] - - # Compute section locations along the span - span_locations = np.linspace(0, span, num_sections) - span_locations = span_locations / span - chord_lengths = tip_chord + (root_chord - tip_chord) * (1 - span_locations / span) - - # Compute section airfoil geometry - if airfoil_data_file and os.path.exists(airfoil_data_file): - airfoil_data = np.loadtxt(airfoil_data_file) - x_coords = airfoil_data[:, 0] - y_coords = airfoil_data[:, 1] - - camber, camber_location, max_thickness, thickness, camber_line = self.extract_airfoil_features(x_coords, y_coords) - thickness_dist = thickness - else: - # Parse the NACA airfoil type (4-digit) - camber = int(airfoil_type[0]) / 100.0 # Maximum camber - camber_location = int(airfoil_type[1]) / 10.0 # Location of max camber - max_thickness = int(airfoil_type[2:4]) / 100.0 # Max thickness - - # Compute section airfoil geometry - n_points = num_sections - x_points = np.linspace(0, 1, n_points) - dx = 1 / (num_sections - 1) - - #A_ref, err = quad(lambda x: np.interp(x, x_points, thickness_dist), 0, 1, limit=100) # \int_0^1 t(x) dx - A_ref = np.trapz(thickness_dist, x_points, dx=dx) - - density = MATERIAL_DENSITIES[material] - - total_moment_x = 0 - total_moment_y = 0 - total_moment_z = 0 - total_weight = 0 - - rotated_x_vals = np.zeros(num_sections) - rotated_z_vals = np.zeros(num_sections) - #section_weights = np.zeros(num_sections) - section_areas = np.zeros(num_sections) - dA_dspan = 0 - dA_droot_chord = 0 - dA_dtip_chord = 0 - dweight_dspan = 0 - dmoment_x_dtwist = np.zeros(num_sections) - dmoment_z_dtwist = np.zeros(num_sections) - dweight_dthickness = np.zeros(num_sections) - - for i, location in enumerate(span_locations): - # Calculate the chord for this section - chord = root_chord - (root_chord - tip_chord) * (location / span) # Assuming linear variation from root to tip - - # Apply twist - twist_angle = twist[i] - - section_area, centroid_x, centroid_z = self.compute_airfoil_geometry(chord, camber, camber_location, thickness_dist, x_points, dx) - section_weight = density * section_area * (span / num_sections) - centroid_y = location - - rotated_x_vals[i] = centroid_x * np.cos(twist_angle) - centroid_z * np.sin(twist_angle) - rotated_z_vals[i] = centroid_x * np.sin(twist_angle) + centroid_z * np.cos(twist_angle) - - total_weight += section_weight - total_moment_x += rotated_x_vals[i] * section_weight - total_moment_y += centroid_y * section_weight - total_moment_z += rotated_z_vals[i] * section_weight - - #section_weights[i] = section_weight - section_areas[i] = section_area - - # For dweight_dspan - dci_dspan = -(root_chord - tip_chord) * (location / span**2) - #dA_dspan, _ = quad(lambda x: np.interp(x, x_points, thickness_dist) * dci_dspan, 0, 1, limit=100) - dA_ds = np.trapz(thickness_dist * dci_dspan, x_points, dx=dx) - dA_dc_root = np.trapz(thickness_dist * (1 - i / num_sections), x_points, dx=dx) - dA_dc_tip = np.trapz(thickness_dist * i / num_sections, x_points, dx=dx) - dA_dspan += dA_ds - dA_droot_chord += dA_dc_root - dA_dtip_chord += dA_dc_tip - dweight_dspan += density * (section_area / num_sections - dA_ds * span / num_sections) - dmoment_x_dtwist[i] = -section_weight * (centroid_x * np.sin(twist_angle) + centroid_z * np.cos(twist_angle)) - dmoment_z_dtwist[i] = section_weight * (centroid_x * np.cos(twist_angle) - centroid_z * np.sin(twist_angle)) - dweight_dthickness[i] = density * span * chord / num_sections # dW_total / dthickness_dist -- vector value - - dweight_droot_chord = np.sum(density * A_ref * span / 2) # ((num_sections - 1) / (2 * num_sections)) ~ 1/2 for large N - dweight_dtip_chord = np.sum(density * A_ref * span / 2) # ((num_sections + 1) / (2 * num_sections)) ~ 1/2 for large N - - J['total_weight', 'span'] = dweight_dspan - J['total_weight', 'root_chord'] = dweight_droot_chord - J['total_weight', 'tip_chord'] = dweight_dtip_chord - J['total_weight', 'thickness_dist'] = dweight_dthickness - J['total_weight', 'twist'] = 0 - - dxcg_droot_chord = 0 - dzcg_droot_chord = 0 - dxcg_dtip_chord = 0 - dzcg_dtip_chord = 0 - for i, location in enumerate(span_locations): - dxcg_dcroot = np.sum( - np.trapz( - (x_points * thickness_dist * np.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * np.sin(twist)) * (1 - i / num_sections), x_points, dx=dx - ) - ) / np.sum(section_areas) - np.sum( - ( - np.trapz( - x_points * thickness_dist * chord_lengths * np.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * np.sin(twist), x_points, dx=dx - ) * np.trapz( - thickness_dist * (1 - i / num_sections), x_points, dx=dx - ) - ) - ) / np.sum(section_areas)**2 - dxcg_droot_chord += dxcg_dcroot - - dzcg_dcroot = np.sum( - np.trapz( - (x_points * thickness_dist * (1 - i / num_sections) * np.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist) * (1 - i / num_sections) * np.cos(twist), x_points, dx=dx - ) - ) / np.sum(section_areas) - np.sum( - np.trapz( - x_points * thickness_dist * chord_lengths * np.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * np.cos(twist), x_points, dx=dx - ) * dA_droot_chord - ) / np.sum(section_areas)**2 - dzcg_droot_chord += dzcg_dcroot - - dxcg_dctip = np.sum( - np.trapz( - (x_points * thickness_dist *np.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * np.sin(twist)) * (i / num_sections), x_points, dx=dx - ) / section_areas - ) - np.sum( - ( - np.trapz( - x_points * thickness_dist * chord_lengths * np.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * np.sin(twist), x_points, dx=dx - ) - ) * dA_dtip_chord - ) / np.sum(section_areas)**2 - dxcg_dtip_chord += dxcg_dctip - - dzcg_dctip = np.sum( - np.trapz( - x_points * thickness_dist * (i / num_sections) * np.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * (i / num_sections) * np.cos(twist), x_points, dx=dx - ) - ) / np.sum(section_areas) - np.sum( - np.trapz( - x_points * thickness_dist * chord_lengths * np.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * np.cos(twist), x_points, dx=dx - ) * dA_dtip_chord - ) / np.sum(section_areas)**2 - dzcg_dtip_chord += dzcg_dctip - - # partials of cog x - J['center_of_gravity_x', 'span'] = 0 - J['center_of_gravity_x', 'root_chord'] = dxcg_droot_chord - J['center_of_gravity_x', 'tip_chord'] = dxcg_dtip_chord - J['center_of_gravity_x', 'thickness_dist'] = np.sum( - np.trapz( - x_points * chord_lengths * np.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * chord_lengths * np.sin(twist), x_points, dx=dx - ) / section_areas - ) - ( - np.sum( - np.trapz(x_points * thickness_dist * chord_lengths * np.cos(twist) - self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist * chord_lengths * np.sin(twist), x_points, dx=dx) - ) * np.sum(chord_lengths) - ) / np.sum(section_areas)**2 - J['center_of_gravity_x', 'twist'] = dmoment_x_dtwist / total_weight - - # For center of gravity in y calculations - - sum_area_times_i = 0 - sum_darea_times_i = 0 - - for i in range(len(x_points)): - sum_area_times_i += i * section_areas[i] - sum_darea_times_i += i * dA_dspan # for cg_Y calculations - - dcg_y_dspan = np.sum(sum_area_times_i / (num_sections * section_areas)) #+ np.sum((span * sum_darea_times_i) / (num_sections * section_areas)) - np.sum((span * sum_area_times_i) / (num_sections * np.sum(section_areas)**2)) * dA_dspan - - # partials of cog y - J['center_of_gravity_y', 'span'] = dcg_y_dspan - J['center_of_gravity_y', 'root_chord'] = -total_moment_y / total_weight * dweight_droot_chord / total_weight - J['center_of_gravity_y', 'tip_chord'] = -total_moment_y / total_weight * dweight_dtip_chord / total_weight - J['center_of_gravity_y', 'thickness_dist'] = -total_moment_y / total_weight * dweight_dthickness / total_weight - J['center_of_gravity_y', 'twist'] = 0 - - # partials of cog z - J['center_of_gravity_z', 'span'] = 0 - J['center_of_gravity_z', 'root_chord'] = dzcg_droot_chord - J['center_of_gravity_z', 'tip_chord'] = dzcg_dtip_chord - J['center_of_gravity_z', 'thickness_dist'] = np.sum( - np.trapz( - x_points * chord_lengths * np.sin(twist) + self.airfoil_camber_line(x_points, camber, camber_location) * chord_lengths * np.cos(twist), x_points, dx=dx - ) - ) / np.sum( - section_areas - ) - J['center_of_gravity_z', 'twist'] = dmoment_z_dtwist / total_weight - - def precompute_airfoil_geometry(self): - num_sections = self.options['num_sections'] - n_points = num_sections - x_points = np.linspace(0, 1, n_points) - dx = 1 / (n_points - 1) - return x_points, dx - - def compute_airfoil_geometry(self, chord, camber, camber_location, thickness_dist, x_points, dx): - - #section_area, _ = quad(lambda x: np.interp(x, x_points, thickness_dist), 0, 1, limit=100) - section_area = np.trapz(thickness_dist, x_points, dx=dx) # trying np.trapz rather than quad to get rid of IntegrationWarning - section_area *= chord - - #centroid_x, _ = quad(lambda x: x * np.interp(x, x_points, thickness_dist), 0, 1, limit=100) - centroid_x = np.trapz(x_points * thickness_dist, x_points, dx=dx) - centroid_x = (centroid_x * chord) / section_area - - #centroid_z, _ = quad(lambda x: self.airfoil_camber_line(x, camber, camber_location) * np.interp(x, x_points, thickness_dist), 0, 1, limit=100) - centroid_z = np.trapz(self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist, x_points, dx=dx) - centroid_z = (centroid_z * chord) / section_area - return section_area, centroid_x, centroid_z - - def airfoil_thickness(self, x, max_thickness): - return 5 * max_thickness * (0.2969 * np.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) - - def airfoil_camber_line(self, x, camber, camber_location): - camber_location = max(camber_location, 1e-9) # Divide by zero check - return np.where( - x < camber_location, - (camber / camber_location**2) * (2 * camber_location * x - x**2), - (camber / (1 - camber_location)**2) * ((1 - 2 * camber_location) + 2 * camber_location * x - x**2) - ) - - def extract_airfoil_features(self, x_coords, y_coords): - """ - Extract camber, camber location, and max thickness from the given airfoil data. - This method assumes x_coords are normalized (ranging from 0 to 1). - """ - # Approximate the camber line and max thickness from the data - # Assume the camber line is the line of symmetry between the upper and lower surfaces - upper_surface = y_coords[:int(len(x_coords) // 2)] - lower_surface = y_coords[int(len(x_coords) // 2):] - x_upper = x_coords[:int(len(x_coords) // 2)] - x_lower = x_coords[int(len(x_coords) // 2):] - - upper_spline = CubicSpline(x_upper, upper_surface, bc_type='natural') - lower_spline = CubicSpline(x_lower, lower_surface, bc_type='natural') - - camber_line = (upper_spline(x_coords) + lower_spline(x_coords)) / 2.0 - - thickness = upper_spline(x_coords) - lower_spline(x_coords) - - max_thickness_index = np.argmax(thickness) - max_thickness_value = thickness[max_thickness_index] - - camber_slope = np.gradient(camber_line, x_coords) - camber_location_index = np.argmax(np.abs(camber_slope)) - camber_location = x_coords[camber_location_index] - - camber = camber_line[camber_location_index] - - return camber, camber_location, max_thickness_value, thickness, camber_line - - -# Build OpenMDAO problem -prob = om.Problem() - -# Add the center of gravity component -prob.model.add_subsystem('cog', WingMassAndCOG() , promotes_inputs=['span', 'root_chord', 'tip_chord', 'twist', 'thickness_dist']) - -n_points = 1000 # = num_sections -x = np.linspace(0, 1, n_points) -max_thickness_chord_ratio = 0.12 -thickness_dist = 5 * max_thickness_chord_ratio * (0.2969 * np.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) - -# Setup the problem -prob.setup() - -# Define some example inputs -prob.set_val('span', 2.438) -prob.set_val('root_chord', 0.3722) -prob.set_val('tip_chord', 0.2792) -prob.set_val('twist', np.linspace(0, 0, 1000)) -#prob.set_val('thickness_dist', thickness_dist) - - -prob.model.cog.options['airfoil_data_file'] = 'Clark_Y.dat' -prob.model.cog.options['material'] = 'wood' -#prob.model.cog.options['airfoil_type'] = '2412' - -# Run the model -prob.run_model() - -# Get the results -center_of_gravity_x = prob.get_val('cog.center_of_gravity_x') -center_of_gravity_y = prob.get_val('cog.center_of_gravity_y') -center_of_gravity_z = prob.get_val('cog.center_of_gravity_z') -total_weight = prob.get_val('cog.total_weight') - -#data = prob.check_partials(compact_print=True, method='cs') -#om.partial_deriv_plot(data) - -print(f"Center of gravity: X = {center_of_gravity_x} m, Y = {center_of_gravity_y} m, Z = {center_of_gravity_z} m") -print(f"Total weight of the wing: {total_weight} kg") - From 3a95cf006e9d94d20645353b9e8bbb3eff2dcc11 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Mon, 12 May 2025 14:36:45 -0400 Subject: [PATCH 046/147] Delete aviary/docs/examples/test_wing.py --- aviary/docs/examples/test_wing.py | 42 ------------------------------- 1 file changed, 42 deletions(-) delete mode 100644 aviary/docs/examples/test_wing.py diff --git a/aviary/docs/examples/test_wing.py b/aviary/docs/examples/test_wing.py deleted file mode 100644 index 7ec5f07ff..000000000 --- a/aviary/docs/examples/test_wing.py +++ /dev/null @@ -1,42 +0,0 @@ -import unittest - -import openmdao.api as om -from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal - - - -class WingMassTestCase(unittest.TestCase): - """ - Wing mass test case - - """ - - def setUp(self): - - #self.prob = om.Problem() - #self.prob.model.add_subsystem( - # "wing", - # WingMassAndCOG(), - # promotes_inputs=["*"], - # promotes_outputs=['*'], - #) - - self.prob.model.set_input_defaults( - "wing_mass", val=10, units="kg" - ) - - self.prob.setup(check=False, force_alloc_complex=True) - - def test_case(self): - - self.prob.run_model() - - tol = 1e-10 - assert_near_equal(self.prob["wing_mass"], 100, tol) # Need to calculate first -- filler value for now - - partial_data = self.prob.check_partials(out_stream=None, method="fd") # finite difference used because cs is used in wing.py calculation - assert_check_partials(partial_data, atol=1e-15, rtol=1e-15) - - -if __name__ == "__main__": - unittest.main() \ No newline at end of file From d988607c9c3774b674ac8c2ed9e7b2a66c4e615f Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Mon, 12 May 2025 14:36:58 -0400 Subject: [PATCH 047/147] Delete aviary/docs/examples/tail.py --- aviary/docs/examples/tail.py | 289 ----------------------------------- 1 file changed, 289 deletions(-) delete mode 100644 aviary/docs/examples/tail.py diff --git a/aviary/docs/examples/tail.py b/aviary/docs/examples/tail.py deleted file mode 100644 index 84d61f1ee..000000000 --- a/aviary/docs/examples/tail.py +++ /dev/null @@ -1,289 +0,0 @@ -import openmdao.api as om -import numpy as np -import scipy.integrate as spi -from scipy.interpolate import interp1d -from scipy.interpolate import CubicSpline -import os - -# Material densities, all in kg/m^3 -MATERIALS = { - 'Aluminum': 2700, - 'Steel': 7850, - 'Titanium': 4500, - 'Carbon Fiber': 1600, - 'Wood': 600 -} - -class TailMassAndCOG(om.ExplicitComponent): - def initialize(self): - self.options.declare('tail_type', - default='horizontal', - values=['horizontal', 'vertical'], - desc="Type of tail: 'horizontal' or 'vertical'") - - self.options.declare('airfoil_type', - default='NACA', - values=['NACA', 'file'], - desc="Airfoil type: 'NACA' for 4-digit or 'file' for user-provided coordinates") - - if self.options['airfoil_type'] == 'NACA': - self.options.declare('NACA_digits', - default='2412', - desc="4 digit code for NACA airfoil, if that is given.") - - self.options.declare('material', - default='Aluminum', - values=list(MATERIALS.keys()), - desc="Material type") - - self.options.declare('airfoil_file', - default=None, - desc="File path for airfoil coordinates (if applicable)") - - self.options.declare('num_sections', - default=1000, - desc="Number of sections for enumeration") - - def setup(self): - # Inputs - self.add_input('span', - val=5.0, - units='m', - desc="Tail span") - - self.add_input('root_chord', - val=1.2, - units='m', - desc="Root chord length") - - self.add_input('tip_chord', - val=0.8, - units='m', - desc="Tip chord length") - - self.add_input('thickness_ratio', - val=0.12, - desc="Max thickness to chord ratio for NACA airfoil") - - self.add_input('skin_thickness', - val=0.002, - units='m', - desc="Skin panel thickness") - - self.add_input('twist', - val=np.zeros(self.options['num_sections']), - units='deg', - desc="Twist distribution") - - # Outputs - self.add_output('mass', - val=0.0, - units='kg', - desc="Total mass of the tail") - - self.add_output('cg_x', - val=0.0, - units='m', - desc="X location of the center of gravity") - - self.add_output('cg_y', - val=0.0, - units='m', - desc="Y location of the center of gravity") - - self.add_output('cg_z', - val=0.0, - units='m', - desc="Z location of the center of gravity") - - def compute(self, inputs, outputs): - tail_type = self.options["tail_type"] - airfoil_type = self.options["airfoil_type"] - material = self.options['material'] - span = inputs['span'] - root_chord = inputs['root_chord'] - tip_chord = inputs['tip_chord'] - thickness_ratio = inputs['thickness_ratio'] - density = MATERIALS[material] - airfoil_file = self.options['airfoil_file'] - skin_thickness = inputs['skin_thickness'] - num_sections = self.options['num_sections'] - twist = inputs['twist'] - NACA_digits = self.options['NACA_digits'] - - # File check - if airfoil_type == 'file': - if airfoil_type == 'file' and (airfoil_file is None or not os.path.isfile(airfoil_file)): - raise FileNotFoundError(f"Airfoil file '{airfoil_file}' not found or not provided.") - try: - airfoil_data = np.loadtxt(airfoil_file, skiprows=1) # Assume a header - x_coords, y_coords = airfoil_data[:, 0], airfoil_data[:, 1] - except Exception as e: - raise ValueError(f"Error reading airfoil file: {e}") - - # Compute section airfoil geometry - if airfoil_file and os.path.exists(airfoil_file): - airfoil_data = np.loadtxt(airfoil_file) - x_coords = airfoil_data[:, 0] - y_coords = airfoil_data[:, 1] - - camber, camber_location, max_thickness = self.extract_airfoil_features(x_coords, y_coords) - else: - # Parse the NACA airfoil type (4-digit) - camber = int(NACA_digits[0]) / 100.0 # Maximum camber - camber_location = int(NACA_digits[1]) / 10.0 # Location of max camber - max_thickness = int(NACA_digits[2:4]) / 100.0 # Max thickness - - # Tail type check - if tail_type not in ['horizontal', 'vertical']: - raise ValueError("Invalid tail_type. Must be 'horizontal' or 'vertical'.") - - # Input validation checks - if span <= 0: - raise ValueError("Span must be greater than zero.") - - if root_chord <= 0 or tip_chord <= 0: - raise ValueError("Root chord and tip chord must be greater than zero.") - - if tip_chord > root_chord: - raise ValueError("Tip chord cannot be larger than root chord.") - - if thickness_ratio <= 0: - raise ValueError("Thickness ratio must be greater than zero.") - - if skin_thickness <= 0: - raise ValueError("Skin thickness must be greater than zero.") - - if any(abs(twist)) > np.pi / 2: - raise ValueError("Twist angle is too extreme; must be within -90 to 90 degrees.") - - span_locations = np.linspace(0, span, num_sections) - - # Get x_points and dx for later - x_points, dx = self.precompute_airfoil_geometry() - - # Thickness distribution - thickness_dist = self.airfoil_thickness(x_points, max_thickness) - - total_mass = 0 - total_moment_x = 0 - total_moment_y = 0 - total_moment_z = 0 - - for i, y in enumerate(span_locations): - section_chord = root_chord - (root_chord - tip_chord) * (y / span) # Assume linear variation in chord - section_area, centroid_x, centroid_z = self.compute_airfoil_geometry(section_chord, - camber, - camber_location, - thickness_dist, - x_points, - dx) - - - section_mass = density * section_area * (span / num_sections) - - # Twist - twist_angle = twist[i] - rotated_x = centroid_x * np.cos(twist_angle) - centroid_z * np.sin(twist_angle) - rotated_z = centroid_x * np.sin(twist_angle) + centroid_z * np.cos(twist_angle) - - total_mass += section_mass - total_moment_x += rotated_x * section_mass - if tail_type == 'horizontal': - total_moment_y += y * section_mass - total_moment_z += rotated_z * section_mass - elif tail_type == 'vertical': - total_moment_y += rotated_z * section_mass - total_moment_z += y * section_mass - - # COG - outputs['mass'] = total_mass - outputs['cg_x'] = total_moment_x / total_mass - outputs['cg_y'] = total_moment_y / total_mass - outputs['cg_z'] = total_moment_z / total_mass - - def precompute_airfoil_geometry(self): - num_sections = self.options['num_sections'] - n_points = num_sections - x_points = np.linspace(0, 1, n_points) - dx = 1 / (n_points - 1) - return x_points, dx - - def compute_airfoil_geometry(self, chord, camber, camber_location, thickness_dist, x_points, dx): - - #section_area, _ = quad(lambda x: np.interp(x, x_points, thickness_dist), 0, 1, limit=100) - section_area = np.trapz(thickness_dist, x_points, dx=dx) - section_area *= chord - - #centroid_x, _ = quad(lambda x: x * np.interp(x, x_points, thickness_dist), 0, 1, limit=100) - centroid_x = np.trapz(x_points * thickness_dist, x_points, dx=dx) - centroid_x = (centroid_x * chord) / section_area - - #centroid_z, _ = quad(lambda x: self.airfoil_camber_line(x, camber, camber_location) * np.interp(x, x_points, thickness_dist), 0, 1, limit=100) - centroid_z = np.trapz(self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist, x_points, dx=dx) - centroid_z = (centroid_z * chord) / section_area - return section_area, centroid_x, centroid_z - - def airfoil_thickness(self, x, max_thickness): - return 5 * max_thickness * (0.2969 * np.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) - - def airfoil_camber_line(self, x, camber, camber_location): - camber_location = max(camber_location, 1e-9) # Divide by zero check - return np.where( - x < camber_location, - (camber / camber_location**2) * (2 * camber_location * x - x**2), - (camber / (1 - camber_location)**2) * ((1 - 2 * camber_location) + 2 * camber_location * x - x**2) - ) - - def extract_airfoil_features(self, x_coords, y_coords): - """ - Extract camber, camber location, and max thickness from the given airfoil data. - This method assumes x_coords are normalized (ranging from 0 to 1). - """ - # Approximate the camber line and max thickness from the data - # Assume the camber line is the line of symmetry between the upper and lower surfaces - upper_surface = y_coords[:int(len(x_coords) // 2)] - lower_surface = y_coords[int(len(x_coords) // 2):] - x_upper = x_coords[:int(len(x_coords) // 2)] - x_lower = x_coords[int(len(x_coords) // 2):] - - upper_spline = CubicSpline(x_upper, upper_surface, bc_type='natural') - lower_spline = CubicSpline(x_lower, lower_surface, bc_type='natural') - - camber_line = (upper_spline(x_coords) + lower_spline(x_coords)) / 2.0 - - thickness = upper_spline(x_coords) - lower_spline(x_coords) - - max_thickness_index = np.argmax(thickness) - max_thickness_value = thickness[max_thickness_index] - - camber_slope = np.gradient(camber_line, x_coords) - camber_location_index = np.argmax(np.abs(camber_slope)) - camber_location = x_coords[camber_location_index] - - camber = camber_line[camber_location_index] - - return camber, camber_location, max_thickness_value - - -prob = om.Problem() - -prob.model.add_subsystem('tail', TailMassAndCOG(), promotes_inputs=['*'], promotes_outputs=['*']) - -prob.setup() - -# Input values -prob.set_val('span', 0.3912) -prob.set_val('tip_chord', 0.15) -prob.set_val('root_chord', 0.26) -prob.set_val('thickness_ratio', 0.12) -prob.set_val('skin_thickness', 0.002) -prob.model.tail.options['tail_type'] = 'vertical' - -prob.model.tail.options['material'] = 'Carbon Fiber' - -prob.run_model() - -# Print -print(f"Mass: {prob.get_val('mass')} kg") -print(f"Center of gravity (X: {prob.get_val('cg_x')} m, Y: {prob.get_val('cg_y')} m, Z: {prob.get_val('cg_z')} m)") \ No newline at end of file From 018d8deb310d93b192309c01fb31b042c58215a3 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Mon, 12 May 2025 14:37:07 -0400 Subject: [PATCH 048/147] Delete aviary/docs/examples/test_mass_summation.py --- aviary/docs/examples/test_mass_summation.py | 233 -------------------- 1 file changed, 233 deletions(-) delete mode 100644 aviary/docs/examples/test_mass_summation.py diff --git a/aviary/docs/examples/test_mass_summation.py b/aviary/docs/examples/test_mass_summation.py deleted file mode 100644 index 32d08235b..000000000 --- a/aviary/docs/examples/test_mass_summation.py +++ /dev/null @@ -1,233 +0,0 @@ -import unittest - -import numpy as np -import jax.numpy as jnp -import openmdao.api as om -from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal - - -""" -The little bit of path code below is not important overall. This is for me to test -within the Docker container and VS Code before I push everything fully to the Github -repository. These lines can be deleted as things are updated further. - -""" - -import sys -import os - - -module_path = os.path.abspath("/home/omdao/Aviary/aviary/subsystems/mass") -if module_path not in sys.path: - sys.path.append(module_path) - -from simple_mass.fuselage import FuselageMassAndCOG -from simple_mass.wing import WingMassAndCOG -from simple_mass.tail import TailMassAndCOG -from simple_mass.mass_summation import MassSummation, StructureMass - -class MassSummationTest(unittest.TestCase): - """ - Total mass summation test case. - - """ - - def test_case(self): - self.prob = om.Problem() - - self.prob.model.add_subsystem( - 'tot', - MassSummation(), - promotes_inputs=['*'], - promotes_outputs=['*'] - ) - - # self.prob.model.set_input_defaults( - # 'span', - # val=1.0, - # units='m' - # ) - - # self.prob.model.set_input_defaults( - # 'span_tail', - # val=1.0, - # units='m' - # ) - - # self.prob.model.set_input_defaults( - # "root_chord", - # val=1, - # units="m" - # ) - - # self.prob.model.set_input_defaults( - # "root_chord_tail", - # val=1, - # units="m" - # ) - - # self.prob.model.set_input_defaults( - # "tip_chord", - # val=0.5, - # units="m" - # ) - - # self.prob.model.set_input_defaults( - # "tip_chord_tail", - # val=0.5, - # units="m" - # ) - - # self.prob.model.set_input_defaults( - # "thickness_ratio", - # val=0.12 - # ) - - # self.prob.model.set_input_defaults( - # "skin_thickness", - # val=0.002, - # units="m" - # ) - - # self.prob.model.set_input_defaults( - # "twist", - # val=jnp.zeros(10), - # units="deg" - # ) - - # self.prob.model.set_input_defaults( - # "twist_tail", - # val=jnp.zeros(10), - # units="deg" - # ) - - # self.prob.model.set_input_defaults( - # "length", - # val=2.5, - # units="m") - - # self.prob.model.set_input_defaults( - # "diameter", - # val=0.5, - # units="m" - # ) - - # self.prob.model.set_input_defaults( - # "taper_ratio", - # val=0.5 - # ) - - # self.prob.model.set_input_defaults( - # "curvature", - # val=0.0, - # units="m" - # ) - - # self.prob.model.set_input_defaults( - # "y_offset", - # val=0.0, - # units="m" - # ) - - # self.prob.model.set_input_defaults( - # "z_offset", - # val=0.0, - # units="m" - # ) - - # self.prob.model.set_input_defaults( - # 'thickness', - # val=0.05, - # units='m' - # ) - - # self.prob.model.set_input_defaults( - # "is_hollow", - # val=True - # ) - - # n_points = 10 # = num_sections - # x = jnp.linspace(0, 1, n_points) - # max_thickness_chord_ratio = 0.12 - # thickness_dist = 5 * max_thickness_chord_ratio * (0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) - - # self.prob.model.set_input_defaults( - # "thickness_dist", - # val=thickness_dist, - # units="m" - # ) - - self.prob.setup( - check=False, - force_alloc_complex=True - ) - - self.prob.run_model() - - om.n2(self.prob) - - tol = 1e-10 - assert_near_equal( - self.prob['total_weight_wing'], - 4.22032, - tol - ) - - partial_data = self.prob.check_partials( - out_stream=None, - method="cs" - ) - - assert_check_partials( - partial_data - ) - - -class StructureMassTest(unittest.TestCase): - """ - Total structure summation mass test case. - - """ - - def setUp(self): - self.prob = om.Problem() - - self.prob.model.add_subsystem( - "tot", - StructureMass(), - promotes_inputs=['*'], - promotes_outputs=['*'], - ) - - self.prob.setup( - check=False, - force_alloc_complex=True - ) - - self.prob.set_val('fuse_mass', val=100.0) - self.prob.set_val('wing_mass', val=4.2) - self.prob.set_val('tail_mass', val=4.25) - - def test_case(self): - - self.prob.run_model() - - tol = 1e-10 - assert_near_equal( - self.prob['structure_mass'], - 108.45, - tol - ) - - partial_data = self.prob.check_partials( - out_stream=None, - method="cs" - ) - - assert_check_partials(partial_data) - -if __name__ == "__main__": - unittest.main() - - - From c9fa3f469eafd714c33729f58c4b13321abc66b9 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Mon, 12 May 2025 14:37:19 -0400 Subject: [PATCH 049/147] Delete aviary/docs/examples/materials_database.py --- aviary/docs/examples/materials_database.py | 66 ---------------------- 1 file changed, 66 deletions(-) delete mode 100644 aviary/docs/examples/materials_database.py diff --git a/aviary/docs/examples/materials_database.py b/aviary/docs/examples/materials_database.py deleted file mode 100644 index 77b0fb5f4..000000000 --- a/aviary/docs/examples/materials_database.py +++ /dev/null @@ -1,66 +0,0 @@ -""" -Database for various material densities that are to be used for mass calculations for small aircraft in particular. - -This database will be expanded as needed. - -""" -from aviary.utils.named_values import NamedValues - -materials = NamedValues() - -""" -All densities below came from https://tpsx.arc.nasa.gov/MaterialsDatabase - -""" - -# Wood -materials.set_val('Balsa', 130, units='kg/m**3') -materials.set_val('Cypress', 460, units='kg/m**3') -materials.set_val('Mahogany', 540, units='kg/m**3') -materials.set_val('Maple', 710, units='kg/m**3') -materials.set_val('Teak', 640, units='kg/m**3') - -# Aluminum Compounds and Alloys -materials.set_val('Aluminum Oxide', 3400, units='kg/m**3') -materials.set_val('2024-T8XX', 2800, units='kg/m**3') # aircraft-grade strength Aluminum alloy -materials.set_val('2219-T8XX', 2810, units='kg/m**3') # Exceptionally strong Aluminum alloy -materials.set_val('2024-T6', 2770, units='kg/m**3') # Another Aluminum alloy -materials.set_val('Aluminum Foam', 1300, units='kg/m**3') - -# Steel -materials.set_val('Stainless Steel 17-4 PH', 7830, units='kg/m**3') # 17-4 PH stainless steel -materials.set_val('Stainless Steel-AISI 302', 8060, units='kg/m**3') # AISI 302 -materials.set_val('Stainless Steel-AISI 304', 7900, units='kg/m**3') # AISI 304 -materials.set_val('Steel Alloy Cast', 7830, units='kg/m**3') # General steel alloy cast -materials.set_val('Steel 321', 8030, units='kg/m**3') # Steel type 321 - -# Carbon Fibers / Carbon - Silicon Fibers -materials.set_val('Carbon/Silicon-Carbide', 2080, units='kg/m**3') # Carbon fiber reinforced SiC -materials.set_val('Silicon-Carbide/Silicon-Carbide', 2400, units='kg/m**3') # SiC fiber reinforced SiC matrix -materials.set_val('Advanced Carbon-Carbon Composite', 1600, units='kg/m**3') # ACC -materials.set_val('Reinfoced Carbon-Carbon', 1580, units='kg/m**3') -materials.set_val('Reinforced Carbon-Carbon Composite', 1580, units='kg/m**3') # Generally, ACC is better, but RCC is slightly cheaper - -""" -Below are miscellaneous values that could be of importance, particularly for small aircraft. - -These values were found from a variety of sources, and depending on the source/brand, the density -could be slightly different. For some cases, temperature of the material also matters (typically -the values are provided as a relative density). If there is a temperature dependence from the source, -it will be noted as a comment next to the line where the material value is set. Below are some sources -for various values. - -The values below were not explicity listed from the above source. - -Wood glue: https://www.gorillatough.com/wp-content/uploads/Gorilla-Wood-Glue-v1.2.pdf - -EPS Foam: https://www.abtfoam.com/wp-content/uploads/2020/05/EPS-Standard-Sheet-Sizes-Densities-and-R-values.pdf - Note that there is a density range given, along with different types. The density value used is for Type I, - and the value given is the average of the minimum and maximum within the range provided. The base unit in - this document is pcf for the density. It was converted to kg/m^3 for the actual value input. - -""" - -materials.set_val('Wood Glue', 1080, units='kg/m**3') # Relative density value -- corresponds to 25 C (77 F) -materials.set_val('EPS Foam', 16.3388, units='kg/m**3') - From 53d3016db31af52111546b687e83d379521ac321 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Mon, 12 May 2025 14:37:28 -0400 Subject: [PATCH 050/147] Delete aviary/docs/examples/Clark_Y.dat --- aviary/docs/examples/Clark_Y.dat | 122 ------------------------------- 1 file changed, 122 deletions(-) delete mode 100644 aviary/docs/examples/Clark_Y.dat diff --git a/aviary/docs/examples/Clark_Y.dat b/aviary/docs/examples/Clark_Y.dat deleted file mode 100644 index 3649ca4e2..000000000 --- a/aviary/docs/examples/Clark_Y.dat +++ /dev/null @@ -1,122 +0,0 @@ -0.0000000 0.0000000 -0.0005000 0.0023390 -0.0010000 0.0037271 -0.0020000 0.0058025 -0.0040000 0.0089238 -0.0080000 0.0137350 -0.0120000 0.0178581 -0.0200000 0.0253735 -0.0300000 0.0330215 -0.0400000 0.0391283 -0.0500000 0.0442753 -0.0600000 0.0487571 -0.0800000 0.0564308 -0.1000000 0.0629981 -0.1200000 0.0686204 -0.1400000 0.0734360 -0.1600000 0.0775707 -0.1800000 0.0810687 -0.2000000 0.0839202 -0.2200000 0.0861433 -0.2400000 0.0878308 -0.2600000 0.0890840 -0.2800000 0.0900016 -0.3000000 0.0906804 -0.3200000 0.0911857 -0.3400000 0.0915079 -0.3600000 0.0916266 -0.3800000 0.0915212 -0.4000000 0.0911712 -0.4200000 0.0905657 -0.4400000 0.0897175 -0.4600000 0.0886427 -0.4800000 0.0873572 -0.5000000 0.0858772 -0.5200000 0.0842145 -0.5400000 0.0823712 -0.5600000 0.0803480 -0.5800000 0.0781451 -0.6000000 0.0757633 -0.6200000 0.0732055 -0.6400000 0.0704822 -0.6600000 0.0676046 -0.6800000 0.0645843 -0.7000000 0.0614329 -0.7200000 0.0581599 -0.7400000 0.0547675 -0.7600000 0.0512565 -0.7800000 0.0476281 -0.8000000 0.0438836 -0.8200000 0.0400245 -0.8400000 0.0360536 -0.8600000 0.0319740 -0.8800000 0.0277891 -0.9000000 0.0235025 -0.9200000 0.0191156 -0.9400000 0.0146239 -0.9600000 0.0100232 -0.9700000 0.0076868 -0.9800000 0.0053335 -0.9900000 0.0029690 -1.0000000 0.0005993 -0.0000000 0.0000000 -0.0005000 -.0046700 -0.0010000 -.0059418 -0.0020000 -.0078113 -0.0040000 -.0105126 -0.0080000 -.0142862 -0.0120000 -.0169733 -0.0200000 -.0202723 -0.0300000 -.0226056 -0.0400000 -.0245211 -0.0500000 -.0260452 -0.0600000 -.0271277 -0.0800000 -.0284595 -0.1000000 -.0293786 -0.1200000 -.0299633 -0.1400000 -.0302404 -0.1600000 -.0302546 -0.1800000 -.0300490 -0.2000000 -.0296656 -0.2200000 -.0291445 -0.2400000 -.0285181 -0.2600000 -.0278164 -0.2800000 -.0270696 -0.3000000 -.0263079 -0.3200000 -.0255565 -0.3400000 -.0248176 -0.3600000 -.0240870 -0.3800000 -.0233606 -0.4000000 -.0226341 -0.4200000 -.0219042 -0.4400000 -.0211708 -0.4600000 -.0204353 -0.4800000 -.0196986 -0.5000000 -.0189619 -0.5200000 -.0182262 -0.5400000 -.0174914 -0.5600000 -.0167572 -0.5800000 -.0160232 -0.6000000 -.0152893 -0.6200000 -.0145551 -0.6400000 -.0138207 -0.6600000 -.0130862 -0.6800000 -.0123515 -0.7000000 -.0116169 -0.7200000 -.0108823 -0.7400000 -.0101478 -0.7600000 -.0094133 -0.7800000 -.0086788 -0.8000000 -.0079443 -0.8200000 -.0072098 -0.8400000 -.0064753 -0.8600000 -.0057408 -0.8800000 -.0050063 -0.9000000 -.0042718 -0.9200000 -.0035373 -0.9400000 -.0028028 -0.9600000 -.0020683 -0.9700000 -.0017011 -0.9800000 -.0013339 -0.9900000 -.0009666 -1.0000000 -.0005993 \ No newline at end of file From bf165f807697cdf493eee34dda5e3c3949628d01 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Mon, 12 May 2025 14:37:34 -0400 Subject: [PATCH 051/147] Delete aviary/docs/examples/Clark_Y.yaml --- aviary/docs/examples/Clark_Y.yaml | 122 ------------------------------ 1 file changed, 122 deletions(-) delete mode 100644 aviary/docs/examples/Clark_Y.yaml diff --git a/aviary/docs/examples/Clark_Y.yaml b/aviary/docs/examples/Clark_Y.yaml deleted file mode 100644 index 3649ca4e2..000000000 --- a/aviary/docs/examples/Clark_Y.yaml +++ /dev/null @@ -1,122 +0,0 @@ -0.0000000 0.0000000 -0.0005000 0.0023390 -0.0010000 0.0037271 -0.0020000 0.0058025 -0.0040000 0.0089238 -0.0080000 0.0137350 -0.0120000 0.0178581 -0.0200000 0.0253735 -0.0300000 0.0330215 -0.0400000 0.0391283 -0.0500000 0.0442753 -0.0600000 0.0487571 -0.0800000 0.0564308 -0.1000000 0.0629981 -0.1200000 0.0686204 -0.1400000 0.0734360 -0.1600000 0.0775707 -0.1800000 0.0810687 -0.2000000 0.0839202 -0.2200000 0.0861433 -0.2400000 0.0878308 -0.2600000 0.0890840 -0.2800000 0.0900016 -0.3000000 0.0906804 -0.3200000 0.0911857 -0.3400000 0.0915079 -0.3600000 0.0916266 -0.3800000 0.0915212 -0.4000000 0.0911712 -0.4200000 0.0905657 -0.4400000 0.0897175 -0.4600000 0.0886427 -0.4800000 0.0873572 -0.5000000 0.0858772 -0.5200000 0.0842145 -0.5400000 0.0823712 -0.5600000 0.0803480 -0.5800000 0.0781451 -0.6000000 0.0757633 -0.6200000 0.0732055 -0.6400000 0.0704822 -0.6600000 0.0676046 -0.6800000 0.0645843 -0.7000000 0.0614329 -0.7200000 0.0581599 -0.7400000 0.0547675 -0.7600000 0.0512565 -0.7800000 0.0476281 -0.8000000 0.0438836 -0.8200000 0.0400245 -0.8400000 0.0360536 -0.8600000 0.0319740 -0.8800000 0.0277891 -0.9000000 0.0235025 -0.9200000 0.0191156 -0.9400000 0.0146239 -0.9600000 0.0100232 -0.9700000 0.0076868 -0.9800000 0.0053335 -0.9900000 0.0029690 -1.0000000 0.0005993 -0.0000000 0.0000000 -0.0005000 -.0046700 -0.0010000 -.0059418 -0.0020000 -.0078113 -0.0040000 -.0105126 -0.0080000 -.0142862 -0.0120000 -.0169733 -0.0200000 -.0202723 -0.0300000 -.0226056 -0.0400000 -.0245211 -0.0500000 -.0260452 -0.0600000 -.0271277 -0.0800000 -.0284595 -0.1000000 -.0293786 -0.1200000 -.0299633 -0.1400000 -.0302404 -0.1600000 -.0302546 -0.1800000 -.0300490 -0.2000000 -.0296656 -0.2200000 -.0291445 -0.2400000 -.0285181 -0.2600000 -.0278164 -0.2800000 -.0270696 -0.3000000 -.0263079 -0.3200000 -.0255565 -0.3400000 -.0248176 -0.3600000 -.0240870 -0.3800000 -.0233606 -0.4000000 -.0226341 -0.4200000 -.0219042 -0.4400000 -.0211708 -0.4600000 -.0204353 -0.4800000 -.0196986 -0.5000000 -.0189619 -0.5200000 -.0182262 -0.5400000 -.0174914 -0.5600000 -.0167572 -0.5800000 -.0160232 -0.6000000 -.0152893 -0.6200000 -.0145551 -0.6400000 -.0138207 -0.6600000 -.0130862 -0.6800000 -.0123515 -0.7000000 -.0116169 -0.7200000 -.0108823 -0.7400000 -.0101478 -0.7600000 -.0094133 -0.7800000 -.0086788 -0.8000000 -.0079443 -0.8200000 -.0072098 -0.8400000 -.0064753 -0.8600000 -.0057408 -0.8800000 -.0050063 -0.9000000 -.0042718 -0.9200000 -.0035373 -0.9400000 -.0028028 -0.9600000 -.0020683 -0.9700000 -.0017011 -0.9800000 -.0013339 -0.9900000 -.0009666 -1.0000000 -.0005993 \ No newline at end of file From 2bca1b9b939f86dc4f1cc68ea08aa3b2524b2f81 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Mon, 12 May 2025 14:37:43 -0400 Subject: [PATCH 052/147] Delete aviary/docs/examples/C:UsersszoppeltDesktop --- aviary/docs/examples/C:UsersszoppeltDesktop | 231 -------------------- 1 file changed, 231 deletions(-) delete mode 100644 aviary/docs/examples/C:UsersszoppeltDesktop diff --git a/aviary/docs/examples/C:UsersszoppeltDesktop b/aviary/docs/examples/C:UsersszoppeltDesktop deleted file mode 100644 index 383c06e15..000000000 --- a/aviary/docs/examples/C:UsersszoppeltDesktop +++ /dev/null @@ -1,231 +0,0 @@ -import openmdao.api as om -import numpy as np -import matplotlib.pyplot as plt -import os -from scipy.interpolate import CubicSpline - -# Material densities (g/cm³ converted to kg/m³) -- these are just some random examples -MATERIAL_DENSITIES = { - 'wood': 600, # This isn't even a real wood density that I'm aware of, I just made it up for the sake of debugging - 'metal': 2700, # Aluminum - 'carbon_fiber': 1600 -} - - - -class CenterOfGravity3D(om.ExplicitComponent): - def initialize(self): - self.options.declare('num_sections', types=int, default=50) - self.options.declare('airfoil_type', types=str, default='2412') # use 2412 as example for default - self.options.declare('material', default='metal', values=['wood', 'metal', 'carbon_fiber']) - self.options.declare('airfoil_data_file', default=None, types=str) # For user-provided airfoil data file - - def setup(self): - # Inputs - self.add_input('span', val=10.0, units='m') # Full wingspan (adjustable) - self.add_input('root_chord', val=2.0, units='m') # Root chord length - self.add_input('tip_chord', val=1.0, units='m') # Tip chord length - self.add_input('twist', val=np.zeros(self.options['num_sections']), units='deg') # Twist angles - self.add_input('thickness', val=0.2, units='m') # Thickness of the wing (height) - - - # Outputs - self.add_output('center_of_gravity_x', val=0.0, units='m') - self.add_output('center_of_gravity_y', val=0.0, units='m') - self.add_output('center_of_gravity_z', val=0.0, units='m') - self.add_output('total_weight', val=0.0, units='kg') - self.add_output('x_coords', val=np.zeros(self.options['num_sections']), units='m') - self.add_output('y_coords', val=np.zeros(self.options['num_sections']), units='m') - self.add_output('z_coords', val=np.zeros(self.options['num_sections']), units='m') - - - def compute(self, inputs, outputs): - span = inputs['span'] - root_chord = inputs['root_chord'] - tip_chord = inputs['tip_chord'] - twist = np.radians(inputs['twist']) # Convert twist to radians - thickness = inputs['thickness'] - material = self.options['material'] # Material is taken from options - num_sections = self.options['num_sections'] - airfoil_type = self.options['airfoil_type'] # NACA airfoil type - airfoil_data_file = self.options['airfoil_data_file'] - - # Get material density - density = MATERIAL_DENSITIES[material] # in kg/m³ - - if airfoil_data_file: - airfoil_data = np.loadtxt(airfoil_data_file) - x_coords = airfoil_data[:, 0] - y_coords = airfoil_data[:, 1] - - camber, camber_location, max_thickness = self.extract_airfoil_features(x_coords, y_coords) - else: - # Parse the NACA airfoil type (4-digit) - camber = int(airfoil_type[0]) / 100.0 # Maximum camber - camber_location = int(airfoil_type[1]) / 10.0 # Location of max camber - max_thickness = int(airfoil_type[2:4]) / 100.0 # Max thickness - - # Wing spanwise distribution - span_locations = np.linspace(0, span, num_sections) - - # Initialize total weight and moment accumulators - total_weight = 0 - total_moment_x = 0 - total_moment_y = 0 - total_moment_z = 0 - - # Arrays for storing 3D coordinates of the wing - x_coords = [] - y_coords = [] - z_coords = [] - top_coords = [] - bottom_coords = [] - - # Loop over each section along the span (3D wing approximation) - for i, location in enumerate(span_locations): - # Calculate the chord for this section - chord = root_chord - (root_chord - tip_chord) * (location / span) # Assuming linear variation from root to tip - - # Apply twist - twist_angle = twist[i] - - # Calculate the camber and thickness distribution - # Airfoil thickness distribution using the NACA Equation - def airfoil_thickness(x): - return 5 * max_thickness * (0.2969 * np.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) - - # Airfoil camber line (NACA 4-digit) - def airfoil_camber_line(x, camber, camber_location): - if x < camber_location: - return (camber / camber_location**2) * (2 * camber_location * x - x**2) - else: - return (camber / (1 - camber_location)**2) * ((1 - 2 * camber_location) + 2 * camber_location * x - x**2) - - # Numerical integration: sum up the areas using small segments along the chord - n_points = 100 - x_points = np.linspace(0, 1, n_points) - dx = 1 / (n_points - 1) - - area = 0 # Cross-sectional area of the wing section - centroid_x = 0 - centroid_z = 0 - - for x in x_points: - # Thickness at each point along the chord - thickness_at_x = airfoil_thickness(x) * chord - # Camber at each point (for z-coordinate) - camber_at_x = airfoil_camber_line(x, camber, camber_location) * chord - - # Area of small rectangle at x - area += thickness_at_x * dx - - centroid_x += (x * thickness_at_x) * dx - centroid_z += (camber_at_x * thickness_at_x) * dx - # Weight of this section (density * area * thickness) - section_weight = density * area * thickness # Volume approximation - - # Normalize - if area > 0: - centroid_x /= area - centroid_z /= area - else: - centroid_x = 0 - centroid_z = 0 - # Centroid of this section (assuming centroid is at half chord) - centroid_y = location - - # Debug print line - #print("Section " + str(i+1) + ", Location: " + str(location) + " m, Weight: " + str(section_weight) + " kg, Centroid Z: " + str(centroid_z)) - - # Apply twist - rotated_z = centroid_z * np.cos(twist_angle) - centroid_x * np.sin(twist_angle) - rotated_x = centroid_z * np.sin(twist_angle) + centroid_x * np.cos(twist_angle) - - # Add the section's contributions - total_weight += section_weight - total_moment_x += rotated_x * section_weight - total_moment_y += centroid_y * section_weight - total_moment_z += rotated_z * section_weight - - # Store the coordinates for plotting later - x_coords.append(rotated_x) - y_coords.append(centroid_y) - z_coords.append(rotated_z) - - # Calculate the overall center of gravity - outputs['center_of_gravity_x'] = total_moment_x / total_weight - outputs['center_of_gravity_y'] = total_moment_y / total_weight - outputs['center_of_gravity_z'] = total_moment_z / total_weight - outputs['total_weight'] = total_weight - - # Store the x, y, and z coordinates for the entire wing - outputs['x_coords'] = np.array(x_coords) - outputs['y_coords'] = np.array(y_coords) - outputs['z_coords'] = np.array(z_coords) - - def extract_airfoil_features(self, x_coords, y_coords): - """ - Extract camber, camber location, and max thickness from the given airfoil data. - This method assumes x_coords are normalized (ranging from 0 to 1). - """ - # Approximate the camber line and max thickness from the data - # Assume the camber line is the line of symmetry between the upper and lower surfaces - upper_surface = y_coords[:int(len(x_coords) / 2)] - lower_surface = y_coords[int(len(x_coords) / 2):] - x_upper = x_coords[:int(len(x_coords) / 2)] - x_lower = x_coords[int(len(x_coords) / 2):] - - upper_spline = CubicSpline(x_upper, upper_surface, bc_type='natural') - lower_spline = CubicSpline(x_lower, lower_surface, bc_type='natural') - - camber_line = (upper_spline(x_coords) + lower_spline(x_coords)) / 2.0 - - thickness = upper_spline(x_coords) - lower_spline(x_coords) - - max_thickness_index = np.argmax(thickness) - max_thickness_value = thickness[max_thickness_index] - - camber_slope = np.gradient(camber_line, x_coords) - camber_location_index = np.argmax(np.abs(camber_slope)) - camber_location = x_coords[camber_location_index] - - camber = camber_line[camber_location_index] - - return camber, camber_location, max_thickness_value - - -# Build OpenMDAO problem -prob = om.Problem() - -# Add the center of gravity component -prob.model.add_subsystem('cog', CenterOfGravity3D() , promotes_inputs=['span', 'root_chord', 'tip_chord', 'twist', 'thickness']) - -# Setup the problem -prob.setup() - -# Define some example inputs -prob.set_val('span', 11.0) -prob.set_val('root_chord', 1.9) -prob.set_val('tip_chord', 0.5) -#prob.set_val('twist', np.linspace(0, 0, 50)) -prob.set_val('thickness', 0.2) - -prob.model.cog.options['airfoil_data_file'] = 'airfoil_data_test.dat' - -# Run the model -prob.run_model() - -# Get the results -center_of_gravity_x = prob.get_val('cog.center_of_gravity_x') -center_of_gravity_y = prob.get_val('cog.center_of_gravity_y') -center_of_gravity_z = prob.get_val('cog.center_of_gravity_z') -total_weight = prob.get_val('cog.total_weight') - -# Get the 3D coordinates for the entire wing -x_coords = prob.get_val('cog.x_coords') -y_coords = prob.get_val('cog.y_coords') -z_coords = prob.get_val('cog.z_coords') - -print(f"Center of gravity: X = {center_of_gravity_x} m, Y = {center_of_gravity_y} m, Z = {center_of_gravity_z} m") -print(f"Total weight of the wing: {total_weight} kg") - From 07004e718e64d4b9a39f0c3e567e0d7f7cf116d2 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Mon, 12 May 2025 14:37:50 -0400 Subject: [PATCH 053/147] Delete aviary/docs/examples/C:UsersszoppeltDesktoptest.py --- .../examples/C:UsersszoppeltDesktoptest.py | 231 ------------------ 1 file changed, 231 deletions(-) delete mode 100644 aviary/docs/examples/C:UsersszoppeltDesktoptest.py diff --git a/aviary/docs/examples/C:UsersszoppeltDesktoptest.py b/aviary/docs/examples/C:UsersszoppeltDesktoptest.py deleted file mode 100644 index 383c06e15..000000000 --- a/aviary/docs/examples/C:UsersszoppeltDesktoptest.py +++ /dev/null @@ -1,231 +0,0 @@ -import openmdao.api as om -import numpy as np -import matplotlib.pyplot as plt -import os -from scipy.interpolate import CubicSpline - -# Material densities (g/cm³ converted to kg/m³) -- these are just some random examples -MATERIAL_DENSITIES = { - 'wood': 600, # This isn't even a real wood density that I'm aware of, I just made it up for the sake of debugging - 'metal': 2700, # Aluminum - 'carbon_fiber': 1600 -} - - - -class CenterOfGravity3D(om.ExplicitComponent): - def initialize(self): - self.options.declare('num_sections', types=int, default=50) - self.options.declare('airfoil_type', types=str, default='2412') # use 2412 as example for default - self.options.declare('material', default='metal', values=['wood', 'metal', 'carbon_fiber']) - self.options.declare('airfoil_data_file', default=None, types=str) # For user-provided airfoil data file - - def setup(self): - # Inputs - self.add_input('span', val=10.0, units='m') # Full wingspan (adjustable) - self.add_input('root_chord', val=2.0, units='m') # Root chord length - self.add_input('tip_chord', val=1.0, units='m') # Tip chord length - self.add_input('twist', val=np.zeros(self.options['num_sections']), units='deg') # Twist angles - self.add_input('thickness', val=0.2, units='m') # Thickness of the wing (height) - - - # Outputs - self.add_output('center_of_gravity_x', val=0.0, units='m') - self.add_output('center_of_gravity_y', val=0.0, units='m') - self.add_output('center_of_gravity_z', val=0.0, units='m') - self.add_output('total_weight', val=0.0, units='kg') - self.add_output('x_coords', val=np.zeros(self.options['num_sections']), units='m') - self.add_output('y_coords', val=np.zeros(self.options['num_sections']), units='m') - self.add_output('z_coords', val=np.zeros(self.options['num_sections']), units='m') - - - def compute(self, inputs, outputs): - span = inputs['span'] - root_chord = inputs['root_chord'] - tip_chord = inputs['tip_chord'] - twist = np.radians(inputs['twist']) # Convert twist to radians - thickness = inputs['thickness'] - material = self.options['material'] # Material is taken from options - num_sections = self.options['num_sections'] - airfoil_type = self.options['airfoil_type'] # NACA airfoil type - airfoil_data_file = self.options['airfoil_data_file'] - - # Get material density - density = MATERIAL_DENSITIES[material] # in kg/m³ - - if airfoil_data_file: - airfoil_data = np.loadtxt(airfoil_data_file) - x_coords = airfoil_data[:, 0] - y_coords = airfoil_data[:, 1] - - camber, camber_location, max_thickness = self.extract_airfoil_features(x_coords, y_coords) - else: - # Parse the NACA airfoil type (4-digit) - camber = int(airfoil_type[0]) / 100.0 # Maximum camber - camber_location = int(airfoil_type[1]) / 10.0 # Location of max camber - max_thickness = int(airfoil_type[2:4]) / 100.0 # Max thickness - - # Wing spanwise distribution - span_locations = np.linspace(0, span, num_sections) - - # Initialize total weight and moment accumulators - total_weight = 0 - total_moment_x = 0 - total_moment_y = 0 - total_moment_z = 0 - - # Arrays for storing 3D coordinates of the wing - x_coords = [] - y_coords = [] - z_coords = [] - top_coords = [] - bottom_coords = [] - - # Loop over each section along the span (3D wing approximation) - for i, location in enumerate(span_locations): - # Calculate the chord for this section - chord = root_chord - (root_chord - tip_chord) * (location / span) # Assuming linear variation from root to tip - - # Apply twist - twist_angle = twist[i] - - # Calculate the camber and thickness distribution - # Airfoil thickness distribution using the NACA Equation - def airfoil_thickness(x): - return 5 * max_thickness * (0.2969 * np.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) - - # Airfoil camber line (NACA 4-digit) - def airfoil_camber_line(x, camber, camber_location): - if x < camber_location: - return (camber / camber_location**2) * (2 * camber_location * x - x**2) - else: - return (camber / (1 - camber_location)**2) * ((1 - 2 * camber_location) + 2 * camber_location * x - x**2) - - # Numerical integration: sum up the areas using small segments along the chord - n_points = 100 - x_points = np.linspace(0, 1, n_points) - dx = 1 / (n_points - 1) - - area = 0 # Cross-sectional area of the wing section - centroid_x = 0 - centroid_z = 0 - - for x in x_points: - # Thickness at each point along the chord - thickness_at_x = airfoil_thickness(x) * chord - # Camber at each point (for z-coordinate) - camber_at_x = airfoil_camber_line(x, camber, camber_location) * chord - - # Area of small rectangle at x - area += thickness_at_x * dx - - centroid_x += (x * thickness_at_x) * dx - centroid_z += (camber_at_x * thickness_at_x) * dx - # Weight of this section (density * area * thickness) - section_weight = density * area * thickness # Volume approximation - - # Normalize - if area > 0: - centroid_x /= area - centroid_z /= area - else: - centroid_x = 0 - centroid_z = 0 - # Centroid of this section (assuming centroid is at half chord) - centroid_y = location - - # Debug print line - #print("Section " + str(i+1) + ", Location: " + str(location) + " m, Weight: " + str(section_weight) + " kg, Centroid Z: " + str(centroid_z)) - - # Apply twist - rotated_z = centroid_z * np.cos(twist_angle) - centroid_x * np.sin(twist_angle) - rotated_x = centroid_z * np.sin(twist_angle) + centroid_x * np.cos(twist_angle) - - # Add the section's contributions - total_weight += section_weight - total_moment_x += rotated_x * section_weight - total_moment_y += centroid_y * section_weight - total_moment_z += rotated_z * section_weight - - # Store the coordinates for plotting later - x_coords.append(rotated_x) - y_coords.append(centroid_y) - z_coords.append(rotated_z) - - # Calculate the overall center of gravity - outputs['center_of_gravity_x'] = total_moment_x / total_weight - outputs['center_of_gravity_y'] = total_moment_y / total_weight - outputs['center_of_gravity_z'] = total_moment_z / total_weight - outputs['total_weight'] = total_weight - - # Store the x, y, and z coordinates for the entire wing - outputs['x_coords'] = np.array(x_coords) - outputs['y_coords'] = np.array(y_coords) - outputs['z_coords'] = np.array(z_coords) - - def extract_airfoil_features(self, x_coords, y_coords): - """ - Extract camber, camber location, and max thickness from the given airfoil data. - This method assumes x_coords are normalized (ranging from 0 to 1). - """ - # Approximate the camber line and max thickness from the data - # Assume the camber line is the line of symmetry between the upper and lower surfaces - upper_surface = y_coords[:int(len(x_coords) / 2)] - lower_surface = y_coords[int(len(x_coords) / 2):] - x_upper = x_coords[:int(len(x_coords) / 2)] - x_lower = x_coords[int(len(x_coords) / 2):] - - upper_spline = CubicSpline(x_upper, upper_surface, bc_type='natural') - lower_spline = CubicSpline(x_lower, lower_surface, bc_type='natural') - - camber_line = (upper_spline(x_coords) + lower_spline(x_coords)) / 2.0 - - thickness = upper_spline(x_coords) - lower_spline(x_coords) - - max_thickness_index = np.argmax(thickness) - max_thickness_value = thickness[max_thickness_index] - - camber_slope = np.gradient(camber_line, x_coords) - camber_location_index = np.argmax(np.abs(camber_slope)) - camber_location = x_coords[camber_location_index] - - camber = camber_line[camber_location_index] - - return camber, camber_location, max_thickness_value - - -# Build OpenMDAO problem -prob = om.Problem() - -# Add the center of gravity component -prob.model.add_subsystem('cog', CenterOfGravity3D() , promotes_inputs=['span', 'root_chord', 'tip_chord', 'twist', 'thickness']) - -# Setup the problem -prob.setup() - -# Define some example inputs -prob.set_val('span', 11.0) -prob.set_val('root_chord', 1.9) -prob.set_val('tip_chord', 0.5) -#prob.set_val('twist', np.linspace(0, 0, 50)) -prob.set_val('thickness', 0.2) - -prob.model.cog.options['airfoil_data_file'] = 'airfoil_data_test.dat' - -# Run the model -prob.run_model() - -# Get the results -center_of_gravity_x = prob.get_val('cog.center_of_gravity_x') -center_of_gravity_y = prob.get_val('cog.center_of_gravity_y') -center_of_gravity_z = prob.get_val('cog.center_of_gravity_z') -total_weight = prob.get_val('cog.total_weight') - -# Get the 3D coordinates for the entire wing -x_coords = prob.get_val('cog.x_coords') -y_coords = prob.get_val('cog.y_coords') -z_coords = prob.get_val('cog.z_coords') - -print(f"Center of gravity: X = {center_of_gravity_x} m, Y = {center_of_gravity_y} m, Z = {center_of_gravity_z} m") -print(f"Total weight of the wing: {total_weight} kg") - From 3ce8adf02fb2ff74be43318d51517c1e9e0fb9e8 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Mon, 12 May 2025 14:37:57 -0400 Subject: [PATCH 054/147] Delete aviary/docs/examples/Custom_Fuselage.dat --- aviary/docs/examples/Custom_Fuselage.dat | 179 ----------------------- 1 file changed, 179 deletions(-) delete mode 100644 aviary/docs/examples/Custom_Fuselage.dat diff --git a/aviary/docs/examples/Custom_Fuselage.dat b/aviary/docs/examples/Custom_Fuselage.dat deleted file mode 100644 index ce85fe585..000000000 --- a/aviary/docs/examples/Custom_Fuselage.dat +++ /dev/null @@ -1,179 +0,0 @@ -0.0 0.5 -0.5 0.45 -1.0 0.4 -1.5 0.6 -2.0 0.3 -2.5 0.35 - -class CenterOfGravity3D(om.ExplicitComponent): - def initialize(self): - self.options.declare('num_sections', types=int, default=50) - self.options.declare('airfoil_type', types=str, default='2412') - self.options.declare('material', default='metal', values=['wood', 'metal', 'carbon_fiber']) - self.options.declare('airfoil_data_file', default=None, types=str) - - def setup(self): - num_sections = self.options['num_sections'] - - # Inputs - self.add_input('span', val=10.0, units='m') - self.add_input('root_chord', val=2.0, units='m') - self.add_input('tip_chord', val=1.0, units='m') - self.add_input('twist', val=np.zeros(num_sections), units='deg') - self.add_input('thickness', val=0.2, units='m') - - # Outputs - self.add_output('center_of_gravity_x', val=0.0, units='m') - self.add_output('center_of_gravity_y', val=0.0, units='m') - self.add_output('center_of_gravity_z', val=0.0, units='m') - self.add_output('total_weight', val=0.0, units='kg') - self.add_output('x_coords', val=np.zeros(num_sections), units='m') - self.add_output('y_coords', val=np.zeros(num_sections), units='m') - self.add_output('z_coords', val=np.zeros(num_sections), units='m') - - def setup_partials(self): - num_sections = self.options['num_sections'] - - self.declare_partials(of=['center_of_gravity_x', 'center_of_gravity_y', 'center_of_gravity_z'], - wrt=['span', 'root_chord', 'tip_chord', 'thickness']) - self.declare_partials(of='total_weight', wrt=['span', 'root_chord', 'tip_chord', 'thickness']) - self.declare_partials(of='x_coords', wrt=['twist'], rows=np.arange(num_sections), cols=np.arange(num_sections)) - self.declare_partials(of='y_coords', wrt=['span'], rows=np.arange(num_sections), cols=np.arange(num_sections)) - self.declare_partials(of='z_coords', wrt=['twist'], rows=np.arange(num_sections), cols=np.arange(num_sections)) - - def compute_partials(self, inputs, partials): - """Compute the analytical derivatives of outputs with respect to inputs.""" - span = inputs['span'] - root_chord = inputs['root_chord'] - tip_chord = inputs['tip_chord'] - thickness = inputs['thickness'] - num_sections = self.options['num_sections'] - - # Compute section locations along the span - span_locations = np.linspace(0, span, num_sections) - chord_lengths = root_chord - (root_chord - tip_chord) * (span_locations / span) - dchord_dspan = (tip_chord - root_chord) / span # Chord gradient w.r.t. span - - # Compute derivatives of total weight - total_weight = np.sum(chord_lengths * thickness * (span / num_sections)) - d_weight_dspan = np.sum(dchord_dspan * thickness * (span / num_sections)) + np.sum(chord_lengths * thickness / num_sections) - d_weight_droot_chord = np.sum(thickness * (span / num_sections)) - d_weight_dtip_chord = np.sum(thickness * (span / num_sections) * (span_locations / span)) - d_weight_dthickness = np.sum(chord_lengths * (span / num_sections)) - - partials['total_weight', 'span'] = d_weight_dspan - partials['total_weight', 'root_chord'] = d_weight_droot_chord - partials['total_weight', 'tip_chord'] = d_weight_dtip_chord - partials['total_weight', 'thickness'] = d_weight_dthickness - - # Compute derivatives of center of gravity coordinates - centroid_xs = chord_lengths / 4 # Approximate centroid of airfoil section - centroid_ys = span_locations - centroid_zs = np.zeros_like(span_locations) # Assuming zero camber - - total_moment_x = np.sum(centroid_xs * chord_lengths * thickness * (span / num_sections)) - total_moment_y = np.sum(centroid_ys * chord_lengths * thickness * (span / num_sections)) - total_moment_z = np.sum(centroid_zs * chord_lengths * thickness * (span / num_sections)) - - partials['center_of_gravity_x', 'span'] = (np.sum(dchord_dspan * centroid_xs * thickness * (span / num_sections)) - - total_moment_x / total_weight * d_weight_dspan) / total_weight - partials['center_of_gravity_x', 'root_chord'] = (np.sum(centroid_xs * thickness * (span / num_sections)) - - total_moment_x / total_weight * d_weight_droot_chord) / total_weight - partials['center_of_gravity_x', 'tip_chord'] = (np.sum(centroid_xs * thickness * (span / num_sections) * (span_locations / span)) - - total_moment_x / total_weight * d_weight_dtip_chord) / total_weight - partials['center_of_gravity_x', 'thickness'] = (np.sum(centroid_xs * chord_lengths * (span / num_sections)) - - total_moment_x / total_weight * d_weight_dthickness) / total_weight - - partials['center_of_gravity_y', 'span'] = (np.sum(dchord_dspan * centroid_ys * thickness * (span / num_sections)) - - total_moment_y / total_weight * d_weight_dspan) / total_weight - partials['center_of_gravity_y', 'root_chord'] = (np.sum(centroid_ys * thickness * (span / num_sections)) - - total_moment_y / total_weight * d_weight_droot_chord) / total_weight - partials['center_of_gravity_y', 'tip_chord'] = (np.sum(centroid_ys * thickness * (span / num_sections) * (span_locations / span)) - - total_moment_y / total_weight * d_weight_dtip_chord) / total_weight - partials['center_of_gravity_y', 'thickness'] = (np.sum(centroid_ys * chord_lengths * (span / num_sections)) - - total_moment_y / total_weight * d_weight_dthickness) / total_weight - - partials['center_of_gravity_z', 'span'] = 0 # No camber means no variation - partials['center_of_gravity_z', 'root_chord'] = 0 - partials['center_of_gravity_z', 'tip_chord'] = 0 - partials['center_of_gravity_z', 'thickness'] = 0 - - # Compute derivatives of x_coords and z_coords w.r.t. twist - twist = np.radians(inputs['twist']) - for i in range(num_sections): - partials['x_coords', 'twist'][i] = -centroid_xs[i] * np.sin(twist[i]) - partials['z_coords', 'twist'][i] = centroid_xs[i] * np.cos(twist[i]) - - -def compute_partials(self, inputs, partials): - """Compute the analytical derivatives of outputs with respect to inputs.""" - span = inputs['span'] - root_chord = inputs['root_chord'] - tip_chord = inputs['tip_chord'] - thickness = inputs['thickness'] - twist = np.radians(inputs['twist']) # Convert twist from degrees to radians - num_sections = self.options['num_sections'] - - # Spanwise locations - span_locations = np.linspace(0, span, num_sections) - - # Chord length variation (linear taper) - chord_lengths = root_chord - (root_chord - tip_chord) * (span_locations / span) - dchord_dspan = (tip_chord - root_chord) / span # Chord gradient w.r.t. span - - # Compute centroid locations - centroid_xs = chord_lengths / 4 # Approximate centroid X-location (quarter chord) - centroid_ys = span_locations # The spanwise locations - centroid_zs = np.zeros_like(span_locations) # Assume zero camber for now - - # Compute rotated centroid due to twist - rotated_xs = centroid_xs * np.cos(twist) - centroid_zs * np.sin(twist) - rotated_zs = centroid_xs * np.sin(twist) + centroid_zs * np.cos(twist) - - # Compute weight of each section - section_areas = chord_lengths * thickness # Simple approximation - section_volumes = section_areas * (span / num_sections) # Volume of each section - section_weights = section_volumes # Assuming uniform density - - # Compute total weight - total_weight = np.sum(section_weights) - - # Compute moments for CoG - total_moment_x = np.sum(rotated_xs * section_weights) - total_moment_y = np.sum(centroid_ys * section_weights) - total_moment_z = np.sum(rotated_zs * section_weights) - - # Compute derivatives of weight - d_weight_dspan = np.sum(dchord_dspan * thickness * (span / num_sections)) + np.sum(chord_lengths * thickness / num_sections) - d_weight_droot_chord = np.sum(thickness * (span / num_sections)) - d_weight_dtip_chord = np.sum(thickness * (span / num_sections) * (span_locations / span)) - d_weight_dthickness = np.sum(chord_lengths * (span / num_sections)) - - # Compute derivatives of moments - d_moment_x_dspan = np.sum((dchord_dspan / 4) * np.cos(twist) * section_weights) - d_moment_y_dspan = np.sum(centroid_ys * (section_weights / span)) # dY/dspan is straightforward - d_moment_z_dspan = np.sum((dchord_dspan / 4) * np.sin(twist) * section_weights) - - # Compute partials for CoG X - partials['center_of_gravity_x', 'span'] = (d_moment_x_dspan - total_moment_x / total_weight * d_weight_dspan) / total_weight - partials['center_of_gravity_x', 'root_chord'] = (np.sum(thickness * (span / num_sections) / 4) - total_moment_x / total_weight * d_weight_droot_chord) / total_weight - partials['center_of_gravity_x', 'tip_chord'] = (np.sum(thickness * (span / num_sections) * (span_locations / span) / 4) - total_moment_x / total_weight * d_weight_dtip_chord) / total_weight - partials['center_of_gravity_x', 'thickness'] = (np.sum(chord_lengths * (span / num_sections) / 4) - total_moment_x / total_weight * d_weight_dthickness) / total_weight - - # Compute partials for CoG Y - partials['center_of_gravity_y', 'span'] = (d_moment_y_dspan - total_moment_y / total_weight * d_weight_dspan) / total_weight - partials['center_of_gravity_y', 'root_chord'] = -total_moment_y / total_weight * d_weight_droot_chord / total_weight - partials['center_of_gravity_y', 'tip_chord'] = -total_moment_y / total_weight * d_weight_dtip_chord / total_weight - partials['center_of_gravity_y', 'thickness'] = -total_moment_y / total_weight * d_weight_dthickness / total_weight - - # Compute partials for CoG Z - partials['center_of_gravity_z', 'span'] = (d_moment_z_dspan - total_moment_z / total_weight * d_weight_dspan) / total_weight - partials['center_of_gravity_z', 'root_chord'] = (np.sum(thickness * (span / num_sections) / 4 * np.sin(twist)) - total_moment_z / total_weight * d_weight_droot_chord) / total_weight - partials['center_of_gravity_z', 'tip_chord'] = (np.sum(thickness * (span / num_sections) * (span_locations / span) / 4 * np.sin(twist)) - total_moment_z / total_weight * d_weight_dtip_chord) / total_weight - partials['center_of_gravity_z', 'thickness'] = (np.sum(chord_lengths * (span / num_sections) / 4 * np.sin(twist)) - total_moment_z / total_weight * d_weight_dthickness) / total_weight - - # Compute derivatives of x_coords and z_coords w.r.t. twist - for i in range(num_sections): - partials['x_coords', 'twist'][i] = -centroid_xs[i] * np.sin(twist[i]) # dx/dtwist - partials['z_coords', 'twist'][i] = centroid_xs[i] * np.cos(twist[i]) # dz/dtwist - From a0d2e418110db7072216a99761e535ee973c7348 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Mon, 12 May 2025 14:38:05 -0400 Subject: [PATCH 055/147] Delete aviary/docs/examples/airfoil_data_test.dat --- aviary/docs/examples/airfoil_data_test.dat | 124 --------------------- 1 file changed, 124 deletions(-) delete mode 100644 aviary/docs/examples/airfoil_data_test.dat diff --git a/aviary/docs/examples/airfoil_data_test.dat b/aviary/docs/examples/airfoil_data_test.dat deleted file mode 100644 index 2e2249c98..000000000 --- a/aviary/docs/examples/airfoil_data_test.dat +++ /dev/null @@ -1,124 +0,0 @@ - 0.00000 0.00001 - 0.00050 0.00430 - 0.00100 0.00600 - 0.00200 0.00903 - 0.00300 0.01127 - 0.00500 0.01490 - 0.00750 0.01861 - 0.01000 0.02180 - 0.02000 0.03186 - 0.03000 0.03967 - 0.04000 0.04688 - 0.05000 0.05192 - 0.06000 0.05698 - 0.07000 0.06110 - 0.08000 0.06562 - 0.09000 0.06937 - 0.10000 0.07280 - 0.12000 0.07886 - 0.14000 0.08401 - 0.16000 0.08839 - 0.18000 0.09211 - 0.20000 0.09525 - 0.22000 0.09786 - 0.24000 0.10000 - 0.26000 0.10173 - 0.28000 0.10313 - 0.30000 0.10418 - 0.34000 0.10542 - 0.36000 0.10632 - 0.38000 0.10687 - 0.40000 0.10700 - 0.44000 0.10656 - 0.46000 0.10600 - 0.48000 0.10526 - 0.50000 0.10423 - 0.54000 0.10154 - 0.56000 0.09965 - 0.58000 0.09795 - 0.60000 0.09587 - 0.64000 0.09125 - 0.66000 0.08872 - 0.68000 0.08605 - 0.70000 0.08322 - 0.74000 0.07789 - 0.76000 0.07477 - 0.78000 0.07028 - 0.80000 0.06668 - 0.82000 0.06262 - 0.84000 0.05834 - 0.86000 0.05368 - 0.88000 0.04856 - 0.90000 0.04299 - 0.91000 0.03997 - 0.92000 0.03686 - 0.93000 0.03364 - 0.94000 0.03032 - 0.95000 0.02689 - 0.96000 0.02335 - 0.97000 0.01968 - 0.98000 0.01570 - 0.99000 0.01171 - 1.00000 0.00720 - 0.00000 0.00000 - 0.00050 -0.00377 - 0.00100 -0.00519 - 0.00200 -0.00709 - 0.00300 -0.00842 - 0.00500 -0.01044 - 0.00750 -0.01230 - 0.01000 -0.01376 - 0.02000 -0.01767 - 0.03000 -0.02006 - 0.04000 -0.02109 - 0.05000 -0.02283 - 0.06000 -0.02353 - 0.07000 -0.02417 - 0.08000 -0.02450 - 0.09000 -0.02466 - 0.10000 -0.02469 - 0.12000 -0.02440 - 0.14000 -0.02374 - 0.16000 -0.02279 - 0.18000 -0.02159 - 0.20000 -0.02030 - 0.22000 -0.01901 - 0.24000 -0.01786 - 0.26000 -0.01688 - 0.28000 -0.01607 - 0.30000 -0.01536 - 0.34000 -0.01389 - 0.36000 -0.01344 - 0.38000 -0.01279 - 0.40000 -0.01216 - 0.44000 -0.01105 - 0.46000 -0.01060 - 0.48000 -0.01020 - 0.50000 -0.00985 - 0.54000 -0.00919 - 0.56000 -0.00888 - 0.58000 -0.00856 - 0.60000 -0.00824 - 0.64000 -0.00756 - 0.66000 -0.00721 - 0.68000 -0.00687 - 0.70000 -0.00658 - 0.74000 -0.00619 - 0.76000 -0.00611 - 0.78000 -0.00609 - 0.80000 -0.00611 - 0.82000 -0.00614 - 0.84000 -0.00621 - 0.86000 -0.00633 - 0.88000 -0.00653 - 0.90000 -0.00683 - 0.91000 -0.00701 - 0.92000 -0.00721 - 0.93000 -0.00742 - 0.94000 -0.00753 - 0.95000 -0.00785 - 0.96000 -0.00807 - 0.97000 -0.00829 - 0.98000 -0.00882 - 0.99000 -0.00976 - 1.00000 -0.01070 \ No newline at end of file From 6dfd2d2d410c2ed26296d6992776aa9faa2cba47 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Mon, 12 May 2025 14:38:16 -0400 Subject: [PATCH 056/147] Delete aviary/docs/examples/mass_builder.py --- aviary/docs/examples/mass_builder.py | 92 ---------------------------- 1 file changed, 92 deletions(-) delete mode 100644 aviary/docs/examples/mass_builder.py diff --git a/aviary/docs/examples/mass_builder.py b/aviary/docs/examples/mass_builder.py deleted file mode 100644 index 050daf052..000000000 --- a/aviary/docs/examples/mass_builder.py +++ /dev/null @@ -1,92 +0,0 @@ -from aviary.interface.utils.markdown_utils import write_markdown_variable_table -from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase -from aviary.subsystems.mass.mass_builder import MassBuilderBase -from aviary.subsystems.mass.simple_mass.mass_premission import MassPremission # This will be the new folder in there \ -# along with flops_based and gasp_based folders. I just called it simple_mass for now. - -""" - -Define subsystem builder for Aviary core mass. - -Classes --------------------------------------------------------------------------------------------------- - -MassBuilderBase: the interface for a mass subsystem builder. **Not sure how necessary this is for - my work right now, but wanted to include it as a just in case. I basically copied - it over from the mass_builder.py under the mass subsystems folder in Aviary github. - -StructureMassBuilder: the interface for Aviary's core mass builder -- in this case, - the core mass builder will work for wing and fuselage mass calculations - will be updated as more mass calculations are added - -""" - -_default_name = 'mass' - -#class MassBuilderBase(SubsystemBuilderBase): - #""" - #Base mass builder - # - #This class is basically copied line by line from the mass subsystems folder - #** Ask Jason if this is even necessary. - # - #""" - - #def __init__(self, name=None, meta_data=None): - # if name is None: - # name = _default_name - # - # super().__init__(name=name, meta_data=meta_data) - # - #def mission_inputs(self, **kwargs): - # return ['*'] - # - #def mission_outputs(self, **kwargs): - # return ['*'] - -class StructureMassBuilder(MassBuilderBase): - """ - Core mass subsystem builder - - Unlike the CoreMassBuilder on the github under the mass subsystems folder, - I am not including the __init__'s, since I don't have any FLOPS or GASP - dependence in my mass calculations at the moment; the math is essentially - hard coded from my calculations right now. - - """ - - def build_pre_mission(self, aviary_inputs): - return MassPremission # See the commented line above in the imports - - def build_mission(self, num_nodes, aviary_inputs, **kwargs): - super().build_mission(num_nodes, aviary_inputs) - - def report(self, prob, reports_folder, **kwargs): - """ - Generate the report for Aviary core mass - - Parameters - ---------- - prob : AviaryProblem - The AviaryProblem that will be used to generate the report - reports_folder : Path - Location of the subsystems_report folder this report will be placed in - - * This comment is copied from the mass subsystems folder * - - """ - - filename = self.name + '.md' - filepath = reports_folder / filename - - # Ask Jason about how I should format this - outputs = [ - - ] - - with open(filepath, mode='w') as f: - method = self.code_origin.value + '-derived relations' # Ask Jason about this too since I don't have FLOPS or GASP for code_origin_value - f.write(f'# Mass estimation: {method}') - write_markdown_variable_table(f, prob, outputs, self.meta_data) - - \ No newline at end of file From 860756a7220cb8acdcd9790e7c95ac3a94a3e0c1 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Mon, 12 May 2025 14:38:24 -0400 Subject: [PATCH 057/147] Delete aviary/docs/examples/mass_premission.py --- aviary/docs/examples/mass_premission.py | 54 ------------------------- 1 file changed, 54 deletions(-) delete mode 100644 aviary/docs/examples/mass_premission.py diff --git a/aviary/docs/examples/mass_premission.py b/aviary/docs/examples/mass_premission.py deleted file mode 100644 index 31a98c778..000000000 --- a/aviary/docs/examples/mass_premission.py +++ /dev/null @@ -1,54 +0,0 @@ -import openmdao.api as om - -""" -The little bit of path code below is not important overall. This is for me to test -within the Docker container and VS Code before I push everything fully to the Github -repository. These lines can be deleted as things are updated further. - -""" - -import sys -import os - - -module_path = os.path.abspath("/home/omdao/Aviary/aviary/subsystems/mass") -if module_path not in sys.path: - sys.path.append(module_path) - -# Maybe some Aviary inputs as well? -from aviary.subsystems.mass.simple_mass.wing import WingMassAndCOG -from aviary.subsystems.mass.simple_mass.fuselage import FuselageMassAndCOG -from aviary.subsystems.mass.simple_mass.tail import TailMassAndCOG -from aviary.subsystems.mass.simple_mass.mass_summation import MassSummation - -class MassPremission(om.Group): - """ - Pre-mission group of top-level mass estimation groups and components for - the simple small-scale aircraft mass build-up. - """ - - def setup(self): - - self.add_subsystem( - 'Wing', - WingMassAndCOG(), - promotes_inputs=['*'], promotes_outputs=['*'] - ) - - self.add_subsystem( - 'Fuselage', - FuselageMassAndCOG(), - promotes_inputs=['*'], promotes_outputs=['*'] - ) - - self.add_subsystem( - 'Tail', - TailMassAndCOG(), - promotes_inputs=['*'], promotes_outputs=['*'] - ) - - self.add_subsystem( - 'total_mass', - MassSummation(), - promotes_inputs=['*'], promotes_outputs=['*'] - ) \ No newline at end of file From da228e4cb3827faf21086c35ff8ea0a8cb77350e Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Mon, 12 May 2025 14:38:32 -0400 Subject: [PATCH 058/147] Delete aviary/docs/examples/fuselage.py --- aviary/docs/examples/fuselage.py | 303 ------------------------------- 1 file changed, 303 deletions(-) delete mode 100644 aviary/docs/examples/fuselage.py diff --git a/aviary/docs/examples/fuselage.py b/aviary/docs/examples/fuselage.py deleted file mode 100644 index 3764a4eff..000000000 --- a/aviary/docs/examples/fuselage.py +++ /dev/null @@ -1,303 +0,0 @@ -import openmdao.api as om -import numpy as np -from scipy.interpolate import interp1d -import logging - -# Configure logging -logging.basicConfig(level=logging.INFO) -logger = logging.getLogger(__name__) - -# Material densities (kg/m^3) -MATERIAL_DENSITIES = { - 'wood': 600, # Not any real wood density - 'metal': 2700, # Aluminum - 'carbon_fiber': 1600, - 'foam': 300 # Example density for foam (just for something lightweight) -} - -class FuselageMassAndCOG(om.ExplicitComponent): - def initialize(self): - self.options.declare('num_sections', - types=int, - default=1000) - - self.options.declare('material', - default='foam', - values=list(MATERIAL_DENSITIES.keys())) - - self.options.declare('custom_fuselage_data_file', - types=(str, type(None)), - default=None, - allow_none=True) - - self.custom_fuselage_function = None - - def setup(self): - - # Inputs - self.add_input('length', - val=2.0, - units='m') - - self.add_input('diameter', - val=0.4, - units='m') - - self.add_input('taper_ratio', - val=1.0, - units=None) # 1.0 means no taper - - self.add_input('curvature', - val=0.0, - units='m') # 0 for straight, positive for upward curve - - self.add_input('thickness', - val=0.05, - units='m') # Wall thickness of the fuselage - - # Allow for asymmetry in the y and z axes -- this value acts as a slope for linear variation along these axes - self.add_input('y_offset', - val=0.0, - units='m') - - self.add_input('z_offset', - val=0.0, - units='m') - - self.add_input('is_hollow', - val=True, - units=None) # Whether the fuselage is hollow or not (default is hollow) - - - # Outputs - self.add_output('center_of_gravity_x', - val=0.0, - units='m') - - self.add_output('center_of_gravity_y', - val=0.0, - units='m') - - self.add_output('center_of_gravity_z', - val=0.0, - units='m') - - self.add_output('total_weight', - val=0.0, - units='kg') - - def setup_partials(self): - """ - Complex step is used for the derivatives for now as they are very complicated to calculate - analytically. Compute_partials function has the framework for analytical derivatives, but not - all of them match the check_partials. - """ - self.declare_partials('center_of_gravity_x', ['length', 'diameter', 'taper_ratio', 'curvature', 'thickness'], method='cs') - self.declare_partials('center_of_gravity_y', ['length', 'y_offset', 'curvature'], method='cs') - self.declare_partials('total_weight', ['length', 'diameter', 'thickness'], method='cs') - - def compute_partials(self, inputs, partials): - length = inputs['length'] - diameter = inputs['diameter'] - taper_ratio = inputs['taper_ratio'] - curvature = inputs['curvature'] - thickness = inputs['thickness'] - y_offset = inputs['y_offset'] - z_offset = inputs['z_offset'] - is_hollow = inputs['is_hollow'] - - #custom_fuselage_function = getattr(self, 'custom_fuselage_function', None) # Custom fuselage model function -- if provided - - custom_fuselage_data_file = self.options['custom_fuselage_data_file'] - - material = self.options['material'] - num_sections = self.options['num_sections'] - - self.validate_inputs(length, diameter, thickness, taper_ratio, is_hollow) - - density = MATERIAL_DENSITIES[material] - - section_locations = np.linspace(0, length, num_sections).flatten() - dx = 1 / (num_sections - 1) - - total_weight = 0 - total_moment_x = 0 - total_moment_y = 0 - total_moment_z = 0 - - interpolate_diameter = self.load_fuselage_data(custom_fuselage_data_file) - - out_r = np.zeros(num_sections) - in_r = np.zeros(num_sections) - - - # Loop through each section - for i, location in enumerate(section_locations): - section_diameter = self.get_section_diameter(location, length, diameter, taper_ratio, interpolate_diameter) - outer_radius = section_diameter / 2.0 - inner_radius = max(0, outer_radius - thickness) if is_hollow else 0 - - out_r[i] = outer_radius - in_r[i] = inner_radius - - section_volume = np.pi * (outer_radius**2 - inner_radius**2) * (length / num_sections) - section_weight = density * section_volume - - centroid_x, centroid_y, centroid_z = self.compute_centroid(location, length, y_offset, z_offset, curvature, taper_ratio) - - total_weight += section_weight - total_moment_x += centroid_x * section_weight - total_moment_y += centroid_y * section_weight - total_moment_z += centroid_z * section_weight - - dzcg_dz_offset = np.sum( - np.trapz( - (1 - section_locations / length) * density * np.pi * (out_r**2 - in_r**2), section_locations, dx=dx - ) - ) / total_weight - - - partials['center_of_gravity_x', 'length'] = 3 / 4 if taper_ratio > 0 else 1 - partials['center_of_gravity_x', 'taper_ratio'] = - (3/4) * length if taper_ratio > 0 else 0 - partials['center_of_gravity_x', 'curvature'] = 0 - partials['center_of_gravity_x', 'thickness'] = 0 - - partials['center_of_gravity_y', 'length'] = -y_offset / length - partials['center_of_gravity_y', 'y_offset'] = 1 - - partials['center_of_gravity_z', 'length'] = -z_offset / length - partials['center_of_gravity_z', 'z_offset'] = dzcg_dz_offset - partials['center_of_gravity_z', 'curvature'] = length**2 / num_sections - - partials['total_weight', 'length'] = density * np.pi * (diameter**2 - (diameter - 2 * thickness)**2) / num_sections - partials['total_weight', 'diameter'] = 2 * density * np.pi * length * diameter / num_sections - partials['total_weight', 'thickness'] = -2 * density * np.pi * length * (diameter - thickness) / num_sections - - - def compute(self, inputs, outputs): - length = inputs['length'] - diameter = inputs['diameter'] - taper_ratio = inputs['taper_ratio'] - curvature = inputs['curvature'] - thickness = inputs['thickness'] - y_offset = inputs['y_offset'] - z_offset = inputs['z_offset'] - is_hollow = inputs['is_hollow'] - - # Input validation checks - if length <= 0: - raise ValueError("Length must be greater than zero.") - - if diameter <= 0: - raise ValueError("Diameter must be greater than zero.") - - custom_fuselage_function = getattr(self, 'custom_fuselage_function', None) # Custom fuselage model function -- if provided - - custom_fuselage_data_file = self.options['custom_fuselage_data_file'] - - material = self.options['material'] - num_sections = self.options['num_sections'] - - self.validate_inputs(length, diameter, thickness, taper_ratio, is_hollow) - - density = MATERIAL_DENSITIES[material] - - section_locations = np.linspace(0, length, num_sections) - - total_weight = 0 - total_moment_x = 0 - total_moment_y = 0 - total_moment_z = 0 - - interpolate_diameter = self.load_fuselage_data(custom_fuselage_data_file) - - # Loop through each section - for location in section_locations: - section_diameter = self.get_section_diameter(location, length, diameter, taper_ratio, interpolate_diameter) - outer_radius = section_diameter / 2.0 - inner_radius = max(0, outer_radius - thickness) if is_hollow else 0 - - section_volume = np.pi * (outer_radius**2 - inner_radius**2) * (length / num_sections) - section_weight = density * section_volume - - centroid_x, centroid_y, centroid_z = self.compute_centroid(location, length, y_offset, z_offset, curvature, taper_ratio) - - total_weight += section_weight - total_moment_x += centroid_x * section_weight - total_moment_y += centroid_y * section_weight - total_moment_z += centroid_z * section_weight - - outputs['center_of_gravity_x'] = total_moment_x / total_weight - outputs['center_of_gravity_y'] = total_moment_y / total_weight - outputs['center_of_gravity_z'] = total_moment_z / total_weight - outputs['total_weight'] = total_weight - - def validate_inputs(self, length, diameter, thickness, taper_ratio, is_hollow): - if length <= 0 or diameter <= 0 or thickness <= 0: - raise ValueError("Length, diameter, and thickness must be positive values.") - if taper_ratio < 0 or taper_ratio > 1: - raise ValueError("Taper ratio must be between 0 and 1.") - if is_hollow and thickness >= diameter / 2: - raise ValueError("Wall thickness is too large for a hollow fuselage.") - - def load_fuselage_data(self, custom_fuselage_data_file): - if custom_fuselage_data_file: - try: - # Load the file - custom_data = np.loadtxt(custom_fuselage_data_file) - fuselage_locations = custom_data[:, 0] - fuselage_diameters = custom_data[:, 1] - return interp1d(fuselage_locations, fuselage_diameters, kind='linear', fill_value='extrapolate') - except Exception as e: - raise ValueError(f"Error loading fuselage data file: {e}") - else: - return None - - def get_section_diameter(self, location, length, diameter, taper_ratio, interpolate_diameter): - if self.custom_fuselage_function: - return self.custom_fuselage_function(location) - elif self.load_fuselage_data: - return interpolate_diameter(location) if interpolate_diameter is not None else max(0.01, diameter * (1 - taper_ratio * (location / length))) - else: - return max(0.01, diameter * (1 - taper_ratio * (location / length))) - - def compute_centroid(self, location, length, y_offset, z_offset, curvature, taper_ratio): - centroid_x = (3/4) * location if taper_ratio > 0 else location # This is an approximation that could and should be better modeled in the future - centroid_y = y_offset * (1 - location / length) - centroid_z = z_offset * (1 - location / length) + curvature * location**2 / length - return centroid_x, centroid_y, centroid_z - -prob = om.Problem() - -prob.model.add_subsystem('fuselage_cg', FuselageMassAndCOG(), promotes_inputs=['length', 'diameter', 'taper_ratio', 'curvature', 'thickness', 'y_offset', 'z_offset', 'is_hollow']) - -prob.setup() - -prob.set_val('length', 2.5) -prob.set_val('diameter', 0.5) -prob.set_val('taper_ratio', 0.5) -prob.set_val('curvature', 0.0) -prob.set_val('thickness', 0.05) # Wall thickness of 5 cm -#prob.set_val('is_hollow', False) # Default is True, uncomment to use False -- for testing purposes - -# Example using custom function -- uncomment to run -#def custom_fuselage_model(location): -# return 0.5 * np.exp(-0.1 * location) - -#prob.model.fuselage_cg.custom_fuselage_function = custom_fuselage_model - -# Example for custom .dat file -- uncomment to run -#prob.model.fuselage_cg.options['custom_fuselage_data_file'] = 'Custom_Fuselage.dat' - -prob.run_model() - -center_of_gravity_x = prob.get_val('fuselage_cg.center_of_gravity_x') -center_of_gravity_y = prob.get_val('fuselage_cg.center_of_gravity_y') -center_of_gravity_z = prob.get_val('fuselage_cg.center_of_gravity_z') -total_weight = prob.get_val('fuselage_cg.total_weight') - -#data = prob.check_partials(compact_print=True, abs_err_tol=1e-04, rel_err_tol=1e-04, step=1e-8, step_calc='rel') - -logger.info(f"Center of gravity of the fuselage: X = {center_of_gravity_x} m, Y = {center_of_gravity_y} m, Z = {center_of_gravity_z} m") -logger.info(f"Total weight of the fuselage: {total_weight} kg") - From 41962bd2250d40e585cb4581dcfcaafa2c9a4e89 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Mon, 12 May 2025 14:38:39 -0400 Subject: [PATCH 059/147] Delete aviary/docs/examples/mass_summation.py --- aviary/docs/examples/mass_summation.py | 82 -------------------------- 1 file changed, 82 deletions(-) delete mode 100644 aviary/docs/examples/mass_summation.py diff --git a/aviary/docs/examples/mass_summation.py b/aviary/docs/examples/mass_summation.py deleted file mode 100644 index 7546ec87b..000000000 --- a/aviary/docs/examples/mass_summation.py +++ /dev/null @@ -1,82 +0,0 @@ -import numpy as np - -import openmdao.api as om -import openmdao.jax as omj - -# Maybe add some aviary inputs at some point here - -""" -The little bit of path code below is not important overall. This is for me to test -within the Docker container and VS Code before I push everything fully to the Github -repository. These lines can be deleted as things are updated further. - -""" - -import sys -import os - - -module_path = os.path.abspath("/home/omdao/Aviary/aviary/subsystems/mass") -if module_path not in sys.path: - sys.path.append(module_path) - -from simple_mass.fuselage import FuselageMassAndCOG -from simple_mass.wing import WingMassAndCOG -from simple_mass.tail import TailMassAndCOG - -class MassSummation(om.Group): - """ - - Group to compute various design masses for this mass group. - - This group will be expanded greatly as more subsystems are created. - - """ - - def setup(self): - - self.add_subsystem( - 'fuse_mass', - FuselageMassAndCOG(), - promotes_inputs=['*'], - promotes_outputs=['total_weight_fuse'] - ) - - self.add_subsystem( - 'wing_mass', - WingMassAndCOG(), - promotes_inputs=['*'], - promotes_outputs=['total_weight_wing'] - ) - - self.add_subsystem( - 'tail_mass', - TailMassAndCOG(), - promotes_inputs=['*'], - promotes_outputs=['mass'] - ) - - self.add_subsystem( - 'structure_mass', - StructureMass(), - promotes_inputs=['*'], - promotes_outputs=['*'] - ) - - -class StructureMass(om.JaxExplicitComponent): - - def setup(self): - # Maybe later change these to Aviary inputs? - self.add_input('total_weight_wing', val=0.0, units='kg') - self.add_input('total_weight_fuse', val=0.0, units='kg') - self.add_input('mass', val=0.0, units='kg') - # More masses can be added, i.e., tail, spars, flaps, etc. as needed - - self.add_output('structure_mass', val=0.0, units='kg') - - def compute_primal(self, total_weight_wing, total_weight_fuse, mass): - - structure_mass = total_weight_wing + total_weight_fuse + mass - - return structure_mass \ No newline at end of file From 33484ad4a385ca9c3dd4f6979b0c24f19c8ef5e3 Mon Sep 17 00:00:00 2001 From: szoppelt Date: Mon, 12 May 2025 19:05:34 +0000 Subject: [PATCH 060/147] commit. --- .../mass/simple_mass/mass_summation.py | 22 +- .../simple_mass/test/test_mass_summation.py | 259 ++++++++---------- 2 files changed, 123 insertions(+), 158 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/mass_summation.py b/aviary/subsystems/mass/simple_mass/mass_summation.py index 7546ec87b..a7c7a6501 100644 --- a/aviary/subsystems/mass/simple_mass/mass_summation.py +++ b/aviary/subsystems/mass/simple_mass/mass_summation.py @@ -3,27 +3,11 @@ import openmdao.api as om import openmdao.jax as omj +from aviary.subsystems.mass.simple_mass.fuselage import FuselageMassAndCOG +from aviary.subsystems.mass.simple_mass.wing import WingMassAndCOG +from aviary.subsystems.mass.simple_mass.tail import TailMassAndCOG # Maybe add some aviary inputs at some point here -""" -The little bit of path code below is not important overall. This is for me to test -within the Docker container and VS Code before I push everything fully to the Github -repository. These lines can be deleted as things are updated further. - -""" - -import sys -import os - - -module_path = os.path.abspath("/home/omdao/Aviary/aviary/subsystems/mass") -if module_path not in sys.path: - sys.path.append(module_path) - -from simple_mass.fuselage import FuselageMassAndCOG -from simple_mass.wing import WingMassAndCOG -from simple_mass.tail import TailMassAndCOG - class MassSummation(om.Group): """ diff --git a/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py b/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py index 32d08235b..48de87de7 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py +++ b/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py @@ -5,26 +5,7 @@ import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal - -""" -The little bit of path code below is not important overall. This is for me to test -within the Docker container and VS Code before I push everything fully to the Github -repository. These lines can be deleted as things are updated further. - -""" - -import sys -import os - - -module_path = os.path.abspath("/home/omdao/Aviary/aviary/subsystems/mass") -if module_path not in sys.path: - sys.path.append(module_path) - -from simple_mass.fuselage import FuselageMassAndCOG -from simple_mass.wing import WingMassAndCOG -from simple_mass.tail import TailMassAndCOG -from simple_mass.mass_summation import MassSummation, StructureMass +from aviary.subsystems.mass.simple_mass.mass_summation import MassSummation, StructureMass class MassSummationTest(unittest.TestCase): """ @@ -42,120 +23,120 @@ def test_case(self): promotes_outputs=['*'] ) - # self.prob.model.set_input_defaults( - # 'span', - # val=1.0, - # units='m' - # ) - - # self.prob.model.set_input_defaults( - # 'span_tail', - # val=1.0, - # units='m' - # ) - - # self.prob.model.set_input_defaults( - # "root_chord", - # val=1, - # units="m" - # ) - - # self.prob.model.set_input_defaults( - # "root_chord_tail", - # val=1, - # units="m" - # ) - - # self.prob.model.set_input_defaults( - # "tip_chord", - # val=0.5, - # units="m" - # ) - - # self.prob.model.set_input_defaults( - # "tip_chord_tail", - # val=0.5, - # units="m" - # ) - - # self.prob.model.set_input_defaults( - # "thickness_ratio", - # val=0.12 - # ) - - # self.prob.model.set_input_defaults( - # "skin_thickness", - # val=0.002, - # units="m" - # ) - - # self.prob.model.set_input_defaults( - # "twist", - # val=jnp.zeros(10), - # units="deg" - # ) - - # self.prob.model.set_input_defaults( - # "twist_tail", - # val=jnp.zeros(10), - # units="deg" - # ) - - # self.prob.model.set_input_defaults( - # "length", - # val=2.5, - # units="m") + self.prob.model.set_input_defaults( + 'span', + val=1.0, + units='m' + ) + + self.prob.model.set_input_defaults( + 'span_tail', + val=1.0, + units='m' + ) + + self.prob.model.set_input_defaults( + "root_chord", + val=1, + units="m" + ) + + self.prob.model.set_input_defaults( + "root_chord_tail", + val=1, + units="m" + ) + + self.prob.model.set_input_defaults( + "tip_chord", + val=0.5, + units="m" + ) + + self.prob.model.set_input_defaults( + "tip_chord_tail", + val=0.5, + units="m" + ) + + self.prob.model.set_input_defaults( + "thickness_ratio", + val=0.12 + ) + + self.prob.model.set_input_defaults( + "skin_thickness", + val=0.002, + units="m" + ) + + self.prob.model.set_input_defaults( + "twist", + val=jnp.zeros(10), + units="deg" + ) + + self.prob.model.set_input_defaults( + "twist_tail", + val=jnp.zeros(10), + units="deg" + ) + + self.prob.model.set_input_defaults( + "length", + val=2.5, + units="m") - # self.prob.model.set_input_defaults( - # "diameter", - # val=0.5, - # units="m" - # ) - - # self.prob.model.set_input_defaults( - # "taper_ratio", - # val=0.5 - # ) - - # self.prob.model.set_input_defaults( - # "curvature", - # val=0.0, - # units="m" - # ) - - # self.prob.model.set_input_defaults( - # "y_offset", - # val=0.0, - # units="m" - # ) - - # self.prob.model.set_input_defaults( - # "z_offset", - # val=0.0, - # units="m" - # ) - - # self.prob.model.set_input_defaults( - # 'thickness', - # val=0.05, - # units='m' - # ) - - # self.prob.model.set_input_defaults( - # "is_hollow", - # val=True - # ) - - # n_points = 10 # = num_sections - # x = jnp.linspace(0, 1, n_points) - # max_thickness_chord_ratio = 0.12 - # thickness_dist = 5 * max_thickness_chord_ratio * (0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) - - # self.prob.model.set_input_defaults( - # "thickness_dist", - # val=thickness_dist, - # units="m" - # ) + self.prob.model.set_input_defaults( + "diameter", + val=0.5, + units="m" + ) + + self.prob.model.set_input_defaults( + "taper_ratio", + val=0.5 + ) + + self.prob.model.set_input_defaults( + "curvature", + val=0.0, + units="m" + ) + + self.prob.model.set_input_defaults( + "y_offset", + val=0.0, + units="m" + ) + + self.prob.model.set_input_defaults( + "z_offset", + val=0.0, + units="m" + ) + + self.prob.model.set_input_defaults( + 'thickness', + val=0.05, + units='m' + ) + + self.prob.model.set_input_defaults( + "is_hollow", + val=True + ) + + n_points = 10 # = num_sections + x = jnp.linspace(0, 1, n_points) + max_thickness_chord_ratio = 0.12 + thickness_dist = 5 * max_thickness_chord_ratio * (0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) + + self.prob.model.set_input_defaults( + "thickness_dist", + val=thickness_dist, + units="m" + ) self.prob.setup( check=False, @@ -164,12 +145,12 @@ def test_case(self): self.prob.run_model() - om.n2(self.prob) + #om.n2(self.prob) tol = 1e-10 assert_near_equal( - self.prob['total_weight_wing'], - 4.22032, + self.prob['structure_mass'], + 440, tol ) @@ -204,9 +185,9 @@ def setUp(self): force_alloc_complex=True ) - self.prob.set_val('fuse_mass', val=100.0) - self.prob.set_val('wing_mass', val=4.2) - self.prob.set_val('tail_mass', val=4.25) + self.prob.set_val('total_weight_fuse', val=100.0) + self.prob.set_val('total_weight_wing', val=4.2) + self.prob.set_val('mass', val=4.25) def test_case(self): From a13ef2ecdc959e0de46aedec56be9ab8ec4d10bc Mon Sep 17 00:00:00 2001 From: szoppelt Date: Tue, 13 May 2025 12:47:03 +0000 Subject: [PATCH 061/147] Commit. --- aviary/mission/sixdof/six_dof_EOM.py | 405 +++++++++++++++++++++++++++ aviary/mission/sixdof/six_dof_ODE.py | 110 ++++++++ 2 files changed, 515 insertions(+) create mode 100644 aviary/mission/sixdof/six_dof_EOM.py create mode 100644 aviary/mission/sixdof/six_dof_ODE.py diff --git a/aviary/mission/sixdof/six_dof_EOM.py b/aviary/mission/sixdof/six_dof_EOM.py new file mode 100644 index 000000000..735d140fc --- /dev/null +++ b/aviary/mission/sixdof/six_dof_EOM.py @@ -0,0 +1,405 @@ +import numpy as np +import openmdao.api as om + +class SixDOF_EOM(om.ExplicitComponent): + """ + Six DOF EOM component, with particular emphasis for rotorcraft. + ASSUMPTIONS: + - Assume Flat Earth model (particularly for rotorcraft) + - Earth is the internal f.o.r. + - Gravity is constant and normal to the tangent plane (Earth's surface) -- g = (0 0 G)^T + - (aircraft) mass is constant + - aircraft is a rigid body + - Symmetry in the xz plane (for moment of inertia matrix -- J_xy = J_yx = J_zy = J_yz = 0) + + Reference: https://youtu.be/hr_PqdkG6XY?si=_hFAZZMnk58eV9GJ + + """ + + def setup(self): + self.add_input( + 'mass', + val=0.0, + units='kg', + desc="mass -- assume constant" + ) + + self.add_input( + 'axial_vel', + val=0.0, + units='m/s', # meters per second + desc="axial velocity of CM wrt inertial CS resolved in aircraft body fixed CS" + ) + + self.add_input( + 'lat_vel', + val=0.0, + units='m/s', + desc="lateral velocity of CM wrt inertial CS resolved in aircraft body fixed CS" + ) + + self.add_input( + 'vert_vel', + val=0.0, + units='m/s', + desc="vertical velocity of CM wrt inertial CS resolved in aircraft body fixed CS" + ) + + self.add_input( + 'roll_ang_vel', + val=0.0, + units='rad/s', # radians per second + desc="roll angular velocity of body fixed CS wrt intertial CS" + ) + + self.add_input( + 'pitch_ang_vel', + val=0.0, + units='rad/s', + desc="pitch angular velocity of body fixed CS wrt intertial CS" + ) + + self.add_input( + 'yaw_ang_vel', + val=0.0, + units='rad/s', + desc="yaw angular velocity of body fixed CS wrt intertial CS" + ) + + self.add_input( + 'roll', + val=0.0, + units='rad', # radians + desc="roll angle" + ) + + self.add_input( + 'pitch', + val=0.0, + units='rad', + desc="pitch angle" + ) + + self.add_input( + 'yaw', + val=0.0, + units='rad', + desc="yaw angle" + ) + + self.add_input( + 'x', + val=0.0, + units='m', + desc="x-axis position of aircraft resolved in North-East-Down (NED) CS" + ) + + self.add_input( + 'y', + val=0.0, + units='m', + desc="y-axis position of aircraft resolved in NED CS" + ) + + self.add_input( + 'z', + val=0.0, + units='m', + desc="z-axis position of aircraft resolved in NED CS" + ) + + self.add_input( + 'time', + val=0.0, + desc="scalar time in seconds" + ) + + self.add_input( + 'g', + val=9.81, + units='m/s**2', + desc="acceleration due to gravity" + ) + + self.add_input( + 'Fx_ext', + val=0.0, + units='N', + desc="external forces in the x direciton" + ) + + self.add_input( + 'Fy_ext', + val=0.0, + units='N', + desc="external forces in the y direction" + ) + + self.add_input( + 'Fz_ext', + val=0.0, + units='N', + desc="external forces in the z direction" + ) + + self.add_input( + 'lx_ext', + val=0.0, + units='kg*m**2/s**2', # kg times m^2 / s^2 + desc="external moments in the x direction" + ) + + self.add_input( + 'ly_ext', + val=0.0, + units='kg*m**2/s**2', + desc="external moments in the y direction" + ) + + self.add_input( + 'lz_ext', + val=0.0, + units='kg*m**2/s**2', + desc="external moments in the z direction" + ) + + # Below are the necessary components for the moment of inertia matrix (J) + # Only xx, yy, zz, and xz are needed (xy and yz are 0 with assumptions) + # For now, these are separated. + # TODO: Rewrite J and EOM in matrix form + + self.add_input( + 'J_xz', + val=0.0, + units='kg*m**2', + desc="x-z (top right and bottom left corner of 3x3 matrix, assuming symmetry) " \ + "component" + ) + + self.add_input( + 'J_xx', + val=0.0, + units='kg*m**2', + desc="first diag component" + ) + + self.add_input( + 'J_yy', + val=0.0, + units='kg*m**2', + desc="second diag component" + ) + + self.add_input( + 'J_zz', + val=0.0, + units='kg*m**2', + desc="third diag component" + ) + + # Outputs + + self.add_output( + 'dx_accel', + val=0.0, + units='m/s**2', # meters per seconds squared + desc="x-axis (roll-axis) velocity equation, " \ + "state: axial_vel" + ) + + self.add_output( + 'dy_accel', + val=0.0, + units='m/s**2', + desc="y-axis (pitch axis) velocity equation, " \ + "state: lat_vel" + ) + + self.add_output( + 'dz_accel', + val=0.0, + units='m/s**2', + desc="z-axis (yaw axis) velocity equation, " \ + "state: vert_vel" + ) + + self.add_output( + 'roll_accel', + val=0.0, + units='rad/s**2', # radians per second squared + desc="roll equation, " \ + "state: roll_ang_vel" + ) + + self.add_output( + 'pitch_accel', + val=0.0, + units='rad/s**2', + desc="pitch equation, " \ + "state: pitch_ang_vel" + ) + + self.add_output( + 'yaw_accel', + val=0.0, + units='rad/s**2', + desc="yaw equation, " \ + "state: yaw_ang_vel" + ) + + self.add_output( + 'roll_angle_rate_eq', + val=0.0, + units='rad/s', + desc="Euler angular roll rate" + ) + + self.add_output( + 'pitch_angle_rate_eq', + val=0.0, + units='rad/s', + desc="Euler angular pitch rate" + ) + + self.add_output( + 'yaw_angle_rate_eq', + val=0.0, + units='rad/s', + desc="Euler angular yaw rate" + ) + + self.add_output( + 'dx_dt', + val=0.0, + units='m/s', + desc="x-position derivative of aircraft COM wrt point in NED CS" + ) + + self.add_output( + 'dy_dt', + val=0.0, + units='m/s', + desc="y-position derivative of aircraft COM wrt point in NED CS" + ) + + self.add_output( + 'dz_dt', + val=0.0, + units='m/s', + desc="z-position derivative of aircraft COM wrt point in NED CS" + ) + + def compute(self, inputs, outputs): + """ + Compute function for EOM. + TODO: Same as above, potentially rewrite equations for \ + matrix form, and add potential assymetry to moment \ + of inertia matrix. + + """ + + # inputs + + mass = inputs['mass'] + axial_vel = inputs['axial_vel'] # u + lat_vel = inputs['lat_vel'] # v + vert_vel = inputs['vert_vel'] # w + roll_ang_vel = inputs['roll_ang_vel'] # p + pitch_ang_vel = inputs['pitch_ang_vel'] # q + yaw_ang_vel = inputs['yaw_ang_vel'] # r + roll = inputs['roll'] # phi + pitch = inputs['pitch'] # theta + yaw = inputs['yaw'] # psi + x = inputs['x'] # p1 + y = inputs['y'] # p2 + z = inputs['z'] # p3 + time = inputs['time'] + g = inputs['g'] + Fx_ext = inputs['Fx_ext'] + Fy_ext = inputs['Fy_ext'] + Fz_ext = inputs['Fz_ext'] + lx_ext = inputs['lx_ext'] # l + ly_ext = inputs['ly_ext'] # m + lz_ext = inputs['lz_ext'] # n + J_xz = inputs['J_xz'] + J_xx = inputs['J_xx'] + J_yy = inputs['J_yy'] + J_zz = inputs['J_zz'] + + # Resolve gravity in body coordinate system -- denoted with subscript 'b' + gx_b = -np.sin(pitch) * g + gy_b = np.sin(roll) * np.cos(pitch) * g + gz_b = np.cos(roll) * np.cos(pitch) * g + + # TODO: could add external forces and moments here if needed + + # Denominator for roll and yaw rate equations + Den = J_xx * J_zz - J_xz**2 + + # roll-axis velocity equation + + dx_accel = 1 / mass * Fx_ext + gx_b - vert_vel * pitch_ang_vel + lat_vel * yaw_ang_vel + + # pitch-axis velocity equation + + dy_accel = 1 / mass * Fy_ext + gy_b - axial_vel * yaw_ang_vel + vert_vel * roll_ang_vel + + # yaw-axis velocity equation + + dz_accel = 1 / mass * Fz_ext + gz_b - lat_vel * roll_ang_vel + axial_vel * pitch_ang_vel + + # Roll equation + + roll_accel = (J_xz * (J_xx - J_yy + J_zz) * roll_ang_vel * pitch_ang_vel - + (J_zz * (J_zz - J_yy) + J_xz**2) * pitch_ang_vel * yaw_ang_vel + + J_zz * lx_ext + + J_xz * lz_ext) / Den + + # Pitch equation + + pitch_accel = ((J_zz - J_xx) * roll_ang_vel * yaw_ang_vel - + J_xz * (roll_ang_vel**2 - yaw_ang_vel**2) + ly_ext) / J_yy + + # Yaw equation + + yaw_accel = ((J_xx * (J_xx - J_yy) + J_xz**2) * roll_ang_vel * pitch_ang_vel + + J_xz * (J_xx - J_yy + J_zz) * pitch_ang_vel * yaw_ang_vel + + J_xz * lx_ext + + J_xz * lz_ext) / Den + + # Kinematic equations + + roll_angle_rate_eq = roll_ang_vel + np.sin(roll) * np.tan(pitch) * pitch_ang_vel + \ + np.cos(roll) * np.tan(pitch) * yaw_ang_vel + + pitch_angle_rate_eq = np.cos(roll) * pitch_ang_vel - np.sin(roll) * yaw_ang_vel + + yaw_angle_rate_eq = np.sin(roll) / np.cos(pitch) * pitch_ang_vel + \ + np.cos(roll) / np.cos(pitch) * yaw_ang_vel + + # Position equations + + dx_dt = np.cos(pitch) * np.cos(yaw) * axial_vel + \ + (-np.cos(roll) * np.sin(yaw) + np.sin(roll) * np.sin(pitch) * np.cos(yaw)) * lat_vel + \ + (np.sin(roll) * np.sin(yaw) + np.cos(roll) * np.sin(pitch) * np.cos(yaw)) * vert_vel + + dy_dt = np.cos(pitch) * np.sin(yaw) * axial_vel + \ + (np.cos(roll) * np.cos(yaw) + np.sin(roll) * np.sin(pitch) * np.sin(yaw)) * lat_vel + \ + (-np.sin(roll) * np.cos(yaw) + np.cos(roll) * np.sin(pitch) * np.sin(yaw)) * vert_vel + + dz_dt = -np.sin(pitch) * axial_vel + \ + np.sin(roll) * np.cos(pitch) * lat_vel + \ + np.cos(roll) * np.cos(pitch) * vert_vel + + outputs['dx_accel'] = dx_accel + outputs['dy_accel'] = dy_accel + outputs['dz_accel'] = dz_accel + outputs['roll_accel'] = roll_accel + outputs['pitch_accel'] = pitch_accel + outputs['yaw_accel'] = yaw_accel + outputs['roll_angle_rate_eq'] = roll_angle_rate_eq + outputs['pitch_angle_rate_eq'] = pitch_angle_rate_eq + outputs['yaw_angle_rate_eq'] = yaw_angle_rate_eq + outputs['dx_dt'] = dx_dt + outputs['dy_dt'] = dy_dt + outputs['dz_dt'] = dz_dt \ No newline at end of file diff --git a/aviary/mission/sixdof/six_dof_ODE.py b/aviary/mission/sixdof/six_dof_ODE.py new file mode 100644 index 000000000..b9a2a60fc --- /dev/null +++ b/aviary/mission/sixdof/six_dof_ODE.py @@ -0,0 +1,110 @@ +import numpy as np +import openmdao.api as om + +# Here will import the 6dof equations of motion + +from aviary.mission.base_ode import BaseODE as _BaseODE + +from aviary.variable_info.enums import AnalysisScheme, SpeedType, ThrottleAllocation +from aviary.variable_info.variables import Aircraft, Dynamic, Mission + +class SixDOF_ODE(_BaseODE): + + def initialize(self): + super().initialize() + + def setup(self): + options = self.options + nn = options['num_nodes'] + analysis_scheme = options['analysis_scheme'] + self.add_atmosphere(input_speed_type=SpeedType.MACH) + + self.add_subsystem( + name='veclocity_rate_comp', + subsys=om.ExecComp( + 'velocity_rate = mach_rate * sos', + mach_rate = {'units': 'unitless/s', 'shape': (nn,)}, + sos={'units': 'm/s', 'shape': (nn,)}, + velocity_rate={'units': 'm/s**2', 'shape': (nn,)}, + has_diag_partials=True, + ), + promotes_inputs=[ + ('mach_rate', Dynamic.Atmosphere.MACH_RATE), + ('sos', Dynamic.Atmosphere.SPEED_OF_SOUND), + ], + promotes_outputs=[ + 'velocity_rate', Dynamic.Mission.VELOCITY_RATE + ], + ) + + sub1 = self.add_subsystem( + 'solver_sub', + om.Group(), + promotes=['*'] + ) + + self.add_core_subsystems(solver_group=sub1) + + self.add_external_subsystems(solver_group=sub1) + + sub1.add_subsystem( + name='SixDOF_EOM', + subsys=SixDOF_EOM(num_nodes=nn), + promotes_inputs=[ + 'mass', + 'axial_vel', + 'lat_vel', + 'vert_vel', + 'roll_ang_vel', + 'pitch_ang_vel', + 'yaw_ang_vel', + 'roll', + 'pitch', + 'yaw', + 'g', + 'Fx_ext', + 'Fy_ext', + 'Fz_ext', + 'lx_ext', + 'ly_ext', + 'lz_ext', + 'J_xz', + 'J_xx', + 'J_yy', + 'J_zz', + ], + promotes_outputs=[ + 'dx_accel', + 'dy_accel', + 'dz_accel', + 'roll_accel', + 'pitch_accel', + 'yaw_accel', + 'roll_angle_rate_eq', + 'pitch_angle_rate_eq', + 'yaw_angle_rate_eq', + 'dx_dt', + 'dy_dt', + 'dz_dt', + ] + ) + + self.set_input_defaults(Dynamic.Atmosphere.MACH, val=np.ones(nn), units='unitless') + self.set_input_defaults(Dynamic.Vehicle.MASS, val=np.ones(nn), units='kg') + self.set_input_defaults(Dynamic.Mission.VELOCITY, val=np.ones(nn), units='m/s') + self.set_input_defaults(Dynamic.Mission.ALTITUDE, val=np.ones(nn), units='m') + self.set_input_defaults(Dynamic.Mission.ALTITUDE_RATE, val=np.ones(nn), units='m/s') + + print_level = 0 if analysis_scheme is AnalysisScheme.SHOOTING else 2 + + sub1.nonlinear_solver = om.NewtonSolver( + solve_subsystems=True, + atol=1.0e-10, + rtol=1.0e-10, + ) + sub1.nonlinear_solver.linesearch = om.BoundsEnforceLS() + sub1.linear_solver = om.DirectSolver(assemble_jac=True) + sub1.nonlinear_solver.options['err_on_non_converge'] = True + sub1.nonlinear_solver.options['iprint'] = print_level + + self.options['auto_order'] = True \ No newline at end of file From d2ca94c49d832999d09ef73f432516140f08c033 Mon Sep 17 00:00:00 2001 From: szoppelt Date: Tue, 13 May 2025 12:48:01 +0000 Subject: [PATCH 062/147] commit --- .../mass/simple_mass/test/test_fuselage.py | 17 +---------------- .../mass/simple_mass/test/test_tail.py | 17 +---------------- .../mass/simple_mass/test/test_wing.py | 17 +---------------- 3 files changed, 3 insertions(+), 48 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/test/test_fuselage.py b/aviary/subsystems/mass/simple_mass/test/test_fuselage.py index 553720f21..1eaf791d0 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_fuselage.py +++ b/aviary/subsystems/mass/simple_mass/test/test_fuselage.py @@ -3,22 +3,7 @@ import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal -""" -The little bit of path code below is not important overall. This is for me to test -within the Docker container and VS Code before I push everything fully to the Github -repository. These lines can be deleted as things are updated further. - -""" - -import sys -import os - - -module_path = os.path.abspath("/home/omdao/Aviary/aviary/subsystems/mass") -if module_path not in sys.path: - sys.path.append(module_path) - -from simple_mass.fuselage import FuselageMassAndCOG +from aviary.subsystems.mass.simple_mass.fuselage import FuselageMassAndCOG class FuselageMassTestCase(unittest.TestCase): """ diff --git a/aviary/subsystems/mass/simple_mass/test/test_tail.py b/aviary/subsystems/mass/simple_mass/test/test_tail.py index 372928553..05f3cd467 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_tail.py +++ b/aviary/subsystems/mass/simple_mass/test/test_tail.py @@ -5,22 +5,7 @@ import numpy as np -""" -The little bit of path code below is not important overall. This is for me to test -within the Docker container and VS Code before I push everything fully to the Github -repository. These lines can be deleted as things are updated further. - -""" - -import sys -import os - - -module_path = os.path.abspath("/home/omdao/Aviary/aviary/subsystems/mass") -if module_path not in sys.path: - sys.path.append(module_path) - -from simple_mass.tail import TailMassAndCOG +from aviary.subsystems.mass.simple_mass.tail import TailMassAndCOG class TailMassTestCase(unittest.TestCase): """ diff --git a/aviary/subsystems/mass/simple_mass/test/test_wing.py b/aviary/subsystems/mass/simple_mass/test/test_wing.py index fe4524ee5..fd5b218f6 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_wing.py +++ b/aviary/subsystems/mass/simple_mass/test/test_wing.py @@ -7,22 +7,7 @@ import numpy as np import jax.numpy as jnp -""" -The little bit of path code below is not important overall. This is for me to test -within the Docker container and VS Code before I push everything fully to the Github -repository. These lines can be deleted as things are updated further. - -""" - -import sys -import os - - -module_path = os.path.abspath("/home/omdao/Aviary/aviary/subsystems/mass") -if module_path not in sys.path: - sys.path.append(module_path) - -from simple_mass.wing import WingMassAndCOG +from aviary.subsystems.mass.simple_mass.wing import WingMassAndCOG #@av.skipIfMissingDependencies(WingMassAndCOG) class WingMassTestCase(unittest.TestCase): From 1b40693f167a697d4e3252cdcb6a979770ecf334 Mon Sep 17 00:00:00 2001 From: szoppelt Date: Tue, 13 May 2025 19:41:54 +0000 Subject: [PATCH 063/147] First draft of force resolver. --- aviary/mission/sixdof/force_component_calc.py | 129 ++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 aviary/mission/sixdof/force_component_calc.py diff --git a/aviary/mission/sixdof/force_component_calc.py b/aviary/mission/sixdof/force_component_calc.py new file mode 100644 index 000000000..ac03a8d45 --- /dev/null +++ b/aviary/mission/sixdof/force_component_calc.py @@ -0,0 +1,129 @@ +import numpy as np +import openmdao.api as om + + +class ForceComponentResolver(om.ExplicitComponent): + """ + This class will resolve forces (thrust, drag, lift, etc.) into their + respective x,y,z components for the 6 DOF equations of motion. + + This class assumes that the total force is given and needs to be resolved + into the separate components. + + """ + + def setup(self): + + # inputs + + self.add_input( + 'u', + val=0.0, + units='m/s', + desc="axial velocity" + ) + + self.add_input( + 'v', + val=0.0, + units='m/s', + desc="lateral velocity" + ) + + self.add_input( + 'w', + val=0.0, + units='m/s', + desc="vertical velocity" + ) + + self.add_input( + 'drag', + val=0.0, + units='N', + desc="Drag vector (unresolved)" + ) + + self.add_input( + 'thrust', + val=0.0, + units='N', + desc="Thrust vector (unresolved)" + ) + + self.add_input( + 'lift', + val=0.0, + units='N', + desc="Lift vector (unresolved)" + ) + + self.add_input( + 'side', + val=0.0, + units='N', + desc="Side vector (unresolved)" + ) + + # outputs + + self.add_output( + 'Fx', + val=0.0, + units='N', + desc="x-comp of final force" + ) + + self.add_output( + 'Fy', + val=0.0, + units='N', + desc="y-comp of final force" + ) + + self.add_output( + 'Fz', + val=0.0, + units='N', + desc="z-comp of final force" + ) + + def compute(self, inputs, outputs): + + u = inputs['u'] + v = inputs['v'] + w = inputs['w'] + D = inputs['drag'] + T = inputs['thrust'] + L = inputs['lift'] + S = inputs['side'] # side force + + # true air speed + + V = np.sqrt(u**2 + v**2 + w**2) + + # ------------------------------------------------------------------------------ + # ----------------------------- Drag calculation ------------------------------- + # ------------------------------------------------------------------------------ + + alpha = np.arctan(w / u) + + beta = np.arctan(v / np.sqrt(u**2 + w**2)) + + # some trig needed + + cos_a = np.cos(alpha) + cos_b = np.cos(beta) + sin_a = np.sin(alpha) + sin_b = np.sin(beta) + + Fx_NoThrust = -(cos_a * cos_b * D - cos_a * sin_b * S - sin_a * L) + Fy_NoThrust = -(sin_b * D + cos_b * S) + Fz_NoThrust = -(sin_a * cos_b * D + sin_a * sin_b * S + cos_a * L) + + + + + + + From dac43c3131ab73fc904a5dedbd5a87202d09b62d Mon Sep 17 00:00:00 2001 From: szoppelt Date: Wed, 14 May 2025 14:31:48 +0000 Subject: [PATCH 064/147] Updates. --- aviary/mission/sixdof/force_component_calc.py | 14 +-- aviary/mission/sixdof/six_dof_ODE.py | 92 +++++++++++++------ 2 files changed, 73 insertions(+), 33 deletions(-) diff --git a/aviary/mission/sixdof/force_component_calc.py b/aviary/mission/sixdof/force_component_calc.py index ac03a8d45..14810f45c 100644 --- a/aviary/mission/sixdof/force_component_calc.py +++ b/aviary/mission/sixdof/force_component_calc.py @@ -96,18 +96,18 @@ def compute(self, inputs, outputs): D = inputs['drag'] T = inputs['thrust'] L = inputs['lift'] - S = inputs['side'] # side force + S = inputs['side'] # side force -- assume 0 for now # true air speed V = np.sqrt(u**2 + v**2 + w**2) - # ------------------------------------------------------------------------------ - # ----------------------------- Drag calculation ------------------------------- - # ------------------------------------------------------------------------------ + # angle of attack alpha = np.arctan(w / u) + # side slip angle + beta = np.arctan(v / np.sqrt(u**2 + w**2)) # some trig needed @@ -117,9 +117,9 @@ def compute(self, inputs, outputs): sin_a = np.sin(alpha) sin_b = np.sin(beta) - Fx_NoThrust = -(cos_a * cos_b * D - cos_a * sin_b * S - sin_a * L) - Fy_NoThrust = -(sin_b * D + cos_b * S) - Fz_NoThrust = -(sin_a * cos_b * D + sin_a * sin_b * S + cos_a * L) + outputs['Fx'] = -(cos_a * cos_b * D - cos_a * sin_b * S - sin_a * L) + outputs['Fy'] = -(sin_b * D + cos_b * S) + outputs['Fz'] = -(sin_a * cos_b * D + sin_a * sin_b * S + cos_a * L) diff --git a/aviary/mission/sixdof/six_dof_ODE.py b/aviary/mission/sixdof/six_dof_ODE.py index b9a2a60fc..5c8e1da35 100644 --- a/aviary/mission/sixdof/six_dof_ODE.py +++ b/aviary/mission/sixdof/six_dof_ODE.py @@ -1,13 +1,14 @@ import numpy as np import openmdao.api as om -# Here will import the 6dof equations of motion - from aviary.mission.base_ode import BaseODE as _BaseODE from aviary.variable_info.enums import AnalysisScheme, SpeedType, ThrottleAllocation from aviary.variable_info.variables import Aircraft, Dynamic, Mission +from aviary.mission.sixdof.six_dof_EOM import SixDOF_EOM +from aviary.mission.sixdof.force_component_calc import ForceComponentResolver + class SixDOF_ODE(_BaseODE): def initialize(self): @@ -19,28 +20,67 @@ def setup(self): analysis_scheme = options['analysis_scheme'] self.add_atmosphere(input_speed_type=SpeedType.MACH) - self.add_subsystem( - name='veclocity_rate_comp', + # self.add_subsystem( + # name='veclocity_rate_comp', + # subsys=om.ExecComp( + # 'velocity_rate = mach_rate * sos', + # mach_rate = {'units': 'unitless/s', 'shape': (nn,)}, + # sos={'units': 'm/s', 'shape': (nn,)}, + # velocity_rate={'units': 'm/s**2', 'shape': (nn,)}, + # has_diag_partials=True, + # ), + # promotes_inputs=[ + # ('mach_rate', Dynamic.Atmosphere.MACH_RATE), + # ('sos', Dynamic.Atmosphere.SPEED_OF_SOUND), + # ], + # promotes_outputs=[ + # 'velocity_rate', Dynamic.Mission.VELOCITY_RATE + # ], + # ) + + sub1 = self.add_subsystem( + 'solver_sub', + om.Group(), + promotes=['*'] + ) + + sub1.add_subsystem( + 'true_airspeed_comp', subsys=om.ExecComp( - 'velocity_rate = mach_rate * sos', - mach_rate = {'units': 'unitless/s', 'shape': (nn,)}, - sos={'units': 'm/s', 'shape': (nn,)}, - velocity_rate={'units': 'm/s**2', 'shape': (nn,)}, - has_diag_partials=True, + 'true_airspeed = (axial_vel**2 + lat_vel**2 + vert_vel**2)**0.5', + true_airspeed = {'units': 'm/s', 'shape': (nn,)}, + axial_vel = {'units': 'm/s', 'shape': (nn,)}, + lat_vel = {'units': 'm/s', 'shape': (nn,)}, + vert_vel = {'units': 'm/s', 'shape': (nn,)}, + has_diag_partials=True ), promotes_inputs=[ - ('mach_rate', Dynamic.Atmosphere.MACH_RATE), - ('sos', Dynamic.Atmosphere.SPEED_OF_SOUND), + 'axial_vel', + 'lat_vel', + 'vert_vel', ], promotes_outputs=[ - 'velocity_rate', Dynamic.Mission.VELOCITY_RATE - ], + 'true_airspeed' + ] ) - sub1 = self.add_subsystem( - 'solver_sub', - om.Group(), - promotes=['*'] + sub1.add_subsystem( + 'sum_forces_comp', + ForceComponentResolver(num_nodes=nn), + promotes_inputs=[ + 'u', + 'v', + 'w', + 'drag', + 'lift', + 'side', + 'thrust', + ], + promotes_outputs=[ + 'Fx', + 'Fy', + 'Fz', + ] ) self.add_core_subsystems(solver_group=sub1) @@ -48,8 +88,8 @@ def setup(self): self.add_external_subsystems(solver_group=sub1) sub1.add_subsystem( - name='SixDOF_EOM', - subsys=SixDOF_EOM(num_nodes=nn), + 'SixDOF_EOM', + SixDOF_EOM(num_nodes=nn), promotes_inputs=[ 'mass', 'axial_vel', @@ -71,7 +111,7 @@ def setup(self): 'J_xz', 'J_xx', 'J_yy', - 'J_zz', + 'J_zz' ], promotes_outputs=[ 'dx_accel', @@ -85,15 +125,15 @@ def setup(self): 'yaw_angle_rate_eq', 'dx_dt', 'dy_dt', - 'dz_dt', + 'dz_dt' ] ) - self.set_input_defaults(Dynamic.Atmosphere.MACH, val=np.ones(nn), units='unitless') - self.set_input_defaults(Dynamic.Vehicle.MASS, val=np.ones(nn), units='kg') - self.set_input_defaults(Dynamic.Mission.VELOCITY, val=np.ones(nn), units='m/s') - self.set_input_defaults(Dynamic.Mission.ALTITUDE, val=np.ones(nn), units='m') - self.set_input_defaults(Dynamic.Mission.ALTITUDE_RATE, val=np.ones(nn), units='m/s') + # self.set_input_defaults(Dynamic.Atmosphere.MACH, val=np.ones(nn), units='unitless') + # self.set_input_defaults(Dynamic.Vehicle.MASS, val=np.ones(nn), units='kg') + # self.set_input_defaults(Dynamic.Mission.VELOCITY, val=np.ones(nn), units='m/s') + # self.set_input_defaults(Dynamic.Mission.ALTITUDE, val=np.ones(nn), units='m') + # self.set_input_defaults(Dynamic.Mission.ALTITUDE_RATE, val=np.ones(nn), units='m/s') print_level = 0 if analysis_scheme is AnalysisScheme.SHOOTING else 2 From 2966467697d48b6fb5cdc5e599d711457ca4414a Mon Sep 17 00:00:00 2001 From: szoppelt Date: Wed, 14 May 2025 16:52:32 +0000 Subject: [PATCH 065/147] updates. --- aviary/mission/sixdof/six_dof_ODE.py | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/aviary/mission/sixdof/six_dof_ODE.py b/aviary/mission/sixdof/six_dof_ODE.py index 5c8e1da35..1c44216c6 100644 --- a/aviary/mission/sixdof/six_dof_ODE.py +++ b/aviary/mission/sixdof/six_dof_ODE.py @@ -20,24 +20,6 @@ def setup(self): analysis_scheme = options['analysis_scheme'] self.add_atmosphere(input_speed_type=SpeedType.MACH) - # self.add_subsystem( - # name='veclocity_rate_comp', - # subsys=om.ExecComp( - # 'velocity_rate = mach_rate * sos', - # mach_rate = {'units': 'unitless/s', 'shape': (nn,)}, - # sos={'units': 'm/s', 'shape': (nn,)}, - # velocity_rate={'units': 'm/s**2', 'shape': (nn,)}, - # has_diag_partials=True, - # ), - # promotes_inputs=[ - # ('mach_rate', Dynamic.Atmosphere.MACH_RATE), - # ('sos', Dynamic.Atmosphere.SPEED_OF_SOUND), - # ], - # promotes_outputs=[ - # 'velocity_rate', Dynamic.Mission.VELOCITY_RATE - # ], - # ) - sub1 = self.add_subsystem( 'solver_sub', om.Group(), From 58eeee639c3abfcf3deb74b95f67fc519acccc40 Mon Sep 17 00:00:00 2001 From: szoppelt Date: Wed, 14 May 2025 17:38:17 +0000 Subject: [PATCH 066/147] updates --- .../subsystems/mass/simple_mass/materials_database.py | 2 +- aviary/subsystems/mass/simple_mass/wing.py | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/materials_database.py b/aviary/subsystems/mass/simple_mass/materials_database.py index 7fcb8f8b8..fc8bba94c 100644 --- a/aviary/subsystems/mass/simple_mass/materials_database.py +++ b/aviary/subsystems/mass/simple_mass/materials_database.py @@ -39,7 +39,7 @@ materials.set_val('Carbon/Silicon-Carbide', 2080, units='kg/m**3') # Carbon fiber reinforced SiC materials.set_val('Silicon-Carbide/Silicon-Carbide', 2400, units='kg/m**3') # SiC fiber reinforced SiC matrix materials.set_val('Advanced Carbon-Carbon Composite', 1600, units='kg/m**3') # ACC -materials.set_val('Reinfoced Carbon-Carbon', 1580, units='kg/m**3') +materials.set_val('Reinforced Carbon-Carbon', 1580, units='kg/m**3') materials.set_val('Reinforced Carbon-Carbon Composite', 1580, units='kg/m**3') # Generally, ACC is better, but RCC is slightly cheaper """ diff --git a/aviary/subsystems/mass/simple_mass/wing.py b/aviary/subsystems/mass/simple_mass/wing.py index 832339ea9..9aad64e5b 100644 --- a/aviary/subsystems/mass/simple_mass/wing.py +++ b/aviary/subsystems/mass/simple_mass/wing.py @@ -215,15 +215,15 @@ def extract_airfoil_features(self, x_coords, y_coords): prob.setup() # Define some example inputs - prob.set_val('span', 1) - prob.set_val('root_chord', 1) - prob.set_val('tip_chord', 0.5) - prob.set_val('twist', jnp.linspace(0, 0, 10)) + prob.set_val('span', 3.74904) + prob.set_val('root_chord', 0.40005) + prob.set_val('tip_chord', 0.100076) + prob.set_val('twist', jnp.linspace(0,0,10)) prob.set_val('thickness_dist', thickness_dist) #prob.model.cog.options['airfoil_data_file'] = 'Clark_Y.dat' - prob.model.cog.options['material'] = 'Balsa' + prob.model.cog.options['material'] = 'Reinfoced Carbon-Carbon' prob.model.cog.options['airfoil_type'] = '2412' # Run the model From efb7b3cee3bb7d9b103de12608cf3aa06fbdcb10 Mon Sep 17 00:00:00 2001 From: szoppelt Date: Wed, 14 May 2025 17:58:47 +0000 Subject: [PATCH 067/147] updates --- aviary/mission/sixdof/force_component_calc.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/aviary/mission/sixdof/force_component_calc.py b/aviary/mission/sixdof/force_component_calc.py index 14810f45c..38c955e82 100644 --- a/aviary/mission/sixdof/force_component_calc.py +++ b/aviary/mission/sixdof/force_component_calc.py @@ -108,7 +108,15 @@ def compute(self, inputs, outputs): # side slip angle - beta = np.arctan(v / np.sqrt(u**2 + w**2)) + # divide by zero checks + if (V == 0) and ((u != 0 or w != 0)) : + beta = np.arctan(v / np.sqrt(u**2 + w**2)) + elif (V == 0) and ((u == 0) and (w == 0)): + u = 1.0e-4 + beta = np.arctan(v / np.sqrt(u**2 + w**2)) + else: + beta = np.arcsin(v / V) + # some trig needed From cf33f8255d9a94e1e624f98bd9bc28d458f6b6fc Mon Sep 17 00:00:00 2001 From: szoppelt Date: Thu, 15 May 2025 14:16:49 +0000 Subject: [PATCH 068/147] updates. --- aviary/mission/sixdof/six_dof_EOM.py | 186 ++++++++++++++------- aviary/mission/sixdof/six_dof_ODE.py | 17 +- aviary/subsystems/mass/simple_mass/wing.py | 2 +- 3 files changed, 133 insertions(+), 72 deletions(-) diff --git a/aviary/mission/sixdof/six_dof_EOM.py b/aviary/mission/sixdof/six_dof_EOM.py index 735d140fc..c8b690dc7 100644 --- a/aviary/mission/sixdof/six_dof_EOM.py +++ b/aviary/mission/sixdof/six_dof_EOM.py @@ -15,104 +15,109 @@ class SixDOF_EOM(om.ExplicitComponent): Reference: https://youtu.be/hr_PqdkG6XY?si=_hFAZZMnk58eV9GJ """ + + def initialize(self): + self.options.declare('num_nodes', types=int) def setup(self): + nn = self.options['num_nodes'] + self.add_input( 'mass', - val=0.0, + val=np.zeros(nn), units='kg', desc="mass -- assume constant" ) self.add_input( 'axial_vel', - val=0.0, + val=np.zeros(nn), units='m/s', # meters per second desc="axial velocity of CM wrt inertial CS resolved in aircraft body fixed CS" ) self.add_input( 'lat_vel', - val=0.0, + val=np.zeros(nn), units='m/s', desc="lateral velocity of CM wrt inertial CS resolved in aircraft body fixed CS" ) self.add_input( 'vert_vel', - val=0.0, + val=np.zeros(nn), units='m/s', desc="vertical velocity of CM wrt inertial CS resolved in aircraft body fixed CS" ) self.add_input( 'roll_ang_vel', - val=0.0, + val=np.zeros(nn), units='rad/s', # radians per second desc="roll angular velocity of body fixed CS wrt intertial CS" ) self.add_input( 'pitch_ang_vel', - val=0.0, + val=np.zeros(nn), units='rad/s', desc="pitch angular velocity of body fixed CS wrt intertial CS" ) self.add_input( 'yaw_ang_vel', - val=0.0, + val=np.zeros(nn), units='rad/s', desc="yaw angular velocity of body fixed CS wrt intertial CS" ) self.add_input( 'roll', - val=0.0, + val=np.zeros(nn), units='rad', # radians desc="roll angle" ) self.add_input( 'pitch', - val=0.0, + val=np.zeros(nn), units='rad', desc="pitch angle" ) self.add_input( 'yaw', - val=0.0, + val=np.zeros(nn), units='rad', desc="yaw angle" ) - self.add_input( - 'x', - val=0.0, - units='m', - desc="x-axis position of aircraft resolved in North-East-Down (NED) CS" - ) - - self.add_input( - 'y', - val=0.0, - units='m', - desc="y-axis position of aircraft resolved in NED CS" - ) - - self.add_input( - 'z', - val=0.0, - units='m', - desc="z-axis position of aircraft resolved in NED CS" - ) - - self.add_input( - 'time', - val=0.0, - desc="scalar time in seconds" - ) + # self.add_input( + # 'x', + # val=0.0, + # units='m', + # desc="x-axis position of aircraft resolved in North-East-Down (NED) CS" + # ) + + # self.add_input( + # 'y', + # val=0.0, + # units='m', + # desc="y-axis position of aircraft resolved in NED CS" + # ) + + # self.add_input( + # 'z', + # val=0.0, + # units='m', + # desc="z-axis position of aircraft resolved in NED CS" + # ) + + # self.add_input( + # 'time', + # val=0.0, + # desc="scalar time in seconds" + # ) self.add_input( 'g', @@ -123,42 +128,42 @@ def setup(self): self.add_input( 'Fx_ext', - val=0.0, + val=np.zeros(nn), units='N', desc="external forces in the x direciton" ) self.add_input( 'Fy_ext', - val=0.0, + val=np.zeros(nn), units='N', desc="external forces in the y direction" ) self.add_input( 'Fz_ext', - val=0.0, + val=np.zeros(nn), units='N', desc="external forces in the z direction" ) self.add_input( 'lx_ext', - val=0.0, + val=np.zeros(nn), units='kg*m**2/s**2', # kg times m^2 / s^2 desc="external moments in the x direction" ) self.add_input( 'ly_ext', - val=0.0, + val=np.zeros(nn), units='kg*m**2/s**2', desc="external moments in the y direction" ) self.add_input( 'lz_ext', - val=0.0, + val=np.zeros(nn), units='kg*m**2/s**2', desc="external moments in the z direction" ) @@ -170,7 +175,7 @@ def setup(self): self.add_input( 'J_xz', - val=0.0, + val=np.zeros(1), units='kg*m**2', desc="x-z (top right and bottom left corner of 3x3 matrix, assuming symmetry) " \ "component" @@ -178,21 +183,21 @@ def setup(self): self.add_input( 'J_xx', - val=0.0, + val=np.zeros(1), units='kg*m**2', desc="first diag component" ) self.add_input( 'J_yy', - val=0.0, + val=np.zeros(1), units='kg*m**2', desc="second diag component" ) self.add_input( 'J_zz', - val=0.0, + val=np.zeros(1), units='kg*m**2', desc="third diag component" ) @@ -201,7 +206,7 @@ def setup(self): self.add_output( 'dx_accel', - val=0.0, + val=np.zeros(nn), units='m/s**2', # meters per seconds squared desc="x-axis (roll-axis) velocity equation, " \ "state: axial_vel" @@ -209,7 +214,7 @@ def setup(self): self.add_output( 'dy_accel', - val=0.0, + val=np.zeros(nn), units='m/s**2', desc="y-axis (pitch axis) velocity equation, " \ "state: lat_vel" @@ -217,7 +222,7 @@ def setup(self): self.add_output( 'dz_accel', - val=0.0, + val=np.zeros(nn), units='m/s**2', desc="z-axis (yaw axis) velocity equation, " \ "state: vert_vel" @@ -225,7 +230,7 @@ def setup(self): self.add_output( 'roll_accel', - val=0.0, + val=np.zeros(nn), units='rad/s**2', # radians per second squared desc="roll equation, " \ "state: roll_ang_vel" @@ -233,7 +238,7 @@ def setup(self): self.add_output( 'pitch_accel', - val=0.0, + val=np.zeros(nn), units='rad/s**2', desc="pitch equation, " \ "state: pitch_ang_vel" @@ -241,7 +246,7 @@ def setup(self): self.add_output( 'yaw_accel', - val=0.0, + val=np.zeros(nn), units='rad/s**2', desc="yaw equation, " \ "state: yaw_ang_vel" @@ -249,42 +254,42 @@ def setup(self): self.add_output( 'roll_angle_rate_eq', - val=0.0, + val=np.zeros(nn), units='rad/s', desc="Euler angular roll rate" ) self.add_output( 'pitch_angle_rate_eq', - val=0.0, + val=np.zeros(nn), units='rad/s', desc="Euler angular pitch rate" ) self.add_output( 'yaw_angle_rate_eq', - val=0.0, + val=np.zeros(nn), units='rad/s', desc="Euler angular yaw rate" ) self.add_output( 'dx_dt', - val=0.0, + val=np.zeros(nn), units='m/s', desc="x-position derivative of aircraft COM wrt point in NED CS" ) self.add_output( 'dy_dt', - val=0.0, + val=np.zeros(nn), units='m/s', desc="y-position derivative of aircraft COM wrt point in NED CS" ) self.add_output( 'dz_dt', - val=0.0, + val=np.zeros(nn), units='m/s', desc="z-position derivative of aircraft COM wrt point in NED CS" ) @@ -310,10 +315,10 @@ def compute(self, inputs, outputs): roll = inputs['roll'] # phi pitch = inputs['pitch'] # theta yaw = inputs['yaw'] # psi - x = inputs['x'] # p1 - y = inputs['y'] # p2 - z = inputs['z'] # p3 - time = inputs['time'] + # x = inputs['x'] # p1 + # y = inputs['y'] # p2 + # z = inputs['z'] # p3 + # time = inputs['time'] g = inputs['g'] Fx_ext = inputs['Fx_ext'] Fy_ext = inputs['Fy_ext'] @@ -402,4 +407,59 @@ def compute(self, inputs, outputs): outputs['yaw_angle_rate_eq'] = yaw_angle_rate_eq outputs['dx_dt'] = dx_dt outputs['dy_dt'] = dy_dt - outputs['dz_dt'] = dz_dt \ No newline at end of file + outputs['dz_dt'] = dz_dt + + +if __name__ == "__main__": + + p = om.Problem() + p.model = om.Group() + des_vars = p.model.add_subsystem('des_vars', om.IndepVarComp(), promotes=['*']) + + des_vars.add_output('mass', 3.0, units='kg') + des_vars.add_output('axial_vel', 0.1, units='m/s') + des_vars.add_output('lat_vel', 0.7, units='m/s') + des_vars.add_output('vert_vel', 0.12, units='m/s') + des_vars.add_output('roll_ang_vel', 0.1, units='rad/s') + des_vars.add_output('pitch_ang_vel', 0.9, units='rad/s') + des_vars.add_output('yaw_ang_vel', 0.12, units='rad/s') + des_vars.add_output('roll', 0.9, units='rad') + des_vars.add_output('pitch', 0.19, units='rad') + des_vars.add_output('yaw', 0.70, units='rad') + des_vars.add_output('g', 9.81, units='m/s**2') + des_vars.add_output('Fx_ext', 0.1, units='N') + des_vars.add_output('Fy_ext', 0.9, units='N') + des_vars.add_output('Fz_ext', 0.12, units='N') + des_vars.add_output('lx_ext', 3.0, units='N*m') + des_vars.add_output('ly_ext', 4.0, units='N*m') + des_vars.add_output('lz_ext', 5.0, units='N*m') + des_vars.add_output('J_xz', 9.0, units='kg*m**2') + des_vars.add_output('J_xx', 50.0, units='kg*m**2') + des_vars.add_output('J_yy', 51.0, units='kg*m**2') + des_vars.add_output('J_zz', 52.0, units='kg*m**2') + + p.model.add_subsystem('SixDOF_EOM', SixDOF_EOM(num_nodes=1), promotes=['*']) + + p.setup(check=False, force_alloc_complex=True) + + p.run_model() + + dx_accel = p.get_val('dx_accel') + dy_accel = p.get_val('dy_accel') + dz_accel = p.get_val('dz_accel') + roll_accel = p.get_val('roll_accel') + pitch_accel = p.get_val('pitch_accel') + yaw_accel = p.get_val('yaw_accel') + roll_angle_rate_eq = p.get_val('roll_angle_rate_eq') + pitch_angle_rate_eq = p.get_val('pitch_angle_rate_eq') + yaw_angle_rate_eq = p.get_val('yaw_angle_rate_eq') + dx_dt = p.get_val('dx_dt') + dy_dt = p.get_val('dy_dt') + dz_dt = p.get_val('dz_dt') + + print(f"Accelerations in x,y,z: {dx_accel}, {dy_accel}, {dz_accel}") + print(f"Euler angle accels in roll, pitch, yaw: {roll_accel}, {pitch_accel}, {yaw_accel}") + print(f"Euler angular rates: {roll_angle_rate_eq}, {pitch_angle_rate_eq}, {yaw_angle_rate_eq}") + print(f"velocities: {dx_dt}, {dy_dt}, {dz_dt}") + + diff --git a/aviary/mission/sixdof/six_dof_ODE.py b/aviary/mission/sixdof/six_dof_ODE.py index 1c44216c6..604e05c8e 100644 --- a/aviary/mission/sixdof/six_dof_ODE.py +++ b/aviary/mission/sixdof/six_dof_ODE.py @@ -18,15 +18,8 @@ def setup(self): options = self.options nn = options['num_nodes'] analysis_scheme = options['analysis_scheme'] - self.add_atmosphere(input_speed_type=SpeedType.MACH) - sub1 = self.add_subsystem( - 'solver_sub', - om.Group(), - promotes=['*'] - ) - - sub1.add_subsystem( + self.add_subsystem( 'true_airspeed_comp', subsys=om.ExecComp( 'true_airspeed = (axial_vel**2 + lat_vel**2 + vert_vel**2)**0.5', @@ -46,6 +39,14 @@ def setup(self): ] ) + self.add_atmosphere(input_speed_type=SpeedType.TAS) + + sub1 = self.add_subsystem( + 'solver_sub', + om.Group(), + promotes=['*'] + ) + sub1.add_subsystem( 'sum_forces_comp', ForceComponentResolver(num_nodes=nn), diff --git a/aviary/subsystems/mass/simple_mass/wing.py b/aviary/subsystems/mass/simple_mass/wing.py index 9aad64e5b..e17f1cca9 100644 --- a/aviary/subsystems/mass/simple_mass/wing.py +++ b/aviary/subsystems/mass/simple_mass/wing.py @@ -223,7 +223,7 @@ def extract_airfoil_features(self, x_coords, y_coords): #prob.model.cog.options['airfoil_data_file'] = 'Clark_Y.dat' - prob.model.cog.options['material'] = 'Reinfoced Carbon-Carbon' + prob.model.cog.options['material'] = 'Reinforced Carbon-Carbon' prob.model.cog.options['airfoil_type'] = '2412' # Run the model From 66d9313ae114a0b24efd6a9e1560ee2ceb5d8e0d Mon Sep 17 00:00:00 2001 From: szoppelt Date: Mon, 19 May 2025 14:21:10 +0000 Subject: [PATCH 069/147] updates. --- .../subsystems/mass/simple_mass/fuselage.py | 44 +++++++++---------- .../mass/simple_mass/test/test_fuselage.py | 12 ++--- 2 files changed, 27 insertions(+), 29 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/fuselage.py b/aviary/subsystems/mass/simple_mass/fuselage.py index 9f50d0067..5928447be 100644 --- a/aviary/subsystems/mass/simple_mass/fuselage.py +++ b/aviary/subsystems/mass/simple_mass/fuselage.py @@ -59,13 +59,13 @@ def setup(self): val=2.0, units='m') - self.add_input('diameter', + self.add_input('base_diameter', val=0.4, units='m') - - self.add_input('taper_ratio', - val=1.0, - units=None) # 1.0 means no taper + + self.add_input('tip_diameter', + val=0.2, + units='m') self.add_input('curvature', val=0.0, @@ -106,12 +106,12 @@ def setup(self): val=0.0, units='kg') - def compute_primal(self, length, diameter, taper_ratio, curvature, thickness, y_offset, z_offset, is_hollow): + def compute_primal(self, length, base_diameter, tip_diameter, curvature, thickness, y_offset, z_offset, is_hollow): # Input validation checks if length <= 0: raise ValueError("Length must be greater than zero.") - if diameter <= 0: + if base_diameter <= 0 or tip_diameter <= 0: raise ValueError("Diameter must be greater than zero.") custom_fuselage_function = getattr(self, 'custom_fuselage_function', None) # Custom fuselage model function -- if provided @@ -121,7 +121,7 @@ def compute_primal(self, length, diameter, taper_ratio, curvature, thickness, y_ material = self.options['material'] num_sections = self.options['num_sections'] - self.validate_inputs(length, diameter, thickness, taper_ratio, is_hollow) + self.validate_inputs(length, base_diameter, thickness, tip_diameter, is_hollow) density, _ = materials.get_item(material) @@ -136,14 +136,14 @@ def compute_primal(self, length, diameter, taper_ratio, curvature, thickness, y_ # Loop through each section for location in section_locations: - section_diameter = self.get_section_diameter(location, length, diameter, taper_ratio, interpolate_diameter) + section_diameter = self.get_section_diameter(location, length, base_diameter, tip_diameter, interpolate_diameter) outer_radius = section_diameter / 2.0 inner_radius = jnp.where(is_hollow, omj.smooth_max(0, outer_radius - thickness), 0) section_volume = jnp.pi * (outer_radius**2 - inner_radius**2) * (length / num_sections) section_weight = density * section_volume - centroid_x, centroid_y, centroid_z = self.compute_centroid(location, length, y_offset, z_offset, curvature, taper_ratio) + centroid_x, centroid_y, centroid_z = self.compute_centroid(location, length, y_offset, z_offset, curvature, base_diameter, tip_diameter) total_weight_fuse += section_weight total_moment_x += centroid_x * section_weight @@ -156,12 +156,10 @@ def compute_primal(self, length, diameter, taper_ratio, curvature, thickness, y_ return center_of_gravity_x_fuse, center_of_gravity_y_fuse, center_of_gravity_z_fuse, total_weight_fuse - def validate_inputs(self, length, diameter, thickness, taper_ratio, is_hollow): - if length <= 0 or diameter <= 0 or thickness <= 0: + def validate_inputs(self, length, base_diameter, thickness, tip_diameter, is_hollow): + if length <= 0 or base_diameter <= 0 or tip_diameter <= 0 or thickness <= 0: raise ValueError("Length, diameter, and thickness must be positive values.") - if taper_ratio < 0 or taper_ratio > 1: - raise ValueError("Taper ratio must be between 0 and 1.") - if is_hollow and thickness >= diameter / 2: + if is_hollow and thickness >= base_diameter / 2: raise ValueError("Wall thickness is too large for a hollow fuselage.") def load_fuselage_data(self, custom_fuselage_data_file): @@ -177,16 +175,16 @@ def load_fuselage_data(self, custom_fuselage_data_file): else: return None - def get_section_diameter(self, location, length, diameter, taper_ratio, interpolate_diameter): + def get_section_diameter(self, location, length, base_diameter, tip_diameter, interpolate_diameter): if self.custom_fuselage_function: return self.custom_fuselage_function(location) elif self.load_fuselage_data: - return interpolate_diameter(location) if interpolate_diameter is not None else omj.smooth_max(0.01, diameter * (1 - taper_ratio * (location / length))) + return interpolate_diameter(location) if interpolate_diameter is not None else base_diameter + ((tip_diameter - base_diameter) / length) * location else: - return omj.smooth_max(0.01, diameter * (1 - taper_ratio * (location / length))) + return base_diameter + ((tip_diameter - base_diameter) / length) * location - def compute_centroid(self, location, length, y_offset, z_offset, curvature, taper_ratio): - centroid_x = jnp.where(taper_ratio > 0, (3/4) * location, location) + def compute_centroid(self, location, length, y_offset, z_offset, curvature, base_diameter, tip_diameter): + centroid_x = jnp.where(tip_diameter / base_diameter != 1, (3/4) * location, location) centroid_y = y_offset * (1 - location / length) centroid_z = z_offset * (1 - location / length) + curvature * location**2 / length return centroid_x, centroid_y, centroid_z @@ -195,13 +193,13 @@ def compute_centroid(self, location, length, y_offset, z_offset, curvature, tape if __name__ == "__main__": prob = om.Problem() - prob.model.add_subsystem('fuselage_cg', FuselageMassAndCOG(), promotes_inputs=['length', 'diameter', 'taper_ratio', 'curvature', 'thickness', 'y_offset', 'z_offset', 'is_hollow']) + prob.model.add_subsystem('fuselage_cg', FuselageMassAndCOG(), promotes_inputs=['*']) prob.setup() prob.set_val('length', 2.5) - prob.set_val('diameter', 0.5) - prob.set_val('taper_ratio', 0.5) + prob.set_val('base_diameter', 0.5) + prob.set_val('tip_diameter', 0.3) prob.set_val('curvature', 0.0) prob.set_val('thickness', 0.05) # Wall thickness of 5 cm #prob.set_val('is_hollow', False) # Default is True, uncomment to use False -- for testing purposes diff --git a/aviary/subsystems/mass/simple_mass/test/test_fuselage.py b/aviary/subsystems/mass/simple_mass/test/test_fuselage.py index 1eaf791d0..17134bfaa 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_fuselage.py +++ b/aviary/subsystems/mass/simple_mass/test/test_fuselage.py @@ -27,14 +27,14 @@ def setUp(self): units="m") self.prob.model.set_input_defaults( - "diameter", - val=0.4, + "base_diameter", + val=0.5, units="m" ) self.prob.model.set_input_defaults( - "taper_ratio", - val=0.9999999999 + "tip_diameter", + val=0.3 ) self.prob.model.set_input_defaults( @@ -71,8 +71,8 @@ def test_case(self): tol=1e-3 assert_near_equal( - self.prob["total_weight"], - 167.35489, + self.prob["total_weight_fuse"], + 467.3119, tol) partial_data = self.prob.check_partials( From 5cd215dbf14e612e6e29a05f6845f863e0331eec Mon Sep 17 00:00:00 2001 From: szoppelt Date: Wed, 21 May 2025 19:10:24 +0000 Subject: [PATCH 070/147] updates. --- aviary/docs/examples/six_dof_ODE.py | 2 + aviary/mission/sixdof/force_component_calc.py | 149 +++++++- aviary/mission/sixdof/plottest.py | 10 + aviary/mission/sixdof/six_dof_EOM.py | 350 ++++++++++++++++-- aviary/mission/sixdof/test_mission_6dof.py | 179 +++++++++ 5 files changed, 639 insertions(+), 51 deletions(-) create mode 100644 aviary/mission/sixdof/plottest.py create mode 100644 aviary/mission/sixdof/test_mission_6dof.py diff --git a/aviary/docs/examples/six_dof_ODE.py b/aviary/docs/examples/six_dof_ODE.py index b9a2a60fc..f73190597 100644 --- a/aviary/docs/examples/six_dof_ODE.py +++ b/aviary/docs/examples/six_dof_ODE.py @@ -8,6 +8,8 @@ from aviary.variable_info.enums import AnalysisScheme, SpeedType, ThrottleAllocation from aviary.variable_info.variables import Aircraft, Dynamic, Mission +from aviary.mission.sixdof.six_dof_EOM import SixDOF_EOM + class SixDOF_ODE(_BaseODE): def initialize(self): diff --git a/aviary/mission/sixdof/force_component_calc.py b/aviary/mission/sixdof/force_component_calc.py index 38c955e82..814b372f4 100644 --- a/aviary/mission/sixdof/force_component_calc.py +++ b/aviary/mission/sixdof/force_component_calc.py @@ -12,55 +12,59 @@ class ForceComponentResolver(om.ExplicitComponent): """ + def initialize(self): + self.options.declare('num_nodes', types=int) + def setup(self): + nn = self.options['num_nodes'] # inputs self.add_input( 'u', - val=0.0, + val=np.zeros(nn), units='m/s', desc="axial velocity" ) self.add_input( 'v', - val=0.0, + val=np.zeros(nn), units='m/s', desc="lateral velocity" ) self.add_input( 'w', - val=0.0, + val=np.zeros(nn), units='m/s', desc="vertical velocity" ) self.add_input( 'drag', - val=0.0, + val=np.zeros(nn), units='N', desc="Drag vector (unresolved)" ) self.add_input( 'thrust', - val=0.0, + val=np.zeros(nn), units='N', desc="Thrust vector (unresolved)" ) self.add_input( 'lift', - val=0.0, + val=np.zeros(nn), units='N', desc="Lift vector (unresolved)" ) self.add_input( 'side', - val=0.0, + val=np.zeros(nn), units='N', desc="Side vector (unresolved)" ) @@ -69,25 +73,48 @@ def setup(self): self.add_output( 'Fx', - val=0.0, + val=np.zeros(nn), units='N', desc="x-comp of final force" ) self.add_output( 'Fy', - val=0.0, + val=np.zeros(nn), units='N', desc="y-comp of final force" ) self.add_output( 'Fz', - val=0.0, + val=np.zeros(nn), units='N', desc="z-comp of final force" ) + ar = np.arange(nn) + + self.declare_partials(of='Fx', wrt='u', rows=ar, cols=ar) + self.declare_partials(of='Fx', wrt='v', rows=ar, cols=ar) + self.declare_partials(of='Fx', wrt='w', rows=ar, cols=ar) + self.declare_partials(of='Fx', wrt='drag', rows=ar, cols=ar) + self.declare_partials(of='Fx', wrt='lift', rows=ar, cols=ar) + self.declare_partials(of='Fx', wrt='side', rows=ar, cols=ar) + + self.declare_partials(of='Fy', wrt='u', rows=ar, cols=ar) + self.declare_partials(of='Fy', wrt='v', rows=ar, cols=ar) + self.declare_partials(of='Fy', wrt='w', rows=ar, cols=ar) + self.declare_partials(of='Fy', wrt='drag', rows=ar, cols=ar) + self.declare_partials(of='Fy', wrt='lift', rows=ar, cols=ar) + self.declare_partials(of='Fy', wrt='side', rows=ar, cols=ar) + + self.declare_partials(of='Fz', wrt='u', rows=ar, cols=ar) + self.declare_partials(of='Fz', wrt='v', rows=ar, cols=ar) + self.declare_partials(of='Fz', wrt='w', rows=ar, cols=ar) + self.declare_partials(of='Fz', wrt='drag', rows=ar, cols=ar) + self.declare_partials(of='Fz', wrt='lift', rows=ar, cols=ar) + self.declare_partials(of='Fz', wrt='side', rows=ar, cols=ar) + def compute(self, inputs, outputs): u = inputs['u'] @@ -98,24 +125,31 @@ def compute(self, inputs, outputs): L = inputs['lift'] S = inputs['side'] # side force -- assume 0 for now + nn = self.options['num_nodes'] + # true air speed V = np.sqrt(u**2 + v**2 + w**2) # angle of attack - alpha = np.arctan(w / u) + # divide by zero checks + if np.any(u == 0): + u[u == 0] = 1e-4 + alpha = np.arctan(w / u) + else: + alpha = np.arctan(w / u) # side slip angle # divide by zero checks - if (V == 0) and ((u != 0 or w != 0)) : - beta = np.arctan(v / np.sqrt(u**2 + w**2)) - elif (V == 0) and ((u == 0) and (w == 0)): - u = 1.0e-4 + if ((np.any(u != 0) or np.any(w != 0))) : beta = np.arctan(v / np.sqrt(u**2 + w**2)) else: - beta = np.arcsin(v / V) + u[u == 0] = 1.0e-4 + beta = np.arctan(v / np.sqrt(u**2 + w**2)) + + # some trig needed @@ -128,6 +162,89 @@ def compute(self, inputs, outputs): outputs['Fx'] = -(cos_a * cos_b * D - cos_a * sin_b * S - sin_a * L) outputs['Fy'] = -(sin_b * D + cos_b * S) outputs['Fz'] = -(sin_a * cos_b * D + sin_a * sin_b * S + cos_a * L) + + def compute_partials(self, inputs, J): + + u = inputs['u'] + v = inputs['v'] + w = inputs['w'] + D = inputs['drag'] + T = inputs['thrust'] + L = inputs['lift'] + S = inputs['side'] # side force -- assume 0 for now + + V = np.sqrt(u**2 + v**2 + w**2) + + # divide by zero checks + if u == 0: + u = 1e-4 + alpha = np.arctan(w / u) + else: + alpha = np.arctan(w / u) + + # side slip angle + + # divide by zero checks + if ((u != 0 or w != 0)) : + beta = np.arctan(v / np.sqrt(u**2 + w**2)) + else: + u = 1.0e-4 + beta = np.arctan(v / np.sqrt(u**2 + w**2)) + + # note: d/dx arctan(a/x) = -a / (x^2 + a^2) + # note: d/dx arctan(a / sqrt(b^2 + x^2)) = - ax / ((b^2 + x^2 + a^2) * sqrt(b^2 + x^2)) + # note: d/dx arctan(x / sqrt(a^2 + b^2)) = sqrt(a^2 + b^2) / (a^2 + b^2 + x^2) + # note: d/dx arctan(x/a) = a / (a^2 + x^2) + + J['Fx', 'u'] = np.cos(alpha) * np.sin(beta) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * D + \ + np.cos(beta) * np.sin(alpha) * (-w / (w**2 + u**2)) * D + \ + (np.cos(alpha) * np.cos(beta) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * S - np.sin(beta) * np.sin(alpha) * (-w / (w**2 + u**2)) * S) + \ + (np.cos(alpha) * (-w / (w**2 + u**2)) * L) + J['Fx', 'v'] = np.cos(alpha) * np.sin(beta) * (np.sqrt(w**2 + u**2) / V**2) * D + np.cos(alpha) * np.cos(beta) * (np.sqrt(w**2 + u**2) / V**2) * S + J['Fx', 'w'] = np.cos(alpha) * np.sin(beta) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) * D + np.sin(alpha) * np.cos(beta) * (u / (w**2 + u**2)) * D + \ + np.cos(alpha) * np.cos(beta) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) * S - np.sin(alpha) * np.sin(beta) * (u / (w**2 + u**2)) * S + \ + np.cos(alpha) * (u / (w**2 + u**2)) * L + J['Fx', 'drag'] = -np.cos(alpha) * np.cos(beta) + J['Fx', 'lift'] = np.sin(alpha) + J['Fx', 'side'] = np.cos(alpha) * np.sin(beta) + + J['Fy', 'u'] = -np.cos(beta) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * D + np.sin(beta) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * S + J['Fy', 'v'] = -np.cos(beta) * (np.sqrt(w**2 + u**2) / V**2) * D + np.sin(beta) * (np.sqrt(w**2 + u**2) / V**2) * S + J['Fy', 'w'] = -np.cos(beta) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) * D + np.sin(beta) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) * S + J['Fy', 'drag'] = -np.sin(beta) + J['Fy', 'side'] = -np.cos(beta) + + J['Fz', 'u'] = np.sin(alpha) * np.sin(beta) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * D - np.cos(alpha) * np.cos(beta) * (-w / (w**2 + u**2)) * D - \ + np.sin(alpha) * np.cos(beta) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * S - np.cos(alpha) * np.sin(beta) * (-w / (w**2 + u**2)) * S + \ + np.sin(alpha) * (-w / (w**2 + u**2)) * L + J['Fz', 'v'] = np.sin(alpha) * np.sin(beta) * (np.sqrt(w**2 + u**2) / V**2) * D - np.sin(alpha) * np.cos(beta) * (np.sqrt(w**2 + u**2) / V**2) * S + J['Fz', 'w'] = np.sin(alpha) * np.sin(beta) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) * D - np.cos(alpha) * np.cos(beta) * (u / (w**2 + u**2)) * D - \ + np.sin(alpha) * np.cos(beta) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) * S - np.cos(alpha) * np.sin(beta) * (u / (w**2 + u**2)) * S + \ + np.sin(alpha) * (u / (w**2 + u**2)) * L + J['Fz', 'drag'] = -np.sin(alpha) * np.cos(beta) + J['Fz', 'lift'] = -np.cos(alpha) + J['Fz', 'side'] = -np.sin(alpha) * np.sin(beta) + +if __name__ == "__main__": + p = om.Problem() + p.model = om.Group() + des_vars = p.model.add_subsystem('des_vars', om.IndepVarComp(), promotes=['*']) + + des_vars.add_output('u', 0.5, units='m/s') + des_vars.add_output('v', 0.6, units='m/s') + des_vars.add_output('w', 0.7, units='m/s') + des_vars.add_output('drag', 50, units='N') + des_vars.add_output('thrust', 50, units='N') + des_vars.add_output('lift', 60, units='N') + des_vars.add_output('side', 70, units='N') + + p.model.add_subsystem('ForceComponentResolver', ForceComponentResolver(num_nodes=1), promotes=['*']) + + p.setup(check=False, force_alloc_complex=True) + + p.run_model() + + p.check_partials(compact_print=True, show_only_incorrect=True, method='cs') diff --git a/aviary/mission/sixdof/plottest.py b/aviary/mission/sixdof/plottest.py new file mode 100644 index 000000000..f406812d7 --- /dev/null +++ b/aviary/mission/sixdof/plottest.py @@ -0,0 +1,10 @@ +# importing mplot3d toolkits, numpy and matplotlib +from mpl_toolkits import mplot3d +import numpy as np +import matplotlib.pyplot as plt + +x = np.linspace(0, 10, 100) +y = x+2 + +plt.plot(x, y) +plt.show() \ No newline at end of file diff --git a/aviary/mission/sixdof/six_dof_EOM.py b/aviary/mission/sixdof/six_dof_EOM.py index c8b690dc7..11e1022dd 100644 --- a/aviary/mission/sixdof/six_dof_EOM.py +++ b/aviary/mission/sixdof/six_dof_EOM.py @@ -92,26 +92,26 @@ def setup(self): desc="yaw angle" ) - # self.add_input( - # 'x', - # val=0.0, - # units='m', - # desc="x-axis position of aircraft resolved in North-East-Down (NED) CS" - # ) + self.add_input( + 'x', + val=np.zeros(nn), + units='m', + desc="x-axis position of aircraft resolved in North-East-Down (NED) CS" + ) - # self.add_input( - # 'y', - # val=0.0, - # units='m', - # desc="y-axis position of aircraft resolved in NED CS" - # ) + self.add_input( + 'y', + val=np.zeros(nn), + units='m', + desc="y-axis position of aircraft resolved in NED CS" + ) - # self.add_input( - # 'z', - # val=0.0, - # units='m', - # desc="z-axis position of aircraft resolved in NED CS" - # ) + self.add_input( + 'z', + val=np.zeros(nn), + units='m', + desc="z-axis position of aircraft resolved in NED CS" + ) # self.add_input( # 'time', @@ -209,7 +209,8 @@ def setup(self): val=np.zeros(nn), units='m/s**2', # meters per seconds squared desc="x-axis (roll-axis) velocity equation, " \ - "state: axial_vel" + "state: axial_vel", + tags=['dymos.state_rate_source:axial_vel', 'dymos.state_units:m/s'] ) self.add_output( @@ -217,7 +218,8 @@ def setup(self): val=np.zeros(nn), units='m/s**2', desc="y-axis (pitch axis) velocity equation, " \ - "state: lat_vel" + "state: lat_vel", + tags=['dymos.state_rate_source:lat_vel', 'dymos.state_units:m/s'] ) self.add_output( @@ -225,7 +227,8 @@ def setup(self): val=np.zeros(nn), units='m/s**2', desc="z-axis (yaw axis) velocity equation, " \ - "state: vert_vel" + "state: vert_vel", + tags=['dymos.state_rate_source:vert_vel', 'dymos.state_units:m/s'] ) self.add_output( @@ -233,7 +236,8 @@ def setup(self): val=np.zeros(nn), units='rad/s**2', # radians per second squared desc="roll equation, " \ - "state: roll_ang_vel" + "state: roll_ang_vel", + tags=['dymos.state_rate_source:roll_ang_vel', 'dymos.state_units:rad/s'] ) self.add_output( @@ -241,7 +245,8 @@ def setup(self): val=np.zeros(nn), units='rad/s**2', desc="pitch equation, " \ - "state: pitch_ang_vel" + "state: pitch_ang_vel", + tags=['dymos.state_rate_source:pitch_ang_vel', 'dymos.state_units:rad/s'] ) self.add_output( @@ -249,51 +254,152 @@ def setup(self): val=np.zeros(nn), units='rad/s**2', desc="yaw equation, " \ - "state: yaw_ang_vel" + "state: yaw_ang_vel", + tags=['dymos.state_rate_source:yaw_ang_vel', 'dymos.state_units:rad/s'] ) self.add_output( 'roll_angle_rate_eq', val=np.zeros(nn), units='rad/s', - desc="Euler angular roll rate" + desc="Euler angular roll rate", + tags=['dymos.state_rate_source:roll', 'dymos.state_units:rad'] ) self.add_output( 'pitch_angle_rate_eq', val=np.zeros(nn), units='rad/s', - desc="Euler angular pitch rate" + desc="Euler angular pitch rate", + tags=['dymos.state_rate_source:pitch', 'dymos.state_units:rad'] ) self.add_output( 'yaw_angle_rate_eq', val=np.zeros(nn), units='rad/s', - desc="Euler angular yaw rate" + desc="Euler angular yaw rate", + tags=['dymos.state_rate_source:yaw', 'dymos.state_units:rad'] ) self.add_output( 'dx_dt', val=np.zeros(nn), units='m/s', - desc="x-position derivative of aircraft COM wrt point in NED CS" + desc="x-position derivative of aircraft COM wrt point in NED CS", + tags=['dymos.state_rate_source:x', 'dymos.state_units:m'] ) self.add_output( 'dy_dt', val=np.zeros(nn), units='m/s', - desc="y-position derivative of aircraft COM wrt point in NED CS" + desc="y-position derivative of aircraft COM wrt point in NED CS", + tags=['dymos.state_rate_source:y', 'dymos.state_units:m'] ) self.add_output( 'dz_dt', val=np.zeros(nn), units='m/s', - desc="z-position derivative of aircraft COM wrt point in NED CS" - ) - + desc="z-position derivative of aircraft COM wrt point in NED CS", + tags=['dymos.state_rate_source:z', 'dymos.state_units:m'] + ) + + ar = np.arange(nn) + self.declare_partials(of='dx_accel', wrt='mass', rows=ar, cols=ar) + self.declare_partials(of='dx_accel', wrt='Fx_ext', rows=ar, cols=ar) + self.declare_partials(of='dx_accel', wrt='lat_vel', rows=ar, cols=ar) + self.declare_partials(of='dx_accel', wrt='vert_vel', rows=ar, cols=ar) + self.declare_partials(of='dx_accel', wrt='yaw_ang_vel', rows=ar, cols=ar) + self.declare_partials(of='dx_accel', wrt='pitch_ang_vel', rows=ar, cols=ar) + self.declare_partials(of='dx_accel', wrt='g') + self.declare_partials(of='dx_accel', wrt='pitch', rows=ar, cols=ar) + + self.declare_partials(of='dy_accel', wrt='mass', rows=ar, cols=ar) + self.declare_partials(of='dy_accel', wrt='Fy_ext', rows=ar, cols=ar) + self.declare_partials(of='dy_accel', wrt='axial_vel', rows=ar, cols=ar) + self.declare_partials(of='dy_accel', wrt='vert_vel', rows=ar, cols=ar) + self.declare_partials(of='dy_accel', wrt='yaw_ang_vel', rows=ar, cols=ar) + self.declare_partials(of='dy_accel', wrt='roll_ang_vel', rows=ar, cols=ar) + self.declare_partials(of='dy_accel', wrt='g') + self.declare_partials(of='dy_accel', wrt='roll', rows=ar, cols=ar) + self.declare_partials(of='dy_accel', wrt='pitch', rows=ar, cols=ar) + + self.declare_partials(of='dz_accel', wrt='mass', rows=ar, cols=ar) + self.declare_partials(of='dz_accel', wrt='Fz_ext', rows=ar, cols=ar) + self.declare_partials(of='dz_accel', wrt='lat_vel', rows=ar, cols=ar) + self.declare_partials(of='dz_accel', wrt='axial_vel', rows=ar, cols=ar) + self.declare_partials(of='dz_accel', wrt='roll_ang_vel', rows=ar, cols=ar) + self.declare_partials(of='dz_accel', wrt='pitch_ang_vel', rows=ar, cols=ar) + self.declare_partials(of='dz_accel', wrt='g') + self.declare_partials(of='dz_accel', wrt='roll', rows=ar, cols=ar) + self.declare_partials(of='dz_accel', wrt='pitch', rows=ar, cols=ar) + + self.declare_partials(of='roll_accel', wrt='J_xz') + self.declare_partials(of='roll_accel', wrt='J_xx') + self.declare_partials(of='roll_accel', wrt='J_yy') + self.declare_partials(of='roll_accel', wrt='J_zz') + self.declare_partials(of='roll_accel', wrt='roll_ang_vel', rows=ar, cols=ar) + self.declare_partials(of='roll_accel', wrt='pitch_ang_vel', rows=ar, cols=ar) + self.declare_partials(of='roll_accel', wrt='yaw_ang_vel', rows=ar, cols=ar) + self.declare_partials(of='roll_accel', wrt='lx_ext', rows=ar, cols=ar) + self.declare_partials(of='roll_accel', wrt='lz_ext', rows=ar, cols=ar) + + self.declare_partials(of='pitch_accel', wrt='J_xz') + self.declare_partials(of='pitch_accel', wrt='J_xx') + self.declare_partials(of='pitch_accel', wrt='J_yy') + self.declare_partials(of='pitch_accel', wrt='J_zz') + self.declare_partials(of='pitch_accel', wrt='roll_ang_vel', rows=ar, cols=ar) + self.declare_partials(of='pitch_accel', wrt='yaw_ang_vel', rows=ar, cols=ar) + self.declare_partials(of='pitch_accel', wrt='ly_ext', rows=ar, cols=ar) + + self.declare_partials(of='yaw_accel', wrt='J_xz') + self.declare_partials(of='yaw_accel', wrt='J_xx') + self.declare_partials(of='yaw_accel', wrt='J_yy') + self.declare_partials(of='yaw_accel', wrt='J_zz') + self.declare_partials(of='yaw_accel', wrt='roll_ang_vel', rows=ar, cols=ar) + self.declare_partials(of='yaw_accel', wrt='pitch_ang_vel', rows=ar, cols=ar) + self.declare_partials(of='yaw_accel', wrt='yaw_ang_vel', rows=ar, cols=ar) + self.declare_partials(of='yaw_accel', wrt='lx_ext', rows=ar, cols=ar) + self.declare_partials(of='yaw_accel', wrt='lz_ext', rows=ar, cols=ar) + + self.declare_partials(of='roll_angle_rate_eq', wrt='roll_ang_vel', rows=ar, cols=ar) + self.declare_partials(of='roll_angle_rate_eq', wrt='pitch_ang_vel', rows=ar, cols=ar) + self.declare_partials(of='roll_angle_rate_eq', wrt='yaw_ang_vel', rows=ar, cols=ar) + self.declare_partials(of='roll_angle_rate_eq', wrt='roll', rows=ar, cols=ar) + self.declare_partials(of='roll_angle_rate_eq', wrt='pitch', rows=ar, cols=ar) + + self.declare_partials(of='pitch_angle_rate_eq', wrt='pitch_ang_vel', rows=ar, cols=ar) + self.declare_partials(of='pitch_angle_rate_eq', wrt='yaw_ang_vel', rows=ar, cols=ar) + self.declare_partials(of='pitch_angle_rate_eq', wrt='roll', rows=ar, cols=ar) + + self.declare_partials(of='yaw_angle_rate_eq', wrt='pitch_ang_vel', rows=ar, cols=ar) + self.declare_partials(of='yaw_angle_rate_eq', wrt='yaw_ang_vel', rows=ar, cols=ar) + self.declare_partials(of='yaw_angle_rate_eq', wrt='roll', rows=ar, cols=ar) + self.declare_partials(of='yaw_angle_rate_eq', wrt='pitch', rows=ar, cols=ar) + + self.declare_partials(of='dx_dt', wrt='axial_vel', rows=ar, cols=ar) + self.declare_partials(of='dx_dt', wrt='lat_vel', rows=ar, cols=ar) + self.declare_partials(of='dx_dt', wrt='vert_vel', rows=ar, cols=ar) + self.declare_partials(of='dx_dt', wrt='roll', rows=ar, cols=ar) + self.declare_partials(of='dx_dt', wrt='pitch', rows=ar, cols=ar) + self.declare_partials(of='dx_dt', wrt='yaw', rows=ar, cols=ar) + + self.declare_partials(of='dy_dt', wrt='axial_vel', rows=ar, cols=ar) + self.declare_partials(of='dy_dt', wrt='lat_vel', rows=ar, cols=ar) + self.declare_partials(of='dy_dt', wrt='vert_vel', rows=ar, cols=ar) + self.declare_partials(of='dy_dt', wrt='roll', rows=ar, cols=ar) + self.declare_partials(of='dy_dt', wrt='pitch', rows=ar, cols=ar) + self.declare_partials(of='dy_dt', wrt='yaw', rows=ar, cols=ar) + + self.declare_partials(of='dz_dt', wrt='axial_vel', rows=ar, cols=ar) + self.declare_partials(of='dz_dt', wrt='lat_vel', rows=ar, cols=ar) + self.declare_partials(of='dz_dt', wrt='vert_vel', rows=ar, cols=ar) + self.declare_partials(of='dz_dt', wrt='roll', rows=ar, cols=ar) + self.declare_partials(of='dz_dt', wrt='pitch', rows=ar, cols=ar) + + def compute(self, inputs, outputs): """ Compute function for EOM. @@ -315,9 +421,9 @@ def compute(self, inputs, outputs): roll = inputs['roll'] # phi pitch = inputs['pitch'] # theta yaw = inputs['yaw'] # psi - # x = inputs['x'] # p1 - # y = inputs['y'] # p2 - # z = inputs['z'] # p3 + x = inputs['x'] # p1 + y = inputs['y'] # p2 + z = inputs['z'] # p3 # time = inputs['time'] g = inputs['g'] Fx_ext = inputs['Fx_ext'] @@ -408,6 +514,178 @@ def compute(self, inputs, outputs): outputs['dx_dt'] = dx_dt outputs['dy_dt'] = dy_dt outputs['dz_dt'] = dz_dt + + def compute_partials(self, inputs, J): + mass = inputs['mass'] + axial_vel = inputs['axial_vel'] # u + lat_vel = inputs['lat_vel'] # v + vert_vel = inputs['vert_vel'] # w + roll_ang_vel = inputs['roll_ang_vel'] # p + pitch_ang_vel = inputs['pitch_ang_vel'] # q + yaw_ang_vel = inputs['yaw_ang_vel'] # r + roll = inputs['roll'] # phi + pitch = inputs['pitch'] # theta + yaw = inputs['yaw'] # psi + x = inputs['x'] # p1 + y = inputs['y'] # p2 + z = inputs['z'] # p3 + # time = inputs['time'] + g = inputs['g'] + Fx_ext = inputs['Fx_ext'] + Fy_ext = inputs['Fy_ext'] + Fz_ext = inputs['Fz_ext'] + lx_ext = inputs['lx_ext'] # l + ly_ext = inputs['ly_ext'] # m + lz_ext = inputs['lz_ext'] # n + J_xz = inputs['J_xz'] + J_xx = inputs['J_xx'] + J_yy = inputs['J_yy'] + J_zz = inputs['J_zz'] + + # for roll and yaw + Den = J_xx * J_zz - J_xz**2 + + J['dx_accel', 'mass'] = -Fx_ext / mass**2 + J['dx_accel', 'Fx_ext'] = 1 / mass + J['dx_accel', 'lat_vel'] = yaw_ang_vel + J['dx_accel', 'vert_vel'] = -pitch_ang_vel + J['dx_accel', 'yaw_ang_vel'] = lat_vel + J['dx_accel', 'pitch_ang_vel'] = -vert_vel + J['dx_accel', 'g'] = -np.sin(pitch) + J['dx_accel', 'pitch'] = -np.cos(pitch) * g + + J['dy_accel', 'mass'] = -Fy_ext / mass**2 + J['dy_accel', 'Fy_ext'] = 1 / mass + J['dy_accel', 'axial_vel'] = -yaw_ang_vel + J['dy_accel', 'vert_vel'] = roll_ang_vel + J['dy_accel', 'yaw_ang_vel'] = -axial_vel + J['dy_accel', 'roll_ang_vel'] = vert_vel + J['dy_accel', 'g'] = np.sin(roll) * np.cos(pitch) + J['dy_accel', 'roll'] = np.cos(roll) * np.cos(pitch) * g + J['dy_accel', 'pitch'] = -np.sin(roll) * np.sin(pitch) * g + + J['dz_accel', 'mass'] = -Fz_ext / mass**2 + J['dz_accel', 'Fz_ext'] = 1 / mass + J['dz_accel', 'lat_vel'] = -roll_ang_vel + J['dz_accel', 'axial_vel'] = pitch_ang_vel + J['dz_accel', 'roll_ang_vel'] = -lat_vel + J['dz_accel', 'pitch_ang_vel'] = axial_vel + J['dz_accel', 'g'] = np.cos(roll) * np.cos(pitch) + J['dz_accel', 'roll'] = -np.sin(roll) * np.cos(pitch) * g + J['dz_accel', 'pitch'] = -np.cos(roll) * np.sin(pitch) * g + + J['roll_accel', 'J_xz'] = (Den * ( + (J_xx - J_yy + J_zz) * roll_ang_vel * pitch_ang_vel - 2 * J_xz * pitch_ang_vel * yaw_ang_vel + lz_ext) - ( + J_xz * (J_xx - J_yy + J_zz) * roll_ang_vel * pitch_ang_vel - + (J_zz * (J_zz - J_yy) + J_xz**2) * pitch_ang_vel * yaw_ang_vel + + J_zz * lx_ext + + J_xz * lz_ext) * -2 * J_xz) / Den**2 + J['roll_accel', 'J_xx'] = (Den * ( + J_xz * roll_ang_vel * pitch_ang_vel + ) - (J_xz * (J_xx - J_yy + J_zz) * roll_ang_vel * pitch_ang_vel - + (J_zz * (J_zz - J_yy) + J_xz**2) * pitch_ang_vel * yaw_ang_vel + + J_zz * lx_ext + + J_xz * lz_ext) * J_zz) / Den**2 + J['roll_accel', 'J_yy'] = (-J_xz * roll_ang_vel * pitch_ang_vel + J_zz * pitch_ang_vel * yaw_ang_vel) / Den + J['roll_accel', 'J_zz'] = (Den * ( + J_xz * roll_ang_vel * pitch_ang_vel - 2 * J_zz * pitch_ang_vel * yaw_ang_vel + J_yy * pitch_ang_vel * yaw_ang_vel + lx_ext + ) - (J_xz * (J_xx - J_yy + J_zz) * roll_ang_vel * pitch_ang_vel - + (J_zz * (J_zz - J_yy) + J_xz**2) * pitch_ang_vel * yaw_ang_vel + + J_zz * lx_ext + + J_xz * lz_ext) * J_xx) / Den**2 + J['roll_accel', 'roll_ang_vel'] = (J_xz * (J_xx - J_yy + J_zz) * pitch_ang_vel) / Den + J['roll_accel', 'pitch_ang_vel'] = (J_xz * (J_xx - J_yy + J_zz) * roll_ang_vel - (J_zz * (J_zz - J_yy) + J_xz**2) * yaw_ang_vel) / Den + J['roll_accel', 'yaw_ang_vel'] = -((J_zz * (J_zz - J_yy) + J_xz**2) * pitch_ang_vel) / Den + J['roll_accel', 'lx_ext'] = J_zz / Den + J['roll_accel', 'lz_ext'] = J_xz / Den + + J['pitch_accel', 'J_xz'] = -(roll_ang_vel**2 - yaw_ang_vel**2) / J_yy + J['pitch_accel', 'J_xx'] = -(roll_ang_vel * yaw_ang_vel) / J_yy + J['pitch_accel', 'J_yy'] = -((J_zz - J_xx) * roll_ang_vel * yaw_ang_vel - + J_xz * (roll_ang_vel**2 - yaw_ang_vel**2) + ly_ext) / J_yy**2 + J['pitch_accel', 'J_zz'] = roll_ang_vel * yaw_ang_vel / J_yy + J['pitch_accel', 'roll_ang_vel'] = ((J_zz - J_xx) * yaw_ang_vel - 2 * J_xz * roll_ang_vel) / J_yy + J['pitch_accel', 'yaw_ang_vel'] = ((J_zz - J_xx) * roll_ang_vel + 2 * J_xz * yaw_ang_vel) / J_yy + J['pitch_accel', 'ly_ext'] = 1 / J_yy + + J['yaw_accel', 'J_xz'] = (Den * ( + 2 * J_xz * roll_ang_vel * pitch_ang_vel + (J_xx - J_yy + J_zz) * pitch_ang_vel * yaw_ang_vel + lx_ext + lz_ext + ) - ((J_xx * (J_xx - J_yy) + J_xz**2) * roll_ang_vel * pitch_ang_vel + + J_xz * (J_xx - J_yy + J_zz) * pitch_ang_vel * yaw_ang_vel + + J_xz * lx_ext + + J_xz * lz_ext) * -2 * J_xz) / Den**2 + J['yaw_accel', 'J_xx'] = (Den * ( + 2 * J_xx * roll_ang_vel * pitch_ang_vel - J_yy * roll_ang_vel * pitch_ang_vel + J_xz * pitch_ang_vel * yaw_ang_vel + ) - ((J_xx * (J_xx - J_yy) + J_xz**2) * roll_ang_vel * pitch_ang_vel + + J_xz * (J_xx - J_yy + J_zz) * pitch_ang_vel * yaw_ang_vel + + J_xz * lx_ext + + J_xz * lz_ext) * J_zz) / Den**2 + J['yaw_accel', 'J_yy'] = (-J_xx * roll_ang_vel * pitch_ang_vel - J_xz * pitch_ang_vel * yaw_ang_vel) / Den + J['yaw_accel', 'J_zz'] = (Den * ( + J_xz * pitch_ang_vel * yaw_ang_vel + ) - ((J_xx * (J_xx - J_yy) + J_xz**2) * roll_ang_vel * pitch_ang_vel + + J_xz * (J_xx - J_yy + J_zz) * pitch_ang_vel * yaw_ang_vel + + J_xz * lx_ext + + J_xz * lz_ext) * J_xx) / Den**2 + J['yaw_accel', 'roll_ang_vel'] = ((J_xx * (J_xx - J_yy) + J_xz**2) * pitch_ang_vel) / Den + J['yaw_accel', 'pitch_ang_vel'] = ((J_xx * (J_xx - J_yy) + J_xz**2) * roll_ang_vel + J_xz * (J_xx - J_yy + J_zz) * yaw_ang_vel) / Den + J['yaw_accel', 'yaw_ang_vel'] = (J_xz * (J_xx - J_yy + J_zz) * pitch_ang_vel) / Den + J['yaw_accel', 'lx_ext'] = J_xz / Den + J['yaw_accel', 'lz_ext'] = J_xz / Den + + J['roll_angle_rate_eq', 'roll_ang_vel'] = 1 + J['roll_angle_rate_eq', 'pitch_ang_vel'] = np.sin(roll) * np.tan(pitch) + J['roll_angle_rate_eq', 'yaw_ang_vel'] = np.cos(roll) * np.tan(pitch) + J['roll_angle_rate_eq', 'roll'] = np.cos(roll) * np.tan(pitch) * pitch_ang_vel - np.sin(roll) * np.tan(pitch) * yaw_ang_vel + J['roll_angle_rate_eq', 'pitch'] = np.sin(roll) * (1 / np.cos(pitch)**2) * pitch_ang_vel + np.cos(roll) * (1 / np.cos(pitch)**2) * yaw_ang_vel + + J['pitch_angle_rate_eq', 'pitch_ang_vel'] = np.cos(roll) + J['pitch_angle_rate_eq', 'yaw_ang_vel'] = -np.sin(roll) + J['pitch_angle_rate_eq', 'roll'] = -np.sin(roll) * pitch_ang_vel - np.cos(roll) * yaw_ang_vel + + J['yaw_angle_rate_eq', 'pitch_ang_vel'] = np.sin(roll) / np.cos(pitch) + J['yaw_angle_rate_eq', 'yaw_ang_vel'] = np.cos(roll) / np.cos(pitch) + J['yaw_angle_rate_eq', 'roll'] = np.cos(roll) / np.cos(pitch) * pitch_ang_vel - np.sin(roll) / np.cos(pitch) * yaw_ang_vel + J['yaw_angle_rate_eq', 'pitch'] = np.sin(roll) * (np.tan(pitch) / np.cos(pitch)) * pitch_ang_vel + np.cos(roll) * (np.tan(pitch) / np.cos(pitch)) * yaw_ang_vel + + # note: d/dx tan(x) = sec^2(x) = 1 / cos^2(x) + # note: d/dx 1 / cos(x) = d/dx sec(x) = sec(x)tan(x) = tan(x) / cos(x) + + J['dx_dt', 'axial_vel'] = np.cos(pitch) * np.cos(yaw) + J['dx_dt', 'lat_vel'] = -np.cos(roll) * np.sin(yaw) + np.sin(roll) * np.sin(pitch) * np.cos(yaw) + J['dx_dt', 'vert_vel'] = np.sin(roll) * np.sin(yaw) + np.cos(roll) * np.sin(pitch) * np.cos(yaw) + J['dx_dt', 'roll'] = (np.sin(roll) * np.sin(yaw) + np.cos(roll) * np.sin(pitch) * np.cos(yaw)) * lat_vel + \ + (np.cos(roll) * np.sin(yaw) - np.sin(roll) * np.sin(pitch) * np.cos(yaw)) * vert_vel + J['dx_dt', 'pitch'] = -np.sin(pitch) * np.cos(yaw) * axial_vel + \ + np.sin(roll) * np.cos(pitch) * np.cos(yaw) * lat_vel + \ + np.cos(roll) * np.cos(pitch) * np.cos(yaw) * vert_vel + J['dx_dt', 'yaw'] = -np.cos(pitch) * np.sin(yaw) * axial_vel + \ + (-np.cos(roll) * np.cos(yaw) - np.sin(roll) * np.sin(pitch) * np.sin(yaw)) * lat_vel + \ + (np.sin(roll) * np.cos(yaw) - np.cos(roll) * np.sin(pitch) * np.sin(yaw)) * vert_vel + + J['dy_dt', 'axial_vel'] = np.cos(pitch) * np.sin(yaw) + J['dy_dt', 'lat_vel'] = np.cos(roll) * np.cos(yaw) + np.sin(roll) * np.sin(pitch) * np.sin(yaw) + J['dy_dt', 'vert_vel'] = -np.sin(roll) * np.cos(yaw) + np.cos(roll) * np.sin(pitch) * np.sin(yaw) + J['dy_dt', 'roll'] = (-np.sin(roll) * np.cos(yaw) + np.cos(roll) * np.sin(pitch) * np.sin(yaw)) * lat_vel + \ + (-np.cos(roll) * np.cos(yaw) - np.sin(roll) * np.sin(pitch) * np.sin(yaw)) * vert_vel + J['dy_dt', 'pitch'] = -np.sin(pitch) * np.sin(yaw) * axial_vel + \ + np.sin(roll) * np.cos(pitch) * np.sin(yaw) * lat_vel + \ + np.cos(roll) * np.cos(pitch) * np.sin(yaw) * vert_vel + J['dy_dt', 'yaw'] = np.cos(pitch) * np.cos(yaw) * axial_vel + \ + (-np.cos(roll) * np.sin(yaw) + np.sin(roll) * np.sin(pitch) * np.cos(yaw)) * lat_vel + \ + (np.sin(roll) * np.sin(yaw) + np.cos(roll) * np.sin(pitch) * np.cos(yaw)) * vert_vel + + J['dz_dt', 'axial_vel'] = -np.sin(pitch) + J['dz_dt', 'lat_vel'] = np.sin(roll) * np.cos(pitch) + J['dz_dt', 'vert_vel'] = np.cos(roll) * np.cos(pitch) + J['dz_dt', 'roll'] = np.cos(roll) * np.cos(pitch) * lat_vel - \ + np.sin(roll) * np.cos(pitch) * vert_vel + J['dz_dt', 'pitch'] = -np.cos(pitch) * axial_vel - \ + np.sin(roll) * np.sin(pitch) * lat_vel - \ + np.cos(roll) * np.sin(pitch) * vert_vel + + + if __name__ == "__main__": @@ -462,4 +740,6 @@ def compute(self, inputs, outputs): print(f"Euler angular rates: {roll_angle_rate_eq}, {pitch_angle_rate_eq}, {yaw_angle_rate_eq}") print(f"velocities: {dx_dt}, {dy_dt}, {dz_dt}") + p.check_partials(compact_print=True, show_only_incorrect=True, method='cs') + diff --git a/aviary/mission/sixdof/test_mission_6dof.py b/aviary/mission/sixdof/test_mission_6dof.py new file mode 100644 index 000000000..36f04e97c --- /dev/null +++ b/aviary/mission/sixdof/test_mission_6dof.py @@ -0,0 +1,179 @@ +from mpl_toolkits import mplot3d +import matplotlib.pyplot as plt + +import os +import numpy as np + +import unittest +import openmdao.api as om +import dymos as dm + +from dymos.examples.plotting import plot_results + +from openmdao.api import Group, IndepVarComp, ExecComp +from dymos.transcriptions.transcription_base import TranscriptionBase + +from dymos.models.atmosphere.atmos_1976 import USatm1976Comp + +from aviary.mission.sixdof.six_dof_EOM import SixDOF_EOM +from aviary.mission.sixdof.force_component_calc import ForceComponentResolver + +from openmdao.utils.assert_utils import assert_check_partials + +from openmdao.utils.general_utils import set_pyoptsparse_opt +OPT, OPTIMIZER = set_pyoptsparse_opt('SNOPT') +if OPTIMIZER: + from openmdao.drivers.pyoptsparse_driver import pyOptSparseDriver + +class vtolODE(Group): + + def initialize(self): + self.options.declare('num_nodes', types=int) + + def setup(self): + nn = self.options['num_nodes'] + + self.add_subsystem('USatm1976comp', USatm1976Comp(num_nodes=nn), + promotes_inputs=['*'], + promotes_outputs=['rho']) + + self.add_subsystem('ForceComponents', ForceComponentResolver(num_nodes=nn), + promotes_inputs=['*'], + promotes_outputs=['*']) + + self.add_subsystem('SixDOF_EOM', SixDOF_EOM(num_nodes=nn), + promotes_inputs=['*'], + promotes_outputs=['*']) + +# class main_phase_class(dm.Phase): + +# def initialize(self): +# super(main_phase_class, self).initialize() +# self.options.declare('interp_to', types=TranscriptionBase) + +# def setup(self): +# self.options['ode_class'] = vtolODE + +# super(main_phase_class, self).setup() + +def sixdof_test(): + p = om.Problem() + + traj = dm.Trajectory() + phase = dm.Phase(ode_class=vtolODE, + transcription=dm.Radau(num_segments=10, order=3) + ) + + p.model.add_subsystem('traj', traj) + + # SETUP + + traj.add_phase(name='main_phase', phase=phase) + + phase.set_time_options(fix_initial=True, fix_duration=False, units='s') + + phase.add_state('axial_vel', fix_initial=True, rate_source='dx_accel', targets=['axial_vel'], lower=0, upper=10, units='m/s') + phase.add_state('lat_vel', fix_initial=True, rate_source='dy_accel', targets=['lat_vel'], lower=0, upper=10, units='m/s') + phase.add_state('vert_vel', fix_initial=True, rate_source='dz_accel', targets=['vert_vel'], lower=0, upper=10, units='m/s') + phase.add_state('roll_ang_vel', fix_initial=True, rate_source='roll_accel', targets=['roll_ang_vel'], lower=0, upper=10, units='rad/s') + phase.add_state('pitch_ang_vel', fix_initial=True, rate_source='pitch_accel', targets=['pitch_ang_vel'], lower=0, upper=10, units='rad/s') + phase.add_state('yaw_ang_vel', fix_initial=True, rate_source='yaw_accel', targets=['yaw_ang_vel'], lower=0, upper=10, units='rad/s') + phase.add_state('roll', fix_initial=True, rate_source='roll_angle_rate_eq', targets=['roll'], lower=0, upper=np.pi, units='rad') + phase.add_state('pitch', fix_initial=True, rate_source='pitch_angle_rate_eq', targets=['pitch'], lower=0, upper=np.pi, units='rad') + phase.add_state('yaw', fix_initial=True, rate_source='yaw_angle_rate_eq', targets=['yaw'], lower=0, upper=np.pi, units='rad') + phase.add_state('x', fix_initial=True, fix_final=True, rate_source='dx_dt', targets=['x'],lower=0, upper=100, units='m') + phase.add_state('y', fix_initial=True, fix_final=True, rate_source='dy_dt', targets=['y'], lower=0, upper=100, units='m') + phase.add_state('z', fix_initial=True, rate_source='dz_dt', targets=['z'], lower=0, upper=100, units='m') + + phase.add_control('Fx_ext', targets=['Fx_ext'], units='N') + phase.add_control('Fy_ext', targets=['Fy_ext'], units='N') + phase.add_control('Fz_ext', targets=['Fz_ext'], units='N') + phase.add_control('lx_ext', targets=['lx_ext'], units='N*m') + phase.add_control('ly_ext', targets=['ly_ext'], units='N*m') + phase.add_control('lz_ext', targets=['lz_ext'], units='N*m') + + phase.add_parameter('mass', units='kg', targets=['mass'], opt=False) + phase.add_parameter('J_xx', units='kg * m**2', targets=['J_xx'], opt=False) + phase.add_parameter('J_yy', units='kg * m**2', targets=['J_yy'], opt=False) + phase.add_parameter('J_zz', units='kg * m**2', targets=['J_zz'], opt=False) + phase.add_parameter('J_xz', units='kg * m**2', targets=['J_xz'], opt=False) + + + phase.add_objective('Fz_ext', loc='final') + + p.driver = om.pyOptSparseDriver() + p.driver.options["optimizer"] = "IPOPT" + + p.driver.opt_settings['mu_init'] = 1e-1 + p.driver.opt_settings['max_iter'] = 600 + p.driver.opt_settings['constr_viol_tol'] = 1e-6 + p.driver.opt_settings['compl_inf_tol'] = 1e-6 + p.driver.opt_settings['tol'] = 1e-5 + p.driver.opt_settings['print_level'] = 0 + p.driver.opt_settings['nlp_scaling_method'] = 'gradient-based' + p.driver.opt_settings['alpha_for_y'] = 'safer-min-dual-infeas' + p.driver.opt_settings['mu_strategy'] = 'monotone' + p.driver.opt_settings['bound_mult_init_method'] = 'mu-based' + p.driver.options['print_results'] = True + + p.driver.declare_coloring() + + p.setup() + + phase.set_time_val(initial=0, duration=60, units='s') + phase.set_state_val('axial_vel', vals=[0, 0], units='m/s') + phase.set_state_val('lat_vel', vals=[0, 0], units='m/s') + phase.set_state_val('vert_vel', vals=[0, 10], units='m/s') + phase.set_state_val('roll_ang_vel', vals=[0, 10], units='rad/s') + phase.set_state_val('pitch_ang_vel', vals=[0, 10], units='rad/s') + phase.set_state_val('yaw_ang_vel', vals=[0, 10], units='rad/s') + phase.set_state_val('roll', vals=[0, 0], units='rad') + phase.set_state_val('pitch', vals=[0, 0], units='rad') + phase.set_state_val('yaw', vals=[0, 0], units='rad') + phase.set_state_val('x', vals=[0, 0], units='m') + phase.set_state_val('y', vals=[0, 0], units='m') + phase.set_state_val('z', vals=[0, 100], units='m') + + phase.set_control_val('Fx_ext', vals=[0, 0], units='N') + phase.set_control_val('Fy_ext', vals=[0, 0], units='N') + phase.set_control_val('Fz_ext', vals=[200, 200], units='N') + phase.set_control_val('lx_ext', vals=[0, 0], units='N*m') + phase.set_control_val('ly_ext', vals=[0, 0], units='N*m') + phase.set_control_val('lz_ext', vals=[0, 0], units='N*m') + + phase.set_parameter_val('mass', val=10, units='kg') + phase.set_parameter_val('J_xx', val=16, units='kg*m**2') # assume a sphere of 10 kg with radius = 2 + phase.set_parameter_val('J_yy', val=16, units='kg*m**2') + phase.set_parameter_val('J_zz', val=16, units='kg*m**2') + phase.set_parameter_val('J_xz', val=0, units='kg*m**2') + + phase.add_path_constraint('x', equals=0) + phase.add_path_constraint('y', equals=0) + + + p.final_setup() + + p.run_model() + + dm.run_problem(p, run_driver=True, simulate=True, make_plots=True) + #print(p.get_reports_dir()) + + exp_out = traj.simulate() + + plot_results([('traj.main_phase.timeseries.x', 'traj.main_phase.timeseries.z', + 'x (m)', 'z (m)'), + ('traj.main_phase.timeseries.y', 'traj.main_phase.timeseries.z', + 'y (m)', 'z (m)')], + title='Trajectory of Vertical Take Off', + p_sol=p, p_sim=exp_out) + + plt.show() + plt.savefig('./TrajPlots.pdf') + + +if __name__ == "__main__": + sixdof_test() + + + + From 6b12740ee68b467c9d8002bd68897e745567e72a Mon Sep 17 00:00:00 2001 From: szoppelt Date: Mon, 9 Jun 2025 17:51:39 +0000 Subject: [PATCH 071/147] updates. --- aviary/mission/sixdof/force_component_calc.py | 63 +++++----- aviary/mission/sixdof/six_dof_EOM.py | 55 ++++---- aviary/mission/sixdof/six_dof_ODE.py | 14 ++- aviary/mission/sixdof/test_mission_6dof.py | 119 +++++++++--------- .../subsystems/mass/simple_mass/fuselage.py | 43 +++---- .../mass/simple_mass/mass_summation.py | 21 ++-- aviary/subsystems/mass/simple_mass/tail.py | 84 ++++++++----- .../mass/simple_mass/test/test_fuselage.py | 14 +-- .../simple_mass/test/test_mass_summation.py | 56 +++++++-- .../mass/simple_mass/test/test_tail.py | 46 +++++-- .../mass/simple_mass/test/test_wing.py | 7 +- aviary/subsystems/mass/simple_mass/wing.py | 50 +++----- 12 files changed, 323 insertions(+), 249 deletions(-) diff --git a/aviary/mission/sixdof/force_component_calc.py b/aviary/mission/sixdof/force_component_calc.py index 814b372f4..8b43dee3f 100644 --- a/aviary/mission/sixdof/force_component_calc.py +++ b/aviary/mission/sixdof/force_component_calc.py @@ -69,6 +69,13 @@ def setup(self): desc="Side vector (unresolved)" ) + # self.add_input( + # 'true_air_speed', + # val=np.zeros(nn), + # units='m/s', + # desc="True air speed" + # ) # This is an aviary variable + # outputs self.add_output( @@ -131,14 +138,14 @@ def compute(self, inputs, outputs): V = np.sqrt(u**2 + v**2 + w**2) - # angle of attack + # flight path angle # divide by zero checks if np.any(u == 0): u[u == 0] = 1e-4 - alpha = np.arctan(w / u) + gamma = np.arctan(w / u) else: - alpha = np.arctan(w / u) + gamma = np.arctan(w / u) # side slip angle @@ -154,9 +161,9 @@ def compute(self, inputs, outputs): # some trig needed - cos_a = np.cos(alpha) + cos_a = np.cos(gamma) cos_b = np.cos(beta) - sin_a = np.sin(alpha) + sin_a = np.sin(gamma) sin_b = np.sin(beta) outputs['Fx'] = -(cos_a * cos_b * D - cos_a * sin_b * S - sin_a * L) @@ -178,9 +185,9 @@ def compute_partials(self, inputs, J): # divide by zero checks if u == 0: u = 1e-4 - alpha = np.arctan(w / u) + gamma = np.arctan(w / u) else: - alpha = np.arctan(w / u) + gamma = np.arctan(w / u) # side slip angle @@ -196,17 +203,17 @@ def compute_partials(self, inputs, J): # note: d/dx arctan(x / sqrt(a^2 + b^2)) = sqrt(a^2 + b^2) / (a^2 + b^2 + x^2) # note: d/dx arctan(x/a) = a / (a^2 + x^2) - J['Fx', 'u'] = np.cos(alpha) * np.sin(beta) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * D + \ - np.cos(beta) * np.sin(alpha) * (-w / (w**2 + u**2)) * D + \ - (np.cos(alpha) * np.cos(beta) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * S - np.sin(beta) * np.sin(alpha) * (-w / (w**2 + u**2)) * S) + \ - (np.cos(alpha) * (-w / (w**2 + u**2)) * L) - J['Fx', 'v'] = np.cos(alpha) * np.sin(beta) * (np.sqrt(w**2 + u**2) / V**2) * D + np.cos(alpha) * np.cos(beta) * (np.sqrt(w**2 + u**2) / V**2) * S - J['Fx', 'w'] = np.cos(alpha) * np.sin(beta) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) * D + np.sin(alpha) * np.cos(beta) * (u / (w**2 + u**2)) * D + \ - np.cos(alpha) * np.cos(beta) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) * S - np.sin(alpha) * np.sin(beta) * (u / (w**2 + u**2)) * S + \ - np.cos(alpha) * (u / (w**2 + u**2)) * L - J['Fx', 'drag'] = -np.cos(alpha) * np.cos(beta) - J['Fx', 'lift'] = np.sin(alpha) - J['Fx', 'side'] = np.cos(alpha) * np.sin(beta) + J['Fx', 'u'] = np.cos(gamma) * np.sin(beta) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * D + \ + np.cos(beta) * np.sin(gamma) * (-w / (w**2 + u**2)) * D + \ + (np.cos(gamma) * np.cos(beta) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * S - np.sin(beta) * np.sin(gamma) * (-w / (w**2 + u**2)) * S) + \ + (np.cos(gamma) * (-w / (w**2 + u**2)) * L) + J['Fx', 'v'] = np.cos(gamma) * np.sin(beta) * (np.sqrt(w**2 + u**2) / V**2) * D + np.cos(gamma) * np.cos(beta) * (np.sqrt(w**2 + u**2) / V**2) * S + J['Fx', 'w'] = np.cos(gamma) * np.sin(beta) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) * D + np.sin(gamma) * np.cos(beta) * (u / (w**2 + u**2)) * D + \ + np.cos(gamma) * np.cos(beta) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) * S - np.sin(gamma) * np.sin(beta) * (u / (w**2 + u**2)) * S + \ + np.cos(gamma) * (u / (w**2 + u**2)) * L + J['Fx', 'drag'] = -np.cos(gamma) * np.cos(beta) + J['Fx', 'lift'] = np.sin(gamma) + J['Fx', 'side'] = np.cos(gamma) * np.sin(beta) J['Fy', 'u'] = -np.cos(beta) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * D + np.sin(beta) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * S J['Fy', 'v'] = -np.cos(beta) * (np.sqrt(w**2 + u**2) / V**2) * D + np.sin(beta) * (np.sqrt(w**2 + u**2) / V**2) * S @@ -214,16 +221,16 @@ def compute_partials(self, inputs, J): J['Fy', 'drag'] = -np.sin(beta) J['Fy', 'side'] = -np.cos(beta) - J['Fz', 'u'] = np.sin(alpha) * np.sin(beta) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * D - np.cos(alpha) * np.cos(beta) * (-w / (w**2 + u**2)) * D - \ - np.sin(alpha) * np.cos(beta) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * S - np.cos(alpha) * np.sin(beta) * (-w / (w**2 + u**2)) * S + \ - np.sin(alpha) * (-w / (w**2 + u**2)) * L - J['Fz', 'v'] = np.sin(alpha) * np.sin(beta) * (np.sqrt(w**2 + u**2) / V**2) * D - np.sin(alpha) * np.cos(beta) * (np.sqrt(w**2 + u**2) / V**2) * S - J['Fz', 'w'] = np.sin(alpha) * np.sin(beta) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) * D - np.cos(alpha) * np.cos(beta) * (u / (w**2 + u**2)) * D - \ - np.sin(alpha) * np.cos(beta) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) * S - np.cos(alpha) * np.sin(beta) * (u / (w**2 + u**2)) * S + \ - np.sin(alpha) * (u / (w**2 + u**2)) * L - J['Fz', 'drag'] = -np.sin(alpha) * np.cos(beta) - J['Fz', 'lift'] = -np.cos(alpha) - J['Fz', 'side'] = -np.sin(alpha) * np.sin(beta) + J['Fz', 'u'] = np.sin(gamma) * np.sin(beta) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * D - np.cos(gamma) * np.cos(beta) * (-w / (w**2 + u**2)) * D - \ + np.sin(gamma) * np.cos(beta) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * S - np.cos(gamma) * np.sin(beta) * (-w / (w**2 + u**2)) * S + \ + np.sin(gamma) * (-w / (w**2 + u**2)) * L + J['Fz', 'v'] = np.sin(gamma) * np.sin(beta) * (np.sqrt(w**2 + u**2) / V**2) * D - np.sin(gamma) * np.cos(beta) * (np.sqrt(w**2 + u**2) / V**2) * S + J['Fz', 'w'] = np.sin(gamma) * np.sin(beta) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) * D - np.cos(gamma) * np.cos(beta) * (u / (w**2 + u**2)) * D - \ + np.sin(gamma) * np.cos(beta) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) * S - np.cos(gamma) * np.sin(beta) * (u / (w**2 + u**2)) * S + \ + np.sin(gamma) * (u / (w**2 + u**2)) * L + J['Fz', 'drag'] = -np.sin(gamma) * np.cos(beta) + J['Fz', 'lift'] = -np.cos(gamma) + J['Fz', 'side'] = -np.sin(gamma) * np.sin(beta) if __name__ == "__main__": p = om.Problem() diff --git a/aviary/mission/sixdof/six_dof_EOM.py b/aviary/mission/sixdof/six_dof_EOM.py index 11e1022dd..4b6040ce6 100644 --- a/aviary/mission/sixdof/six_dof_EOM.py +++ b/aviary/mission/sixdof/six_dof_EOM.py @@ -113,12 +113,6 @@ def setup(self): desc="z-axis position of aircraft resolved in NED CS" ) - # self.add_input( - # 'time', - # val=0.0, - # desc="scalar time in seconds" - # ) - self.add_input( 'g', val=9.81, @@ -127,21 +121,21 @@ def setup(self): ) self.add_input( - 'Fx_ext', + 'Fx', val=np.zeros(nn), units='N', desc="external forces in the x direciton" ) self.add_input( - 'Fy_ext', + 'Fy', val=np.zeros(nn), units='N', desc="external forces in the y direction" ) self.add_input( - 'Fz_ext', + 'Fz', val=np.zeros(nn), units='N', desc="external forces in the z direction" @@ -308,7 +302,7 @@ def setup(self): ar = np.arange(nn) self.declare_partials(of='dx_accel', wrt='mass', rows=ar, cols=ar) - self.declare_partials(of='dx_accel', wrt='Fx_ext', rows=ar, cols=ar) + self.declare_partials(of='dx_accel', wrt='Fx', rows=ar, cols=ar) self.declare_partials(of='dx_accel', wrt='lat_vel', rows=ar, cols=ar) self.declare_partials(of='dx_accel', wrt='vert_vel', rows=ar, cols=ar) self.declare_partials(of='dx_accel', wrt='yaw_ang_vel', rows=ar, cols=ar) @@ -317,7 +311,7 @@ def setup(self): self.declare_partials(of='dx_accel', wrt='pitch', rows=ar, cols=ar) self.declare_partials(of='dy_accel', wrt='mass', rows=ar, cols=ar) - self.declare_partials(of='dy_accel', wrt='Fy_ext', rows=ar, cols=ar) + self.declare_partials(of='dy_accel', wrt='Fy', rows=ar, cols=ar) self.declare_partials(of='dy_accel', wrt='axial_vel', rows=ar, cols=ar) self.declare_partials(of='dy_accel', wrt='vert_vel', rows=ar, cols=ar) self.declare_partials(of='dy_accel', wrt='yaw_ang_vel', rows=ar, cols=ar) @@ -327,7 +321,7 @@ def setup(self): self.declare_partials(of='dy_accel', wrt='pitch', rows=ar, cols=ar) self.declare_partials(of='dz_accel', wrt='mass', rows=ar, cols=ar) - self.declare_partials(of='dz_accel', wrt='Fz_ext', rows=ar, cols=ar) + self.declare_partials(of='dz_accel', wrt='Fz', rows=ar, cols=ar) self.declare_partials(of='dz_accel', wrt='lat_vel', rows=ar, cols=ar) self.declare_partials(of='dz_accel', wrt='axial_vel', rows=ar, cols=ar) self.declare_partials(of='dz_accel', wrt='roll_ang_vel', rows=ar, cols=ar) @@ -426,9 +420,9 @@ def compute(self, inputs, outputs): z = inputs['z'] # p3 # time = inputs['time'] g = inputs['g'] - Fx_ext = inputs['Fx_ext'] - Fy_ext = inputs['Fy_ext'] - Fz_ext = inputs['Fz_ext'] + Fx = inputs['Fx'] + Fy = inputs['Fy'] + Fz = inputs['Fz'] lx_ext = inputs['lx_ext'] # l ly_ext = inputs['ly_ext'] # m lz_ext = inputs['lz_ext'] # n @@ -449,15 +443,15 @@ def compute(self, inputs, outputs): # roll-axis velocity equation - dx_accel = 1 / mass * Fx_ext + gx_b - vert_vel * pitch_ang_vel + lat_vel * yaw_ang_vel + dx_accel = 1 / mass * Fx + gx_b - vert_vel * pitch_ang_vel + lat_vel * yaw_ang_vel # pitch-axis velocity equation - dy_accel = 1 / mass * Fy_ext + gy_b - axial_vel * yaw_ang_vel + vert_vel * roll_ang_vel + dy_accel = 1 / mass * Fy + gy_b - axial_vel * yaw_ang_vel + vert_vel * roll_ang_vel # yaw-axis velocity equation - dz_accel = 1 / mass * Fz_ext + gz_b - lat_vel * roll_ang_vel + axial_vel * pitch_ang_vel + dz_accel = 1 / mass * Fz + gz_b - lat_vel * roll_ang_vel + axial_vel * pitch_ang_vel # Roll equation @@ -514,6 +508,7 @@ def compute(self, inputs, outputs): outputs['dx_dt'] = dx_dt outputs['dy_dt'] = dy_dt outputs['dz_dt'] = dz_dt + def compute_partials(self, inputs, J): mass = inputs['mass'] @@ -531,9 +526,9 @@ def compute_partials(self, inputs, J): z = inputs['z'] # p3 # time = inputs['time'] g = inputs['g'] - Fx_ext = inputs['Fx_ext'] - Fy_ext = inputs['Fy_ext'] - Fz_ext = inputs['Fz_ext'] + Fx = inputs['Fx'] + Fy = inputs['Fy'] + Fz = inputs['Fz'] lx_ext = inputs['lx_ext'] # l ly_ext = inputs['ly_ext'] # m lz_ext = inputs['lz_ext'] # n @@ -545,8 +540,8 @@ def compute_partials(self, inputs, J): # for roll and yaw Den = J_xx * J_zz - J_xz**2 - J['dx_accel', 'mass'] = -Fx_ext / mass**2 - J['dx_accel', 'Fx_ext'] = 1 / mass + J['dx_accel', 'mass'] = -Fx / mass**2 + J['dx_accel', 'Fx'] = 1 / mass J['dx_accel', 'lat_vel'] = yaw_ang_vel J['dx_accel', 'vert_vel'] = -pitch_ang_vel J['dx_accel', 'yaw_ang_vel'] = lat_vel @@ -554,8 +549,8 @@ def compute_partials(self, inputs, J): J['dx_accel', 'g'] = -np.sin(pitch) J['dx_accel', 'pitch'] = -np.cos(pitch) * g - J['dy_accel', 'mass'] = -Fy_ext / mass**2 - J['dy_accel', 'Fy_ext'] = 1 / mass + J['dy_accel', 'mass'] = -Fy / mass**2 + J['dy_accel', 'Fy'] = 1 / mass J['dy_accel', 'axial_vel'] = -yaw_ang_vel J['dy_accel', 'vert_vel'] = roll_ang_vel J['dy_accel', 'yaw_ang_vel'] = -axial_vel @@ -564,8 +559,8 @@ def compute_partials(self, inputs, J): J['dy_accel', 'roll'] = np.cos(roll) * np.cos(pitch) * g J['dy_accel', 'pitch'] = -np.sin(roll) * np.sin(pitch) * g - J['dz_accel', 'mass'] = -Fz_ext / mass**2 - J['dz_accel', 'Fz_ext'] = 1 / mass + J['dz_accel', 'mass'] = -Fz / mass**2 + J['dz_accel', 'Fz'] = 1 / mass J['dz_accel', 'lat_vel'] = -roll_ang_vel J['dz_accel', 'axial_vel'] = pitch_ang_vel J['dz_accel', 'roll_ang_vel'] = -lat_vel @@ -705,9 +700,9 @@ def compute_partials(self, inputs, J): des_vars.add_output('pitch', 0.19, units='rad') des_vars.add_output('yaw', 0.70, units='rad') des_vars.add_output('g', 9.81, units='m/s**2') - des_vars.add_output('Fx_ext', 0.1, units='N') - des_vars.add_output('Fy_ext', 0.9, units='N') - des_vars.add_output('Fz_ext', 0.12, units='N') + des_vars.add_output('Fx', 0.1, units='N') + des_vars.add_output('Fy', 0.9, units='N') + des_vars.add_output('Fz', 0.12, units='N') des_vars.add_output('lx_ext', 3.0, units='N*m') des_vars.add_output('ly_ext', 4.0, units='N*m') des_vars.add_output('lz_ext', 5.0, units='N*m') diff --git a/aviary/mission/sixdof/six_dof_ODE.py b/aviary/mission/sixdof/six_dof_ODE.py index 604e05c8e..09b8eb2cd 100644 --- a/aviary/mission/sixdof/six_dof_ODE.py +++ b/aviary/mission/sixdof/six_dof_ODE.py @@ -47,7 +47,13 @@ def setup(self): promotes=['*'] ) - sub1.add_subsystem( + # Need something here to figure out how to actually fly aircraft + + self.add_core_subsystems(solver_group=sub1) + + self.add_external_subsystems(solver_group=sub1) + + self.add_subsystem( 'sum_forces_comp', ForceComponentResolver(num_nodes=nn), promotes_inputs=[ @@ -66,11 +72,7 @@ def setup(self): ] ) - self.add_core_subsystems(solver_group=sub1) - - self.add_external_subsystems(solver_group=sub1) - - sub1.add_subsystem( + self.add_subsystem( 'SixDOF_EOM', SixDOF_EOM(num_nodes=nn), promotes_inputs=[ diff --git a/aviary/mission/sixdof/test_mission_6dof.py b/aviary/mission/sixdof/test_mission_6dof.py index 36f04e97c..9a2ef1754 100644 --- a/aviary/mission/sixdof/test_mission_6dof.py +++ b/aviary/mission/sixdof/test_mission_6dof.py @@ -1,25 +1,17 @@ -from mpl_toolkits import mplot3d import matplotlib.pyplot as plt -import os import numpy as np -import unittest import openmdao.api as om import dymos as dm -from dymos.examples.plotting import plot_results - -from openmdao.api import Group, IndepVarComp, ExecComp -from dymos.transcriptions.transcription_base import TranscriptionBase +from openmdao.api import Group from dymos.models.atmosphere.atmos_1976 import USatm1976Comp from aviary.mission.sixdof.six_dof_EOM import SixDOF_EOM from aviary.mission.sixdof.force_component_calc import ForceComponentResolver -from openmdao.utils.assert_utils import assert_check_partials - from openmdao.utils.general_utils import set_pyoptsparse_opt OPT, OPTIMIZER = set_pyoptsparse_opt('SNOPT') if OPTIMIZER: @@ -44,20 +36,10 @@ def setup(self): self.add_subsystem('SixDOF_EOM', SixDOF_EOM(num_nodes=nn), promotes_inputs=['*'], promotes_outputs=['*']) - -# class main_phase_class(dm.Phase): - -# def initialize(self): -# super(main_phase_class, self).initialize() -# self.options.declare('interp_to', types=TranscriptionBase) - -# def setup(self): -# self.options['ode_class'] = vtolODE - -# super(main_phase_class, self).setup() def sixdof_test(): p = om.Problem() + traj = dm.Trajectory() phase = dm.Phase(ode_class=vtolODE, @@ -72,34 +54,39 @@ def sixdof_test(): phase.set_time_options(fix_initial=True, fix_duration=False, units='s') - phase.add_state('axial_vel', fix_initial=True, rate_source='dx_accel', targets=['axial_vel'], lower=0, upper=10, units='m/s') - phase.add_state('lat_vel', fix_initial=True, rate_source='dy_accel', targets=['lat_vel'], lower=0, upper=10, units='m/s') - phase.add_state('vert_vel', fix_initial=True, rate_source='dz_accel', targets=['vert_vel'], lower=0, upper=10, units='m/s') - phase.add_state('roll_ang_vel', fix_initial=True, rate_source='roll_accel', targets=['roll_ang_vel'], lower=0, upper=10, units='rad/s') - phase.add_state('pitch_ang_vel', fix_initial=True, rate_source='pitch_accel', targets=['pitch_ang_vel'], lower=0, upper=10, units='rad/s') - phase.add_state('yaw_ang_vel', fix_initial=True, rate_source='yaw_accel', targets=['yaw_ang_vel'], lower=0, upper=10, units='rad/s') + phase.add_state('axial_vel', fix_initial=True, rate_source='dx_accel', targets=['axial_vel'], lower=0, upper=100, units='m/s') + phase.add_state('lat_vel', fix_initial=True, rate_source='dy_accel', targets=['lat_vel'], lower=0, upper=100, units='m/s') + phase.add_state('vert_vel', fix_initial=True, rate_source='dz_accel', targets=['vert_vel'], lower=0, upper=100, units='m/s') + phase.add_state('roll_ang_vel', fix_initial=True, rate_source='roll_accel', targets=['roll_ang_vel'], lower=0, upper=100, units='rad/s') + phase.add_state('pitch_ang_vel', fix_initial=True, rate_source='pitch_accel', targets=['pitch_ang_vel'], lower=0, upper=100, units='rad/s') + phase.add_state('yaw_ang_vel', fix_initial=True, rate_source='yaw_accel', targets=['yaw_ang_vel'], lower=0, upper=100, units='rad/s') phase.add_state('roll', fix_initial=True, rate_source='roll_angle_rate_eq', targets=['roll'], lower=0, upper=np.pi, units='rad') phase.add_state('pitch', fix_initial=True, rate_source='pitch_angle_rate_eq', targets=['pitch'], lower=0, upper=np.pi, units='rad') phase.add_state('yaw', fix_initial=True, rate_source='yaw_angle_rate_eq', targets=['yaw'], lower=0, upper=np.pi, units='rad') - phase.add_state('x', fix_initial=True, fix_final=True, rate_source='dx_dt', targets=['x'],lower=0, upper=100, units='m') - phase.add_state('y', fix_initial=True, fix_final=True, rate_source='dy_dt', targets=['y'], lower=0, upper=100, units='m') + phase.add_state('x', fix_initial=True, rate_source='dx_dt', targets=['x'],lower=0, upper=100, units='m') + phase.add_state('y', fix_initial=True, rate_source='dy_dt', targets=['y'], lower=0, upper=100, units='m') phase.add_state('z', fix_initial=True, rate_source='dz_dt', targets=['z'], lower=0, upper=100, units='m') + phase.add_state('energy', fix_initial=True, rate_source='dE_dt', targets=['energy'], lower=0, upper=300, units='J') - phase.add_control('Fx_ext', targets=['Fx_ext'], units='N') - phase.add_control('Fy_ext', targets=['Fy_ext'], units='N') - phase.add_control('Fz_ext', targets=['Fz_ext'], units='N') - phase.add_control('lx_ext', targets=['lx_ext'], units='N*m') - phase.add_control('ly_ext', targets=['ly_ext'], units='N*m') - phase.add_control('lz_ext', targets=['lz_ext'], units='N*m') + phase.add_control('Fx_ext', targets=['Fx_ext'], opt=True, units='N') + phase.add_control('Fy_ext', targets=['Fy_ext'], opt=True, units='N') + phase.add_control('Fz_ext', targets=['Fz_ext'], opt=True, units='N') + phase.add_control('lx_ext', targets=['lx_ext'], opt=True, units='N*m') + phase.add_control('ly_ext', targets=['ly_ext'], opt=True, units='N*m') + phase.add_control('lz_ext', targets=['lz_ext'], opt=True, units='N*m') + phase.add_control('power', targets=['power'], opt=True, units='W') phase.add_parameter('mass', units='kg', targets=['mass'], opt=False) phase.add_parameter('J_xx', units='kg * m**2', targets=['J_xx'], opt=False) phase.add_parameter('J_yy', units='kg * m**2', targets=['J_yy'], opt=False) phase.add_parameter('J_zz', units='kg * m**2', targets=['J_zz'], opt=False) phase.add_parameter('J_xz', units='kg * m**2', targets=['J_xz'], opt=False) - + + phase.add_boundary_constraint('z', loc='final', equals=33, units='m') + phase.add_path_constraint('x', lower=0, upper=0.1, units='m') + phase.add_path_constraint('y', lower=0, upper=0.1, units='m') - phase.add_objective('Fz_ext', loc='final') + phase.add_objective('energy', loc='final', units='J') # minimize energy p.driver = om.pyOptSparseDriver() p.driver.options["optimizer"] = "IPOPT" @@ -109,12 +96,12 @@ def sixdof_test(): p.driver.opt_settings['constr_viol_tol'] = 1e-6 p.driver.opt_settings['compl_inf_tol'] = 1e-6 p.driver.opt_settings['tol'] = 1e-5 - p.driver.opt_settings['print_level'] = 0 + p.driver.opt_settings['print_level'] = 3 p.driver.opt_settings['nlp_scaling_method'] = 'gradient-based' p.driver.opt_settings['alpha_for_y'] = 'safer-min-dual-infeas' p.driver.opt_settings['mu_strategy'] = 'monotone' p.driver.opt_settings['bound_mult_init_method'] = 'mu-based' - p.driver.options['print_results'] = True + p.driver.options['print_results'] = False p.driver.declare_coloring() @@ -123,23 +110,25 @@ def sixdof_test(): phase.set_time_val(initial=0, duration=60, units='s') phase.set_state_val('axial_vel', vals=[0, 0], units='m/s') phase.set_state_val('lat_vel', vals=[0, 0], units='m/s') - phase.set_state_val('vert_vel', vals=[0, 10], units='m/s') - phase.set_state_val('roll_ang_vel', vals=[0, 10], units='rad/s') - phase.set_state_val('pitch_ang_vel', vals=[0, 10], units='rad/s') - phase.set_state_val('yaw_ang_vel', vals=[0, 10], units='rad/s') + phase.set_state_val('vert_vel', vals=[10, 10], units='m/s') + phase.set_state_val('roll_ang_vel', vals=[0, 0], units='rad/s') + phase.set_state_val('pitch_ang_vel', vals=[0, 0], units='rad/s') + phase.set_state_val('yaw_ang_vel', vals=[0, 0], units='rad/s') phase.set_state_val('roll', vals=[0, 0], units='rad') phase.set_state_val('pitch', vals=[0, 0], units='rad') phase.set_state_val('yaw', vals=[0, 0], units='rad') phase.set_state_val('x', vals=[0, 0], units='m') phase.set_state_val('y', vals=[0, 0], units='m') - phase.set_state_val('z', vals=[0, 100], units='m') + phase.set_state_val('z', vals=[0, 33], units='m') + phase.set_state_val('energy', vals=[0, 300], units='J') phase.set_control_val('Fx_ext', vals=[0, 0], units='N') phase.set_control_val('Fy_ext', vals=[0, 0], units='N') - phase.set_control_val('Fz_ext', vals=[200, 200], units='N') + phase.set_control_val('Fz_ext', vals=[10, 10], units='N') phase.set_control_val('lx_ext', vals=[0, 0], units='N*m') phase.set_control_val('ly_ext', vals=[0, 0], units='N*m') phase.set_control_val('lz_ext', vals=[0, 0], units='N*m') + phase.set_control_val('power', vals=[0, 300], units='W') phase.set_parameter_val('mass', val=10, units='kg') phase.set_parameter_val('J_xx', val=16, units='kg*m**2') # assume a sphere of 10 kg with radius = 2 @@ -147,28 +136,45 @@ def sixdof_test(): phase.set_parameter_val('J_zz', val=16, units='kg*m**2') phase.set_parameter_val('J_xz', val=0, units='kg*m**2') - phase.add_path_constraint('x', equals=0) - phase.add_path_constraint('y', equals=0) - p.final_setup() p.run_model() dm.run_problem(p, run_driver=True, simulate=True, make_plots=True) - #print(p.get_reports_dir()) exp_out = traj.simulate() - plot_results([('traj.main_phase.timeseries.x', 'traj.main_phase.timeseries.z', - 'x (m)', 'z (m)'), - ('traj.main_phase.timeseries.y', 'traj.main_phase.timeseries.z', - 'y (m)', 'z (m)')], - title='Trajectory of Vertical Take Off', - p_sol=p, p_sim=exp_out) + p_sol = p + p_sim = exp_out + + x_traj = p_sol.get_val('traj.main_phase.timeseries.x') + x_sim = p_sim.get_val('traj.main_phase.timeseries.x') + y_traj = p_sol.get_val('traj.main_phase.timeseries.y') + y_sim = p_sim.get_val('traj.main_phase.timeseries.y') + z_traj = p_sol.get_val('traj.main_phase.timeseries.z') + z_sim = p_sim.get_val('traj.main_phase.timeseries.z') + t_traj = p_sol.get_val('traj.main_phase.timeseries.time') + t_sim = p_sim.get_val('traj.main_phase.timeseries.time') - plt.show() - plt.savefig('./TrajPlots.pdf') + + + + + + # plt.plot(t_traj, z_traj, marker='o', ms=4, linestyle='None', label='solution') + # plt.plot(t_sim, z_sim, marker=None, linestyle='-', label='simulation') + # plt.legend(fontsize=12) + # plt.xlabel('t (s)', fontsize=12) + # plt.ylabel('z (m)', fontsize=12) + # plt.xticks(fontsize=12) + # plt.yticks(fontsize=12) + # plt.title('Trajectory of Vertical Take Off vs. Time', fontsize=12) + # plt.show() + # plt.savefig('./TrajPlots_Largerfontt.pdf') + + + if __name__ == "__main__": @@ -177,3 +183,4 @@ def sixdof_test(): + diff --git a/aviary/subsystems/mass/simple_mass/fuselage.py b/aviary/subsystems/mass/simple_mass/fuselage.py index 5928447be..68d088c8f 100644 --- a/aviary/subsystems/mass/simple_mass/fuselage.py +++ b/aviary/subsystems/mass/simple_mass/fuselage.py @@ -6,6 +6,8 @@ import openmdao.jax as omj import jax.scipy.interpolate as jinterp +from aviary.variable_info.variables import Aircraft + try: from quadax import quadgk except ImportError: @@ -13,22 +15,7 @@ "quadax package not found. You can install it by running 'pip install quadax'." ) -""" -The little bit of path code below is not important overall. This is for me to test -within the Docker container and VS Code before I push everything fully to the Github -repository. These lines can be deleted as things are updated further. - -""" - -import sys -import os - - -module_path = os.path.abspath("/home/omdao/Aviary/aviary/subsystems/mass") -if module_path not in sys.path: - sys.path.append(module_path) - -from simple_mass.materials_database import materials +from aviary.subsystems.mass.simple_mass.materials_database import materials from aviary.utils.named_values import get_keys @@ -55,17 +42,17 @@ def setup(self): self.options['use_jit'] = not(Debug) # Inputs - self.add_input('length', - val=2.0, - units='m') + self.add_input(Aircraft.Fuselage.LENGTH, + units='m', + primal_name='length') self.add_input('base_diameter', val=0.4, - units='m') + units='m') # no aviary input self.add_input('tip_diameter', - val=0.2, - units='m') + val=0.2, + units='m') # no aviary input self.add_input('curvature', val=0.0, @@ -102,9 +89,9 @@ def setup(self): val=0.0, units='m') - self.add_output('total_weight_fuse', - val=0.0, - units='kg') + self.add_output(Aircraft.Fuselage.MASS, + units='kg', + primal_name='total_weight_fuse') def compute_primal(self, length, base_diameter, tip_diameter, curvature, thickness, y_offset, z_offset, is_hollow): # Input validation checks @@ -193,11 +180,11 @@ def compute_centroid(self, location, length, y_offset, z_offset, curvature, base if __name__ == "__main__": prob = om.Problem() - prob.model.add_subsystem('fuselage_cg', FuselageMassAndCOG(), promotes_inputs=['*']) + prob.model.add_subsystem('fuselage_cg', FuselageMassAndCOG(), promotes_inputs=['*'], promotes_outputs=['*']) prob.setup() - prob.set_val('length', 2.5) + prob.set_val(Aircraft.Fuselage.LENGTH, 2.5) prob.set_val('base_diameter', 0.5) prob.set_val('tip_diameter', 0.3) prob.set_val('curvature', 0.0) @@ -218,7 +205,7 @@ def compute_centroid(self, location, length, y_offset, z_offset, curvature, base center_of_gravity_x = prob.get_val('fuselage_cg.center_of_gravity_x_fuse') center_of_gravity_y = prob.get_val('fuselage_cg.center_of_gravity_y_fuse') center_of_gravity_z = prob.get_val('fuselage_cg.center_of_gravity_z_fuse') - total_weight = prob.get_val('fuselage_cg.total_weight_fuse') + total_weight = prob.get_val(Aircraft.Fuselage.MASS) #data = prob.check_partials(compact_print=True, abs_err_tol=1e-04, rel_err_tol=1e-04, step=1e-8, step_calc='rel') diff --git a/aviary/subsystems/mass/simple_mass/mass_summation.py b/aviary/subsystems/mass/simple_mass/mass_summation.py index a7c7a6501..bff4764b2 100644 --- a/aviary/subsystems/mass/simple_mass/mass_summation.py +++ b/aviary/subsystems/mass/simple_mass/mass_summation.py @@ -6,6 +6,7 @@ from aviary.subsystems.mass.simple_mass.fuselage import FuselageMassAndCOG from aviary.subsystems.mass.simple_mass.wing import WingMassAndCOG from aviary.subsystems.mass.simple_mass.tail import TailMassAndCOG +from aviary.variable_info.variables import Aircraft # Maybe add some aviary inputs at some point here class MassSummation(om.Group): @@ -23,21 +24,21 @@ def setup(self): 'fuse_mass', FuselageMassAndCOG(), promotes_inputs=['*'], - promotes_outputs=['total_weight_fuse'] + promotes_outputs=[Aircraft.Fuselage.MASS] ) self.add_subsystem( 'wing_mass', WingMassAndCOG(), promotes_inputs=['*'], - promotes_outputs=['total_weight_wing'] + promotes_outputs=[Aircraft.Wing.MASS] ) self.add_subsystem( 'tail_mass', TailMassAndCOG(), promotes_inputs=['*'], - promotes_outputs=['mass'] + promotes_outputs=[Aircraft.HorizontalTail.MASS, Aircraft.VerticalTail.MASS] ) self.add_subsystem( @@ -47,14 +48,20 @@ def setup(self): promotes_outputs=['*'] ) - +# Horizontal tail only class StructureMass(om.JaxExplicitComponent): def setup(self): # Maybe later change these to Aviary inputs? - self.add_input('total_weight_wing', val=0.0, units='kg') - self.add_input('total_weight_fuse', val=0.0, units='kg') - self.add_input('mass', val=0.0, units='kg') + self.add_input(Aircraft.Wing.MASS, val=0.0, units='kg', primal_name='total_weight_wing') + self.add_input(Aircraft.Fuselage.MASS, val=0.0, units='kg', primal_name='total_weight_fuse') + + #tail_type = self.tail_mass.options['tail_type'] + + #if tail_type == 'horizontal': + self.add_input(Aircraft.HorizontalTail.MASS, val=0.0, units='kg', primal_name='mass') + #else: + self.add_input(Aircraft.HorizontalTail.MASS, val=0.0, units='kg', tags='mass') # More masses can be added, i.e., tail, spars, flaps, etc. as needed self.add_output('structure_mass', val=0.0, units='kg') diff --git a/aviary/subsystems/mass/simple_mass/tail.py b/aviary/subsystems/mass/simple_mass/tail.py index 28e8d52cd..bb2d29fae 100644 --- a/aviary/subsystems/mass/simple_mass/tail.py +++ b/aviary/subsystems/mass/simple_mass/tail.py @@ -1,12 +1,13 @@ import openmdao.api as om import openmdao.jax as omj import jax.numpy as jnp -from jax.scipy.integrate import trapezoid as jtrapz import numpy as np from scipy.interpolate import interp1d from scipy.interpolate import CubicSpline import os +from aviary.variable_info.variables import Aircraft + try: from quadax import quadgk except ImportError: @@ -14,24 +15,9 @@ "quadax package not found. You can install it by running 'pip install quadax'." ) -""" -The little bit of path code below is not important overall. This is for me to test -within the Docker container and VS Code before I push everything fully to the Github -repository. These lines can be deleted as things are updated further. - -""" - -import sys -import os - - -module_path = os.path.abspath("/home/omdao/Aviary/aviary/subsystems/mass") -if module_path not in sys.path: - sys.path.append(module_path) +from aviary.subsystems.mass.simple_mass.materials_database import materials -from simple_mass.materials_database import materials - -from aviary.utils.named_values import get_keys, get_values +from aviary.utils.named_values import get_keys Debug = True # set to enable printing @@ -69,18 +55,32 @@ def initialize(self): def setup(self): self.options['use_jit'] = not(Debug) + tail_type = self.options['tail_type'] # Inputs - self.add_input('span_tail', - val=5.0, + if tail_type == 'horizontal': + self.add_input(Aircraft.HorizontalTail.SPAN, units='m', - desc="Tail span") + desc="Tail span", + primal_name='span_tail') - self.add_input('root_chord_tail', - val=1.2, + self.add_input(Aircraft.HorizontalTail.ROOT_CHORD, + units='m', + desc="Root chord length", + primal_name='root_chord_tail') + else: + self.add_input(Aircraft.VerticalTail.SPAN, units='m', - desc="Root chord length") + desc="Tail span", + primal_name='span_tail') + self.add_input(Aircraft.VerticalTail.ROOT_CHORD, + units='m', + desc="Root chord length", + primal_name='root_chord_tail') + + # The inputs below have no aviary input, so there is no distinction for now + self.add_input('tip_chord_tail', val=0.8, units='m', @@ -101,10 +101,18 @@ def setup(self): desc="Twist distribution") # Outputs - self.add_output('mass', - val=0.0, - units='kg', - desc="Total mass of the tail") + if tail_type == 'horizontal': + self.add_output(Aircraft.HorizontalTail.MASS, + units='kg', + desc="Total mass of the tail", + primal_name='mass') + else: + self.add_output(Aircraft.VerticalTail.MASS, + units='kg', + desc="Total mass of the tail", + primal_name='mass') + + # Same as above inputs self.add_output('cg_x', val=0.0, @@ -264,17 +272,27 @@ def extract_airfoil_features(self, x_coords, y_coords): prob.setup() # Input values - prob.set_val('span', 1) - prob.set_val('tip_chord', 0.5) - prob.set_val('root_chord', 1) + tail_type = prob.model.tail.options['tail_type'] + prob.model.tail.options['tail_type'] = 'horizontal' + + if tail_type == 'horizontal': + prob.set_val(Aircraft.HorizontalTail.SPAN, 1.0) + prob.set_val(Aircraft.HorizontalTail.ROOT_CHORD, 1.0) + else: + prob.set_val(Aircraft.VerticalTail.SPAN, 1.0) + prob.set_val(Aircraft.VerticalTail.ROOT_CHORD, 1.0) + + prob.set_val('tip_chord_tail', 0.5) prob.set_val('thickness_ratio', 0.12) prob.set_val('skin_thickness', 0.002) - prob.model.tail.options['tail_type'] = 'horizontal' prob.model.tail.options['material'] = 'Balsa' prob.run_model() # Print - print(f"Total mass of the tail: {prob.get_val('mass')} kg") + if tail_type == 'horizontal': + print(f"Total mass of the tail: {prob.get_val(Aircraft.HorizontalTail.MASS)} kg") + else: + print(f"Total mass of the tail: {prob.get_val(Aircraft.VerticalTail.MASS)} kg") print(f"Center of gravity (X: {prob.get_val('cg_x')} m, Y: {prob.get_val('cg_y')} m, Z: {prob.get_val('cg_z')} m)") \ No newline at end of file diff --git a/aviary/subsystems/mass/simple_mass/test/test_fuselage.py b/aviary/subsystems/mass/simple_mass/test/test_fuselage.py index 17134bfaa..145e1f679 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_fuselage.py +++ b/aviary/subsystems/mass/simple_mass/test/test_fuselage.py @@ -4,6 +4,7 @@ from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal from aviary.subsystems.mass.simple_mass.fuselage import FuselageMassAndCOG +from aviary.variable_info.variables import Aircraft class FuselageMassTestCase(unittest.TestCase): """ @@ -22,7 +23,7 @@ def setUp(self): ) self.prob.model.set_input_defaults( - "length", + Aircraft.Fuselage.LENGTH, val=2.0, units="m") @@ -71,21 +72,18 @@ def test_case(self): tol=1e-3 assert_near_equal( - self.prob["total_weight_fuse"], - 467.3119, + self.prob[Aircraft.Fuselage.MASS], + 373.849, tol) partial_data = self.prob.check_partials( out_stream=None, method="cs") - from pprint import pprint - pprint(partial_data) - assert_check_partials( partial_data, - atol=1e-15, - rtol=1e-15) + atol=1e-12, + rtol=1e-12) if __name__ == "__main__": unittest.main() \ No newline at end of file diff --git a/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py b/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py index 48de87de7..2c4cc2d7d 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py +++ b/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py @@ -6,7 +6,9 @@ from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal from aviary.subsystems.mass.simple_mass.mass_summation import MassSummation, StructureMass +from aviary.variable_info.variables import Aircraft +# Horizontal Tail Only class MassSummationTest(unittest.TestCase): """ Total mass summation test case. @@ -23,26 +25,41 @@ def test_case(self): promotes_outputs=['*'] ) + #tail_type = self.prob.model.tot.options['tail_type'] + self.prob.model.set_input_defaults( - 'span', + Aircraft.Wing.SPAN, val=1.0, units='m' ) self.prob.model.set_input_defaults( - 'span_tail', + Aircraft.Wing.ROOT_CHORD, val=1.0, units='m' ) + #if tail_type == 'horizontal': self.prob.model.set_input_defaults( - "root_chord", + Aircraft.HorizontalTail.SPAN, + val=1, + units="m" + ) + + self.prob.model.set_input_defaults( + Aircraft.HorizontalTail.ROOT_CHORD, val=1, units="m" ) + #else: + self.prob.model.set_input_defaults( + Aircraft.VerticalTail.SPAN, + val=1, + units="m" + ) self.prob.model.set_input_defaults( - "root_chord_tail", + Aircraft.VerticalTail.ROOT_CHORD, val=1, units="m" ) @@ -83,7 +100,7 @@ def test_case(self): ) self.prob.model.set_input_defaults( - "length", + Aircraft.Fuselage.LENGTH, val=2.5, units="m") @@ -148,11 +165,19 @@ def test_case(self): #om.n2(self.prob) tol = 1e-10 + + #if tail_type == 'horizontal': assert_near_equal( self.prob['structure_mass'], 440, tol ) + # else: + # assert_near_equal( + # self.prob['structure_mass'], + # 440, + # tol + # ) partial_data = self.prob.check_partials( out_stream=None, @@ -180,25 +205,40 @@ def setUp(self): promotes_outputs=['*'], ) + #tail_type = self.prob.model.tot.options['tail_type'] + self.prob.setup( check=False, force_alloc_complex=True ) - self.prob.set_val('total_weight_fuse', val=100.0) - self.prob.set_val('total_weight_wing', val=4.2) - self.prob.set_val('mass', val=4.25) + self.prob.set_val(Aircraft.Fuselage.MASS, val=100.0) + self.prob.set_val(Aircraft.Wing.MASS, val=4.2) + + #if tail_type == 'horizontal': + self.prob.set_val(Aircraft.HorizontalTail.MASS, val=4.25) + #else: + self.prob.set_val(Aircraft.VerticalTail.MASS, val=4.25) def test_case(self): self.prob.run_model() + #tail_type = self.prob.model.tot.options['tail_type'] tol = 1e-10 + + #if tail_type == 'horizontal': assert_near_equal( self.prob['structure_mass'], 108.45, tol ) + # else: + # assert_near_equal( + # self.prob['structure_mass'], + # 108.45, + # tol + # ) partial_data = self.prob.check_partials( out_stream=None, diff --git a/aviary/subsystems/mass/simple_mass/test/test_tail.py b/aviary/subsystems/mass/simple_mass/test/test_tail.py index 05f3cd467..6a6072386 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_tail.py +++ b/aviary/subsystems/mass/simple_mass/test/test_tail.py @@ -6,6 +6,7 @@ import numpy as np from aviary.subsystems.mass.simple_mass.tail import TailMassAndCOG +from aviary.variable_info.variables import Aircraft class TailMassTestCase(unittest.TestCase): """ @@ -23,17 +24,32 @@ def setUp(self): promotes_outputs=["*"], ) - self.prob.model.set_input_defaults( - "span_tail", + tail_type = self.prob.model.Tail.options['tail_type'] + + if tail_type == 'horizontal': + self.prob.model.set_input_defaults( + Aircraft.HorizontalTail.SPAN, val=1, units="m" - ) - - self.prob.model.set_input_defaults( - "root_chord_tail", + ) + + self.prob.model.set_input_defaults( + Aircraft.HorizontalTail.ROOT_CHORD, + val=1, + units="m" + ) + else: + self.prob.model.set_input_defaults( + Aircraft.VerticalTail.SPAN, val=1, units="m" - ) + ) + + self.prob.model.set_input_defaults( + Aircraft.VerticalTail.ROOT_CHORD, + val=1, + units="m" + ) self.prob.model.set_input_defaults( "tip_chord_tail", @@ -63,15 +79,23 @@ def setUp(self): force_alloc_complex=True) def test_case(self): + + tail_type = self.prob.model.Tail.options['tail_type'] self.prob.run_model() tol = 1e-4 - assert_near_equal( - self.prob["mass"], - 4.22032, - tol) + if tail_type == 'horizontal': + assert_near_equal( + self.prob[Aircraft.HorizontalTail.MASS], + 4.22032, + tol) + else: + assert_near_equal( + self.prob[Aircraft.VerticalTail.MASS], + 4.22032, + tol) partial_data = self.prob.check_partials( out_stream=None, diff --git a/aviary/subsystems/mass/simple_mass/test/test_wing.py b/aviary/subsystems/mass/simple_mass/test/test_wing.py index fd5b218f6..79c5d5870 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_wing.py +++ b/aviary/subsystems/mass/simple_mass/test/test_wing.py @@ -8,6 +8,7 @@ import jax.numpy as jnp from aviary.subsystems.mass.simple_mass.wing import WingMassAndCOG +from aviary.variable_info.variables import Aircraft #@av.skipIfMissingDependencies(WingMassAndCOG) class WingMassTestCase(unittest.TestCase): @@ -27,13 +28,13 @@ def setUp(self): ) self.prob.model.set_input_defaults( - "span", + Aircraft.Wing.SPAN, val=1, units="m" ) self.prob.model.set_input_defaults( - "root_chord", + Aircraft.Wing.ROOT_CHORD, val=1, units="m" ) @@ -73,7 +74,7 @@ def test_case(self): self.prob.run_model() tol = 1e-10 - assert_near_equal(self.prob["total_weight_wing"], + assert_near_equal(self.prob[Aircraft.Wing.MASS], 4.22032, tol) diff --git a/aviary/subsystems/mass/simple_mass/wing.py b/aviary/subsystems/mass/simple_mass/wing.py index e17f1cca9..cc7baf8d6 100644 --- a/aviary/subsystems/mass/simple_mass/wing.py +++ b/aviary/subsystems/mass/simple_mass/wing.py @@ -7,6 +7,9 @@ from scipy.interpolate import CubicSpline import jax.scipy.integrate as jint +from aviary.variable_info.variables import Aircraft +from aviary.utils.functions import add_aviary_input, add_aviary_output + try: from quadax import quadgk except ImportError: @@ -14,22 +17,7 @@ "quadax package not found. You can install it by running 'pip install quadax'." ) -""" -The little bit of path code below is not important overall. This is for me to test -within the Docker container and VS Code before I push everything fully to the Github -repository. These lines can be deleted as things are updated further. - -""" - -import sys -import os - - -module_path = os.path.abspath("/home/omdao/Aviary/aviary/subsystems/mass") -if module_path not in sys.path: - sys.path.append(module_path) - -from simple_mass.materials_database import materials +from aviary.subsystems.mass.simple_mass.materials_database import materials from aviary.utils.named_values import get_keys @@ -57,26 +45,26 @@ def setup(self): self.options['use_jit'] = not(Debug) # Inputs - self.add_input('span', - val=10.0, - units='m') # Full wingspan (adjustable) + self.add_input(Aircraft.Wing.SPAN, + units='m', + primal_name='span') # Full wingspan (adjustable) - self.add_input('root_chord', - val=2.0, - units='m') # Root chord length + self.add_input(Aircraft.Wing.ROOT_CHORD, + units='m', + primal_name='root_chord') # Root chord length self.add_input('tip_chord', val=1.0, - units='m') # Tip chord length + units='m') # Tip chord length -- no aviary input self.add_input('twist', val=jnp.zeros(self.options['num_sections']), - units='deg') # Twist angles + units='deg') # Twist angles -- no aviary input self.add_input('thickness_dist', val=jnp.ones(self.options['num_sections']) * 0.1, shape=(self.options['num_sections'],), - units='m') # Thickness distribution of the wing (height) + units='m') # Thickness distribution of the wing (height) -- no aviary input # Outputs @@ -92,9 +80,9 @@ def setup(self): val=0.0, units='m') - self.add_output('total_weight_wing', - val=0.0, - units='kg') + self.add_output(Aircraft.Wing.MASS, + units='kg', + primal_name='total_weight_wing') def compute_primal(self, span, root_chord, tip_chord, twist, thickness_dist): material = self.options['material'] # Material is taken from options @@ -215,8 +203,8 @@ def extract_airfoil_features(self, x_coords, y_coords): prob.setup() # Define some example inputs - prob.set_val('span', 3.74904) - prob.set_val('root_chord', 0.40005) + prob.set_val(Aircraft.Wing.SPAN, 3.74904) + prob.set_val(Aircraft.Wing.ROOT_CHORD, 0.40005) prob.set_val('tip_chord', 0.100076) prob.set_val('twist', jnp.linspace(0,0,10)) prob.set_val('thickness_dist', thickness_dist) @@ -233,7 +221,7 @@ def extract_airfoil_features(self, x_coords, y_coords): center_of_gravity_x = prob.get_val('cog.center_of_gravity_x_wing') center_of_gravity_y = prob.get_val('cog.center_of_gravity_y_wing') center_of_gravity_z = prob.get_val('cog.center_of_gravity_z_wing') - total_weight = prob.get_val('cog.total_weight_wing') + total_weight = prob.get_val(Aircraft.Wing.MASS) print(f"Center of gravity: X = {center_of_gravity_x} m, Y = {center_of_gravity_y} m, Z = {center_of_gravity_z} m") print(f"Total mass of the wing: {total_weight} kg") From 27ae9e75d8528145e0f497f33cca2bc967a178ee Mon Sep 17 00:00:00 2001 From: szoppelt Date: Mon, 16 Jun 2025 15:14:14 +0000 Subject: [PATCH 072/147] updates. --- .../subsystems/mass/simple_mass/fuselage.py | 39 +++-- .../mass/simple_mass/mass_summation.py | 53 ++++-- aviary/subsystems/mass/simple_mass/tail.py | 165 +++++++++++------- .../simple_mass/test/test_mass_summation.py | 90 +++++----- .../mass/simple_mass/test/test_tail.py | 42 ++--- aviary/subsystems/mass/simple_mass/wing.py | 42 ++--- 6 files changed, 247 insertions(+), 184 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/fuselage.py b/aviary/subsystems/mass/simple_mass/fuselage.py index 68d088c8f..ce1208dbb 100644 --- a/aviary/subsystems/mass/simple_mass/fuselage.py +++ b/aviary/subsystems/mass/simple_mass/fuselage.py @@ -7,6 +7,7 @@ import jax.scipy.interpolate as jinterp from aviary.variable_info.variables import Aircraft +from aviary.variable_info.functions import add_aviary_output, add_aviary_input try: from quadax import quadgk @@ -42,9 +43,9 @@ def setup(self): self.options['use_jit'] = not(Debug) # Inputs - self.add_input(Aircraft.Fuselage.LENGTH, - units='m', - primal_name='length') + add_aviary_input(self, + Aircraft.Fuselage.LENGTH, + units='m') self.add_input('base_diameter', val=0.4, @@ -89,13 +90,13 @@ def setup(self): val=0.0, units='m') - self.add_output(Aircraft.Fuselage.MASS, - units='kg', - primal_name='total_weight_fuse') + add_aviary_output(self, + Aircraft.Fuselage.MASS, + units='kg') - def compute_primal(self, length, base_diameter, tip_diameter, curvature, thickness, y_offset, z_offset, is_hollow): + def compute_primal(self, aircraft__fuselage__length, base_diameter, tip_diameter, curvature, thickness, y_offset, z_offset, is_hollow): # Input validation checks - if length <= 0: + if aircraft__fuselage__length <= 0: raise ValueError("Length must be greater than zero.") if base_diameter <= 0 or tip_diameter <= 0: @@ -108,13 +109,13 @@ def compute_primal(self, length, base_diameter, tip_diameter, curvature, thickne material = self.options['material'] num_sections = self.options['num_sections'] - self.validate_inputs(length, base_diameter, thickness, tip_diameter, is_hollow) + self.validate_inputs(aircraft__fuselage__length, base_diameter, thickness, tip_diameter, is_hollow) density, _ = materials.get_item(material) - section_locations = jnp.linspace(0, length, num_sections) + section_locations = jnp.linspace(0, aircraft__fuselage__length, num_sections) - total_weight_fuse = 0 + aircraft__fuselage__mass = 0 total_moment_x = 0 total_moment_y = 0 total_moment_z = 0 @@ -123,25 +124,25 @@ def compute_primal(self, length, base_diameter, tip_diameter, curvature, thickne # Loop through each section for location in section_locations: - section_diameter = self.get_section_diameter(location, length, base_diameter, tip_diameter, interpolate_diameter) + section_diameter = self.get_section_diameter(location, aircraft__fuselage__length, base_diameter, tip_diameter, interpolate_diameter) outer_radius = section_diameter / 2.0 inner_radius = jnp.where(is_hollow, omj.smooth_max(0, outer_radius - thickness), 0) - section_volume = jnp.pi * (outer_radius**2 - inner_radius**2) * (length / num_sections) + section_volume = jnp.pi * (outer_radius**2 - inner_radius**2) * (aircraft__fuselage__length / num_sections) section_weight = density * section_volume - centroid_x, centroid_y, centroid_z = self.compute_centroid(location, length, y_offset, z_offset, curvature, base_diameter, tip_diameter) + centroid_x, centroid_y, centroid_z = self.compute_centroid(location, aircraft__fuselage__length, y_offset, z_offset, curvature, base_diameter, tip_diameter) - total_weight_fuse += section_weight + aircraft__fuselage__mass += section_weight total_moment_x += centroid_x * section_weight total_moment_y += centroid_y * section_weight total_moment_z += centroid_z * section_weight - center_of_gravity_x_fuse = total_moment_x / total_weight_fuse - center_of_gravity_y_fuse = total_moment_y / total_weight_fuse - center_of_gravity_z_fuse = total_moment_z / total_weight_fuse + center_of_gravity_x_fuse = total_moment_x / aircraft__fuselage__mass + center_of_gravity_y_fuse = total_moment_y / aircraft__fuselage__mass + center_of_gravity_z_fuse = total_moment_z / aircraft__fuselage__mass - return center_of_gravity_x_fuse, center_of_gravity_y_fuse, center_of_gravity_z_fuse, total_weight_fuse + return center_of_gravity_x_fuse, center_of_gravity_y_fuse, center_of_gravity_z_fuse, aircraft__fuselage__mass def validate_inputs(self, length, base_diameter, thickness, tip_diameter, is_hollow): if length <= 0 or base_diameter <= 0 or tip_diameter <= 0 or thickness <= 0: diff --git a/aviary/subsystems/mass/simple_mass/mass_summation.py b/aviary/subsystems/mass/simple_mass/mass_summation.py index bff4764b2..00b1fd4c3 100644 --- a/aviary/subsystems/mass/simple_mass/mass_summation.py +++ b/aviary/subsystems/mass/simple_mass/mass_summation.py @@ -7,7 +7,8 @@ from aviary.subsystems.mass.simple_mass.wing import WingMassAndCOG from aviary.subsystems.mass.simple_mass.tail import TailMassAndCOG from aviary.variable_info.variables import Aircraft -# Maybe add some aviary inputs at some point here +from aviary.variable_info.functions import add_aviary_input + class MassSummation(om.Group): """ @@ -38,7 +39,7 @@ def setup(self): 'tail_mass', TailMassAndCOG(), promotes_inputs=['*'], - promotes_outputs=[Aircraft.HorizontalTail.MASS, Aircraft.VerticalTail.MASS] + promotes_outputs=[Aircraft.HorizontalTail.MASS] ) self.add_subsystem( @@ -50,24 +51,48 @@ def setup(self): # Horizontal tail only class StructureMass(om.JaxExplicitComponent): + def initialize(self): + self.options.declare('tail_type', + default='horizontal', + values=['horizontal', 'vertical'], + desc="Tail type used for the tail mass from tail.py file") def setup(self): - # Maybe later change these to Aviary inputs? - self.add_input(Aircraft.Wing.MASS, val=0.0, units='kg', primal_name='total_weight_wing') - self.add_input(Aircraft.Fuselage.MASS, val=0.0, units='kg', primal_name='total_weight_fuse') + tail_type = self.options['tail_type'] - #tail_type = self.tail_mass.options['tail_type'] + add_aviary_input(self, + Aircraft.Wing.MASS, + val=0.0, + units='kg') + + add_aviary_input(self, + Aircraft.Fuselage.MASS, + val=0.0, + units='kg') + + add_aviary_input(self, + Aircraft.HorizontalTail.MASS, + val=0.0, + units='kg') + + add_aviary_input(self, + Aircraft.VerticalTail.MASS, + val=0.0, + units='kg') - #if tail_type == 'horizontal': - self.add_input(Aircraft.HorizontalTail.MASS, val=0.0, units='kg', primal_name='mass') - #else: - self.add_input(Aircraft.HorizontalTail.MASS, val=0.0, units='kg', tags='mass') # More masses can be added, i.e., tail, spars, flaps, etc. as needed - self.add_output('structure_mass', val=0.0, units='kg') + self.add_output('structure_mass', + val=0.0, + units='kg') - def compute_primal(self, total_weight_wing, total_weight_fuse, mass): - - structure_mass = total_weight_wing + total_weight_fuse + mass + def compute_primal(self, aircraft__wing__mass, aircraft__fuselage__mass, aircraft__horizontal_tail__mass, aircraft__vertical_tail__mass): + + tail_type = self.options['tail_type'] + + if tail_type == 'horizontal': + structure_mass = aircraft__wing__mass + aircraft__fuselage__mass + aircraft__horizontal_tail__mass + else: + structure_mass = aircraft__wing__mass + aircraft__fuselage__mass + aircraft__vertical_tail__mass return structure_mass \ No newline at end of file diff --git a/aviary/subsystems/mass/simple_mass/tail.py b/aviary/subsystems/mass/simple_mass/tail.py index bb2d29fae..29930dd66 100644 --- a/aviary/subsystems/mass/simple_mass/tail.py +++ b/aviary/subsystems/mass/simple_mass/tail.py @@ -7,6 +7,7 @@ import os from aviary.variable_info.variables import Aircraft +from aviary.variable_info.functions import add_aviary_output, add_aviary_input try: from quadax import quadgk @@ -26,7 +27,6 @@ def initialize(self): #self.options['default_shape'] = () # Sets the default shape to scalar self.options.declare('tail_type', - default='horizontal', values=['horizontal', 'vertical'], desc="Type of tail: 'horizontal' or 'vertical'") @@ -55,29 +55,29 @@ def initialize(self): def setup(self): self.options['use_jit'] = not(Debug) - tail_type = self.options['tail_type'] + #tail_type = self.options['tail_type'] # Inputs - if tail_type == 'horizontal': - self.add_input(Aircraft.HorizontalTail.SPAN, - units='m', - desc="Tail span", - primal_name='span_tail') - - self.add_input(Aircraft.HorizontalTail.ROOT_CHORD, - units='m', - desc="Root chord length", - primal_name='root_chord_tail') - else: - self.add_input(Aircraft.VerticalTail.SPAN, - units='m', - desc="Tail span", - primal_name='span_tail') - - self.add_input(Aircraft.VerticalTail.ROOT_CHORD, - units='m', - desc="Root chord length", - primal_name='root_chord_tail') + #if tail_type == 'horizontal': + add_aviary_input(self, + Aircraft.HorizontalTail.SPAN, + units='m', + desc="Tail span") + + add_aviary_input(self, + Aircraft.HorizontalTail.ROOT_CHORD, + units='m', + desc="Root chord length") + #else: + add_aviary_input(self, + Aircraft.VerticalTail.SPAN, + units='m', + desc="Tail span") + + add_aviary_input(self, + Aircraft.VerticalTail.ROOT_CHORD, + units='m', + desc="Root chord length") # The inputs below have no aviary input, so there is no distinction for now @@ -101,16 +101,16 @@ def setup(self): desc="Twist distribution") # Outputs - if tail_type == 'horizontal': - self.add_output(Aircraft.HorizontalTail.MASS, + #if tail_type == 'horizontal': + add_aviary_output(self, + Aircraft.HorizontalTail.MASS, units='kg', - desc="Total mass of the tail", - primal_name='mass') - else: - self.add_output(Aircraft.VerticalTail.MASS, + desc="Total mass of the tail") + #else: + add_aviary_output(self, + Aircraft.VerticalTail.MASS, units='kg', - desc="Total mass of the tail", - primal_name='mass') + desc="Total mass of the tail") # Same as above inputs @@ -129,7 +129,15 @@ def setup(self): units='m', desc="Z location of the center of gravity") - def compute_primal(self, span_tail, root_chord_tail, tip_chord_tail, thickness_ratio, skin_thickness, twist_tail): + def compute_primal(self, + aircraft__horizontal_tail__span, + aircraft__horizontal_tail__root_chord, + aircraft__vertical_tail__span, + aircraft__vertical_tail__root_chord, + tip_chord_tail, + thickness_ratio, + skin_thickness, + twist_tail): tail_type = self.options["tail_type"] airfoil_type = self.options["airfoil_type"] material = self.options['material'] @@ -138,6 +146,10 @@ def compute_primal(self, span_tail, root_chord_tail, tip_chord_tail, thickness_r num_sections = self.options['num_sections'] NACA_digits = self.options['NACA_digits'] + # This is just so that the differentiation and unittest do not break. If tail_type = horizontal, ignore the vertical tail mass and vice versa. + aircraft__horizontal_tail__mass = 0.0 + aircraft__vertical_tail__mass = 0.0 + # File check if airfoil_type == 'file': if airfoil_type == 'file' and (airfoil_file is None or not os.path.isfile(airfoil_file)): @@ -165,7 +177,10 @@ def compute_primal(self, span_tail, root_chord_tail, tip_chord_tail, thickness_r if tail_type not in ['horizontal', 'vertical']: raise ValueError("Invalid tail_type. Must be 'horizontal' or 'vertical'.") - span_locations = jnp.linspace(0, span_tail, num_sections) + if tail_type == 'horizontal': + span_locations = jnp.linspace(0, aircraft__horizontal_tail__span, num_sections) + elif tail_type == 'vertical': + span_locations = jnp.linspace(0, aircraft__vertical_tail__span, num_sections) # Get x_points and dx for later x_points, dx = self.precompute_airfoil_geometry() @@ -173,36 +188,61 @@ def compute_primal(self, span_tail, root_chord_tail, tip_chord_tail, thickness_r # Thickness distribution thickness_dist = self.airfoil_thickness(x_points, max_thickness) - - total_mass, _ = quadgk(lambda x: density * self.airfoil_thickness(x, max_thickness) * (root_chord_tail - (root_chord_tail - tip_chord_tail) * (x / span_tail)) * span_tail, [0, 1], epsabs=1e-9, epsrel=1e-9) + # if tail_type == 'horizontal': + # aircraft__vertical_tail__mass = None + # elif tail_type == 'vertical': + # aircraft__horizontal_tail__mass = None if tail_type == 'horizontal': - cgz_function = lambda x: (x * self.airfoil_thickness(x, max_thickness) * (root_chord_tail - (root_chord_tail - tip_chord_tail) * (x / span_tail))) * jnp.sin(twist_tail) + (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (root_chord_tail - (root_chord_tail - tip_chord_tail) * (x / span_tail))) * jnp.cos(twist_tail) - cgy_function = lambda x: x * span_tail - else: - cgz_function = lambda x: x * span_tail - cgy_function = lambda x: (x * self.airfoil_thickness(x, max_thickness) * (root_chord_tail - (root_chord_tail - tip_chord_tail) * (x / span_tail))) * jnp.sin(twist_tail) + (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (root_chord_tail - (root_chord_tail - tip_chord_tail) * (x / span_tail))) * jnp.cos(twist_tail) + total_mass, _ = quadgk(lambda x: density * self.airfoil_thickness(x, max_thickness) * (aircraft__horizontal_tail__root_chord - (aircraft__horizontal_tail__root_chord - tip_chord_tail) * (x / aircraft__horizontal_tail__span)) * aircraft__horizontal_tail__span, [0, 1], epsabs=1e-9, epsrel=1e-9) - area, _ = quadgk(lambda x: self.airfoil_thickness(x, max_thickness) * (root_chord_tail- (root_chord_tail - tip_chord_tail) * (x / span_tail)), [0, 1], epsabs=1e-9, epsrel=1e-9) + area, _ = quadgk(lambda x: self.airfoil_thickness(x, max_thickness) * (aircraft__horizontal_tail__root_chord- (aircraft__horizontal_tail__root_chord - tip_chord_tail) * (x / aircraft__horizontal_tail__span)), [0, 1], epsabs=1e-9, epsrel=1e-9) - cg_x_num, _ = quadgk(lambda x: (x * self.airfoil_thickness(x, max_thickness) * (root_chord_tail - (root_chord_tail - tip_chord_tail) * (x / span_tail)) * jnp.cos(twist_tail)) - - (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (root_chord_tail - (root_chord_tail - tip_chord_tail) * (x / span_tail))) * jnp.sin(twist_tail), - [0, 1], epsabs=1e-9, epsrel=1e-9) - - cg_x = cg_x_num / area - cg_x = cg_x[0] - + cg_x_num, _ = quadgk(lambda x: (x * self.airfoil_thickness(x, max_thickness) * (aircraft__horizontal_tail__root_chord - (aircraft__horizontal_tail__root_chord - tip_chord_tail) * (x / aircraft__horizontal_tail__span)) * jnp.cos(twist_tail)) - + (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (aircraft__horizontal_tail__root_chord - (aircraft__horizontal_tail__root_chord - tip_chord_tail) * (x / aircraft__horizontal_tail__span))) * jnp.sin(twist_tail), + [0, 1], epsabs=1e-9, epsrel=1e-9) + + cg_x = cg_x_num / area + cg_x = cg_x[0] - cg_y, _ = quadgk(cgy_function, [0, 1], epsabs=1e-9, epsrel=1e-9) + cgz_function = lambda x: (x * self.airfoil_thickness(x, max_thickness) * (aircraft__horizontal_tail__root_chord - (aircraft__horizontal_tail__root_chord - tip_chord_tail) * (x / aircraft__horizontal_tail__span))) * jnp.sin(twist_tail) + (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (aircraft__horizontal_tail__root_chord - (aircraft__horizontal_tail__root_chord - tip_chord_tail) * (x / aircraft__horizontal_tail__span))) * jnp.cos(twist_tail) + cgy_function = lambda x: x * aircraft__horizontal_tail__span + + + cg_y, _ = quadgk(cgy_function, [0, 1], epsabs=1e-9, epsrel=1e-9) - cg_z_num, _ = quadgk(cgz_function, [0, 1], epsabs=1e-9, epsrel=1e-9) + cg_z_num, _ = quadgk(cgz_function, [0, 1], epsabs=1e-9, epsrel=1e-9) - cg_z = cg_z_num / area - cg_z = cg_z[0] + cg_z = cg_z_num / area + cg_z = cg_z[0] - mass = total_mass + aircraft__horizontal_tail__mass = total_mass + elif tail_type == 'vertical': + total_mass, _ = quadgk(lambda x: density * self.airfoil_thickness(x, max_thickness) * (aircraft__vertical_tail__root_chord - (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span)) * aircraft__vertical_tail__span, [0, 1], epsabs=1e-9, epsrel=1e-9) - return mass, cg_x, cg_y, cg_z + area, _ = quadgk(lambda x: self.airfoil_thickness(x, max_thickness) * (aircraft__vertical_tail__root_chord- (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span)), [0, 1], epsabs=1e-9, epsrel=1e-9) + + cg_x_num, _ = quadgk(lambda x: (x * self.airfoil_thickness(x, max_thickness) * (aircraft__vertical_tail__root_chord - (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span)) * jnp.cos(twist_tail)) - + (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (aircraft__vertical_tail__root_chord - (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span))) * jnp.sin(twist_tail), + [0, 1], epsabs=1e-9, epsrel=1e-9) + + cg_x = cg_x_num / area + cg_x = cg_x[0] + + cgy_function = lambda x: (x * self.airfoil_thickness(x, max_thickness) * (aircraft__vertical_tail__root_chord - (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span))) * jnp.sin(twist_tail) + (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (aircraft__vertical_tail__root_chord - (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span))) * jnp.cos(twist_tail) + cgz_function = lambda x: x * aircraft__vertical_tail__span + + + cg_z, _ = quadgk(cgz_function, [0, 1], epsabs=1e-9, epsrel=1e-9) + + cg_y_num, _ = quadgk(cgy_function, [0, 1], epsabs=1e-9, epsrel=1e-9) + + cg_y = cg_y_num / area + cg_y = cg_y[0] + + aircraft__vertical_tail__mass = total_mass + + return aircraft__horizontal_tail__mass, aircraft__vertical_tail__mass, cg_x, cg_y, cg_z def precompute_airfoil_geometry(self): num_sections = self.options['num_sections'] @@ -272,13 +312,13 @@ def extract_airfoil_features(self, x_coords, y_coords): prob.setup() # Input values - tail_type = prob.model.tail.options['tail_type'] - prob.model.tail.options['tail_type'] = 'horizontal' + #tail_type = prob.model.tail.options['tail_type'] + prob.model.tail.options['tail_type'] = 'vertical' - if tail_type == 'horizontal': + if prob.model.tail.options['tail_type'] == 'horizontal': prob.set_val(Aircraft.HorizontalTail.SPAN, 1.0) prob.set_val(Aircraft.HorizontalTail.ROOT_CHORD, 1.0) - else: + elif prob.model.tail.options['tail_type'] == 'vertical': prob.set_val(Aircraft.VerticalTail.SPAN, 1.0) prob.set_val(Aircraft.VerticalTail.ROOT_CHORD, 1.0) @@ -291,8 +331,9 @@ def extract_airfoil_features(self, x_coords, y_coords): prob.run_model() # Print - if tail_type == 'horizontal': - print(f"Total mass of the tail: {prob.get_val(Aircraft.HorizontalTail.MASS)} kg") - else: - print(f"Total mass of the tail: {prob.get_val(Aircraft.VerticalTail.MASS)} kg") - print(f"Center of gravity (X: {prob.get_val('cg_x')} m, Y: {prob.get_val('cg_y')} m, Z: {prob.get_val('cg_z')} m)") \ No newline at end of file + if prob.model.tail.options['tail_type'] == 'horizontal': + print(f"Total mass of the horizontal tail: {prob.get_val(Aircraft.HorizontalTail.MASS)} kg") + print(f"Center of gravity of horizontal tail (X: {prob.get_val('cg_x')} m, Y: {prob.get_val('cg_y')} m, Z: {prob.get_val('cg_z')} m)") + elif prob.model.tail.options['tail_type'] == 'vertical': + print(f"Total mass of the vertical tail: {prob.get_val(Aircraft.VerticalTail.MASS)} kg") + print(f"Center of gravity of vertical tail (X: {prob.get_val('cg_x')} m, Y: {prob.get_val('cg_y')} m, Z: {prob.get_val('cg_z')} m)") \ No newline at end of file diff --git a/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py b/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py index 2c4cc2d7d..9a08fc00d 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py +++ b/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py @@ -21,12 +21,9 @@ def test_case(self): self.prob.model.add_subsystem( 'tot', MassSummation(), - promotes_inputs=['*'], - promotes_outputs=['*'] + promotes=['*'] ) - #tail_type = self.prob.model.tot.options['tail_type'] - self.prob.model.set_input_defaults( Aircraft.Wing.SPAN, val=1.0, @@ -39,7 +36,6 @@ def test_case(self): units='m' ) - #if tail_type == 'horizontal': self.prob.model.set_input_defaults( Aircraft.HorizontalTail.SPAN, val=1, @@ -51,7 +47,7 @@ def test_case(self): val=1, units="m" ) - #else: + self.prob.model.set_input_defaults( Aircraft.VerticalTail.SPAN, val=1, @@ -105,14 +101,14 @@ def test_case(self): units="m") self.prob.model.set_input_defaults( - "diameter", - val=0.5, + "base_diameter", + val=0.4, units="m" ) self.prob.model.set_input_defaults( - "taper_ratio", - val=0.5 + "tip_diameter", + val=0.2 ) self.prob.model.set_input_defaults( @@ -160,24 +156,26 @@ def test_case(self): force_alloc_complex=True ) + self.prob.model.tot.tail_mass.options['tail_type'] = 'horizontal' + self.prob.run_model() #om.n2(self.prob) tol = 1e-10 - #if tail_type == 'horizontal': - assert_near_equal( - self.prob['structure_mass'], - 440, - tol - ) - # else: - # assert_near_equal( - # self.prob['structure_mass'], - # 440, - # tol - # ) + if self.prob.model.tot.tail_mass.options['tail_type'] == 'horizontal': + assert_near_equal( + self.prob['structure_mass'], + 342.23558104, + tol + ) + else: + assert_near_equal( + self.prob['structure_mass'], + 342.23558104, + tol + ) partial_data = self.prob.check_partials( out_stream=None, @@ -205,40 +203,42 @@ def setUp(self): promotes_outputs=['*'], ) - #tail_type = self.prob.model.tot.options['tail_type'] - self.prob.setup( check=False, force_alloc_complex=True ) - self.prob.set_val(Aircraft.Fuselage.MASS, val=100.0) - self.prob.set_val(Aircraft.Wing.MASS, val=4.2) - - #if tail_type == 'horizontal': - self.prob.set_val(Aircraft.HorizontalTail.MASS, val=4.25) - #else: - self.prob.set_val(Aircraft.VerticalTail.MASS, val=4.25) + self.prob.set_val(Aircraft.Fuselage.MASS, + val=100.0) + + self.prob.set_val(Aircraft.Wing.MASS, + val=4.2) + + self.prob.set_val(Aircraft.HorizontalTail.MASS, + val=4.25) + + self.prob.set_val(Aircraft.VerticalTail.MASS, + val=4.25) def test_case(self): self.prob.run_model() - #tail_type = self.prob.model.tot.options['tail_type'] tol = 1e-10 - - #if tail_type == 'horizontal': - assert_near_equal( - self.prob['structure_mass'], - 108.45, - tol - ) - # else: - # assert_near_equal( - # self.prob['structure_mass'], - # 108.45, - # tol - # ) + self.prob.model.tot.options['tail_type'] = 'horizontal' + + if self.prob.model.tot.options['tail_type'] == 'horizontal': + assert_near_equal( + self.prob['structure_mass'], + 108.45, + tol + ) + else: + assert_near_equal( + self.prob['structure_mass'], + 108.45, + tol + ) partial_data = self.prob.check_partials( out_stream=None, diff --git a/aviary/subsystems/mass/simple_mass/test/test_tail.py b/aviary/subsystems/mass/simple_mass/test/test_tail.py index 6a6072386..2b8eb3bd9 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_tail.py +++ b/aviary/subsystems/mass/simple_mass/test/test_tail.py @@ -24,32 +24,29 @@ def setUp(self): promotes_outputs=["*"], ) - tail_type = self.prob.model.Tail.options['tail_type'] + self.prob.model.set_input_defaults( + Aircraft.HorizontalTail.SPAN, + val=1, + units="m" + ) - if tail_type == 'horizontal': - self.prob.model.set_input_defaults( - Aircraft.HorizontalTail.SPAN, + self.prob.model.set_input_defaults( + Aircraft.HorizontalTail.ROOT_CHORD, val=1, units="m" - ) + ) + #else: + self.prob.model.set_input_defaults( + Aircraft.VerticalTail.SPAN, + val=1, + units="m" + ) - self.prob.model.set_input_defaults( - Aircraft.HorizontalTail.ROOT_CHORD, - val=1, - units="m" - ) - else: - self.prob.model.set_input_defaults( - Aircraft.VerticalTail.SPAN, + self.prob.model.set_input_defaults( + Aircraft.VerticalTail.ROOT_CHORD, val=1, units="m" - ) - - self.prob.model.set_input_defaults( - Aircraft.VerticalTail.ROOT_CHORD, - val=1, - units="m" - ) + ) self.prob.model.set_input_defaults( "tip_chord_tail", @@ -79,14 +76,13 @@ def setUp(self): force_alloc_complex=True) def test_case(self): - - tail_type = self.prob.model.Tail.options['tail_type'] + self.prob.model.Tail.options['tail_type'] = 'vertical' self.prob.run_model() tol = 1e-4 - if tail_type == 'horizontal': + if self.prob.model.Tail.options['tail_type'] == 'horizontal': assert_near_equal( self.prob[Aircraft.HorizontalTail.MASS], 4.22032, diff --git a/aviary/subsystems/mass/simple_mass/wing.py b/aviary/subsystems/mass/simple_mass/wing.py index cc7baf8d6..e6175855b 100644 --- a/aviary/subsystems/mass/simple_mass/wing.py +++ b/aviary/subsystems/mass/simple_mass/wing.py @@ -45,13 +45,13 @@ def setup(self): self.options['use_jit'] = not(Debug) # Inputs - self.add_input(Aircraft.Wing.SPAN, - units='m', - primal_name='span') # Full wingspan (adjustable) + add_aviary_input(self, + Aircraft.Wing.SPAN, + units='m') # Full wingspan (adjustable) - self.add_input(Aircraft.Wing.ROOT_CHORD, - units='m', - primal_name='root_chord') # Root chord length + add_aviary_input(self, + Aircraft.Wing.ROOT_CHORD, + units='m') # Root chord length self.add_input('tip_chord', val=1.0, @@ -80,11 +80,11 @@ def setup(self): val=0.0, units='m') - self.add_output(Aircraft.Wing.MASS, - units='kg', - primal_name='total_weight_wing') + add_aviary_output(self, + Aircraft.Wing.MASS, + units='kg') - def compute_primal(self, span, root_chord, tip_chord, twist, thickness_dist): + def compute_primal(self, aircraft__wing__span, aircraft__wing__root_chord, tip_chord, twist, thickness_dist): material = self.options['material'] # Material is taken from options airfoil_type = self.options['airfoil_type'] # NACA airfoil type airfoil_data_file = self.options['airfoil_data_file'] @@ -108,35 +108,35 @@ def compute_primal(self, span, root_chord, tip_chord, twist, thickness_dist): num_sections = self.options['num_sections'] # Wing spanwise distribution - span_locations = jnp.linspace(0, span, num_sections) + span_locations = jnp.linspace(0, aircraft__wing__span, num_sections) n_points = num_sections x_points = jnp.linspace(0, 1, n_points) dx = 1 / (n_points - 1) - weight_function = lambda x: density * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span)) * span + weight_function = lambda x: density * self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span)) * aircraft__wing__span - total_weight_wing, _ = quadgk(weight_function, [0, 1], epsabs=1e-9, epsrel=1e-9) + aircraft__wing__mass, _ = quadgk(weight_function, [0, 1], epsabs=1e-9, epsrel=1e-9) - center_of_gravity_x_num, _ = quadgk(lambda x: x * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span) * jnp.cos(twist)) - - self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span)) * jnp.sin(twist), + center_of_gravity_x_num, _ = quadgk(lambda x: x * self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span) * jnp.cos(twist)) - + self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span)) * jnp.sin(twist), [0, 1], epsabs=1e-9, epsrel=1e-9) - center_of_gravity_x_denom, _ = quadgk(lambda x: self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span)), [0, 1], epsabs=1e-9, epsrel=1e-9) + center_of_gravity_x_denom, _ = quadgk(lambda x: self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span)), [0, 1], epsabs=1e-9, epsrel=1e-9) center_of_gravity_x = center_of_gravity_x_num / center_of_gravity_x_denom center_of_gravity_x_wing = center_of_gravity_x[0] - center_of_gravity_z_num, _ = quadgk(lambda x: x * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span) * jnp.sin(twist)) + - self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span)) * jnp.cos(twist), + center_of_gravity_z_num, _ = quadgk(lambda x: x * self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span) * jnp.sin(twist)) + + self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span)) * jnp.cos(twist), [0, 1], epsabs=1e-9, epsrel=1e-9) - center_of_gravity_z_denom, _ = quadgk(lambda x: self.airfoil_thickness(x, max_thickness) * (root_chord - (root_chord - tip_chord) * (x / span)), [0, 1], epsabs=1e-9, epsrel=1e-9) + center_of_gravity_z_denom, _ = quadgk(lambda x: self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span)), [0, 1], epsabs=1e-9, epsrel=1e-9) center_of_gravity_z = center_of_gravity_z_num / center_of_gravity_z_denom center_of_gravity_z_wing = center_of_gravity_z[0] - center_of_gravity_y_wing, _ = quadgk(lambda x: x * span, [0, 1], epsabs=1e-9, epsrel=1e-9) + center_of_gravity_y_wing, _ = quadgk(lambda x: x * aircraft__wing__span, [0, 1], epsabs=1e-9, epsrel=1e-9) - return center_of_gravity_x_wing, center_of_gravity_y_wing, center_of_gravity_z_wing, total_weight_wing + return center_of_gravity_x_wing, center_of_gravity_y_wing, center_of_gravity_z_wing, aircraft__wing__mass def precompute_airfoil_geometry(self): num_sections = self.options['num_sections'] From b514fec90192b7686adb9f0ec795326f1e47c223 Mon Sep 17 00:00:00 2001 From: szoppelt Date: Wed, 18 Jun 2025 17:54:02 +0000 Subject: [PATCH 073/147] updates. --- .../subsystems/mass/simple_mass/fuselage.py | 35 ++++----- aviary/subsystems/mass/simple_mass/tail.py | 74 +++++++++---------- aviary/subsystems/mass/simple_mass/wing.py | 55 +++++++------- 3 files changed, 83 insertions(+), 81 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/fuselage.py b/aviary/subsystems/mass/simple_mass/fuselage.py index ce1208dbb..c263737dc 100644 --- a/aviary/subsystems/mass/simple_mass/fuselage.py +++ b/aviary/subsystems/mass/simple_mass/fuselage.py @@ -78,17 +78,17 @@ def setup(self): # Outputs - self.add_output('center_of_gravity_x_fuse', - val=0.0, - units='m') + # self.add_output('center_of_gravity_x_fuse', + # val=0.0, + # units='m') - self.add_output('center_of_gravity_y_fuse', - val=0.0, - units='m') + # self.add_output('center_of_gravity_y_fuse', + # val=0.0, + # units='m') - self.add_output('center_of_gravity_z_fuse', - val=0.0, - units='m') + # self.add_output('center_of_gravity_z_fuse', + # val=0.0, + # units='m') add_aviary_output(self, Aircraft.Fuselage.MASS, @@ -138,11 +138,12 @@ def compute_primal(self, aircraft__fuselage__length, base_diameter, tip_diameter total_moment_y += centroid_y * section_weight total_moment_z += centroid_z * section_weight - center_of_gravity_x_fuse = total_moment_x / aircraft__fuselage__mass - center_of_gravity_y_fuse = total_moment_y / aircraft__fuselage__mass - center_of_gravity_z_fuse = total_moment_z / aircraft__fuselage__mass + # center_of_gravity_x_fuse = total_moment_x / aircraft__fuselage__mass + # center_of_gravity_y_fuse = total_moment_y / aircraft__fuselage__mass + # center_of_gravity_z_fuse = total_moment_z / aircraft__fuselage__mass - return center_of_gravity_x_fuse, center_of_gravity_y_fuse, center_of_gravity_z_fuse, aircraft__fuselage__mass + # return center_of_gravity_x_fuse, center_of_gravity_y_fuse, center_of_gravity_z_fuse, aircraft__fuselage__mass + return aircraft__fuselage__mass def validate_inputs(self, length, base_diameter, thickness, tip_diameter, is_hollow): if length <= 0 or base_diameter <= 0 or tip_diameter <= 0 or thickness <= 0: @@ -203,13 +204,13 @@ def compute_centroid(self, location, length, y_offset, z_offset, curvature, base prob.run_model() - center_of_gravity_x = prob.get_val('fuselage_cg.center_of_gravity_x_fuse') - center_of_gravity_y = prob.get_val('fuselage_cg.center_of_gravity_y_fuse') - center_of_gravity_z = prob.get_val('fuselage_cg.center_of_gravity_z_fuse') + # center_of_gravity_x = prob.get_val('fuselage_cg.center_of_gravity_x_fuse') + # center_of_gravity_y = prob.get_val('fuselage_cg.center_of_gravity_y_fuse') + # center_of_gravity_z = prob.get_val('fuselage_cg.center_of_gravity_z_fuse') total_weight = prob.get_val(Aircraft.Fuselage.MASS) #data = prob.check_partials(compact_print=True, abs_err_tol=1e-04, rel_err_tol=1e-04, step=1e-8, step_calc='rel') - print(f"Center of gravity of the fuselage: X = {center_of_gravity_x} m, Y = {center_of_gravity_y} m, Z = {center_of_gravity_z} m") + # print(f"Center of gravity of the fuselage: X = {center_of_gravity_x} m, Y = {center_of_gravity_y} m, Z = {center_of_gravity_z} m") print(f"Total mass of the fuselage: {total_weight} kg") diff --git a/aviary/subsystems/mass/simple_mass/tail.py b/aviary/subsystems/mass/simple_mass/tail.py index 29930dd66..b4910cbcd 100644 --- a/aviary/subsystems/mass/simple_mass/tail.py +++ b/aviary/subsystems/mass/simple_mass/tail.py @@ -114,20 +114,20 @@ def setup(self): # Same as above inputs - self.add_output('cg_x', - val=0.0, - units='m', - desc="X location of the center of gravity") + # self.add_output('cg_x', + # val=0.0, + # units='m', + # desc="X location of the center of gravity") - self.add_output('cg_y', - val=0.0, - units='m', - desc="Y location of the center of gravity") + # self.add_output('cg_y', + # val=0.0, + # units='m', + # desc="Y location of the center of gravity") - self.add_output('cg_z', - val=0.0, - units='m', - desc="Z location of the center of gravity") + # self.add_output('cg_z', + # val=0.0, + # units='m', + # desc="Z location of the center of gravity") def compute_primal(self, aircraft__horizontal_tail__span, @@ -198,23 +198,23 @@ def compute_primal(self, area, _ = quadgk(lambda x: self.airfoil_thickness(x, max_thickness) * (aircraft__horizontal_tail__root_chord- (aircraft__horizontal_tail__root_chord - tip_chord_tail) * (x / aircraft__horizontal_tail__span)), [0, 1], epsabs=1e-9, epsrel=1e-9) - cg_x_num, _ = quadgk(lambda x: (x * self.airfoil_thickness(x, max_thickness) * (aircraft__horizontal_tail__root_chord - (aircraft__horizontal_tail__root_chord - tip_chord_tail) * (x / aircraft__horizontal_tail__span)) * jnp.cos(twist_tail)) - - (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (aircraft__horizontal_tail__root_chord - (aircraft__horizontal_tail__root_chord - tip_chord_tail) * (x / aircraft__horizontal_tail__span))) * jnp.sin(twist_tail), - [0, 1], epsabs=1e-9, epsrel=1e-9) + # cg_x_num, _ = quadgk(lambda x: (x * self.airfoil_thickness(x, max_thickness) * (aircraft__horizontal_tail__root_chord - (aircraft__horizontal_tail__root_chord - tip_chord_tail) * (x / aircraft__horizontal_tail__span)) * jnp.cos(twist_tail)) - + # (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (aircraft__horizontal_tail__root_chord - (aircraft__horizontal_tail__root_chord - tip_chord_tail) * (x / aircraft__horizontal_tail__span))) * jnp.sin(twist_tail), + # [0, 1], epsabs=1e-9, epsrel=1e-9) - cg_x = cg_x_num / area - cg_x = cg_x[0] + # cg_x = cg_x_num / area + # cg_x = cg_x[0] - cgz_function = lambda x: (x * self.airfoil_thickness(x, max_thickness) * (aircraft__horizontal_tail__root_chord - (aircraft__horizontal_tail__root_chord - tip_chord_tail) * (x / aircraft__horizontal_tail__span))) * jnp.sin(twist_tail) + (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (aircraft__horizontal_tail__root_chord - (aircraft__horizontal_tail__root_chord - tip_chord_tail) * (x / aircraft__horizontal_tail__span))) * jnp.cos(twist_tail) - cgy_function = lambda x: x * aircraft__horizontal_tail__span + # cgz_function = lambda x: (x * self.airfoil_thickness(x, max_thickness) * (aircraft__horizontal_tail__root_chord - (aircraft__horizontal_tail__root_chord - tip_chord_tail) * (x / aircraft__horizontal_tail__span))) * jnp.sin(twist_tail) + (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (aircraft__horizontal_tail__root_chord - (aircraft__horizontal_tail__root_chord - tip_chord_tail) * (x / aircraft__horizontal_tail__span))) * jnp.cos(twist_tail) + # cgy_function = lambda x: x * aircraft__horizontal_tail__span - cg_y, _ = quadgk(cgy_function, [0, 1], epsabs=1e-9, epsrel=1e-9) + # cg_y, _ = quadgk(cgy_function, [0, 1], epsabs=1e-9, epsrel=1e-9) - cg_z_num, _ = quadgk(cgz_function, [0, 1], epsabs=1e-9, epsrel=1e-9) + # cg_z_num, _ = quadgk(cgz_function, [0, 1], epsabs=1e-9, epsrel=1e-9) - cg_z = cg_z_num / area - cg_z = cg_z[0] + # cg_z = cg_z_num / area + # cg_z = cg_z[0] aircraft__horizontal_tail__mass = total_mass elif tail_type == 'vertical': @@ -222,27 +222,27 @@ def compute_primal(self, area, _ = quadgk(lambda x: self.airfoil_thickness(x, max_thickness) * (aircraft__vertical_tail__root_chord- (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span)), [0, 1], epsabs=1e-9, epsrel=1e-9) - cg_x_num, _ = quadgk(lambda x: (x * self.airfoil_thickness(x, max_thickness) * (aircraft__vertical_tail__root_chord - (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span)) * jnp.cos(twist_tail)) - - (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (aircraft__vertical_tail__root_chord - (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span))) * jnp.sin(twist_tail), - [0, 1], epsabs=1e-9, epsrel=1e-9) + # cg_x_num, _ = quadgk(lambda x: (x * self.airfoil_thickness(x, max_thickness) * (aircraft__vertical_tail__root_chord - (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span)) * jnp.cos(twist_tail)) - + # (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (aircraft__vertical_tail__root_chord - (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span))) * jnp.sin(twist_tail), + # [0, 1], epsabs=1e-9, epsrel=1e-9) - cg_x = cg_x_num / area - cg_x = cg_x[0] + # cg_x = cg_x_num / area + # cg_x = cg_x[0] - cgy_function = lambda x: (x * self.airfoil_thickness(x, max_thickness) * (aircraft__vertical_tail__root_chord - (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span))) * jnp.sin(twist_tail) + (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (aircraft__vertical_tail__root_chord - (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span))) * jnp.cos(twist_tail) - cgz_function = lambda x: x * aircraft__vertical_tail__span + # cgy_function = lambda x: (x * self.airfoil_thickness(x, max_thickness) * (aircraft__vertical_tail__root_chord - (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span))) * jnp.sin(twist_tail) + (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (aircraft__vertical_tail__root_chord - (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span))) * jnp.cos(twist_tail) + # cgz_function = lambda x: x * aircraft__vertical_tail__span - cg_z, _ = quadgk(cgz_function, [0, 1], epsabs=1e-9, epsrel=1e-9) + # cg_z, _ = quadgk(cgz_function, [0, 1], epsabs=1e-9, epsrel=1e-9) - cg_y_num, _ = quadgk(cgy_function, [0, 1], epsabs=1e-9, epsrel=1e-9) + # cg_y_num, _ = quadgk(cgy_function, [0, 1], epsabs=1e-9, epsrel=1e-9) - cg_y = cg_y_num / area - cg_y = cg_y[0] + # cg_y = cg_y_num / area + # cg_y = cg_y[0] aircraft__vertical_tail__mass = total_mass - return aircraft__horizontal_tail__mass, aircraft__vertical_tail__mass, cg_x, cg_y, cg_z + return aircraft__horizontal_tail__mass, aircraft__vertical_tail__mass def precompute_airfoil_geometry(self): num_sections = self.options['num_sections'] @@ -333,7 +333,7 @@ def extract_airfoil_features(self, x_coords, y_coords): # Print if prob.model.tail.options['tail_type'] == 'horizontal': print(f"Total mass of the horizontal tail: {prob.get_val(Aircraft.HorizontalTail.MASS)} kg") - print(f"Center of gravity of horizontal tail (X: {prob.get_val('cg_x')} m, Y: {prob.get_val('cg_y')} m, Z: {prob.get_val('cg_z')} m)") + #print(f"Center of gravity of horizontal tail (X: {prob.get_val('cg_x')} m, Y: {prob.get_val('cg_y')} m, Z: {prob.get_val('cg_z')} m)") elif prob.model.tail.options['tail_type'] == 'vertical': print(f"Total mass of the vertical tail: {prob.get_val(Aircraft.VerticalTail.MASS)} kg") - print(f"Center of gravity of vertical tail (X: {prob.get_val('cg_x')} m, Y: {prob.get_val('cg_y')} m, Z: {prob.get_val('cg_z')} m)") \ No newline at end of file + #print(f"Center of gravity of vertical tail (X: {prob.get_val('cg_x')} m, Y: {prob.get_val('cg_y')} m, Z: {prob.get_val('cg_z')} m)") \ No newline at end of file diff --git a/aviary/subsystems/mass/simple_mass/wing.py b/aviary/subsystems/mass/simple_mass/wing.py index e6175855b..e6c369323 100644 --- a/aviary/subsystems/mass/simple_mass/wing.py +++ b/aviary/subsystems/mass/simple_mass/wing.py @@ -68,17 +68,17 @@ def setup(self): # Outputs - self.add_output('center_of_gravity_x_wing', - val=0.0, - units='m') + # self.add_output('center_of_gravity_x_wing', + # val=0.0, + # units='m') - self.add_output('center_of_gravity_y_wing', - val=0.0, - units='m') + # self.add_output('center_of_gravity_y_wing', + # val=0.0, + # units='m') - self.add_output('center_of_gravity_z_wing', - val=0.0, - units='m') + # self.add_output('center_of_gravity_z_wing', + # val=0.0, + # units='m') add_aviary_output(self, Aircraft.Wing.MASS, @@ -118,25 +118,26 @@ def compute_primal(self, aircraft__wing__span, aircraft__wing__root_chord, tip_c aircraft__wing__mass, _ = quadgk(weight_function, [0, 1], epsabs=1e-9, epsrel=1e-9) - center_of_gravity_x_num, _ = quadgk(lambda x: x * self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span) * jnp.cos(twist)) - - self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span)) * jnp.sin(twist), - [0, 1], epsabs=1e-9, epsrel=1e-9) - center_of_gravity_x_denom, _ = quadgk(lambda x: self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span)), [0, 1], epsabs=1e-9, epsrel=1e-9) + # center_of_gravity_x_num, _ = quadgk(lambda x: x * self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span) * jnp.cos(twist)) - + # self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span)) * jnp.sin(twist), + # [0, 1], epsabs=1e-9, epsrel=1e-9) + # center_of_gravity_x_denom, _ = quadgk(lambda x: self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span)), [0, 1], epsabs=1e-9, epsrel=1e-9) - center_of_gravity_x = center_of_gravity_x_num / center_of_gravity_x_denom - center_of_gravity_x_wing = center_of_gravity_x[0] + # center_of_gravity_x = center_of_gravity_x_num / center_of_gravity_x_denom + # center_of_gravity_x_wing = center_of_gravity_x[0] - center_of_gravity_z_num, _ = quadgk(lambda x: x * self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span) * jnp.sin(twist)) + - self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span)) * jnp.cos(twist), - [0, 1], epsabs=1e-9, epsrel=1e-9) + # center_of_gravity_z_num, _ = quadgk(lambda x: x * self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span) * jnp.sin(twist)) + + # self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span)) * jnp.cos(twist), + # [0, 1], epsabs=1e-9, epsrel=1e-9) - center_of_gravity_z_denom, _ = quadgk(lambda x: self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span)), [0, 1], epsabs=1e-9, epsrel=1e-9) + # center_of_gravity_z_denom, _ = quadgk(lambda x: self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span)), [0, 1], epsabs=1e-9, epsrel=1e-9) - center_of_gravity_z = center_of_gravity_z_num / center_of_gravity_z_denom - center_of_gravity_z_wing = center_of_gravity_z[0] - center_of_gravity_y_wing, _ = quadgk(lambda x: x * aircraft__wing__span, [0, 1], epsabs=1e-9, epsrel=1e-9) + # center_of_gravity_z = center_of_gravity_z_num / center_of_gravity_z_denom + # center_of_gravity_z_wing = center_of_gravity_z[0] + # center_of_gravity_y_wing, _ = quadgk(lambda x: x * aircraft__wing__span, [0, 1], epsabs=1e-9, epsrel=1e-9) - return center_of_gravity_x_wing, center_of_gravity_y_wing, center_of_gravity_z_wing, aircraft__wing__mass + # return center_of_gravity_x_wing, center_of_gravity_y_wing, center_of_gravity_z_wing, aircraft__wing__mass + return aircraft__wing__mass def precompute_airfoil_geometry(self): num_sections = self.options['num_sections'] @@ -218,12 +219,12 @@ def extract_airfoil_features(self, x_coords, y_coords): prob.run_model() # Get the results - center_of_gravity_x = prob.get_val('cog.center_of_gravity_x_wing') - center_of_gravity_y = prob.get_val('cog.center_of_gravity_y_wing') - center_of_gravity_z = prob.get_val('cog.center_of_gravity_z_wing') + #center_of_gravity_x = prob.get_val('cog.center_of_gravity_x_wing') + #center_of_gravity_y = prob.get_val('cog.center_of_gravity_y_wing') + #center_of_gravity_z = prob.get_val('cog.center_of_gravity_z_wing') total_weight = prob.get_val(Aircraft.Wing.MASS) - print(f"Center of gravity: X = {center_of_gravity_x} m, Y = {center_of_gravity_y} m, Z = {center_of_gravity_z} m") + #print(f"Center of gravity: X = {center_of_gravity_x} m, Y = {center_of_gravity_y} m, Z = {center_of_gravity_z} m") print(f"Total mass of the wing: {total_weight} kg") From 86a07c46a7bd0052972fbc28d5b35c11fb9abea3 Mon Sep 17 00:00:00 2001 From: szoppelt Date: Wed, 18 Jun 2025 18:02:13 +0000 Subject: [PATCH 074/147] updates. --- .../mass/simple_mass/mass_builder.py | 50 ++++++++++--------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/mass_builder.py b/aviary/subsystems/mass/simple_mass/mass_builder.py index 050daf052..3dc782b4f 100644 --- a/aviary/subsystems/mass/simple_mass/mass_builder.py +++ b/aviary/subsystems/mass/simple_mass/mass_builder.py @@ -1,8 +1,8 @@ from aviary.interface.utils.markdown_utils import write_markdown_variable_table from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase from aviary.subsystems.mass.mass_builder import MassBuilderBase -from aviary.subsystems.mass.simple_mass.mass_premission import MassPremission # This will be the new folder in there \ -# along with flops_based and gasp_based folders. I just called it simple_mass for now. +from aviary.subsystems.mass.simple_mass.mass_premission import MassPremission +from aviary.variable_info.variables import Aircraft """ @@ -23,26 +23,26 @@ _default_name = 'mass' -#class MassBuilderBase(SubsystemBuilderBase): - #""" - #Base mass builder - # - #This class is basically copied line by line from the mass subsystems folder - #** Ask Jason if this is even necessary. - # - #""" - - #def __init__(self, name=None, meta_data=None): - # if name is None: - # name = _default_name - # - # super().__init__(name=name, meta_data=meta_data) - # - #def mission_inputs(self, **kwargs): - # return ['*'] - # - #def mission_outputs(self, **kwargs): - # return ['*'] +class MassBuilderBase(SubsystemBuilderBase): + """ + Base mass builder + + This class is basically copied line by line from the mass subsystems folder + ** Ask Jason if this is even necessary. + + """ + + def __init__(self, name=None, meta_data=None): + if name is None: + name = _default_name + + super().__init__(name=name, meta_data=meta_data) + + def mission_inputs(self, **kwargs): + return ['*'] + + def mission_outputs(self, **kwargs): + return ['*'] class StructureMassBuilder(MassBuilderBase): """ @@ -81,7 +81,11 @@ def report(self, prob, reports_folder, **kwargs): # Ask Jason about how I should format this outputs = [ - + Aircraft.Wing.MASS, + Aircraft.HorizontalTail.MASS, + Aircraft.VerticalTail.MASS, + Aircraft.Fuselage.MASS, + 'structure_mass' ] with open(filepath, mode='w') as f: From 6acdcde940d07cc76c884fc4d22656dcb07a3d5b Mon Sep 17 00:00:00 2001 From: szoppelt Date: Wed, 18 Jun 2025 18:03:36 +0000 Subject: [PATCH 075/147] updates. --- aviary/subsystems/mass/simple_mass/mass_builder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aviary/subsystems/mass/simple_mass/mass_builder.py b/aviary/subsystems/mass/simple_mass/mass_builder.py index 3dc782b4f..4cfdeb5ed 100644 --- a/aviary/subsystems/mass/simple_mass/mass_builder.py +++ b/aviary/subsystems/mass/simple_mass/mass_builder.py @@ -27,7 +27,7 @@ class MassBuilderBase(SubsystemBuilderBase): """ Base mass builder - This class is basically copied line by line from the mass subsystems folder + This class is basically copied line by line from the mass subsystems folder. ** Ask Jason if this is even necessary. """ From 63097e456012cc0fb0272eddd5e16478c647e030 Mon Sep 17 00:00:00 2001 From: Seth Zoppelt Date: Mon, 23 Jun 2025 18:31:24 +0000 Subject: [PATCH 076/147] updates. test --- aviary/subsystems/mass/simple_mass/wing.py | 1 - 1 file changed, 1 deletion(-) diff --git a/aviary/subsystems/mass/simple_mass/wing.py b/aviary/subsystems/mass/simple_mass/wing.py index e6c369323..6de4c9abd 100644 --- a/aviary/subsystems/mass/simple_mass/wing.py +++ b/aviary/subsystems/mass/simple_mass/wing.py @@ -2,7 +2,6 @@ import openmdao.jax as omj import numpy as np import jax.numpy as jnp -import jax import os from scipy.interpolate import CubicSpline import jax.scipy.integrate as jint From bd62739ec83cb6493fceb077b4ee39afa8c96536 Mon Sep 17 00:00:00 2001 From: Seth Zoppelt Date: Mon, 23 Jun 2025 19:21:07 +0000 Subject: [PATCH 077/147] test --- aviary/subsystems/mass/simple_mass/tail.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aviary/subsystems/mass/simple_mass/tail.py b/aviary/subsystems/mass/simple_mass/tail.py index b4910cbcd..81d1a9d90 100644 --- a/aviary/subsystems/mass/simple_mass/tail.py +++ b/aviary/subsystems/mass/simple_mass/tail.py @@ -220,7 +220,7 @@ def compute_primal(self, elif tail_type == 'vertical': total_mass, _ = quadgk(lambda x: density * self.airfoil_thickness(x, max_thickness) * (aircraft__vertical_tail__root_chord - (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span)) * aircraft__vertical_tail__span, [0, 1], epsabs=1e-9, epsrel=1e-9) - area, _ = quadgk(lambda x: self.airfoil_thickness(x, max_thickness) * (aircraft__vertical_tail__root_chord- (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span)), [0, 1], epsabs=1e-9, epsrel=1e-9) + #area, _ = quadgk(lambda x: self.airfoil_thickness(x, max_thickness) * (aircraft__vertical_tail__root_chord- (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span)), [0, 1], epsabs=1e-9, epsrel=1e-9) # cg_x_num, _ = quadgk(lambda x: (x * self.airfoil_thickness(x, max_thickness) * (aircraft__vertical_tail__root_chord - (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span)) * jnp.cos(twist_tail)) - # (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (aircraft__vertical_tail__root_chord - (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span))) * jnp.sin(twist_tail), From ff491ad3ca21795b398e46215c5411c0965c4760 Mon Sep 17 00:00:00 2001 From: Seth Zoppelt Date: Wed, 2 Jul 2025 14:43:25 +0000 Subject: [PATCH 078/147] Final updates. --- aviary/mission/sixdof/six_dof_ODE.py | 24 +- .../subsystems/mass/simple_mass/fuselage.py | 23 - .../mass/simple_mass/mass_builder.py | 74 +- .../mass/simple_mass/mass_premission.py | 10 +- .../mass/simple_mass/mass_summation.py | 3 +- aviary/subsystems/mass/simple_mass/tail.py | 76 +- .../simple_mass/test/test_mass_subsystem.py | 77 + aviary/subsystems/mass/simple_mass/wing.py | 38 +- out.txt | 10142 ++++++++++++++++ pyproject.toml | 94 + 10 files changed, 10351 insertions(+), 210 deletions(-) create mode 100644 aviary/subsystems/mass/simple_mass/test/test_mass_subsystem.py create mode 100644 out.txt create mode 100644 pyproject.toml diff --git a/aviary/mission/sixdof/six_dof_ODE.py b/aviary/mission/sixdof/six_dof_ODE.py index 09b8eb2cd..75e59e6ab 100644 --- a/aviary/mission/sixdof/six_dof_ODE.py +++ b/aviary/mission/sixdof/six_dof_ODE.py @@ -47,7 +47,29 @@ def setup(self): promotes=['*'] ) - # Need something here to figure out how to actually fly aircraft + T_vert_comp = om.ExecComp( + 'T_z = ...', + # variables + units etc. -- see energy_ODE.py line 60, + promotes_inputs=[...], + promotes_outputs=[...] + ) + + comp = om.BalanceComp( + name=Dynamic.Vehicle.Propulsion.THROTTLE, + units='unitless', + val=np.ones((nn,)), + lhs_name='thrust_required', + rhs_name= 'T_z', + eq_units='N', + normalize=False, + ) + + sub1.add_subsystem( + 'throttle_balance', + subsys=comp, + promotes_inputs=['*'], + promotes_outputs=['*'], + ) self.add_core_subsystems(solver_group=sub1) diff --git a/aviary/subsystems/mass/simple_mass/fuselage.py b/aviary/subsystems/mass/simple_mass/fuselage.py index c263737dc..94fad1c5f 100644 --- a/aviary/subsystems/mass/simple_mass/fuselage.py +++ b/aviary/subsystems/mass/simple_mass/fuselage.py @@ -78,18 +78,6 @@ def setup(self): # Outputs - # self.add_output('center_of_gravity_x_fuse', - # val=0.0, - # units='m') - - # self.add_output('center_of_gravity_y_fuse', - # val=0.0, - # units='m') - - # self.add_output('center_of_gravity_z_fuse', - # val=0.0, - # units='m') - add_aviary_output(self, Aircraft.Fuselage.MASS, units='kg') @@ -138,11 +126,6 @@ def compute_primal(self, aircraft__fuselage__length, base_diameter, tip_diameter total_moment_y += centroid_y * section_weight total_moment_z += centroid_z * section_weight - # center_of_gravity_x_fuse = total_moment_x / aircraft__fuselage__mass - # center_of_gravity_y_fuse = total_moment_y / aircraft__fuselage__mass - # center_of_gravity_z_fuse = total_moment_z / aircraft__fuselage__mass - - # return center_of_gravity_x_fuse, center_of_gravity_y_fuse, center_of_gravity_z_fuse, aircraft__fuselage__mass return aircraft__fuselage__mass def validate_inputs(self, length, base_diameter, thickness, tip_diameter, is_hollow): @@ -204,13 +187,7 @@ def compute_centroid(self, location, length, y_offset, z_offset, curvature, base prob.run_model() - # center_of_gravity_x = prob.get_val('fuselage_cg.center_of_gravity_x_fuse') - # center_of_gravity_y = prob.get_val('fuselage_cg.center_of_gravity_y_fuse') - # center_of_gravity_z = prob.get_val('fuselage_cg.center_of_gravity_z_fuse') total_weight = prob.get_val(Aircraft.Fuselage.MASS) - #data = prob.check_partials(compact_print=True, abs_err_tol=1e-04, rel_err_tol=1e-04, step=1e-8, step_calc='rel') - - # print(f"Center of gravity of the fuselage: X = {center_of_gravity_x} m, Y = {center_of_gravity_y} m, Z = {center_of_gravity_z} m") print(f"Total mass of the fuselage: {total_weight} kg") diff --git a/aviary/subsystems/mass/simple_mass/mass_builder.py b/aviary/subsystems/mass/simple_mass/mass_builder.py index 4cfdeb5ed..9231bada3 100644 --- a/aviary/subsystems/mass/simple_mass/mass_builder.py +++ b/aviary/subsystems/mass/simple_mass/mass_builder.py @@ -1,8 +1,6 @@ -from aviary.interface.utils.markdown_utils import write_markdown_variable_table from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase -from aviary.subsystems.mass.mass_builder import MassBuilderBase from aviary.subsystems.mass.simple_mass.mass_premission import MassPremission -from aviary.variable_info.variables import Aircraft + """ @@ -15,82 +13,22 @@ my work right now, but wanted to include it as a just in case. I basically copied it over from the mass_builder.py under the mass subsystems folder in Aviary github. -StructureMassBuilder: the interface for Aviary's core mass builder -- in this case, - the core mass builder will work for wing and fuselage mass calculations - will be updated as more mass calculations are added - """ -_default_name = 'mass' +_default_name = 'simple_mass' class MassBuilderBase(SubsystemBuilderBase): """ Base mass builder - This class is basically copied line by line from the mass subsystems folder. - ** Ask Jason if this is even necessary. - """ - def __init__(self, name=None, meta_data=None): + def __init__(self, name=None): if name is None: name = _default_name - super().__init__(name=name, meta_data=meta_data) + super().__init__(name=name) - def mission_inputs(self, **kwargs): - return ['*'] - - def mission_outputs(self, **kwargs): - return ['*'] - -class StructureMassBuilder(MassBuilderBase): - """ - Core mass subsystem builder - - Unlike the CoreMassBuilder on the github under the mass subsystems folder, - I am not including the __init__'s, since I don't have any FLOPS or GASP - dependence in my mass calculations at the moment; the math is essentially - hard coded from my calculations right now. - - """ - def build_pre_mission(self, aviary_inputs): - return MassPremission # See the commented line above in the imports - - def build_mission(self, num_nodes, aviary_inputs, **kwargs): - super().build_mission(num_nodes, aviary_inputs) - - def report(self, prob, reports_folder, **kwargs): - """ - Generate the report for Aviary core mass - - Parameters - ---------- - prob : AviaryProblem - The AviaryProblem that will be used to generate the report - reports_folder : Path - Location of the subsystems_report folder this report will be placed in - - * This comment is copied from the mass subsystems folder * - - """ - - filename = self.name + '.md' - filepath = reports_folder / filename - - # Ask Jason about how I should format this - outputs = [ - Aircraft.Wing.MASS, - Aircraft.HorizontalTail.MASS, - Aircraft.VerticalTail.MASS, - Aircraft.Fuselage.MASS, - 'structure_mass' - ] - - with open(filepath, mode='w') as f: - method = self.code_origin.value + '-derived relations' # Ask Jason about this too since I don't have FLOPS or GASP for code_origin_value - f.write(f'# Mass estimation: {method}') - write_markdown_variable_table(f, prob, outputs, self.meta_data) - - \ No newline at end of file + return MassPremission() + diff --git a/aviary/subsystems/mass/simple_mass/mass_premission.py b/aviary/subsystems/mass/simple_mass/mass_premission.py index cc2467139..fa29c81a4 100644 --- a/aviary/subsystems/mass/simple_mass/mass_premission.py +++ b/aviary/subsystems/mass/simple_mass/mass_premission.py @@ -1,10 +1,8 @@ import openmdao.api as om -# Maybe some Aviary inputs as well? from aviary.subsystems.mass.simple_mass.wing import WingMassAndCOG from aviary.subsystems.mass.simple_mass.fuselage import FuselageMassAndCOG from aviary.subsystems.mass.simple_mass.tail import TailMassAndCOG -from aviary.subsystems.mass.simple_mass.mass_summation import MassSummation class MassPremission(om.Group): """ @@ -28,12 +26,6 @@ def setup(self): self.add_subsystem( 'Tail', - TailMassAndCOG(), - promotes_inputs=['*'], promotes_outputs=['*'] - ) - - self.add_subsystem( - 'total_mass', - MassSummation(), + TailMassAndCOG(tail_type='horizontal'), promotes_inputs=['*'], promotes_outputs=['*'] ) \ No newline at end of file diff --git a/aviary/subsystems/mass/simple_mass/mass_summation.py b/aviary/subsystems/mass/simple_mass/mass_summation.py index 00b1fd4c3..67a499ec5 100644 --- a/aviary/subsystems/mass/simple_mass/mass_summation.py +++ b/aviary/subsystems/mass/simple_mass/mass_summation.py @@ -1,7 +1,7 @@ import numpy as np import openmdao.api as om -import openmdao.jax as omj + from aviary.subsystems.mass.simple_mass.fuselage import FuselageMassAndCOG from aviary.subsystems.mass.simple_mass.wing import WingMassAndCOG @@ -49,7 +49,6 @@ def setup(self): promotes_outputs=['*'] ) -# Horizontal tail only class StructureMass(om.JaxExplicitComponent): def initialize(self): self.options.declare('tail_type', diff --git a/aviary/subsystems/mass/simple_mass/tail.py b/aviary/subsystems/mass/simple_mass/tail.py index 81d1a9d90..788408585 100644 --- a/aviary/subsystems/mass/simple_mass/tail.py +++ b/aviary/subsystems/mass/simple_mass/tail.py @@ -2,7 +2,6 @@ import openmdao.jax as omj import jax.numpy as jnp import numpy as np -from scipy.interpolate import interp1d from scipy.interpolate import CubicSpline import os @@ -55,10 +54,8 @@ def initialize(self): def setup(self): self.options['use_jit'] = not(Debug) - #tail_type = self.options['tail_type'] # Inputs - #if tail_type == 'horizontal': add_aviary_input(self, Aircraft.HorizontalTail.SPAN, units='m', @@ -101,7 +98,6 @@ def setup(self): desc="Twist distribution") # Outputs - #if tail_type == 'horizontal': add_aviary_output(self, Aircraft.HorizontalTail.MASS, units='kg', @@ -111,23 +107,6 @@ def setup(self): Aircraft.VerticalTail.MASS, units='kg', desc="Total mass of the tail") - - # Same as above inputs - - # self.add_output('cg_x', - # val=0.0, - # units='m', - # desc="X location of the center of gravity") - - # self.add_output('cg_y', - # val=0.0, - # units='m', - # desc="Y location of the center of gravity") - - # self.add_output('cg_z', - # val=0.0, - # units='m', - # desc="Z location of the center of gravity") def compute_primal(self, aircraft__horizontal_tail__span, @@ -147,8 +126,9 @@ def compute_primal(self, NACA_digits = self.options['NACA_digits'] # This is just so that the differentiation and unittest do not break. If tail_type = horizontal, ignore the vertical tail mass and vice versa. - aircraft__horizontal_tail__mass = 0.0 - aircraft__vertical_tail__mass = 0.0 + # TODO: Potentially write these tails as separate files. + aircraft__horizontal_tail__mass = 0.0 * thickness_ratio + aircraft__vertical_tail__mass = 0.0 * thickness_ratio # File check if airfoil_type == 'file': @@ -188,58 +168,14 @@ def compute_primal(self, # Thickness distribution thickness_dist = self.airfoil_thickness(x_points, max_thickness) - # if tail_type == 'horizontal': - # aircraft__vertical_tail__mass = None - # elif tail_type == 'vertical': - # aircraft__horizontal_tail__mass = None - if tail_type == 'horizontal': total_mass, _ = quadgk(lambda x: density * self.airfoil_thickness(x, max_thickness) * (aircraft__horizontal_tail__root_chord - (aircraft__horizontal_tail__root_chord - tip_chord_tail) * (x / aircraft__horizontal_tail__span)) * aircraft__horizontal_tail__span, [0, 1], epsabs=1e-9, epsrel=1e-9) - - area, _ = quadgk(lambda x: self.airfoil_thickness(x, max_thickness) * (aircraft__horizontal_tail__root_chord- (aircraft__horizontal_tail__root_chord - tip_chord_tail) * (x / aircraft__horizontal_tail__span)), [0, 1], epsabs=1e-9, epsrel=1e-9) - - # cg_x_num, _ = quadgk(lambda x: (x * self.airfoil_thickness(x, max_thickness) * (aircraft__horizontal_tail__root_chord - (aircraft__horizontal_tail__root_chord - tip_chord_tail) * (x / aircraft__horizontal_tail__span)) * jnp.cos(twist_tail)) - - # (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (aircraft__horizontal_tail__root_chord - (aircraft__horizontal_tail__root_chord - tip_chord_tail) * (x / aircraft__horizontal_tail__span))) * jnp.sin(twist_tail), - # [0, 1], epsabs=1e-9, epsrel=1e-9) - - # cg_x = cg_x_num / area - # cg_x = cg_x[0] - - # cgz_function = lambda x: (x * self.airfoil_thickness(x, max_thickness) * (aircraft__horizontal_tail__root_chord - (aircraft__horizontal_tail__root_chord - tip_chord_tail) * (x / aircraft__horizontal_tail__span))) * jnp.sin(twist_tail) + (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (aircraft__horizontal_tail__root_chord - (aircraft__horizontal_tail__root_chord - tip_chord_tail) * (x / aircraft__horizontal_tail__span))) * jnp.cos(twist_tail) - # cgy_function = lambda x: x * aircraft__horizontal_tail__span - - # cg_y, _ = quadgk(cgy_function, [0, 1], epsabs=1e-9, epsrel=1e-9) - - # cg_z_num, _ = quadgk(cgz_function, [0, 1], epsabs=1e-9, epsrel=1e-9) - - # cg_z = cg_z_num / area - # cg_z = cg_z[0] - aircraft__horizontal_tail__mass = total_mass + elif tail_type == 'vertical': total_mass, _ = quadgk(lambda x: density * self.airfoil_thickness(x, max_thickness) * (aircraft__vertical_tail__root_chord - (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span)) * aircraft__vertical_tail__span, [0, 1], epsabs=1e-9, epsrel=1e-9) - #area, _ = quadgk(lambda x: self.airfoil_thickness(x, max_thickness) * (aircraft__vertical_tail__root_chord- (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span)), [0, 1], epsabs=1e-9, epsrel=1e-9) - - # cg_x_num, _ = quadgk(lambda x: (x * self.airfoil_thickness(x, max_thickness) * (aircraft__vertical_tail__root_chord - (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span)) * jnp.cos(twist_tail)) - - # (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (aircraft__vertical_tail__root_chord - (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span))) * jnp.sin(twist_tail), - # [0, 1], epsabs=1e-9, epsrel=1e-9) - - # cg_x = cg_x_num / area - # cg_x = cg_x[0] - - # cgy_function = lambda x: (x * self.airfoil_thickness(x, max_thickness) * (aircraft__vertical_tail__root_chord - (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span))) * jnp.sin(twist_tail) + (self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (aircraft__vertical_tail__root_chord - (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span))) * jnp.cos(twist_tail) - # cgz_function = lambda x: x * aircraft__vertical_tail__span - - - # cg_z, _ = quadgk(cgz_function, [0, 1], epsabs=1e-9, epsrel=1e-9) - - # cg_y_num, _ = quadgk(cgy_function, [0, 1], epsabs=1e-9, epsrel=1e-9) - - # cg_y = cg_y_num / area - # cg_y = cg_y[0] - aircraft__vertical_tail__mass = total_mass return aircraft__horizontal_tail__mass, aircraft__vertical_tail__mass @@ -333,7 +269,5 @@ def extract_airfoil_features(self, x_coords, y_coords): # Print if prob.model.tail.options['tail_type'] == 'horizontal': print(f"Total mass of the horizontal tail: {prob.get_val(Aircraft.HorizontalTail.MASS)} kg") - #print(f"Center of gravity of horizontal tail (X: {prob.get_val('cg_x')} m, Y: {prob.get_val('cg_y')} m, Z: {prob.get_val('cg_z')} m)") elif prob.model.tail.options['tail_type'] == 'vertical': - print(f"Total mass of the vertical tail: {prob.get_val(Aircraft.VerticalTail.MASS)} kg") - #print(f"Center of gravity of vertical tail (X: {prob.get_val('cg_x')} m, Y: {prob.get_val('cg_y')} m, Z: {prob.get_val('cg_z')} m)") \ No newline at end of file + print(f"Total mass of the vertical tail: {prob.get_val(Aircraft.VerticalTail.MASS)} kg") \ No newline at end of file diff --git a/aviary/subsystems/mass/simple_mass/test/test_mass_subsystem.py b/aviary/subsystems/mass/simple_mass/test/test_mass_subsystem.py new file mode 100644 index 000000000..728fcb384 --- /dev/null +++ b/aviary/subsystems/mass/simple_mass/test/test_mass_subsystem.py @@ -0,0 +1,77 @@ +""" +Run the a mission with a simple external component that computes the wing +and horizontal tail mass. +""" + +from copy import deepcopy + +import aviary.api as av +from aviary.subsystems.mass.simple_mass.mass_builder import MassBuilderBase +from aviary.variable_info.variables import Aircraft + +import jax.numpy as jnp + +phase_info = deepcopy(av.default_height_energy_phase_info) +# Here we just add the simple weight system to only the pre-mission +phase_info['pre_mission']['external_subsystems'] = [MassBuilderBase()] + +if __name__ == '__main__': + prob = av.AviaryProblem() + + n_points = 10 # = num_sections + x = jnp.linspace(0, 1, n_points) + max_thickness_chord_ratio = 0.12 + thickness_dist = 5 * max_thickness_chord_ratio * (0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) + + # Load aircraft and options data from user + # Allow for user overrides here + prob.load_inputs('models/test_aircraft/aircraft_for_bench_FwFm.csv', phase_info) + prob.aviary_inputs.set_val(Aircraft.HorizontalTail.SPAN, val=1.0, units='m') + prob.aviary_inputs.set_val(Aircraft.HorizontalTail.ROOT_CHORD, val=1.0, units='m') + prob.aviary_inputs.set_val(Aircraft.Wing.SPAN, 3.74904, units='m') + prob.aviary_inputs.set_val(Aircraft.Wing.ROOT_CHORD, 0.40005, units='m') + prob.aviary_inputs.set_val(Aircraft.Fuselage.LENGTH, 2.5, units='m') + + + # Preprocess inputs + prob.check_and_preprocess_inputs() + + prob.add_pre_mission_systems() + + prob.add_phases() + + prob.add_post_mission_systems() + + # Link phases and variables + prob.link_phases() + + prob.add_driver('IPOPT') + + prob.add_design_variables() + + prob.add_objective() + + prob.setup() + + prob.set_val('pre_mission.simple_mass.tip_chord_tail', 0.5) + prob.set_val('pre_mission.simple_mass.thickness_ratio', 0.12) + prob.set_val('pre_mission.simple_mass.skin_thickness', 0.002) + prob.set_val('pre_mission.simple_mass.tip_chord', 0.100076) + prob.set_val('pre_mission.simple_mass.thickness_dist', thickness_dist) + prob.set_val('pre_mission.simple_mass.base_diameter', 0.5) + prob.set_val('pre_mission.simple_mass.tip_diameter', 0.3) + prob.set_val('pre_mission.simple_mass.curvature', 0.0) + prob.set_val('pre_mission.simple_mass.thickness', 0.05) + + prob.set_initial_guesses() + + prob.run_aviary_problem(suppress_solver_print=True) + + #prob.model.list_vars(units=True, print_arrays=True) + + #print('Engine Mass', prob.get_val(av.Aircraft.Engine.MASS)) + print('Wing Mass', prob.get_val(av.Aircraft.Wing.MASS)) + print('Horizontal Tail Mass', prob.get_val(av.Aircraft.HorizontalTail.MASS)) + print('Fuselage Mass', prob.get_val(av.Aircraft.Fuselage.MASS)) + + print('done') diff --git a/aviary/subsystems/mass/simple_mass/wing.py b/aviary/subsystems/mass/simple_mass/wing.py index 6de4c9abd..5052eb981 100644 --- a/aviary/subsystems/mass/simple_mass/wing.py +++ b/aviary/subsystems/mass/simple_mass/wing.py @@ -4,7 +4,7 @@ import jax.numpy as jnp import os from scipy.interpolate import CubicSpline -import jax.scipy.integrate as jint + from aviary.variable_info.variables import Aircraft from aviary.utils.functions import add_aviary_input, add_aviary_output @@ -67,18 +67,6 @@ def setup(self): # Outputs - # self.add_output('center_of_gravity_x_wing', - # val=0.0, - # units='m') - - # self.add_output('center_of_gravity_y_wing', - # val=0.0, - # units='m') - - # self.add_output('center_of_gravity_z_wing', - # val=0.0, - # units='m') - add_aviary_output(self, Aircraft.Wing.MASS, units='kg') @@ -117,25 +105,7 @@ def compute_primal(self, aircraft__wing__span, aircraft__wing__root_chord, tip_c aircraft__wing__mass, _ = quadgk(weight_function, [0, 1], epsabs=1e-9, epsrel=1e-9) - # center_of_gravity_x_num, _ = quadgk(lambda x: x * self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span) * jnp.cos(twist)) - - # self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span)) * jnp.sin(twist), - # [0, 1], epsabs=1e-9, epsrel=1e-9) - # center_of_gravity_x_denom, _ = quadgk(lambda x: self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span)), [0, 1], epsabs=1e-9, epsrel=1e-9) - - # center_of_gravity_x = center_of_gravity_x_num / center_of_gravity_x_denom - # center_of_gravity_x_wing = center_of_gravity_x[0] - - # center_of_gravity_z_num, _ = quadgk(lambda x: x * self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span) * jnp.sin(twist)) + - # self.airfoil_camber_line(x, camber, camber_location) * self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span)) * jnp.cos(twist), - # [0, 1], epsabs=1e-9, epsrel=1e-9) - # center_of_gravity_z_denom, _ = quadgk(lambda x: self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span)), [0, 1], epsabs=1e-9, epsrel=1e-9) - - # center_of_gravity_z = center_of_gravity_z_num / center_of_gravity_z_denom - # center_of_gravity_z_wing = center_of_gravity_z[0] - # center_of_gravity_y_wing, _ = quadgk(lambda x: x * aircraft__wing__span, [0, 1], epsabs=1e-9, epsrel=1e-9) - - # return center_of_gravity_x_wing, center_of_gravity_y_wing, center_of_gravity_z_wing, aircraft__wing__mass return aircraft__wing__mass def precompute_airfoil_geometry(self): @@ -211,19 +181,15 @@ def extract_airfoil_features(self, x_coords, y_coords): #prob.model.cog.options['airfoil_data_file'] = 'Clark_Y.dat' - prob.model.cog.options['material'] = 'Reinforced Carbon-Carbon' + prob.model.cog.options['material'] = 'Balsa' prob.model.cog.options['airfoil_type'] = '2412' # Run the model prob.run_model() # Get the results - #center_of_gravity_x = prob.get_val('cog.center_of_gravity_x_wing') - #center_of_gravity_y = prob.get_val('cog.center_of_gravity_y_wing') - #center_of_gravity_z = prob.get_val('cog.center_of_gravity_z_wing') total_weight = prob.get_val(Aircraft.Wing.MASS) - #print(f"Center of gravity: X = {center_of_gravity_x} m, Y = {center_of_gravity_y} m, Z = {center_of_gravity_z} m") print(f"Total mass of the wing: {total_weight} kg") diff --git a/out.txt b/out.txt new file mode 100644 index 000000000..2081ffa93 --- /dev/null +++ b/out.txt @@ -0,0 +1,10142 @@ +Optimization terminated successfully (Exit mode 0) + Current function value: 2.308936834711119 + Iterations: 7 + Function evaluations: 7 + Gradient evaluations: 7 +Optimization Complete +----------------------------------- +1718 Variables(s) in 'model' + +varname val io units prom_name +----------------------------------------------------------------------- ------------------------ ------ ------------- -------------------------------------------------------------------------------- +pre_mission + simple_mass + Wing + aircraft:wing:span [35.914584] input m aircraft:wing:span + aircraft:wing:root_chord [0.] input m aircraft:wing:root_chord + tip_chord [1.] input m pre_mission.simple_mass.tip_chord + twist |0.0| input deg pre_mission.simple_mass.twist + val: + array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]) + thickness_dist |0.31622777| input m pre_mission.simple_mass.thickness_dist + val: + array([0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]) + aircraft:wing:mass [2.24666] output kg aircraft:wing:mass + Fuselage + aircraft:fuselage:length [39.0144] input m aircraft:fuselage:length + base_diameter [0.4] input m pre_mission.simple_mass.base_diameter + tip_diameter [0.2] input m pre_mission.simple_mass.tip_diameter + curvature [0.] input m pre_mission.simple_mass.curvature + thickness [0.05] input m pre_mission.simple_mass.thickness + y_offset [0.] input m pre_mission.simple_mass.y_offset + z_offset [0.] input m pre_mission.simple_mass.z_offset + is_hollow [1.] input None pre_mission.simple_mass.is_hollow + aircraft:fuselage:mass [5209.12373908] output kg aircraft:fuselage:mass + Tail + aircraft:horizontal_tail:span [0.] input m aircraft:horizontal_tail:span + aircraft:horizontal_tail:root_chord [0.] input m aircraft:horizontal_tail:root_chord + aircraft:vertical_tail:span [0.] input m aircraft:vertical_tail:span + aircraft:vertical_tail:root_chord [0.] input m aircraft:vertical_tail:root_chord + tip_chord_tail [0.8] input m pre_mission.simple_mass.tip_chord_tail + thickness_ratio [0.12] input None pre_mission.simple_mass.thickness_ratio + skin_thickness [0.002] input m pre_mission.simple_mass.skin_thickness + twist_tail |0.0| input deg pre_mission.simple_mass.twist_tail + val: + array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]) + aircraft:horizontal_tail:mass [0.] output kg aircraft:horizontal_tail:mass + aircraft:vertical_tail:mass [0.] output kg aircraft:vertical_tail:mass + core_propulsion + turbofan_28k + aircraft:engine:scale_factor [1.] input unitless aircraft:engine:scale_factor + aircraft:engine:scaled_sls_thrust [28928.1] output lbf aircraft:engine:scaled_sls_thrust + propulsion_sum + aircraft:engine:scaled_sls_thrust [28928.1] input lbf aircraft:engine:scaled_sls_thrust + aircraft:propulsion:total_scaled_sls_thrust [57856.2] output lbf aircraft:propulsion:total_scaled_sls_thrust + core_subsystems + core_geometry + fuselage_prelim + aircraft:fuselage:length [128.] input ft aircraft:fuselage:length + aircraft:fuselage:max_height [13.17] input ft aircraft:fuselage:max_height + aircraft:fuselage:max_width [12.33] input ft aircraft:fuselage:max_width + aircraft:fuselage:avg_diameter [12.75] output ft aircraft:fuselage:avg_diameter + aircraft:fuselage:planform_area [1578.24] output ft**2 pre_mission.AUTO_OVERRIDE:aircraft:fuselage:planform_area + wing_prelim + aircraft:wing:area [1370.] input ft**2 aircraft:wing:area + aircraft:wing:glove_and_bat [134.] input ft**2 aircraft:wing:glove_and_bat + aircraft:wing:span [117.83] input ft aircraft:wing:span + aircraft:wing:aspect_ratio [11.232936] output unitless pre_mission.AUTO_OVERRIDE:aircraft:wing:aspect_ratio + prelim + aircraft:fuselage:avg_diameter [12.75] input ft aircraft:fuselage:avg_diameter + aircraft:fuselage:max_width [12.33] input ft aircraft:fuselage:max_width + aircraft:horizontal_tail:area [355.] input ft**2 aircraft:horizontal_tail:area + aircraft:horizontal_tail:aspect_ratio [6.] input unitless aircraft:horizontal_tail:aspect_ratio + aircraft:horizontal_tail:taper_ratio [0.22] input unitless aircraft:horizontal_tail:taper_ratio + aircraft:horizontal_tail:thickness_to_chord [0.125] input unitless aircraft:horizontal_tail:thickness_to_chord + aircraft:vertical_tail:area [284.] input ft**2 aircraft:vertical_tail:area + aircraft:vertical_tail:aspect_ratio [1.75] input unitless aircraft:vertical_tail:aspect_ratio + aircraft:vertical_tail:taper_ratio [0.33] input unitless aircraft:vertical_tail:taper_ratio + aircraft:vertical_tail:thickness_to_chord [0.1195] input unitless aircraft:vertical_tail:thickness_to_chord + aircraft:wing:area [1370.] input ft**2 aircraft:wing:area + aircraft:wing:glove_and_bat [134.] input ft**2 aircraft:wing:glove_and_bat + aircraft:wing:span [117.83] input ft aircraft:wing:span + aircraft:wing:taper_ratio [0.278] input unitless aircraft:wing:taper_ratio + aircraft:wing:thickness_to_chord [0.13] input unitless aircraft:wing:thickness_to_chord + prep_geom:_Names:CROOT [16.415788] output unitless pre_mission.prelim.prep_geom:_Names:CROOT + prep_geom:_Names:CROOTB [15.13330021] output unitless pre_mission.prelim.prep_geom:_Names:CROOTB + prep_geom:_Names:CROTM [0.92187473] output unitless pre_mission.prelim.prep_geom:_Names:CROTM + prep_geom:_Names:CROTVT [19.15660306] output unitless pre_mission.prelim.prep_geom:_Names:CROTVT + prep_geom:_Names:CRTHTB [13.50207305] output unitless pre_mission.prelim.prep_geom:_Names:CRTHTB + prep_geom:_Names:SPANHT [46.15192304] output unitless pre_mission.prelim.prep_geom:_Names:SPANHT + prep_geom:_Names:SPANVT [22.29349681] output unitless pre_mission.prelim.prep_geom:_Names:SPANVT + prep_geom:_Names:XDX [12.75] output unitless pre_mission.prelim.prep_geom:_Names:XDX + prep_geom:_Names:XMULT [2.05031] output unitless pre_mission.prelim.prep_geom:_Names:XMULT + prep_geom:_Names:XMULTH [2.048375] output unitless pre_mission.prelim.prep_geom:_Names:XMULTH + prep_geom:_Names:XMULTV [2.0462465] output unitless pre_mission.prelim.prep_geom:_Names:XMULTV + wing + prep_geom:_Names:CROOT [16.415788] input unitless pre_mission.wing.prep_geom:_Names:CROOT + prep_geom:_Names:CROOTB [15.13330021] input unitless pre_mission.wing.prep_geom:_Names:CROOTB + prep_geom:_Names:XDX [12.75] input unitless pre_mission.wing.prep_geom:_Names:XDX + prep_geom:_Names:XMULT [2.05031] input unitless pre_mission.wing.prep_geom:_Names:XMULT + aircraft:wing:area [1370.] input ft**2 aircraft:wing:area + aircraft:wing:wetted_area_scaler [1.] input unitless aircraft:wing:wetted_area_scaler + aircraft:wing:wetted_area [2396.55520449] output ft**2 pre_mission.AUTO_OVERRIDE:aircraft:wing:wetted_area + tail + prep_geom:_Names:XMULTH [2.048375] input unitless pre_mission.tail.prep_geom:_Names:XMULTH + prep_geom:_Names:XMULTV [2.0462465] input unitless pre_mission.tail.prep_geom:_Names:XMULTV + aircraft:horizontal_tail:area [355.] input ft**2 aircraft:horizontal_tail:area + aircraft:horizontal_tail:vertical_tail_fraction [0.] input unitless aircraft:horizontal_tail:vertical_tail_fraction + aircraft:horizontal_tail:wetted_area_scaler [1.] input unitless aircraft:horizontal_tail:wetted_area_scaler + aircraft:vertical_tail:area [284.] input ft**2 aircraft:vertical_tail:area + aircraft:vertical_tail:wetted_area_scaler [1.] input unitless aircraft:vertical_tail:wetted_area_scaler + aircraft:horizontal_tail:wetted_area [592.64609688] output ft**2 pre_mission.AUTO_OVERRIDE:aircraft:horizontal_tail:wetted_area + aircraft:vertical_tail:wetted_area [581.134006] output ft**2 pre_mission.AUTO_OVERRIDE:aircraft:vertical_tail:wetted_area + fuselage + prep_geom:_Names:CROOTB [15.13330021] input unitless pre_mission.fuselage.prep_geom:_Names:CROOTB + prep_geom:_Names:CROTVT [19.15660306] input unitless pre_mission.fuselage.prep_geom:_Names:CROTVT + prep_geom:_Names:CRTHTB [13.50207305] input unitless pre_mission.fuselage.prep_geom:_Names:CRTHTB + aircraft:fuselage:avg_diameter [12.75] input ft aircraft:fuselage:avg_diameter + aircraft:fuselage:length [128.] input ft aircraft:fuselage:length + aircraft:fuselage:wetted_area_scaler [1.] input unitless aircraft:fuselage:wetted_area_scaler + aircraft:horizontal_tail:thickness_to_chord [0.125] input unitless aircraft:horizontal_tail:thickness_to_chord + aircraft:horizontal_tail:vertical_tail_fraction [0.] input unitless aircraft:horizontal_tail:vertical_tail_fraction + aircraft:vertical_tail:thickness_to_chord [0.1195] input unitless aircraft:vertical_tail:thickness_to_chord + aircraft:wing:area [1370.] input ft**2 aircraft:wing:area + aircraft:wing:aspect_ratio [11.22091] input unitless aircraft:wing:aspect_ratio + aircraft:wing:glove_and_bat [134.] input ft**2 aircraft:wing:glove_and_bat + aircraft:wing:thickness_to_chord [0.13] input unitless aircraft:wing:thickness_to_chord + aircraft:fuselage:cross_section [127.67628894] output ft**2 aircraft:fuselage:cross_section + aircraft:fuselage:diameter_to_wing_span [0.10826471] output unitless aircraft:fuselage:diameter_to_wing_span + aircraft:fuselage:length_to_diameter [10.03921569] output unitless aircraft:fuselage:length_to_diameter + aircraft:fuselage:wetted_area [4158.62066062] output ft**2 pre_mission.AUTO_OVERRIDE:aircraft:fuselage:wetted_area + nacelles + aircraft:nacelle:avg_diameter [7.94] input ft aircraft:nacelle:avg_diameter + aircraft:nacelle:avg_length [12.3] input ft aircraft:nacelle:avg_length + aircraft:nacelle:wetted_area_scaler [1.] input unitless aircraft:nacelle:wetted_area_scaler + aircraft:nacelle:total_wetted_area [546.9072] output ft**2 aircraft:nacelle:total_wetted_area + aircraft:nacelle:wetted_area [273.4536] output ft**2 aircraft:nacelle:wetted_area + canard + aircraft:canard:area [0.] input ft**2 aircraft:canard:area + aircraft:canard:thickness_to_chord [0.] input unitless aircraft:canard:thickness_to_chord + aircraft:canard:wetted_area_scaler [1.] input unitless aircraft:canard:wetted_area_scaler + aircraft:canard:wetted_area [0.] output ft**2 aircraft:canard:wetted_area + characteristic_lengths + prep_geom:_Names:CROOT [16.415788] input unitless pre_mission.characteristic_lengths.prep_geom:_Names:CROOT + aircraft:canard:area [0.] input ft**2 aircraft:canard:area + aircraft:canard:aspect_ratio [0.] input unitless aircraft:canard:aspect_ratio + aircraft:canard:thickness_to_chord [0.] input unitless aircraft:canard:thickness_to_chord + aircraft:fuselage:avg_diameter [12.75] input ft aircraft:fuselage:avg_diameter + aircraft:fuselage:length [128.] input ft aircraft:fuselage:length + aircraft:horizontal_tail:area [355.] input ft**2 aircraft:horizontal_tail:area + aircraft:horizontal_tail:aspect_ratio [6.] input unitless aircraft:horizontal_tail:aspect_ratio + aircraft:horizontal_tail:thickness_to_chord [0.125] input unitless aircraft:horizontal_tail:thickness_to_chord + aircraft:nacelle:avg_diameter [7.94] input ft aircraft:nacelle:avg_diameter + aircraft:nacelle:avg_length [12.3] input ft aircraft:nacelle:avg_length + aircraft:vertical_tail:area [284.] input ft**2 aircraft:vertical_tail:area + aircraft:vertical_tail:aspect_ratio [1.75] input unitless aircraft:vertical_tail:aspect_ratio + aircraft:vertical_tail:thickness_to_chord [0.1195] input unitless aircraft:vertical_tail:thickness_to_chord + aircraft:wing:area [1370.] input ft**2 aircraft:wing:area + aircraft:wing:aspect_ratio [11.22091] input unitless aircraft:wing:aspect_ratio + aircraft:wing:glove_and_bat [134.] input ft**2 aircraft:wing:glove_and_bat + aircraft:wing:taper_ratio [0.278] input unitless aircraft:wing:taper_ratio + aircraft:wing:thickness_to_chord [0.13] input unitless aircraft:wing:thickness_to_chord + aircraft:canard:characteristic_length [0.] output ft aircraft:canard:characteristic_length + aircraft:canard:fineness [0.] output unitless aircraft:canard:fineness + aircraft:fuselage:characteristic_length [128.] output ft aircraft:fuselage:characteristic_length + aircraft:fuselage:fineness [10.03921569] output unitless aircraft:fuselage:fineness + aircraft:horizontal_tail:characteristic_length [7.69198717] output ft aircraft:horizontal_tail:characteristic_length + aircraft:horizontal_tail:fineness [0.125] output unitless aircraft:horizontal_tail:fineness + aircraft:nacelle:characteristic_length [12.3] output ft aircraft:nacelle:characteristic_length + aircraft:nacelle:fineness [1.54911839] output unitless aircraft:nacelle:fineness + aircraft:vertical_tail:characteristic_length [12.73914103] output ft aircraft:vertical_tail:characteristic_length + aircraft:vertical_tail:fineness [0.1195] output unitless aircraft:vertical_tail:fineness + aircraft:wing:characteristic_length [10.49530819] output ft aircraft:wing:characteristic_length + aircraft:wing:fineness [0.13] output unitless aircraft:wing:fineness + total_wetted_area + aircraft:canard:wetted_area [0.] input ft**2 aircraft:canard:wetted_area + aircraft:fuselage:wetted_area [4158.62] input ft**2 aircraft:fuselage:wetted_area + aircraft:horizontal_tail:wetted_area [592.65] input ft**2 aircraft:horizontal_tail:wetted_area + aircraft:nacelle:total_wetted_area [546.9072] input ft**2 aircraft:nacelle:total_wetted_area + aircraft:vertical_tail:wetted_area [581.13] input ft**2 aircraft:vertical_tail:wetted_area + aircraft:wing:wetted_area [2396.56] input ft**2 aircraft:wing:wetted_area + aircraft:design:total_wetted_area [8275.8672] output ft**2 aircraft:design:total_wetted_area + core_aerodynamics + aircraft:wing:aspect_ratio [11.22091] input unitless aircraft:wing:aspect_ratio + aircraft:wing:max_camber_at_70_semispan [0.] input unitless aircraft:wing:max_camber_at_70_semispan + aircraft:wing:sweep [25.] input deg aircraft:wing:sweep + aircraft:wing:thickness_to_chord [0.13] input unitless aircraft:wing:thickness_to_chord + mission:design:mach [0.80017085] output unitless mission:design:mach + mission:design:lift_coefficient [0.56736557] output unitless mission:design:lift_coefficient + core_mass + cargo + aircraft:crew_and_payload:wing_cargo [0.] input lbm aircraft:crew_and_payload:wing_cargo + aircraft:crew_and_payload:misc_cargo [0.] input lbm aircraft:crew_and_payload:misc_cargo + aircraft:crew_and_payload:passenger_mass [30420.] output lbm aircraft:crew_and_payload:passenger_mass + aircraft:crew_and_payload:baggage_mass [7605.] output lbm aircraft:crew_and_payload:baggage_mass + aircraft:crew_and_payload:passenger_payload_mass [38025.] output lbm aircraft:crew_and_payload:passenger_payload_mass + aircraft:crew_and_payload:cargo_mass [0.] output lbm aircraft:crew_and_payload:cargo_mass + aircraft:crew_and_payload:total_payload_mass [38025.] output lbm aircraft:crew_and_payload:total_payload_mass + cargo_containers + aircraft:crew_and_payload:cargo_container_mass_scaler [1.] input unitless aircraft:crew_and_payload:cargo_container_mass_scaler + aircraft:crew_and_payload:cargo_mass [0.] input lbm aircraft:crew_and_payload:cargo_mass + aircraft:crew_and_payload:baggage_mass [7605.] input lbm aircraft:crew_and_payload:baggage_mass + aircraft:crew_and_payload:cargo_container_mass [1474.31956451] output lbm aircraft:crew_and_payload:cargo_container_mass + engine_controls + aircraft:propulsion:total_scaled_sls_thrust [57856.2] input lbf aircraft:propulsion:total_scaled_sls_thrust + aircraft:propulsion:total_engine_controls_mass [88.44296603] output lbm aircraft:propulsion:total_engine_controls_mass + avionics + aircraft:avionics:mass_scaler [1.2] input unitless aircraft:avionics:mass_scaler + aircraft:fuselage:planform_area [1578.24] input ft**2 aircraft:fuselage:planform_area + mission:design:range [3500.] input nmi mission:design:range + aircraft:avionics:mass [1652.64869221] output lbm aircraft:avionics:mass + fuel_capacity_group + wing_fuel_capacity + aircraft:fuel:density_ratio [1.] input unitless aircraft:fuel:density_ratio + aircraft:fuel:wing_ref_capacity [0.] input lbm aircraft:fuel:wing_ref_capacity + aircraft:fuel:wing_ref_capacity_area [0.] input unitless aircraft:fuel:wing_ref_capacity_area + aircraft:fuel:wing_ref_capacity_term_A [0.] input unitless aircraft:fuel:wing_ref_capacity_term_A + aircraft:fuel:wing_ref_capacity_term_B [0.] input unitless aircraft:fuel:wing_ref_capacity_term_B + aircraft:fuel:capacity_factor [1.] input unitless aircraft:fuel:capacity_factor + aircraft:wing:area [1370.] input ft**2 aircraft:wing:area + aircraft:wing:span [117.83] input ft aircraft:wing:span + aircraft:wing:taper_ratio [0.278] input unitless aircraft:wing:taper_ratio + aircraft:wing:thickness_to_chord [0.13] input unitless aircraft:wing:thickness_to_chord + aircraft:fuel:wing_fuel_capacity [1718.292967] output lbm aircraft:fuel:wing_fuel_capacity + fuselage_fuel_capacity + aircraft:fuel:total_capacity [45694.] input lbm aircraft:fuel:total_capacity + aircraft:fuel:wing_fuel_capacity [1718.292967] input lbm aircraft:fuel:wing_fuel_capacity + aircraft:fuel:fuselage_fuel_capacity [43975.707033] output lbm pre_mission.AUTO_OVERRIDE:aircraft:fuel:fuselage_fuel_capacity + auxiliary_fuel_capacity + aircraft:fuel:total_capacity [45694.] input lbm aircraft:fuel:total_capacity + aircraft:fuel:wing_fuel_capacity [1718.292967] input lbm aircraft:fuel:wing_fuel_capacity + aircraft:fuel:fuselage_fuel_capacity [0.] input lbm aircraft:fuel:fuselage_fuel_capacity + aircraft:fuel:auxiliary_fuel_capacity [43975.707033] output lbm pre_mission.AUTO_OVERRIDE:aircraft:fuel:auxiliary_fuel_capacity + total_fuel_capacity + aircraft:fuel:wing_fuel_capacity [1718.292967] input lbm aircraft:fuel:wing_fuel_capacity + aircraft:fuel:fuselage_fuel_capacity [0.] input lbm aircraft:fuel:fuselage_fuel_capacity + aircraft:fuel:auxiliary_fuel_capacity [0.] input lbm aircraft:fuel:auxiliary_fuel_capacity + aircraft:fuel:total_capacity [1718.292967] output lbm pre_mission.AUTO_OVERRIDE:aircraft:fuel:total_capacity + engine_mass + aircraft:engine:scaled_sls_thrust [28928.1] input lbf aircraft:engine:scaled_sls_thrust + aircraft:engine:mass_scaler [1.15] input unitless aircraft:engine:mass_scaler + aircraft:engine:mass [7400.] output lbm pre_mission.AUTO_OVERRIDE:aircraft:engine:mass + aircraft:engine:additional_mass [0.] output lbm aircraft:engine:additional_mass + aircraft:propulsion:total_engine_mass [14800.] output lbm aircraft:propulsion:total_engine_mass + fuel_system + aircraft:fuel:fuel_system_mass_scaler [1.] input unitless aircraft:fuel:fuel_system_mass_scaler + aircraft:fuel:total_capacity [45694.] input lbm aircraft:fuel:total_capacity + aircraft:fuel:fuel_system_mass [669.57723863] output lbm aircraft:fuel:fuel_system_mass + AC + aircraft:air_conditioning:mass_scaler [1.] input unitless aircraft:air_conditioning:mass_scaler + aircraft:avionics:mass [1652.64869221] input lbm aircraft:avionics:mass + aircraft:fuselage:max_height [13.17] input ft aircraft:fuselage:max_height + aircraft:fuselage:planform_area [1578.24] input ft**2 aircraft:fuselage:planform_area + aircraft:air_conditioning:mass [1601.88685398] output lbm aircraft:air_conditioning:mass + engine_oil + aircraft:propulsion:engine_oil_mass_scaler [1.] input unitless aircraft:propulsion:engine_oil_mass_scaler + aircraft:propulsion:total_scaled_sls_thrust [57856.2] input lbf aircraft:propulsion:total_scaled_sls_thrust + aircraft:propulsion:total_engine_oil_mass [130.22722599] output lbm aircraft:propulsion:total_engine_oil_mass + furnishings + aircraft:furnishings:mass_scaler [1.1] input unitless aircraft:furnishings:mass_scaler + aircraft:fuselage:passenger_compartment_length [85.5] input ft aircraft:fuselage:passenger_compartment_length + aircraft:fuselage:max_width [12.33] input ft aircraft:fuselage:max_width + aircraft:fuselage:max_height [13.17] input ft aircraft:fuselage:max_height + aircraft:furnishings:mass [15517.315] output lbm aircraft:furnishings:mass + hydraulics + aircraft:fuselage:planform_area [1578.24] input ft**2 aircraft:fuselage:planform_area + aircraft:hydraulics:system_pressure [3000.] input psi aircraft:hydraulics:system_pressure + aircraft:hydraulics:mass_scaler [1.] input unitless aircraft:hydraulics:mass_scaler + aircraft:wing:area [1370.] input ft**2 aircraft:wing:area + aircraft:wing:var_sweep_mass_penalty [0.] input unitless aircraft:wing:var_sweep_mass_penalty + aircraft:hydraulics:mass [1086.69550641] output lbm aircraft:hydraulics:mass + pass_service + aircraft:crew_and_payload:passenger_service_mass_scaler [1.] input unitless aircraft:crew_and_payload:passenger_service_mass_scaler + mission:design:range [3500.] input nmi mission:design:range + aircraft:crew_and_payload:passenger_service_mass [3022.74805809] output lbm aircraft:crew_and_payload:passenger_service_mass + unusable_fuel + aircraft:fuel:unusable_fuel_mass_scaler [1.] input unitless aircraft:fuel:unusable_fuel_mass_scaler + aircraft:fuel:density_ratio [1.] input unitless aircraft:fuel:density_ratio + aircraft:fuel:total_capacity [45694.] input lbm aircraft:fuel:total_capacity + aircraft:propulsion:total_scaled_sls_thrust [57856.2] input lbf aircraft:propulsion:total_scaled_sls_thrust + aircraft:wing:area [1370.] input ft**2 aircraft:wing:area + aircraft:fuel:total_volume [0.] output galUS aircraft:fuel:total_volume + aircraft:fuel:unusable_fuel_mass [501.30242136] output lbm aircraft:fuel:unusable_fuel_mass + electrical + aircraft:fuselage:length [128.] input ft aircraft:fuselage:length + aircraft:fuselage:max_width [12.33] input ft aircraft:fuselage:max_width + aircraft:electrical:mass_scaler [1.25] input unitless aircraft:electrical:mass_scaler + aircraft:electrical:mass [2463.87138047] output lbm aircraft:electrical:mass + starter + aircraft:nacelle:avg_diameter [7.94] input ft aircraft:nacelle:avg_diameter + aircraft:propulsion:total_starter_mass [560.39438467] output lbm aircraft:propulsion:total_starter_mass + anti_icing + aircraft:anti_icing:mass_scaler [1.] input unitless aircraft:anti_icing:mass_scaler + aircraft:fuselage:max_width [12.33] input ft aircraft:fuselage:max_width + aircraft:nacelle:avg_diameter [7.94] input ft aircraft:nacelle:avg_diameter + aircraft:wing:span [117.83] input ft aircraft:wing:span + aircraft:wing:sweep [25.] input deg aircraft:wing:sweep + aircraft:anti_icing:mass [208.85002019] output lbm aircraft:anti_icing:mass + apu + aircraft:apu:mass_scaler [1.1] input unitless aircraft:apu:mass_scaler + aircraft:fuselage:planform_area [1578.24] input ft**2 aircraft:fuselage:planform_area + aircraft:apu:mass [1142.06504141] output lbm aircraft:apu:mass + nonflight_crew + aircraft:crew_and_payload:non_flight_crew_mass_scaler [1.] input unitless aircraft:crew_and_payload:non_flight_crew_mass_scaler + aircraft:crew_and_payload:non_flight_crew_mass [465.] output lbm aircraft:crew_and_payload:non_flight_crew_mass + flight_crew + aircraft:crew_and_payload:flight_crew_mass_scaler [1.] input unitless aircraft:crew_and_payload:flight_crew_mass_scaler + aircraft:crew_and_payload:flight_crew_mass [450.] output lbm aircraft:crew_and_payload:flight_crew_mass + instruments + aircraft:fuselage:planform_area [1578.24] input ft**2 aircraft:fuselage:planform_area + aircraft:instruments:mass_scaler [1.25] input unitless aircraft:instruments:mass_scaler + aircraft:instruments:mass [601.16492884] output lbm aircraft:instruments:mass + misc_engine + aircraft:engine:additional_mass [0.] input lbm aircraft:engine:additional_mass + aircraft:propulsion:misc_mass_scaler [1.] input unitless aircraft:propulsion:misc_mass_scaler + aircraft:propulsion:total_engine_controls_mass [88.44296603] input lbm aircraft:propulsion:total_engine_controls_mass + aircraft:propulsion:total_starter_mass [560.39438467] input lbm aircraft:propulsion:total_starter_mass + aircraft:propulsion:total_misc_mass [648.8373507] output lbm aircraft:propulsion:total_misc_mass + nacelle + aircraft:nacelle:avg_diameter [7.94] input ft aircraft:nacelle:avg_diameter + aircraft:nacelle:avg_length [12.3] input ft aircraft:nacelle:avg_length + aircraft:nacelle:mass_scaler [1.] input unitless aircraft:nacelle:mass_scaler + aircraft:engine:scaled_sls_thrust [28928.1] input lbf aircraft:engine:scaled_sls_thrust + aircraft:nacelle:mass [1971.38199541] output lbm aircraft:nacelle:mass + paint + aircraft:design:total_wetted_area [8275.8672] input ft**2 aircraft:design:total_wetted_area + aircraft:paint:mass_per_unit_area [0.037] input lbm/ft**2 aircraft:paint:mass_per_unit_area + aircraft:paint:mass [306.2070864] output lbm aircraft:paint:mass + thrust_rev + aircraft:engine:thrust_reversers_mass_scaler [0.] input unitless aircraft:engine:thrust_reversers_mass_scaler + aircraft:engine:scaled_sls_thrust [28928.1] input lbf aircraft:engine:scaled_sls_thrust + aircraft:engine:thrust_reversers_mass [0.] output lbm aircraft:engine:thrust_reversers_mass + aircraft:propulsion:total_thrust_reversers_mass [0.] output lbm aircraft:propulsion:total_thrust_reversers_mass + landing_group + landing_to_takeoff_mass_ratio + mission:summary:cruise_mach [0.785] input unitless mission:summary:cruise_mach + mission:design:range [3500.] input nmi mission:design:range + aircraft:design:landing_to_takeoff_mass_ratio [0.86] output unitless aircraft:design:landing_to_takeoff_mass_ratio + main_landing_gear_length + aircraft:fuselage:length [128.] input ft aircraft:fuselage:length + aircraft:fuselage:max_width [12.33] input ft aircraft:fuselage:max_width + aircraft:nacelle:avg_diameter [7.94] input ft aircraft:nacelle:avg_diameter + aircraft:engine:wing_locations [0.26869218] input unitless aircraft:engine:wing_locations + aircraft:wing:dihedral [0.] input deg aircraft:wing:dihedral + aircraft:wing:span [117.83] input ft aircraft:wing:span + aircraft:landing_gear:main_gear_oleo_length [125.43479933] output inch pre_mission.AUTO_OVERRIDE:aircraft:landing_gear:main_gear_oleo_length + nose_landing_gear_length + aircraft:landing_gear:main_gear_oleo_length [102.] input inch aircraft:landing_gear:main_gear_oleo_length + aircraft:landing_gear:nose_gear_oleo_length [71.4] output inch pre_mission.AUTO_OVERRIDE:aircraft:landing_gear:nose_gear_oleo_length + landing_mass + mission:design:gross_mass [130904.19882744] input lbm mission:design:gross_mass + aircraft:design:landing_to_takeoff_mass_ratio [0.86] input unitless aircraft:design:landing_to_takeoff_mass_ratio + aircraft:design:touchdown_mass [112577.61099159] output lbm pre_mission.AUTO_OVERRIDE:aircraft:design:touchdown_mass + landing_gear + aircraft:landing_gear:main_gear_oleo_length [102.] input inch aircraft:landing_gear:main_gear_oleo_length + aircraft:landing_gear:main_gear_mass_scaler [1.1] input unitless aircraft:landing_gear:main_gear_mass_scaler + aircraft:landing_gear:nose_gear_oleo_length [67.] input inch aircraft:landing_gear:nose_gear_oleo_length + aircraft:landing_gear:nose_gear_mass_scaler [1.] input unitless aircraft:landing_gear:nose_gear_mass_scaler + aircraft:design:touchdown_mass [152800.] input lbm aircraft:design:touchdown_mass + aircraft:landing_gear:main_gear_mass [7910.31553228] output lbm aircraft:landing_gear:main_gear_mass + aircraft:landing_gear:nose_gear_mass [870.59476203] output lbm aircraft:landing_gear:nose_gear_mass + surf_ctrl + aircraft:wing:surface_ctrl_mass_scaler [1.] input unitless aircraft:wing:surface_ctrl_mass_scaler + mission:design:gross_mass [130904.19882744] input lbm mission:design:gross_mass + aircraft:wing:control_surface_area_ratio [0.1] input unitless aircraft:wing:control_surface_area_ratio + aircraft:wing:area [1370.] input ft**2 aircraft:wing:area + aircraft:wing:surface_ctrl_mass [805.71674878] output lbm aircraft:wing:surface_ctrl_mass + aircraft:wing:control_surface_area [137.] output ft**2 pre_mission.AUTO_OVERRIDE:aircraft:wing:control_surface_area + fuselage + aircraft:fuselage:length [128.] input ft aircraft:fuselage:length + aircraft:fuselage:mass_scaler [1.05] input unitless aircraft:fuselage:mass_scaler + aircraft:fuselage:avg_diameter [12.75] input ft aircraft:fuselage:avg_diameter + aircraft:fuselage:mass [18357.13345514] output lbm pre_mission.EXTERNAL_OVERRIDE:aircraft:fuselage:mass + htail + aircraft:horizontal_tail:area [355.] input ft**2 aircraft:horizontal_tail:area + aircraft:horizontal_tail:taper_ratio [0.22] input unitless aircraft:horizontal_tail:taper_ratio + mission:design:gross_mass [130904.19882744] input lbm mission:design:gross_mass + aircraft:horizontal_tail:mass_scaler [1.2] input unitless aircraft:horizontal_tail:mass_scaler + aircraft:horizontal_tail:mass [1715.57093767] output lbm pre_mission.EXTERNAL_OVERRIDE:aircraft:horizontal_tail:mass + vert_tail + aircraft:vertical_tail:area [284.] input ft**2 aircraft:vertical_tail:area + aircraft:vertical_tail:taper_ratio [0.33] input unitless aircraft:vertical_tail:taper_ratio + aircraft:vertical_tail:mass_scaler [1.] input unitless aircraft:vertical_tail:mass_scaler + mission:design:gross_mass [130904.19882744] input lbm mission:design:gross_mass + aircraft:vertical_tail:mass [1108.24232631] output lbm pre_mission.EXTERNAL_OVERRIDE:aircraft:vertical_tail:mass + canard + mission:design:gross_mass [130904.19882744] input lbm mission:design:gross_mass + aircraft:canard:area [0.] input ft**2 aircraft:canard:area + aircraft:canard:taper_ratio [0.] input unitless aircraft:canard:taper_ratio + aircraft:canard:mass_scaler [1.] input unitless aircraft:canard:mass_scaler + aircraft:canard:mass [0.] output lbm aircraft:canard:mass + fin + mission:design:gross_mass [130904.19882744] input lbm mission:design:gross_mass + aircraft:fins:area [0.] input ft**2 aircraft:fins:area + aircraft:fins:taper_ratio [10.] input unitless aircraft:fins:taper_ratio + aircraft:fins:mass_scaler [1.] input unitless aircraft:fins:mass_scaler + aircraft:fins:mass [0.] output lbm pre_mission.AUTO_OVERRIDE:aircraft:fins:mass + wing_group + engine_pod_mass + aircraft:electrical:mass [2463.87138047] input lbm aircraft:electrical:mass + aircraft:fuel:fuel_system_mass [669.57723863] input lbm aircraft:fuel:fuel_system_mass + aircraft:hydraulics:mass [1086.69550641] input lbm aircraft:hydraulics:mass + aircraft:instruments:mass [601.16492884] input lbm aircraft:instruments:mass + aircraft:nacelle:mass [1971.38199541] input lbm aircraft:nacelle:mass + aircraft:propulsion:total_engine_controls_mass [88.44296603] input lbm aircraft:propulsion:total_engine_controls_mass + aircraft:engine:mass [7400.] input lbm aircraft:engine:mass + aircraft:propulsion:total_starter_mass [560.39438467] input lbm aircraft:propulsion:total_starter_mass + aircraft:engine:thrust_reversers_mass [0.] input lbm aircraft:engine:thrust_reversers_mass + aircraft:engine:scaled_sls_thrust [28928.1] input lbf aircraft:engine:scaled_sls_thrust + aircraft:propulsion:total_scaled_sls_thrust [57856.2] input lbf aircraft:propulsion:total_scaled_sls_thrust + aircraft:engine:pod_mass [9024.49163435] output lbm aircraft:engine:pod_mass + wing_bending_material_factor + aircraft:wing:load_path_sweep_dist |22.0| input deg aircraft:wing:load_path_sweep_dist + val: + array([ 0., 22.]) + aircraft:wing:thickness_to_chord_dist |0.21228754| input unitless aircraft:wing:thickness_to_chord_dist + val: + array([0.145, 0.115, 0.104]) + aircraft:wing:chord_per_semispan |0.39503924| input unitless aircraft:wing:chord_per_semispan + val: + array([0.31 , 0.23 , 0.084]) + mission:design:gross_mass [130904.19882744] input lbm mission:design:gross_mass + aircraft:engine:pod_mass [9024.49163435] input lbm aircraft:engine:pod_mass + aircraft:wing:aspect_ratio [11.22091] input unitless aircraft:wing:aspect_ratio + aircraft:wing:aspect_ratio_reference [0.] input unitless aircraft:wing:aspect_ratio_reference + aircraft:wing:strut_bracing_factor [0.] input unitless aircraft:wing:strut_bracing_factor + aircraft:wing:aeroelastic_tailoring_factor [0.] input unitless aircraft:wing:aeroelastic_tailoring_factor + aircraft:engine:wing_locations [0.26869218] input unitless aircraft:engine:wing_locations + aircraft:wing:thickness_to_chord [0.13] input unitless aircraft:wing:thickness_to_chord + aircraft:wing:thickness_to_chord_reference [0.] input unitless aircraft:wing:thickness_to_chord_reference + aircraft:wing:bending_material_factor [11.5916567] output unitless aircraft:wing:bending_material_factor + aircraft:wing:eng_pod_inertia_factor [0.95478088] output unitless aircraft:wing:eng_pod_inertia_factor + wing_misc + aircraft:wing:composite_fraction [0.2] input unitless aircraft:wing:composite_fraction + aircraft:wing:area [1370.] input ft**2 aircraft:wing:area + aircraft:wing:misc_mass_scaler [1.] input unitless aircraft:wing:misc_mass_scaler + aircraft:wing:misc_mass [1668.30998341] output lbm aircraft:wing:misc_mass + wing_shear_control + aircraft:wing:composite_fraction [0.2] input unitless aircraft:wing:composite_fraction + aircraft:wing:control_surface_area [137.] input ft**2 aircraft:wing:control_surface_area + mission:design:gross_mass [130904.19882744] input lbm mission:design:gross_mass + aircraft:wing:shear_control_mass_scaler [1.] input unitless aircraft:wing:shear_control_mass_scaler + aircraft:wing:shear_control_mass [4112.85291254] output lbm aircraft:wing:shear_control_mass + wing_bending + mission:design:gross_mass [130904.19882744] input lbm mission:design:gross_mass + aircraft:wing:aeroelastic_tailoring_factor [0.] input unitless aircraft:wing:aeroelastic_tailoring_factor + aircraft:wing:bending_material_factor [11.5916567] input unitless aircraft:wing:bending_material_factor + aircraft:wing:bending_material_mass_scaler [1.] input unitless aircraft:wing:bending_material_mass_scaler + aircraft:wing:composite_fraction [0.2] input unitless aircraft:wing:composite_fraction + aircraft:wing:eng_pod_inertia_factor [0.95478088] input unitless aircraft:wing:eng_pod_inertia_factor + aircraft:wing:load_fraction [1.] input unitless aircraft:wing:load_fraction + aircraft:wing:misc_mass [1668.30998341] input lbm aircraft:wing:misc_mass + aircraft:wing:misc_mass_scaler [1.] input unitless aircraft:wing:misc_mass_scaler + aircraft:wing:shear_control_mass [4112.85291254] input lbm aircraft:wing:shear_control_mass + aircraft:wing:shear_control_mass_scaler [1.] input unitless aircraft:wing:shear_control_mass_scaler + aircraft:wing:span [117.83] input ft aircraft:wing:span + aircraft:wing:sweep [25.] input deg aircraft:wing:sweep + aircraft:wing:ultimate_load_factor [3.75] input unitless aircraft:wing:ultimate_load_factor + aircraft:wing:var_sweep_mass_penalty [0.] input unitless aircraft:wing:var_sweep_mass_penalty + aircraft:wing:bending_material_mass [5786.25146563] output lbm aircraft:wing:bending_material_mass + wing_total + aircraft:wing:bending_material_mass [5786.25146563] input lbm aircraft:wing:bending_material_mass + aircraft:wing:shear_control_mass [4112.85291254] input lbm aircraft:wing:shear_control_mass + aircraft:wing:misc_mass [1668.30998341] input lbm aircraft:wing:misc_mass + aircraft:wing:bwb_aft_body_mass [0.] input lbm aircraft:wing:bwb_aft_body_mass + aircraft:wing:mass_scaler [1.23] input unitless aircraft:wing:mass_scaler + aircraft:wing:mass [14227.91966474] output lbm pre_mission.EXTERNAL_OVERRIDE:aircraft:wing:mass + total_mass + structure_mass + aircraft:canard:mass [0.] input lbm aircraft:canard:mass + aircraft:fins:mass [0.] input lbm aircraft:fins:mass + aircraft:fuselage:mass [11484.15203519] input lbm aircraft:fuselage:mass + aircraft:horizontal_tail:mass [0.] input lbm aircraft:horizontal_tail:mass + aircraft:landing_gear:main_gear_mass [7910.31553228] input lbm aircraft:landing_gear:main_gear_mass + aircraft:landing_gear:nose_gear_mass [870.59476203] input lbm aircraft:landing_gear:nose_gear_mass + aircraft:nacelle:mass [1971.38199541] input lbm aircraft:nacelle:mass + aircraft:paint:mass [306.2070864] input lbm aircraft:paint:mass + aircraft:vertical_tail:mass [0.] input lbm aircraft:vertical_tail:mass + aircraft:wing:mass [4.95303746] input lbm aircraft:wing:mass + aircraft:design:structure_mass [22547.60444877] output lbm aircraft:design:structure_mass + propulsion_mass + aircraft:fuel:fuel_system_mass [669.57723863] input lbm aircraft:fuel:fuel_system_mass + aircraft:propulsion:total_misc_mass [648.8373507] input lbm aircraft:propulsion:total_misc_mass + aircraft:propulsion:total_thrust_reversers_mass [0.] input lbm aircraft:propulsion:total_thrust_reversers_mass + aircraft:propulsion:total_engine_mass [14800.] input lbm aircraft:propulsion:total_engine_mass + aircraft:propulsion:mass [16118.41458932] output lbm aircraft:propulsion:mass + system_equip_mass + aircraft:air_conditioning:mass [1601.88685398] input lbm aircraft:air_conditioning:mass + aircraft:anti_icing:mass [208.85002019] input lbm aircraft:anti_icing:mass + aircraft:apu:mass [1142.06504141] input lbm aircraft:apu:mass + aircraft:avionics:mass [1652.64869221] input lbm aircraft:avionics:mass + aircraft:electrical:mass [2463.87138047] input lbm aircraft:electrical:mass + aircraft:furnishings:mass [15517.315] input lbm aircraft:furnishings:mass + aircraft:hydraulics:mass [1086.69550641] input lbm aircraft:hydraulics:mass + aircraft:instruments:mass [601.16492884] input lbm aircraft:instruments:mass + aircraft:wing:surface_ctrl_mass [805.71674878] input lbm aircraft:wing:surface_ctrl_mass + aircraft:design:external_subsystems_mass [0.] input lbm aircraft:design:external_subsystems_mass + aircraft:design:systems_equip_mass [25080.21417229] output lbm aircraft:design:systems_equip_mass + empty_mass_margin + aircraft:propulsion:mass [16118.41458932] input lbm aircraft:propulsion:mass + aircraft:design:structure_mass [22547.60444877] input lbm aircraft:design:structure_mass + aircraft:design:systems_equip_mass [25080.21417229] input lbm aircraft:design:systems_equip_mass + aircraft:design:empty_mass_margin_scaler [0.] input unitless aircraft:design:empty_mass_margin_scaler + aircraft:design:empty_mass_margin [0.] output lbm aircraft:design:empty_mass_margin + empty_mass + aircraft:design:empty_mass_margin [0.] input lbm aircraft:design:empty_mass_margin + aircraft:design:structure_mass [22547.60444877] input lbm aircraft:design:structure_mass + aircraft:propulsion:mass [16118.41458932] input lbm aircraft:propulsion:mass + aircraft:design:systems_equip_mass [25080.21417229] input lbm aircraft:design:systems_equip_mass + aircraft:design:empty_mass [63746.23321038] output lbm aircraft:design:empty_mass + operating_mass + aircraft:crew_and_payload:cargo_container_mass [1474.31956451] input lbm aircraft:crew_and_payload:cargo_container_mass + aircraft:crew_and_payload:non_flight_crew_mass [465.] input lbm aircraft:crew_and_payload:non_flight_crew_mass + aircraft:crew_and_payload:flight_crew_mass [450.] input lbm aircraft:crew_and_payload:flight_crew_mass + aircraft:crew_and_payload:passenger_service_mass [3022.74805809] input lbm aircraft:crew_and_payload:passenger_service_mass + aircraft:design:empty_mass [63746.23321038] input lbm aircraft:design:empty_mass + aircraft:fuel:unusable_fuel_mass [501.30242136] input lbm aircraft:fuel:unusable_fuel_mass + aircraft:propulsion:total_engine_oil_mass [130.22722599] input lbm aircraft:propulsion:total_engine_oil_mass + aircraft:design:operating_mass [69789.83048032] output lbm aircraft:design:operating_mass + zero_fuel_mass + aircraft:crew_and_payload:passenger_mass [30420.] input lbm aircraft:crew_and_payload:passenger_mass + aircraft:crew_and_payload:baggage_mass [7605.] input lbm aircraft:crew_and_payload:baggage_mass + aircraft:crew_and_payload:cargo_mass [0.] input lbm aircraft:crew_and_payload:cargo_mass + aircraft:design:operating_mass [69789.83048032] input lbm aircraft:design:operating_mass + aircraft:design:zero_fuel_mass [107814.83048032] output lbm aircraft:design:zero_fuel_mass + fuel_mass + mission:design:gross_mass [130904.19882744] input lbm mission:design:gross_mass + aircraft:design:zero_fuel_mass [107814.83048032] input lbm aircraft:design:zero_fuel_mass + mission:design:fuel_mass [23089.36834711] output lbm mission:design:fuel_mass +traj + param_comp + parameters:aircraft:design:base_area [0.] input ft**2 aircraft:design:base_area + parameters:aircraft:design:lift_dependent_drag_coeff_factor [0.90983938] input unitless aircraft:design:lift_dependent_drag_coeff_factor + parameters:aircraft:design:subsonic_drag_coeff_factor [1.] input unitless aircraft:design:subsonic_drag_coeff_factor + parameters:aircraft:design:supersonic_drag_coeff_factor [1.] input unitless aircraft:design:supersonic_drag_coeff_factor + parameters:aircraft:design:zero_lift_drag_coeff_factor [0.93089003] input unitless aircraft:design:zero_lift_drag_coeff_factor + parameters:aircraft:fuselage:characteristic_length [128.] input ft aircraft:fuselage:characteristic_length + parameters:aircraft:fuselage:cross_section [127.67628894] input ft**2 aircraft:fuselage:cross_section + parameters:aircraft:fuselage:diameter_to_wing_span [0.10826471] input unitless aircraft:fuselage:diameter_to_wing_span + parameters:aircraft:fuselage:fineness [10.03921569] input unitless aircraft:fuselage:fineness + parameters:aircraft:fuselage:laminar_flow_lower [0.] input unitless aircraft:fuselage:laminar_flow_lower + parameters:aircraft:fuselage:laminar_flow_upper [0.] input unitless aircraft:fuselage:laminar_flow_upper + parameters:aircraft:fuselage:length_to_diameter [10.03921569] input unitless aircraft:fuselage:length_to_diameter + parameters:aircraft:fuselage:wetted_area [4158.62] input ft**2 aircraft:fuselage:wetted_area + parameters:aircraft:horizontal_tail:characteristic_length [7.69198717] input ft aircraft:horizontal_tail:characteristic_length + parameters:aircraft:horizontal_tail:fineness [0.125] input unitless aircraft:horizontal_tail:fineness + parameters:aircraft:horizontal_tail:laminar_flow_lower [0.] input unitless aircraft:horizontal_tail:laminar_flow_lower + parameters:aircraft:horizontal_tail:laminar_flow_upper [0.] input unitless aircraft:horizontal_tail:laminar_flow_upper + parameters:aircraft:horizontal_tail:wetted_area [592.65] input ft**2 aircraft:horizontal_tail:wetted_area + parameters:aircraft:vertical_tail:characteristic_length [12.73914103] input ft aircraft:vertical_tail:characteristic_length + parameters:aircraft:vertical_tail:fineness [0.1195] input unitless aircraft:vertical_tail:fineness + parameters:aircraft:vertical_tail:laminar_flow_lower [0.] input unitless aircraft:vertical_tail:laminar_flow_lower + parameters:aircraft:vertical_tail:laminar_flow_upper [0.] input unitless aircraft:vertical_tail:laminar_flow_upper + parameters:aircraft:vertical_tail:wetted_area [581.13] input ft**2 aircraft:vertical_tail:wetted_area + parameters:aircraft:wing:area [1370.] input ft**2 aircraft:wing:area + parameters:aircraft:wing:aspect_ratio [11.22091] input unitless aircraft:wing:aspect_ratio + parameters:aircraft:wing:characteristic_length [10.49530819] input ft aircraft:wing:characteristic_length + parameters:aircraft:wing:fineness [0.13] input unitless aircraft:wing:fineness + parameters:aircraft:wing:laminar_flow_lower [0.] input unitless aircraft:wing:laminar_flow_lower + parameters:aircraft:wing:laminar_flow_upper [0.] input unitless aircraft:wing:laminar_flow_upper + parameters:aircraft:wing:max_camber_at_70_semispan [0.] input unitless aircraft:wing:max_camber_at_70_semispan + parameters:aircraft:wing:span_efficiency_factor [1.] input unitless aircraft:wing:span_efficiency_factor + parameters:aircraft:wing:sweep [25.] input deg aircraft:wing:sweep + parameters:aircraft:wing:taper_ratio [0.278] input unitless aircraft:wing:taper_ratio + parameters:aircraft:wing:thickness_to_chord [0.13] input unitless aircraft:wing:thickness_to_chord + parameters:aircraft:wing:wetted_area [2396.56] input ft**2 aircraft:wing:wetted_area + parameters:mission:design:lift_coefficient [0.56736557] input unitless mission:design:lift_coefficient + parameters:mission:design:mach [0.80017085] input unitless mission:design:mach + parameters:aircraft:nacelle:characteristic_length [12.3] input ft aircraft:nacelle:characteristic_length + parameters:aircraft:nacelle:fineness [1.54911839] input unitless aircraft:nacelle:fineness + parameters:aircraft:nacelle:laminar_flow_lower [0.] input unitless aircraft:nacelle:laminar_flow_lower + parameters:aircraft:nacelle:laminar_flow_upper [0.] input unitless aircraft:nacelle:laminar_flow_upper + parameters:aircraft:nacelle:wetted_area [273.4536] input ft**2 aircraft:nacelle:wetted_area + parameters:aircraft:engine:scale_factor [1.] input unitless aircraft:engine:scale_factor + parameter_vals:aircraft:design:base_area [[0.]] output ft**2 traj.parameter_vals:aircraft:design:base_area + parameter_vals:aircraft:design:lift_dependent_drag_coeff_factor [[0.90983938]] output unitless traj.parameter_vals:aircraft:design:lift_dependent_drag_coeff_factor + parameter_vals:aircraft:design:subsonic_drag_coeff_factor [[1.]] output unitless traj.parameter_vals:aircraft:design:subsonic_drag_coeff_factor + parameter_vals:aircraft:design:supersonic_drag_coeff_factor [[1.]] output unitless traj.parameter_vals:aircraft:design:supersonic_drag_coeff_factor + parameter_vals:aircraft:design:zero_lift_drag_coeff_factor [[0.93089003]] output unitless traj.parameter_vals:aircraft:design:zero_lift_drag_coeff_factor + parameter_vals:aircraft:fuselage:characteristic_length [[128.]] output ft traj.parameter_vals:aircraft:fuselage:characteristic_length + parameter_vals:aircraft:fuselage:cross_section [[127.67628894]] output ft**2 traj.parameter_vals:aircraft:fuselage:cross_section + parameter_vals:aircraft:fuselage:diameter_to_wing_span [[0.10826471]] output unitless traj.parameter_vals:aircraft:fuselage:diameter_to_wing_span + parameter_vals:aircraft:fuselage:fineness [[10.03921569]] output unitless traj.parameter_vals:aircraft:fuselage:fineness + parameter_vals:aircraft:fuselage:laminar_flow_lower [[0.]] output unitless traj.parameter_vals:aircraft:fuselage:laminar_flow_lower + parameter_vals:aircraft:fuselage:laminar_flow_upper [[0.]] output unitless traj.parameter_vals:aircraft:fuselage:laminar_flow_upper + parameter_vals:aircraft:fuselage:length_to_diameter [[10.03921569]] output unitless traj.parameter_vals:aircraft:fuselage:length_to_diameter + parameter_vals:aircraft:fuselage:wetted_area [[4158.62]] output ft**2 traj.parameter_vals:aircraft:fuselage:wetted_area + parameter_vals:aircraft:horizontal_tail:characteristic_length [[7.69198717]] output ft traj.parameter_vals:aircraft:horizontal_tail:characteristic_length + parameter_vals:aircraft:horizontal_tail:fineness [[0.125]] output unitless traj.parameter_vals:aircraft:horizontal_tail:fineness + parameter_vals:aircraft:horizontal_tail:laminar_flow_lower [[0.]] output unitless traj.parameter_vals:aircraft:horizontal_tail:laminar_flow_lower + parameter_vals:aircraft:horizontal_tail:laminar_flow_upper [[0.]] output unitless traj.parameter_vals:aircraft:horizontal_tail:laminar_flow_upper + parameter_vals:aircraft:horizontal_tail:wetted_area [[592.65]] output ft**2 traj.parameter_vals:aircraft:horizontal_tail:wetted_area + parameter_vals:aircraft:vertical_tail:characteristic_length [[12.73914103]] output ft traj.parameter_vals:aircraft:vertical_tail:characteristic_length + parameter_vals:aircraft:vertical_tail:fineness [[0.1195]] output unitless traj.parameter_vals:aircraft:vertical_tail:fineness + parameter_vals:aircraft:vertical_tail:laminar_flow_lower [[0.]] output unitless traj.parameter_vals:aircraft:vertical_tail:laminar_flow_lower + parameter_vals:aircraft:vertical_tail:laminar_flow_upper [[0.]] output unitless traj.parameter_vals:aircraft:vertical_tail:laminar_flow_upper + parameter_vals:aircraft:vertical_tail:wetted_area [[581.13]] output ft**2 traj.parameter_vals:aircraft:vertical_tail:wetted_area + parameter_vals:aircraft:wing:area [[1370.]] output ft**2 traj.parameter_vals:aircraft:wing:area + parameter_vals:aircraft:wing:aspect_ratio [[11.22091]] output unitless traj.parameter_vals:aircraft:wing:aspect_ratio + parameter_vals:aircraft:wing:characteristic_length [[10.49530819]] output ft traj.parameter_vals:aircraft:wing:characteristic_length + parameter_vals:aircraft:wing:fineness [[0.13]] output unitless traj.parameter_vals:aircraft:wing:fineness + parameter_vals:aircraft:wing:laminar_flow_lower [[0.]] output unitless traj.parameter_vals:aircraft:wing:laminar_flow_lower + parameter_vals:aircraft:wing:laminar_flow_upper [[0.]] output unitless traj.parameter_vals:aircraft:wing:laminar_flow_upper + parameter_vals:aircraft:wing:max_camber_at_70_semispan [[0.]] output unitless traj.parameter_vals:aircraft:wing:max_camber_at_70_semispan + parameter_vals:aircraft:wing:span_efficiency_factor [[1.]] output unitless traj.parameter_vals:aircraft:wing:span_efficiency_factor + parameter_vals:aircraft:wing:sweep [[25.]] output deg traj.parameter_vals:aircraft:wing:sweep + parameter_vals:aircraft:wing:taper_ratio [[0.278]] output unitless traj.parameter_vals:aircraft:wing:taper_ratio + parameter_vals:aircraft:wing:thickness_to_chord [[0.13]] output unitless traj.parameter_vals:aircraft:wing:thickness_to_chord + parameter_vals:aircraft:wing:wetted_area [[2396.56]] output ft**2 traj.parameter_vals:aircraft:wing:wetted_area + parameter_vals:mission:design:lift_coefficient [[0.56736557]] output unitless traj.parameter_vals:mission:design:lift_coefficient + parameter_vals:mission:design:mach [[0.80017085]] output unitless traj.parameter_vals:mission:design:mach + parameter_vals:aircraft:nacelle:characteristic_length [[12.3]] output ft traj.parameter_vals:aircraft:nacelle:characteristic_length + parameter_vals:aircraft:nacelle:fineness [[1.54911839]] output unitless traj.parameter_vals:aircraft:nacelle:fineness + parameter_vals:aircraft:nacelle:laminar_flow_lower [[0.]] output unitless traj.parameter_vals:aircraft:nacelle:laminar_flow_lower + parameter_vals:aircraft:nacelle:laminar_flow_upper [[0.]] output unitless traj.parameter_vals:aircraft:nacelle:laminar_flow_upper + parameter_vals:aircraft:nacelle:wetted_area [[273.4536]] output ft**2 traj.parameter_vals:aircraft:nacelle:wetted_area + parameter_vals:aircraft:engine:scale_factor [[1.]] output unitless traj.parameter_vals:aircraft:engine:scale_factor + phases + climb + param_comp + t_initial [0.] input s traj.climb.t_initial + t_duration [3840.] input s traj.climb.t_duration + parameters:aircraft:design:base_area [0.] input ft**2 traj.climb.parameters:aircraft:design:base_area + parameters:aircraft:design:lift_dependent_drag_coeff_factor [0.90983938] input unitless traj.climb.parameters:aircraft:design:lift_dependent_drag_coeff_factor + parameters:aircraft:design:subsonic_drag_coeff_factor [1.] input unitless traj.climb.parameters:aircraft:design:subsonic_drag_coeff_factor + parameters:aircraft:design:supersonic_drag_coeff_factor [1.] input unitless traj.climb.parameters:aircraft:design:supersonic_drag_coeff_factor + parameters:aircraft:design:zero_lift_drag_coeff_factor [0.93089003] input unitless traj.climb.parameters:aircraft:design:zero_lift_drag_coeff_factor + parameters:aircraft:fuselage:characteristic_length [128.] input ft traj.climb.parameters:aircraft:fuselage:characteristic_length + parameters:aircraft:fuselage:cross_section [127.67628894] input ft**2 traj.climb.parameters:aircraft:fuselage:cross_section + parameters:aircraft:fuselage:diameter_to_wing_span [0.10826471] input unitless traj.climb.parameters:aircraft:fuselage:diameter_to_wing_span + parameters:aircraft:fuselage:fineness [10.03921569] input unitless traj.climb.parameters:aircraft:fuselage:fineness + parameters:aircraft:fuselage:laminar_flow_lower [0.] input unitless traj.climb.parameters:aircraft:fuselage:laminar_flow_lower + parameters:aircraft:fuselage:laminar_flow_upper [0.] input unitless traj.climb.parameters:aircraft:fuselage:laminar_flow_upper + parameters:aircraft:fuselage:length_to_diameter [10.03921569] input unitless traj.climb.parameters:aircraft:fuselage:length_to_diameter + parameters:aircraft:fuselage:wetted_area [4158.62] input ft**2 traj.climb.parameters:aircraft:fuselage:wetted_area + parameters:aircraft:horizontal_tail:characteristic_length [7.69198717] input ft traj.climb.parameters:aircraft:horizontal_tail:characteristic_length + parameters:aircraft:horizontal_tail:fineness [0.125] input unitless traj.climb.parameters:aircraft:horizontal_tail:fineness + parameters:aircraft:horizontal_tail:laminar_flow_lower [0.] input unitless traj.climb.parameters:aircraft:horizontal_tail:laminar_flow_lower + parameters:aircraft:horizontal_tail:laminar_flow_upper [0.] input unitless traj.climb.parameters:aircraft:horizontal_tail:laminar_flow_upper + parameters:aircraft:horizontal_tail:wetted_area [592.65] input ft**2 traj.climb.parameters:aircraft:horizontal_tail:wetted_area + parameters:aircraft:vertical_tail:characteristic_length [12.73914103] input ft traj.climb.parameters:aircraft:vertical_tail:characteristic_length + parameters:aircraft:vertical_tail:fineness [0.1195] input unitless traj.climb.parameters:aircraft:vertical_tail:fineness + parameters:aircraft:vertical_tail:laminar_flow_lower [0.] input unitless traj.climb.parameters:aircraft:vertical_tail:laminar_flow_lower + parameters:aircraft:vertical_tail:laminar_flow_upper [0.] input unitless traj.climb.parameters:aircraft:vertical_tail:laminar_flow_upper + parameters:aircraft:vertical_tail:wetted_area [581.13] input ft**2 traj.climb.parameters:aircraft:vertical_tail:wetted_area + parameters:aircraft:wing:area [1370.] input ft**2 traj.climb.parameters:aircraft:wing:area + parameters:aircraft:wing:aspect_ratio [11.22091] input unitless traj.climb.parameters:aircraft:wing:aspect_ratio + parameters:aircraft:wing:characteristic_length [10.49530819] input ft traj.climb.parameters:aircraft:wing:characteristic_length + parameters:aircraft:wing:fineness [0.13] input unitless traj.climb.parameters:aircraft:wing:fineness + parameters:aircraft:wing:laminar_flow_lower [0.] input unitless traj.climb.parameters:aircraft:wing:laminar_flow_lower + parameters:aircraft:wing:laminar_flow_upper [0.] input unitless traj.climb.parameters:aircraft:wing:laminar_flow_upper + parameters:aircraft:wing:max_camber_at_70_semispan [0.] input unitless traj.climb.parameters:aircraft:wing:max_camber_at_70_semispan + parameters:aircraft:wing:span_efficiency_factor [1.] input unitless traj.climb.parameters:aircraft:wing:span_efficiency_factor + parameters:aircraft:wing:sweep [25.] input deg traj.climb.parameters:aircraft:wing:sweep + parameters:aircraft:wing:taper_ratio [0.278] input unitless traj.climb.parameters:aircraft:wing:taper_ratio + parameters:aircraft:wing:thickness_to_chord [0.13] input unitless traj.climb.parameters:aircraft:wing:thickness_to_chord + parameters:aircraft:wing:wetted_area [2396.56] input ft**2 traj.climb.parameters:aircraft:wing:wetted_area + parameters:mission:design:lift_coefficient [0.56736557] input unitless traj.climb.parameters:mission:design:lift_coefficient + parameters:mission:design:mach [0.80017085] input unitless traj.climb.parameters:mission:design:mach + parameters:aircraft:nacelle:characteristic_length [12.3] input ft traj.climb.parameters:aircraft:nacelle:characteristic_length + parameters:aircraft:nacelle:fineness [1.54911839] input unitless traj.climb.parameters:aircraft:nacelle:fineness + parameters:aircraft:nacelle:laminar_flow_lower [0.] input unitless traj.climb.parameters:aircraft:nacelle:laminar_flow_lower + parameters:aircraft:nacelle:laminar_flow_upper [0.] input unitless traj.climb.parameters:aircraft:nacelle:laminar_flow_upper + parameters:aircraft:nacelle:wetted_area [273.4536] input ft**2 traj.climb.parameters:aircraft:nacelle:wetted_area + parameters:aircraft:engine:scale_factor [1.] input unitless traj.climb.parameters:aircraft:engine:scale_factor + t_initial_val [0.] output s traj.climb.t_initial_val + t_duration_val [3840.] output s traj.climb.t_duration_val + parameter_vals:aircraft:design:base_area [[0.]] output ft**2 traj.climb.parameter_vals:aircraft:design:base_area + parameter_vals:aircraft:design:lift_dependent_drag_coeff_factor [[0.90983938]] output unitless traj.climb.parameter_vals:aircraft:design:lift_dependent_drag_coeff_factor + parameter_vals:aircraft:design:subsonic_drag_coeff_factor [[1.]] output unitless traj.climb.parameter_vals:aircraft:design:subsonic_drag_coeff_factor + parameter_vals:aircraft:design:supersonic_drag_coeff_factor [[1.]] output unitless traj.climb.parameter_vals:aircraft:design:supersonic_drag_coeff_factor + parameter_vals:aircraft:design:zero_lift_drag_coeff_factor [[0.93089003]] output unitless traj.climb.parameter_vals:aircraft:design:zero_lift_drag_coeff_factor + parameter_vals:aircraft:fuselage:characteristic_length [[128.]] output ft traj.climb.parameter_vals:aircraft:fuselage:characteristic_length + parameter_vals:aircraft:fuselage:cross_section [[127.67628894]] output ft**2 traj.climb.parameter_vals:aircraft:fuselage:cross_section + parameter_vals:aircraft:fuselage:diameter_to_wing_span [[0.10826471]] output unitless traj.climb.parameter_vals:aircraft:fuselage:diameter_to_wing_span + parameter_vals:aircraft:fuselage:fineness [[10.03921569]] output unitless traj.climb.parameter_vals:aircraft:fuselage:fineness + parameter_vals:aircraft:fuselage:laminar_flow_lower [[0.]] output unitless traj.climb.parameter_vals:aircraft:fuselage:laminar_flow_lower + parameter_vals:aircraft:fuselage:laminar_flow_upper [[0.]] output unitless traj.climb.parameter_vals:aircraft:fuselage:laminar_flow_upper + parameter_vals:aircraft:fuselage:length_to_diameter [[10.03921569]] output unitless traj.climb.parameter_vals:aircraft:fuselage:length_to_diameter + parameter_vals:aircraft:fuselage:wetted_area [[4158.62]] output ft**2 traj.climb.parameter_vals:aircraft:fuselage:wetted_area + parameter_vals:aircraft:horizontal_tail:characteristic_length [[7.69198717]] output ft traj.climb.parameter_vals:aircraft:horizontal_tail:characteristic_length + parameter_vals:aircraft:horizontal_tail:fineness [[0.125]] output unitless traj.climb.parameter_vals:aircraft:horizontal_tail:fineness + parameter_vals:aircraft:horizontal_tail:laminar_flow_lower [[0.]] output unitless traj.climb.parameter_vals:aircraft:horizontal_tail:laminar_flow_lower + parameter_vals:aircraft:horizontal_tail:laminar_flow_upper [[0.]] output unitless traj.climb.parameter_vals:aircraft:horizontal_tail:laminar_flow_upper + parameter_vals:aircraft:horizontal_tail:wetted_area [[592.65]] output ft**2 traj.climb.parameter_vals:aircraft:horizontal_tail:wetted_area + parameter_vals:aircraft:vertical_tail:characteristic_length [[12.73914103]] output ft traj.climb.parameter_vals:aircraft:vertical_tail:characteristic_length + parameter_vals:aircraft:vertical_tail:fineness [[0.1195]] output unitless traj.climb.parameter_vals:aircraft:vertical_tail:fineness + parameter_vals:aircraft:vertical_tail:laminar_flow_lower [[0.]] output unitless traj.climb.parameter_vals:aircraft:vertical_tail:laminar_flow_lower + parameter_vals:aircraft:vertical_tail:laminar_flow_upper [[0.]] output unitless traj.climb.parameter_vals:aircraft:vertical_tail:laminar_flow_upper + parameter_vals:aircraft:vertical_tail:wetted_area [[581.13]] output ft**2 traj.climb.parameter_vals:aircraft:vertical_tail:wetted_area + parameter_vals:aircraft:wing:area [[1370.]] output ft**2 traj.climb.parameter_vals:aircraft:wing:area + parameter_vals:aircraft:wing:aspect_ratio [[11.22091]] output unitless traj.climb.parameter_vals:aircraft:wing:aspect_ratio + parameter_vals:aircraft:wing:characteristic_length [[10.49530819]] output ft traj.climb.parameter_vals:aircraft:wing:characteristic_length + parameter_vals:aircraft:wing:fineness [[0.13]] output unitless traj.climb.parameter_vals:aircraft:wing:fineness + parameter_vals:aircraft:wing:laminar_flow_lower [[0.]] output unitless traj.climb.parameter_vals:aircraft:wing:laminar_flow_lower + parameter_vals:aircraft:wing:laminar_flow_upper [[0.]] output unitless traj.climb.parameter_vals:aircraft:wing:laminar_flow_upper + parameter_vals:aircraft:wing:max_camber_at_70_semispan [[0.]] output unitless traj.climb.parameter_vals:aircraft:wing:max_camber_at_70_semispan + parameter_vals:aircraft:wing:span_efficiency_factor [[1.]] output unitless traj.climb.parameter_vals:aircraft:wing:span_efficiency_factor + parameter_vals:aircraft:wing:sweep [[25.]] output deg traj.climb.parameter_vals:aircraft:wing:sweep + parameter_vals:aircraft:wing:taper_ratio [[0.278]] output unitless traj.climb.parameter_vals:aircraft:wing:taper_ratio + parameter_vals:aircraft:wing:thickness_to_chord [[0.13]] output unitless traj.climb.parameter_vals:aircraft:wing:thickness_to_chord + parameter_vals:aircraft:wing:wetted_area [[2396.56]] output ft**2 traj.climb.parameter_vals:aircraft:wing:wetted_area + parameter_vals:mission:design:lift_coefficient [[0.56736557]] output unitless traj.climb.parameter_vals:mission:design:lift_coefficient + parameter_vals:mission:design:mach [[0.80017085]] output unitless traj.climb.parameter_vals:mission:design:mach + parameter_vals:aircraft:nacelle:characteristic_length [[12.3]] output ft traj.climb.parameter_vals:aircraft:nacelle:characteristic_length + parameter_vals:aircraft:nacelle:fineness [[1.54911839]] output unitless traj.climb.parameter_vals:aircraft:nacelle:fineness + parameter_vals:aircraft:nacelle:laminar_flow_lower [[0.]] output unitless traj.climb.parameter_vals:aircraft:nacelle:laminar_flow_lower + parameter_vals:aircraft:nacelle:laminar_flow_upper [[0.]] output unitless traj.climb.parameter_vals:aircraft:nacelle:laminar_flow_upper + parameter_vals:aircraft:nacelle:wetted_area [[273.4536]] output ft**2 traj.climb.parameter_vals:aircraft:nacelle:wetted_area + parameter_vals:aircraft:engine:scale_factor [[1.]] output unitless traj.climb.parameter_vals:aircraft:engine:scale_factor + time + t_initial [0.] input s traj.climb.t_initial + t_duration [3840.] input s traj.climb.t_duration + t |10483.03643104| output s traj.climb.t + val: + array([ 0. , 160.1613086 , 381.15122507, 451.09377806, + 451.09377806, 778.18869326, 1229.51291522, 1372.35548836, + 1372.35548836, 1761.23897954, 2297.81882512, 2467.64451164, + 2467.64451164, 2794.73942684, 3246.0636488 , 3388.90622194, + 3388.90622194, 3549.06753054, 3770.05744702, 3840. ]) + t_phase |10483.03643104| output s traj.climb.t_phase + val: + array([ 0. , 160.1613086 , 381.15122507, 451.09377806, + 451.09377806, 778.18869326, 1229.51291522, 1372.35548836, + 1372.35548836, 1761.23897954, 2297.81882512, 2467.64451164, + 2467.64451164, 2794.73942684, 3246.0636488 , 3388.90622194, + 3388.90622194, 3549.06753054, 3770.05744702, 3840. ]) + dt_dstau |1817.71161504| output s traj.climb.dt_dstau + val: + array([225.54688903, 225.54688903, 225.54688903, 225.54688903, + 460.63085515, 460.63085515, 460.63085515, 460.63085515, + 547.64451164, 547.64451164, 547.64451164, 547.64451164, + 460.63085515, 460.63085515, 460.63085515, 460.63085515, + 225.54688903, 225.54688903, 225.54688903, 225.54688903]) + control_comp + dt_dstau |1817.71161504| input s traj.climb.control_comp.dt_dstau + val: + array([225.54688903, 225.54688903, 225.54688903, 225.54688903, + 460.63085515, 460.63085515, 460.63085515, 460.63085515, + 547.64451164, 547.64451164, 547.64451164, 547.64451164, + 460.63085515, 460.63085515, 460.63085515, 460.63085515, + 225.54688903, 225.54688903, 225.54688903, 225.54688903]) + t_duration [3840.] input s traj.climb.control_comp.t_duration + controls:mach |1.00431071| input unitless traj.climb.controls:mach + val: + array([[0.2 ], + [0.34372447], + [0.57627553], + [0.72 ]]) + controls:altitude |40477.15405016| input ft traj.climb.controls:altitude + val: + array([[ 0. ], + [ 8844.582472], + [23155.417528], + [32000. ]]) + control_values:mach |2.22189137| output unitless traj.climb.control_values:mach + val: + array([[0.2 ], + [0.22168851], + [0.25161423], + [0.26108562], + [0.26108562], + [0.30537972], + [0.36649654], + [0.38583981], + [0.38583981], + [0.43850111], + [0.51116297], + [0.53416019], + [0.53416019], + [0.5784543 ], + [0.63957112], + [0.65891438], + [0.65891438], + [0.68060289], + [0.71052861], + [0.72 ]]) + control_rates:mach_rate |0.0006056| output unitless/s traj.climb.control_rates:mach_rate + val: + array([[0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542]]) + control_rates:mach_rate2 |0.0| output unitless/s**2 traj.climb.control_rates:mach_rate2 + val: + array([[-2.40933816e-22], + [ 0.00000000e+00], + [-2.40933816e-22], + [-1.20466908e-22], + [-1.20466908e-22], + [-1.20466908e-22], + [-1.20466908e-22], + [-6.02334540e-23], + [-6.02334540e-23], + [-6.02334540e-23], + [ 0.00000000e+00], + [-1.20466908e-22], + [-1.20466908e-22], + [ 1.20466908e-22], + [ 2.40933816e-22], + [ 0.00000000e+00], + [ 0.00000000e+00], + [ 2.40933816e-22], + [ 2.40933816e-22], + [ 2.40933816e-22]]) + control_boundary_values:mach |0.74726167| output unitless traj.climb.control_comp.control_boundary_values:mach + val: + array([[0.2 ], + [0.72]]) + control_boundary_rates:mach_rate |0.00019151| output unitless/s traj.climb.control_comp.control_boundary_rates:mach_rate + val: + array([[0.00013542], + [0.00013542]]) + control_boundary_rates:mach_rate2 |0.0| output unitless/s**2 traj.climb.control_comp.control_boundary_rates:mach_rate2 + val: + array([[-2.40933816e-22], + [ 2.40933816e-22]]) + control_values:altitude |87358.6369253| output ft traj.climb.control_values:altitude + val: + array([[ 0. ], + [ 1334.67757163], + [ 3176.26020893], + [ 3759.11481713], + [ 3759.11481713], + [ 6484.90577713], + [10245.94096014], + [11436.29573631], + [11436.29573631], + [14676.99149614], + [19148.49020934], + [20563.70426369], + [20563.70426369], + [23289.4952237 ], + [27050.5304067 ], + [28240.88518287], + [28240.88518287], + [29575.5627545 ], + [31417.1453918 ], + [32000. ]]) + control_rates:altitude_rate |37.26779962| output ft/s traj.climb.control_rates:altitude_rate + val: + array([[8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333]]) + control_rates:altitude_rate2 |0.0| output ft/s**2 traj.climb.control_rates:altitude_rate2 + val: + array([[-7.89491929e-18], + [ 0.00000000e+00], + [-3.94745964e-18], + [-7.89491929e-18], + [-7.89491929e-18], + [-3.94745964e-18], + [-5.92118946e-18], + [-3.94745964e-18], + [-3.94745964e-18], + [-1.97372982e-18], + [ 0.00000000e+00], + [ 0.00000000e+00], + [ 0.00000000e+00], + [ 3.94745964e-18], + [ 1.57898386e-17], + [ 1.57898386e-17], + [ 1.57898386e-17], + [ 1.57898386e-17], + [ 1.57898386e-17], + [ 7.89491929e-18]]) + control_boundary_values:altitude |32000.0| output ft traj.climb.control_comp.control_boundary_values:altitude + val: + array([[ 0.], + [32000.]]) + control_boundary_rates:altitude_rate |11.78511302| output ft/s traj.climb.control_comp.control_boundary_rates:altitude_rate + val: + array([[8.33333333], + [8.33333333]]) + control_boundary_rates:altitude_rate2 |0.0| output ft/s**2 traj.climb.control_comp.control_boundary_rates:altitude_rate2 + val: + array([[-7.89491929e-18], + [ 7.89491929e-18]]) + indep_states + states:mass |232631.68332249| output kg traj.climb.states:mass + val: + array([[59377.14578909], + [59253.2001355 ], + [59099.30211114], + [59053.23865024], + [58849.04195155], + [58583.91501949], + [58501.0166128 ], + [58275.75043339], + [57961.72209353], + [57860.85002365], + [57664.1758047 ], + [57387.22609857], + [57298.3740442 ], + [57198.30721763], + [57059.51640479], + [57015.39290411]]) + states:distance |1273831.39141224| output m traj.climb.states:distance + val: + array([[1.00000000e+00], + [1.14581007e+04], + [2.91056018e+04], + [3.51310537e+04], + [6.60814858e+04], + [1.16145544e+05], + [1.33731831e+05], + [1.85754660e+05], + [2.67231556e+05], + [2.95296884e+05], + [3.52354108e+05], + [4.37399478e+05], + [4.65802163e+05], + [4.98478689e+05], + [5.44983286e+05], + [5.60039406e+05]]) + state_interp + dt_dstau |1574.18443538| input s traj.climb.state_interp.dt_dstau + val: + array([225.54688903, 225.54688903, 225.54688903, 460.63085515, + 460.63085515, 460.63085515, 547.64451164, 547.64451164, + 547.64451164, 460.63085515, 460.63085515, 460.63085515, + 225.54688903, 225.54688903, 225.54688903]) + state_disc:mass |260111.77531753| input kg traj.climb.state_interp.state_disc:mass + val: + array([[59377.14578909], + [59253.2001355 ], + [59099.30211114], + [59053.23865024], + [59053.23865024], + [58849.04195155], + [58583.91501949], + [58501.0166128 ], + [58501.0166128 ], + [58275.75043339], + [57961.72209353], + [57860.85002365], + [57860.85002365], + [57664.1758047 ], + [57387.22609857], + [57298.3740442 ], + [57298.3740442 ], + [57198.30721763], + [57059.51640479], + [57015.39290411]]) + state_disc:distance |1394968.35548323| input m traj.climb.state_interp.state_disc:distance + val: + array([[1.00000000e+00], + [1.14581007e+04], + [2.91056018e+04], + [3.51310537e+04], + [3.51310537e+04], + [6.60814858e+04], + [1.16145544e+05], + [1.33731831e+05], + [1.33731831e+05], + [1.85754660e+05], + [2.67231556e+05], + [2.95296884e+05], + [2.95296884e+05], + [3.52354108e+05], + [4.37399478e+05], + [4.65802163e+05], + [4.65802163e+05], + [4.98478689e+05], + [5.44983286e+05], + [5.60039406e+05]]) + staterate_col:mass |2.46548436| output kg/s traj.climb.state_interp.staterate_col:mass + val: + array([[-0.81635589], + [-0.73557259], + [-0.66516889], + [-0.64952724], + [-0.60312819], + [-0.57957803], + [-0.57869286], + [-0.58065035], + [-0.59138326], + [-0.59559425], + [-0.60675259], + [-0.62013408], + [-0.62357343], + [-0.62606633], + [-0.63013871]]) + staterate_col:distance |583.61135954| output m/s traj.climb.state_interp.staterate_col:distance + val: + array([[ 68.00995794], + [ 75.04782293], + [ 84.6430095 ], + [ 87.65174596], + [101.54257372], + [120.21625082], + [126.00588218], + [141.46990952], + [162.07913243], + [168.42295523], + [180.39460351], + [196.37105177], + [201.29434073], + [206.73713847], + [214.11204164]]) + rhs_all + atmosphere + standard_atmosphere + h |87358.6369253| input ft traj.climb.rhs_all.altitude + val: + array([ 0. , 1334.67757163, 3176.26020893, 3759.11481713, + 3759.11481713, 6484.90577713, 10245.94096014, 11436.29573631, + 11436.29573631, 14676.99149614, 19148.49020934, 20563.70426369, + 20563.70426369, 23289.4952237 , 27050.5304067 , 28240.88518287, + 28240.88518287, 29575.5627545 , 31417.1453918 , 32000. ]) + temp |2066.65858384| output degR traj.climb.rhs_all.temperature + val: + array([518.67 , 513.91084435, 507.34509901, 505.26655918, + 505.26655918, 495.5510144 , 482.14891569, 477.90852019, + 477.90852019, 466.36665517, 450.44612086, 445.40906345, + 445.40906345, 435.70829939, 422.32876215, 418.09508175, + 418.09508175, 413.34789509, 406.79997501, 404.72782123]) + pres |41.12989507| output psi traj.climb.rhs_all.static_pressure + val: + array([14.6959 , 14.0009012 , 13.08590864, 12.80663963, 12.80663963, + 11.56420805, 10.01237775, 9.55809623, 9.55809623, 8.40553073, + 7.0030012 , 6.60106653, 6.60106653, 5.8796902 , 4.99066923, + 4.73327683, 4.73327683, 4.45757854, 4.09872669, 3.99016779]) + rho |0.00710413| output slug/ft**3 traj.climb.rhs_all.density + val: + array([0.00237717, 0.00228572, 0.00216399, 0.00212652, 0.00212652, + 0.00195786, 0.00174224, 0.00167795, 0.00167795, 0.00151214, + 0.00130436, 0.0012434 , 0.0012434 , 0.00113217, 0.00099143, + 0.00094982, 0.00094982, 0.00090477, 0.00084532, 0.00082715]) + viscosity |1.54e-06| output lbf*s/ft**2 traj.climb.rhs_all.viscosity + val: + array([3.78456000e-07, 3.75691988e-07, 3.71861243e-07, 3.70643612e-07, + 3.70643612e-07, 3.64920138e-07, 3.56939502e-07, 3.54394280e-07, + 3.54394280e-07, 3.47411497e-07, 3.37652624e-07, 3.34533376e-07, + 3.34533376e-07, 3.28482402e-07, 3.20038906e-07, 3.17342868e-07, + 3.17342868e-07, 3.14307095e-07, 3.10094120e-07, 3.08755112e-07]) + drhos_dh |2.2e-07| output slug/ft**4 traj.climb.rhs_all.drhos_dh + val: + array([-6.95548710e-08, -6.75005931e-08, -6.47287414e-08, -6.38683907e-08, + -6.38683907e-08, -5.99679763e-08, -5.48403871e-08, -5.32949389e-08, + -5.32949389e-08, -4.92050502e-08, -4.39443505e-08, -4.23756474e-08, + -4.23756474e-08, -3.94403259e-08, -3.56212794e-08, -3.44788975e-08, + -3.44788975e-08, -3.32238160e-08, -3.15408200e-08, -3.10133821e-08]) + sos |4704.69211471| output ft/s traj.climb.rhs_all.speed_of_sound + val: + array([1116.42671753, 1111.29292057, 1104.17113919, 1101.90698094, + 1101.90698094, 1091.26151998, 1076.4038783 , 1071.66005531, + 1071.66005531, 1058.64025047, 1040.41374789, 1034.58024563, + 1034.58024563, 1023.25193102, 1007.41864968, 1002.3564424 , + 1002.3564424 , 996.64965751, 988.72408929, 986.20269773]) + flight_conditions + density |0.00710413| input slug/ft**3 traj.climb.rhs_all.density + val: + array([0.00237717, 0.00228572, 0.00216399, 0.00212652, 0.00212652, + 0.00195786, 0.00174224, 0.00167795, 0.00167795, 0.00151214, + 0.00130436, 0.0012434 , 0.0012434 , 0.00113217, 0.00099143, + 0.00094982, 0.00094982, 0.00090477, 0.00084532, 0.00082715]) + speed_of_sound |4704.69211471| input ft/s traj.climb.rhs_all.speed_of_sound + val: + array([1116.42671753, 1111.29292057, 1104.17113919, 1101.90698094, + 1101.90698094, 1091.26151998, 1076.4038783 , 1071.66005531, + 1071.66005531, 1058.64025047, 1040.41374789, 1034.58024563, + 1034.58024563, 1023.25193102, 1007.41864968, 1002.3564424 , + 1002.3564424 , 996.64965751, 988.72408929, 986.20269773]) + mach |2.22189137| input unitless traj.climb.rhs_all.mach + val: + array([0.2 , 0.22168851, 0.25161423, 0.26108562, 0.26108562, + 0.30537972, 0.36649654, 0.38583981, 0.38583981, 0.43850111, + 0.51116297, 0.53416019, 0.53416019, 0.5784543 , 0.63957112, + 0.65891438, 0.65891438, 0.68060289, 0.71052861, 0.72 ]) + dynamic_pressure |729.82648439| output lbf/ft**2 traj.climb.rhs_all.dynamic_pressure + val: + array([ 59.25850338, 69.36442415, 83.51573809, 88.00275154, + 88.00275154, 108.7150004 , 135.57151342, 143.44259835, + 143.44259835, 162.92998731, 184.45796777, 189.86816523, + 189.86816523, 198.32854638, 205.79302246, 207.1635135 , + 207.1635135 , 208.1516967 , 208.59603076, 208.52120555]) + EAS |1612.50052137| output ft/s traj.climb.rhs_all.EAS + val: + array([223.29802501, 241.58943331, 265.09021925, 272.11824924, + 272.11824924, 302.45048022, 337.74876107, 347.41503892, + 347.41503892, 370.26277725, 393.96555484, 399.7013539 , + 399.7013539 , 408.5094965 , 416.12601294, 417.50932185, + 417.50932185, 418.50391026, 418.95035488, 418.87520758]) + velocity |2273.06081681| output ft/s traj.climb.rhs_all.velocity + val: + array([223.28534351, 246.36087233, 277.8251692 , 287.69206265, + 287.69206265, 333.2491362 , 394.49829769, 413.48910753, + 413.48910753, 464.21492684, 531.82097714, 552.63158501, + 552.63158501, 591.90447681, 644.31587319, 660.46707802, + 660.46707802, 678.32264196, 702.51675542, 710.06594237]) + velocity_rate_comp + mach_rate |0.0006056| input unitless/s traj.climb.rhs_all.mach_rate + val: + array([0.00013542, 0.00013542, 0.00013542, 0.00013542, 0.00013542, + 0.00013542, 0.00013542, 0.00013542, 0.00013542, 0.00013542, + 0.00013542, 0.00013542, 0.00013542, 0.00013542, 0.00013542, + 0.00013542, 0.00013542, 0.00013542, 0.00013542, 0.00013542]) + sos |1433.99015656| input m/s traj.climb.rhs_all.speed_of_sound + val: + array([340.2868635 , 338.72208219, 336.55136322, 335.86124779, + 335.86124779, 332.61651129, 328.08790211, 326.64198486, + 326.64198486, 322.67354834, 317.11811036, 315.34005887, + 315.34005887, 311.88718858, 307.06120442, 305.51824364, + 305.51824364, 303.77881561, 301.36310241, 300.59458227]) + velocity_rate |0.19418617| output m/s**2 traj.climb.rhs_all.velocity_rate + val: + array([0.04608051, 0.04586862, 0.04557466, 0.04548121, 0.04548121, + 0.04504182, 0.04442857, 0.04423277, 0.04423277, 0.04369538, + 0.04294308, 0.0427023 , 0.0427023 , 0.04223472, 0.0415812 , + 0.04137226, 0.04137226, 0.04113671, 0.04080959, 0.04070552]) + solver_sub + core_aerodynamics + Mux + aircraft:wing:wetted_area [2396.56] input ft**2 traj.climb.rhs_all.aircraft:wing:wetted_area + aircraft:wing:fineness [0.13] input unitless traj.climb.rhs_all.aircraft:wing:fineness + aircraft:wing:characteristic_length [10.49530819] input ft traj.climb.rhs_all.aircraft:wing:characteristic_length + aircraft:wing:laminar_flow_upper [0.] input unitless traj.climb.rhs_all.aircraft:wing:laminar_flow_upper + aircraft:wing:laminar_flow_lower [0.] input unitless traj.climb.rhs_all.aircraft:wing:laminar_flow_lower + aircraft:horizontal_tail:wetted_area [592.65] input ft**2 traj.climb.rhs_all.aircraft:horizontal_tail:wetted_area + aircraft:horizontal_tail:fineness [0.125] input unitless traj.climb.rhs_all.aircraft:horizontal_tail:fineness + aircraft:horizontal_tail:characteristic_length [7.69198717] input ft traj.climb.rhs_all.aircraft:horizontal_tail:characteristic_length + aircraft:horizontal_tail:laminar_flow_upper [0.] input unitless traj.climb.rhs_all.aircraft:horizontal_tail:laminar_flow_upper + aircraft:horizontal_tail:laminar_flow_lower [0.] input unitless traj.climb.rhs_all.aircraft:horizontal_tail:laminar_flow_lower + aircraft:vertical_tail:wetted_area [581.13] input ft**2 traj.climb.rhs_all.aircraft:vertical_tail:wetted_area + aircraft:vertical_tail:fineness [0.1195] input unitless traj.climb.rhs_all.aircraft:vertical_tail:fineness + aircraft:vertical_tail:characteristic_length [12.73914103] input ft traj.climb.rhs_all.aircraft:vertical_tail:characteristic_length + aircraft:vertical_tail:laminar_flow_upper [0.] input unitless traj.climb.rhs_all.aircraft:vertical_tail:laminar_flow_upper + aircraft:vertical_tail:laminar_flow_lower [0.] input unitless traj.climb.rhs_all.aircraft:vertical_tail:laminar_flow_lower + aircraft:fuselage:wetted_area [4158.62] input ft**2 traj.climb.rhs_all.aircraft:fuselage:wetted_area + aircraft:fuselage:fineness [10.03921569] input unitless traj.climb.rhs_all.aircraft:fuselage:fineness + aircraft:fuselage:characteristic_length [128.] input ft traj.climb.rhs_all.aircraft:fuselage:characteristic_length + aircraft:fuselage:laminar_flow_upper [0.] input unitless traj.climb.rhs_all.aircraft:fuselage:laminar_flow_upper + aircraft:fuselage:laminar_flow_lower [0.] input unitless traj.climb.rhs_all.aircraft:fuselage:laminar_flow_lower + aircraft:nacelle:wetted_area [273.4536] input ft**2 traj.climb.rhs_all.aircraft:nacelle:wetted_area + aircraft:nacelle:fineness [1.54911839] input unitless traj.climb.rhs_all.aircraft:nacelle:fineness + aircraft:nacelle:characteristic_length [12.3] input ft traj.climb.rhs_all.aircraft:nacelle:characteristic_length + aircraft:nacelle:laminar_flow_upper [0.] input unitless traj.climb.rhs_all.aircraft:nacelle:laminar_flow_upper + aircraft:nacelle:laminar_flow_lower [0.] input unitless traj.climb.rhs_all.aircraft:nacelle:laminar_flow_lower + wetted_areas |4886.31967641| output ft**2 traj.climb.rhs_all.core_aerodynamics.wetted_areas + val: + array([2396.56 , 592.65 , 581.13 , 4158.62 , 273.4536, 273.4536]) + fineness_ratios |10.2777523| output unitless traj.climb.rhs_all.core_aerodynamics.fineness_ratios + val: + array([ 0.13 , 0.125 , 0.1195 , 10.03921569, 1.54911839, + 1.54911839]) + characteristic_lengths |130.45376144| output ft traj.climb.rhs_all.core_aerodynamics.characteristic_lengths + val: + array([ 10.49530819, 7.69198717, 12.73914103, 128. , + 12.3 , 12.3 ]) + laminar_fractions_upper |0.0| output unitless traj.climb.rhs_all.core_aerodynamics.laminar_fractions_upper + val: + array([0., 0., 0., 0., 0., 0.]) + laminar_fractions_lower |0.0| output unitless traj.climb.rhs_all.core_aerodynamics.laminar_fractions_lower + val: + array([0., 0., 0., 0., 0., 0.]) + DynamicPressure + static_pressure |5922.70488396| input lbf/ft**2 traj.climb.rhs_all.static_pressure + val: + array([2116.20959775, 2016.12977059, 1884.3708425 , 1844.15610466, + 1844.15610466, 1665.24595683, 1441.7823939 , 1376.36585521, + 1376.36585521, 1210.39642326, 1008.43217102, 950.5535796 , + 950.5535796 , 846.67538744, 718.65636826, 681.59186207, + 681.59186207, 641.89130933, 590.21664278, 574.58416126]) + mach |2.22189137| input unitless traj.climb.rhs_all.mach + val: + array([0.2 , 0.22168851, 0.25161423, 0.26108562, 0.26108562, + 0.30537972, 0.36649654, 0.38583981, 0.38583981, 0.43850111, + 0.51116297, 0.53416019, 0.53416019, 0.5784543 , 0.63957112, + 0.65891438, 0.65891438, 0.68060289, 0.71052861, 0.72 ]) + dynamic_pressure |729.77059557| output lbf/ft**2 traj.climb.rhs_all.core_aerodynamics.dynamic_pressure + val: + array([ 59.25386874, 69.35901127, 83.5092932 , 87.99573266, + 87.99573266, 108.70682458, 135.56185944, 143.43197899, + 143.43197899, 162.91724951, 184.44355948, 189.85309614, + 189.85309614, 198.31386506, 205.77708313, 207.14784198, + 207.14784198, 208.13595957, 208.57998617, 208.50510044]) + lift + aircraft:wing:area [127.2771648] input m**2 traj.climb.rhs_all.aircraft:wing:area + mass |260111.77531753| input kg traj.climb.rhs_all.mass + val: + array([59377.14578909, 59253.2001355 , 59099.30211114, 59053.23865024, + 59053.23865024, 58849.04195155, 58583.91501949, 58501.0166128 , + 58501.0166128 , 58275.75043339, 57961.72209353, 57860.85002365, + 57860.85002365, 57664.1758047 , 57387.22609857, 57298.3740442 , + 57298.3740442 , 57198.30721763, 57059.51640479, 57015.39290411]) + dynamic_pressure |34941.60514958| input N/m**2 traj.climb.rhs_all.core_aerodynamics.dynamic_pressure + val: + array([2837.09058373, 3320.92742596, 3998.4465899 , 4213.25847322, + 4213.25847322, 5204.91091948, 6490.73694453, 6867.56030763, + 6867.56030763, 7800.52010707, 8831.20540436, 9090.215421 , + 9090.215421 , 9495.31922842, 9852.66004282, 9918.29233157, + 9918.29233157, 9965.60365807, 9986.86376675, 9983.27821833]) + cl |3.56252196| output unitless traj.climb.rhs_all.core_aerodynamics.cl + val: + array([1.61256154, 1.37474646, 1.13883613, 1.07993048, 1.07993048, + 0.8711567 , 0.69543183, 0.65634339, 0.65634339, 0.57561817, + 0.50569828, 0.49043428, 0.49043428, 0.46791471, 0.44877837, + 0.44511843, 0.44511843, 0.44223158, 0.44021937, 0.44003693]) + lift |2550825.14141767| output N traj.climb.rhs_all.lift + val: + array([582290.88675256, 581075.39510879, 579566.17104819, 579114.44280941, + 579114.44280941, 577111.9572542 , 574511.95022592, 573698.99456589, + 573698.99456589, 571489.88798758, 568410.32196854, 567421.10488442, + 567421.10488442, 565492.38965516, 562776.44081958, 561905.09982059, + 561905.09982059, 560923.77947573, 559562.70655104, 559130.00282312]) + PressureDrag + mach |2.22189137| input unitless traj.climb.rhs_all.mach + val: + array([0.2 , 0.22168851, 0.25161423, 0.26108562, 0.26108562, + 0.30537972, 0.36649654, 0.38583981, 0.38583981, 0.43850111, + 0.51116297, 0.53416019, 0.53416019, 0.5784543 , 0.63957112, + 0.65891438, 0.65891438, 0.68060289, 0.71052861, 0.72 ]) + lift |573448.30346328| input lbf traj.climb.rhs_all.core_aerodynamics.lift + val: + array([130904.19868796, 130630.94529647, 130291.65823087, 130190.10568305, + 130190.10568305, 129739.92902229, 129155.42419083, 128972.66448831, + 128972.66448831, 128476.03757377, 127783.72359256, 127561.33874562, + 127561.33874562, 127127.74631385, 126517.17672727, 126321.29147841, + 126321.29147841, 126100.68188908, 125794.70052372, 125697.42485608]) + static_pressure |5922.70488396| input lbf/ft**2 traj.climb.rhs_all.static_pressure + val: + array([2116.20959775, 2016.12977059, 1884.3708425 , 1844.15610466, + 1844.15610466, 1665.24595683, 1441.7823939 , 1376.36585521, + 1376.36585521, 1210.39642326, 1008.43217102, 950.5535796 , + 950.5535796 , 846.67538744, 718.65636826, 681.59186207, + 681.59186207, 641.89130933, 590.21664278, 574.58416126]) + mission:design:lift_coefficient [0.56736557] input unitless traj.climb.rhs_all.mission:design:lift_coefficient + mission:design:mach [0.80017085] input unitless traj.climb.rhs_all.mission:design:mach + aircraft:wing:area [1370.] input ft**2 traj.climb.rhs_all.aircraft:wing:area + aircraft:wing:aspect_ratio [11.22091] input unitless traj.climb.rhs_all.aircraft:wing:aspect_ratio + aircraft:wing:max_camber_at_70_semispan [0.] input unitless traj.climb.rhs_all.aircraft:wing:max_camber_at_70_semispan + aircraft:wing:sweep [25.] input deg traj.climb.rhs_all.aircraft:wing:sweep + aircraft:wing:thickness_to_chord [0.13] input unitless traj.climb.rhs_all.aircraft:wing:thickness_to_chord + CD |0.08027558| output unitless traj.climb.rhs_all.core_aerodynamics.PressureDrag.CD + val: + array([0.06048713, 0.03849179, 0.02182262, 0.01846069, 0.01846069, + 0.00912059, 0.00437262, 0.00368886, 0.00368886, 0.00232912, + 0.00128049, 0.00117909, 0.00117909, 0.00110638, 0.00098379, + 0.0009615 , 0.0009615 , 0.00094423, 0.0009321 , 0.00093247]) + InducedDrag + mach |2.22189137| input unitless traj.climb.rhs_all.mach + val: + array([0.2 , 0.22168851, 0.25161423, 0.26108562, 0.26108562, + 0.30537972, 0.36649654, 0.38583981, 0.38583981, 0.43850111, + 0.51116297, 0.53416019, 0.53416019, 0.5784543 , 0.63957112, + 0.65891438, 0.65891438, 0.68060289, 0.71052861, 0.72 ]) + lift |573448.30346328| input lbf traj.climb.rhs_all.core_aerodynamics.lift + val: + array([130904.19868796, 130630.94529647, 130291.65823087, 130190.10568305, + 130190.10568305, 129739.92902229, 129155.42419083, 128972.66448831, + 128972.66448831, 128476.03757377, 127783.72359256, 127561.33874562, + 127561.33874562, 127127.74631385, 126517.17672727, 126321.29147841, + 126321.29147841, 126100.68188908, 125794.70052372, 125697.42485608]) + static_pressure |5922.70488396| input lbf/ft**2 traj.climb.rhs_all.static_pressure + val: + array([2116.20959775, 2016.12977059, 1884.3708425 , 1844.15610466, + 1844.15610466, 1665.24595683, 1441.7823939 , 1376.36585521, + 1376.36585521, 1210.39642326, 1008.43217102, 950.5535796 , + 950.5535796 , 846.67538744, 718.65636826, 681.59186207, + 681.59186207, 641.89130933, 590.21664278, 574.58416126]) + aircraft:wing:area [1370.] input ft**2 traj.climb.rhs_all.aircraft:wing:area + aircraft:wing:aspect_ratio [11.22091] input unitless traj.climb.rhs_all.aircraft:wing:aspect_ratio + aircraft:wing:span_efficiency_factor [1.] input unitless traj.climb.rhs_all.aircraft:wing:span_efficiency_factor + aircraft:wing:sweep [25.] input deg traj.climb.rhs_all.aircraft:wing:sweep + aircraft:wing:taper_ratio [0.278] input unitless traj.climb.rhs_all.aircraft:wing:taper_ratio + induced_drag_coeff |0.11518843| output unitless traj.climb.rhs_all.core_aerodynamics.InducedDrag.induced_drag_coeff + val: + array([0.07376573, 0.05361265, 0.03679125, 0.03308367, 0.03308367, + 0.02152854, 0.01371928, 0.01222037, 0.01222037, 0.0093992 , + 0.00725446, 0.00682313, 0.00682313, 0.00621091, 0.00571328, + 0.00562048, 0.00562048, 0.00554781, 0.00549744, 0.00549288]) + CompressibilityDrag + mach |2.22189137| input unitless traj.climb.rhs_all.mach + val: + array([0.2 , 0.22168851, 0.25161423, 0.26108562, 0.26108562, + 0.30537972, 0.36649654, 0.38583981, 0.38583981, 0.43850111, + 0.51116297, 0.53416019, 0.53416019, 0.5784543 , 0.63957112, + 0.65891438, 0.65891438, 0.68060289, 0.71052861, 0.72 ]) + mission:design:mach [0.80017085] input unitless traj.climb.rhs_all.mission:design:mach + aircraft:design:base_area [0.] input ft**2 traj.climb.rhs_all.aircraft:design:base_area + aircraft:wing:area [1370.] input ft**2 traj.climb.rhs_all.aircraft:wing:area + aircraft:wing:aspect_ratio [11.22091] input unitless traj.climb.rhs_all.aircraft:wing:aspect_ratio + aircraft:wing:max_camber_at_70_semispan [0.] input unitless traj.climb.rhs_all.aircraft:wing:max_camber_at_70_semispan + aircraft:wing:sweep [25.] input deg traj.climb.rhs_all.aircraft:wing:sweep + aircraft:wing:taper_ratio [0.278] input unitless traj.climb.rhs_all.aircraft:wing:taper_ratio + aircraft:wing:thickness_to_chord [0.13] input unitless traj.climb.rhs_all.aircraft:wing:thickness_to_chord + aircraft:fuselage:cross_section [127.67628894] input ft**2 traj.climb.rhs_all.aircraft:fuselage:cross_section + aircraft:fuselage:diameter_to_wing_span [0.10826471] input unitless traj.climb.rhs_all.aircraft:fuselage:diameter_to_wing_span + aircraft:fuselage:length_to_diameter [10.03921569] input unitless traj.climb.rhs_all.aircraft:fuselage:length_to_diameter + compress_drag_coeff |0.00168953| output unitless traj.climb.rhs_all.core_aerodynamics.CompressibilityDrag.compress_drag_coeff + val: + array([0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, + 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, + 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, + 0.00000000e+00, 6.84397531e-05, 4.21572944e-04, 5.38360174e-04, + 5.38360174e-04, 6.74912191e-04, 8.66966315e-04, 9.40914533e-04]) + SkinFrictionCoef + temperature |2066.65858384| input degR traj.climb.rhs_all.temperature + val: + array([518.67 , 513.91084435, 507.34509901, 505.26655918, + 505.26655918, 495.5510144 , 482.14891569, 477.90852019, + 477.90852019, 466.36665517, 450.44612086, 445.40906345, + 445.40906345, 435.70829939, 422.32876215, 418.09508175, + 418.09508175, 413.34789509, 406.79997501, 404.72782123]) + static_pressure |5922.70488396| input lbf/ft**2 traj.climb.rhs_all.static_pressure + val: + array([2116.20959775, 2016.12977059, 1884.3708425 , 1844.15610466, + 1844.15610466, 1665.24595683, 1441.7823939 , 1376.36585521, + 1376.36585521, 1210.39642326, 1008.43217102, 950.5535796 , + 950.5535796 , 846.67538744, 718.65636826, 681.59186207, + 681.59186207, 641.89130933, 590.21664278, 574.58416126]) + mach |2.22189137| input unitless traj.climb.rhs_all.mach + val: + array([0.2 , 0.22168851, 0.25161423, 0.26108562, 0.26108562, + 0.30537972, 0.36649654, 0.38583981, 0.38583981, 0.43850111, + 0.51116297, 0.53416019, 0.53416019, 0.5784543 , 0.63957112, + 0.65891438, 0.65891438, 0.68060289, 0.71052861, 0.72 ]) + characteristic_lengths |130.45376144| input ft traj.climb.rhs_all.core_aerodynamics.characteristic_lengths + val: + array([ 10.49530819, 7.69198717, 12.73914103, 128. , + 12.3 , 12.3 ]) + cf_iter |0.02765794| output unitless traj.climb.rhs_all.core_aerodynamics.SkinFrictionCoef.cf_iter + val: + array([[0.00275238, 0.00289295, 0.00266959, 0.00190747, 0.00268432, + 0.00268432], + [0.00272469, 0.00286322, 0.00264309, 0.00189109, 0.0026576 , + 0.0026576 ], + [0.00269395, 0.00283024, 0.00261365, 0.00187287, 0.00262794, + 0.00262794], + [0.00268571, 0.0028214 , 0.00260576, 0.00186798, 0.00261999, + 0.00261999], + [0.00268571, 0.0028214 , 0.00260576, 0.00186798, 0.00261999, + 0.00261999], + [0.00265482, 0.00278826, 0.00257618, 0.00184962, 0.00259017, + 0.00259017], + [0.00262816, 0.00275967, 0.00255063, 0.00183373, 0.00256443, + 0.00256443], + [0.00262272, 0.00275383, 0.00254542, 0.00183049, 0.00255917, + 0.00255917], + [0.00262272, 0.00275383, 0.00254542, 0.00183049, 0.00255917, + 0.00255917], + [0.00261376, 0.00274423, 0.00253683, 0.00182515, 0.00255052, + 0.00255052], + [0.00261303, 0.00274344, 0.00253614, 0.00182474, 0.00254982, + 0.00254982], + [0.00261518, 0.00274575, 0.0025382 , 0.00182603, 0.0025519 , + 0.0025519 ], + [0.00261518, 0.00274575, 0.0025382 , 0.00182603, 0.0025519 , + 0.0025519 ], + [0.00262218, 0.00275325, 0.00254491, 0.00183022, 0.00255866, + 0.00255866], + [0.0026375 , 0.00276967, 0.00255959, 0.00183939, 0.00257345, + 0.00257345], + [0.00264363, 0.00277624, 0.00256546, 0.00184305, 0.00257937, + 0.00257937], + [0.00264363, 0.00277624, 0.00256546, 0.00184305, 0.00257937, + 0.00257937], + [0.0026512 , 0.00278435, 0.00257272, 0.00184757, 0.00258668, + 0.00258668], + [0.00266284, 0.00279683, 0.00258387, 0.00185451, 0.00259792, + 0.00259792], + [0.00266681, 0.00280109, 0.00258767, 0.00185688, 0.00260175, + 0.00260175]]) + skin_friction_coeff |0.02700108| output unitless traj.climb.rhs_all.core_aerodynamics.skin_friction_coeff + val: + array([[0.00275142, 0.00289141, 0.00266898, 0.0019099 , 0.00268364, + 0.00268364], + [0.00272014, 0.00285796, 0.00263896, 0.00189079, 0.0026534 , + 0.0026534 ], + [0.0026843 , 0.00281966, 0.00260455, 0.00186876, 0.00261874, + 0.00261874], + [0.0026744 , 0.00280909, 0.00259504, 0.00186264, 0.00260916, + 0.00260916], + [0.0026744 , 0.00280909, 0.00259504, 0.00186264, 0.00260916, + 0.00260916], + [0.00263531, 0.00276739, 0.00255747, 0.00183829, 0.00257131, + 0.00257131], + [0.00259601, 0.00272557, 0.00251963, 0.00181333, 0.00253322, + 0.00253322], + [0.00258622, 0.00271518, 0.00251019, 0.00180698, 0.00252372, + 0.00252372], + [0.00258622, 0.00271518, 0.00251019, 0.00180698, 0.00252372, + 0.00252372], + [0.00256449, 0.00269219, 0.0024892 , 0.0017926 , 0.0025026 , + 0.0025026 ], + [0.00254382, 0.00267048, 0.00246914, 0.00177815, 0.00248243, + 0.00248243], + [0.00253908, 0.00266555, 0.00246451, 0.00177461, 0.00247778, + 0.00247778], + [0.00253908, 0.00266555, 0.00246451, 0.00177461, 0.00247778, + 0.00247778], + [0.00253198, 0.00265825, 0.00245753, 0.00176896, 0.00247078, + 0.00247078], + [0.00252603, 0.00265233, 0.00245158, 0.00176333, 0.00246483, + 0.00246483], + [0.00252498, 0.00265136, 0.00245049, 0.00176201, 0.00246374, + 0.00246374], + [0.00252498, 0.00265136, 0.00245049, 0.00176201, 0.00246374, + 0.00246374], + [0.00252424, 0.00265074, 0.00244969, 0.00176078, 0.00246295, + 0.00246295], + [0.00252395, 0.00265068, 0.00244927, 0.00175948, 0.00246256, + 0.00246256], + [0.00252403, 0.00265084, 0.0024493 , 0.00175916, 0.0024626 , + 0.0024626 ]]) + Re |1107669904.6272902| output unitless traj.climb.rhs_all.core_aerodynamics.Re + val: + array([[1.49048396e+07, 1.09237226e+07, 1.80914034e+07, 1.81778318e+08, + 1.74677603e+07, 1.74677603e+07], + [1.59263513e+07, 1.16723862e+07, 1.93313080e+07, 1.94236599e+08, + 1.86649232e+07, 1.86649232e+07], + [1.71753244e+07, 1.25877557e+07, 2.08473040e+07, 2.09468982e+08, + 2.01286600e+07, 2.01286600e+07], + [1.75335338e+07, 1.28502865e+07, 2.12820963e+07, 2.13837677e+08, + 2.05484643e+07, 2.05484643e+07], + [1.75335338e+07, 1.28502865e+07, 2.12820963e+07, 2.13837677e+08, + 2.05484643e+07, 2.05484643e+07], + [1.89861298e+07, 1.39148908e+07, 2.30452485e+07, 2.31553430e+08, + 2.22508374e+07, 2.22508374e+07], + [2.04379008e+07, 1.49788904e+07, 2.48073993e+07, 2.49259122e+08, + 2.39522438e+07, 2.39522438e+07], + [2.07762539e+07, 1.52268686e+07, 2.52180903e+07, 2.53385652e+08, + 2.43487775e+07, 2.43487775e+07], + [2.07762539e+07, 1.52268686e+07, 2.52180903e+07, 2.53385652e+08, + 2.43487775e+07, 2.43487775e+07], + [2.14332068e+07, 1.57083478e+07, 2.60154956e+07, 2.61397800e+08, + 2.51186948e+07, 2.51186948e+07], + [2.17791933e+07, 1.59619205e+07, 2.64354519e+07, 2.65617425e+08, + 2.55241745e+07, 2.55241745e+07], + [2.17705043e+07, 1.59555524e+07, 2.64249053e+07, 2.65511455e+08, + 2.55139914e+07, 2.55139914e+07], + [2.17705043e+07, 1.59555524e+07, 2.64249053e+07, 2.65511455e+08, + 2.55139914e+07, 2.55139914e+07], + [2.16143630e+07, 1.58411168e+07, 2.62353819e+07, 2.63607167e+08, + 2.53310012e+07, 2.53310012e+07], + [2.11348941e+07, 1.54897151e+07, 2.56534055e+07, 2.57759600e+08, + 2.47690866e+07, 2.47690866e+07], + [2.09278119e+07, 1.53379451e+07, 2.54020504e+07, 2.55234041e+08, + 2.45263961e+07, 2.45263961e+07], + [2.09278119e+07, 1.53379451e+07, 2.54020504e+07, 2.55234041e+08, + 2.45263961e+07, 2.45263961e+07], + [2.06675501e+07, 1.51471998e+07, 2.50861462e+07, 2.52059907e+08, + 2.42213817e+07, 2.42213817e+07], + [2.02640027e+07, 1.48514408e+07, 2.45963228e+07, 2.47138273e+08, + 2.37484434e+07, 2.37484434e+07], + [2.01263640e+07, 1.47505658e+07, 2.44292579e+07, 2.45459643e+08, + 2.35871375e+07, 2.35871375e+07]]) + wall_temp |5223.80281063| output degR traj.climb.rhs_all.core_aerodynamics.SkinFrictionCoef.wall_temp + val: + array([[517.45689455, 517.66707174, 517.32335332, 515.58822228, + 517.3476737 , 517.3476737 ], + [513.854417 , 514.0486032 , 513.73102617, 512.12694876, + 513.75349856, 513.75349856], + [508.89835549, 509.07488197, 508.78617651, 507.32703495, + 508.80660754, 508.80660754], + [507.33691225, 507.50868154, 507.22775391, 505.80769049, + 507.24763494, 507.24763494], + [507.33691225, 507.50868154, 507.22775391, 505.80769049, + 507.24763494, 507.24763494], + [500.11106052, 500.26454358, 500.01351449, 498.74379226, + 500.03128108, 500.03128108], + [490.37943577, 490.51525847, 490.2931062 , 489.16874675, + 490.30883032, 490.30883032], + [487.36237489, 487.49388997, 487.27878132, 486.18989638, + 487.29400722, 487.29400722], + [487.36237489, 487.49388997, 487.27878132, 486.18989638, + 487.29400722, 487.29400722], + [479.30136684, 479.4234047 , 479.22379274, 478.2129665 , + 479.23792251, 479.23792251], + [468.52528202, 468.6382647 , 468.45345876, 467.51719419, + 468.46654134, 468.46654134], + [465.19176552, 465.30261739, 465.12129528, 464.20256275, + 465.1341315 , 465.1341315 ], + [465.19176552, 465.30261739, 465.12129528, 464.20256275, + 465.1341315 , 465.1341315 ], + [458.86276147, 458.97030016, 458.79439463, 457.90289629, + 458.80684787, 458.80684787], + [450.30606285, 450.41046911, 450.2396836 , 449.37386472, + 450.25177501, 450.25177501], + [447.63366089, 447.73737307, 447.56772169, 446.70757004, + 447.57973301, 447.57973301], + [447.63366089, 447.73737307, 447.56772169, 446.70757004, + 447.57973301, 447.57973301], + [444.65385165, 444.75693768, 444.58830918, 443.73325265, + 444.60024831, 444.60024831], + [440.57008048, 440.67255101, 440.50492745, 439.65484333, + 440.51679574, 440.51679574], + [439.28316759, 439.38550012, 439.2181017 , 438.36912071, + 439.22995416, 439.22995416]]) + SkinFrictionDrag + skin_friction_coeff |0.02700108| input unitless traj.climb.rhs_all.core_aerodynamics.skin_friction_coeff + val: + array([[0.00275142, 0.00289141, 0.00266898, 0.0019099 , 0.00268364, + 0.00268364], + [0.00272014, 0.00285796, 0.00263896, 0.00189079, 0.0026534 , + 0.0026534 ], + [0.0026843 , 0.00281966, 0.00260455, 0.00186876, 0.00261874, + 0.00261874], + [0.0026744 , 0.00280909, 0.00259504, 0.00186264, 0.00260916, + 0.00260916], + [0.0026744 , 0.00280909, 0.00259504, 0.00186264, 0.00260916, + 0.00260916], + [0.00263531, 0.00276739, 0.00255747, 0.00183829, 0.00257131, + 0.00257131], + [0.00259601, 0.00272557, 0.00251963, 0.00181333, 0.00253322, + 0.00253322], + [0.00258622, 0.00271518, 0.00251019, 0.00180698, 0.00252372, + 0.00252372], + [0.00258622, 0.00271518, 0.00251019, 0.00180698, 0.00252372, + 0.00252372], + [0.00256449, 0.00269219, 0.0024892 , 0.0017926 , 0.0025026 , + 0.0025026 ], + [0.00254382, 0.00267048, 0.00246914, 0.00177815, 0.00248243, + 0.00248243], + [0.00253908, 0.00266555, 0.00246451, 0.00177461, 0.00247778, + 0.00247778], + [0.00253908, 0.00266555, 0.00246451, 0.00177461, 0.00247778, + 0.00247778], + [0.00253198, 0.00265825, 0.00245753, 0.00176896, 0.00247078, + 0.00247078], + [0.00252603, 0.00265233, 0.00245158, 0.00176333, 0.00246483, + 0.00246483], + [0.00252498, 0.00265136, 0.00245049, 0.00176201, 0.00246374, + 0.00246374], + [0.00252498, 0.00265136, 0.00245049, 0.00176201, 0.00246374, + 0.00246374], + [0.00252424, 0.00265074, 0.00244969, 0.00176078, 0.00246295, + 0.00246295], + [0.00252395, 0.00265068, 0.00244927, 0.00175948, 0.00246256, + 0.00246256], + [0.00252403, 0.00265084, 0.0024493 , 0.00175916, 0.0024626 , + 0.0024626 ]]) + Re |1107669904.6272902| input unitless traj.climb.rhs_all.core_aerodynamics.Re + val: + array([[1.49048396e+07, 1.09237226e+07, 1.80914034e+07, 1.81778318e+08, + 1.74677603e+07, 1.74677603e+07], + [1.59263513e+07, 1.16723862e+07, 1.93313080e+07, 1.94236599e+08, + 1.86649232e+07, 1.86649232e+07], + [1.71753244e+07, 1.25877557e+07, 2.08473040e+07, 2.09468982e+08, + 2.01286600e+07, 2.01286600e+07], + [1.75335338e+07, 1.28502865e+07, 2.12820963e+07, 2.13837677e+08, + 2.05484643e+07, 2.05484643e+07], + [1.75335338e+07, 1.28502865e+07, 2.12820963e+07, 2.13837677e+08, + 2.05484643e+07, 2.05484643e+07], + [1.89861298e+07, 1.39148908e+07, 2.30452485e+07, 2.31553430e+08, + 2.22508374e+07, 2.22508374e+07], + [2.04379008e+07, 1.49788904e+07, 2.48073993e+07, 2.49259122e+08, + 2.39522438e+07, 2.39522438e+07], + [2.07762539e+07, 1.52268686e+07, 2.52180903e+07, 2.53385652e+08, + 2.43487775e+07, 2.43487775e+07], + [2.07762539e+07, 1.52268686e+07, 2.52180903e+07, 2.53385652e+08, + 2.43487775e+07, 2.43487775e+07], + [2.14332068e+07, 1.57083478e+07, 2.60154956e+07, 2.61397800e+08, + 2.51186948e+07, 2.51186948e+07], + [2.17791933e+07, 1.59619205e+07, 2.64354519e+07, 2.65617425e+08, + 2.55241745e+07, 2.55241745e+07], + [2.17705043e+07, 1.59555524e+07, 2.64249053e+07, 2.65511455e+08, + 2.55139914e+07, 2.55139914e+07], + [2.17705043e+07, 1.59555524e+07, 2.64249053e+07, 2.65511455e+08, + 2.55139914e+07, 2.55139914e+07], + [2.16143630e+07, 1.58411168e+07, 2.62353819e+07, 2.63607167e+08, + 2.53310012e+07, 2.53310012e+07], + [2.11348941e+07, 1.54897151e+07, 2.56534055e+07, 2.57759600e+08, + 2.47690866e+07, 2.47690866e+07], + [2.09278119e+07, 1.53379451e+07, 2.54020504e+07, 2.55234041e+08, + 2.45263961e+07, 2.45263961e+07], + [2.09278119e+07, 1.53379451e+07, 2.54020504e+07, 2.55234041e+08, + 2.45263961e+07, 2.45263961e+07], + [2.06675501e+07, 1.51471998e+07, 2.50861462e+07, 2.52059907e+08, + 2.42213817e+07, 2.42213817e+07], + [2.02640027e+07, 1.48514408e+07, 2.45963228e+07, 2.47138273e+08, + 2.37484434e+07, 2.37484434e+07], + [2.01263640e+07, 1.47505658e+07, 2.44292579e+07, 2.45459643e+08, + 2.35871375e+07, 2.35871375e+07]]) + fineness_ratios |10.2777523| input unitless traj.climb.rhs_all.core_aerodynamics.fineness_ratios + val: + array([ 0.13 , 0.125 , 0.1195 , 10.03921569, 1.54911839, + 1.54911839]) + wetted_areas |4886.31967641| input ft**2 traj.climb.rhs_all.core_aerodynamics.wetted_areas + val: + array([2396.56 , 592.65 , 581.13 , 4158.62 , 273.4536, 273.4536]) + laminar_fractions_upper |0.0| input unitless traj.climb.rhs_all.core_aerodynamics.laminar_fractions_upper + val: + array([0., 0., 0., 0., 0., 0.]) + laminar_fractions_lower |0.0| input unitless traj.climb.rhs_all.core_aerodynamics.laminar_fractions_lower + val: + array([0., 0., 0., 0., 0., 0.]) + aircraft:wing:area [1370.] input ft**2 traj.climb.rhs_all.aircraft:wing:area + skin_friction_drag_coeff |0.09198219| output unitless traj.climb.rhs_all.core_aerodynamics.SkinFrictionDrag.skin_friction_drag_coeff + val: + array([0.02181828, 0.02157963, 0.02130564, 0.02122983, 0.02122983, + 0.02092983, 0.02062655, 0.02055053, 0.02055053, 0.02038073, + 0.02021645, 0.02017796, 0.02017796, 0.02011904, 0.02006652, + 0.02005606, 0.02005606, 0.02004762, 0.02004138, 0.02004067]) + Drag + CDI + induced_drag_coeff |0.11518843| input unitless traj.climb.rhs_all.core_aerodynamics.Drag.induced_drag_coeff + val: + array([0.07376573, 0.05361265, 0.03679125, 0.03308367, 0.03308367, + 0.02152854, 0.01371928, 0.01222037, 0.01222037, 0.0093992 , + 0.00725446, 0.00682313, 0.00682313, 0.00621091, 0.00571328, + 0.00562048, 0.00562048, 0.00554781, 0.00549744, 0.00549288]) + pressure_drag_coeff |0.08027558| input unitless traj.climb.rhs_all.core_aerodynamics.Drag.pressure_drag_coeff + val: + array([0.06048713, 0.03849179, 0.02182262, 0.01846069, 0.01846069, + 0.00912059, 0.00437262, 0.00368886, 0.00368886, 0.00232912, + 0.00128049, 0.00117909, 0.00117909, 0.00110638, 0.00098379, + 0.0009615 , 0.0009615 , 0.00094423, 0.0009321 , 0.00093247]) + CDI |0.19410682| output unitless traj.climb.rhs_all.core_aerodynamics.CDI + val: + array([0.13425286, 0.09210444, 0.05861387, 0.05154436, 0.05154436, + 0.03064913, 0.01809189, 0.01590923, 0.01590923, 0.01172832, + 0.00853495, 0.00800222, 0.00800222, 0.00731729, 0.00669708, + 0.00658197, 0.00658197, 0.00649204, 0.00642953, 0.00642535]) + CD0 + compress_drag_coeff |0.00168953| input unitless traj.climb.rhs_all.core_aerodynamics.Drag.compress_drag_coeff + val: + array([0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, + 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, + 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, + 0.00000000e+00, 6.84397531e-05, 4.21572944e-04, 5.38360174e-04, + 5.38360174e-04, 6.74912191e-04, 8.66966315e-04, 9.40914533e-04]) + skin_friction_drag_coeff |0.09198219| input unitless traj.climb.rhs_all.core_aerodynamics.Drag.skin_friction_drag_coeff + val: + array([0.02181828, 0.02157963, 0.02130564, 0.02122983, 0.02122983, + 0.02092983, 0.02062655, 0.02055053, 0.02055053, 0.02038073, + 0.02021645, 0.02017796, 0.02017796, 0.02011904, 0.02006652, + 0.02005606, 0.02005606, 0.02004762, 0.02004138, 0.02004067]) + CD0 |0.09287608| output unitless traj.climb.rhs_all.core_aerodynamics.CD0 + val: + array([0.02181828, 0.02157963, 0.02130564, 0.02122983, 0.02122983, + 0.02092983, 0.02062655, 0.02055053, 0.02055053, 0.02038073, + 0.02021645, 0.02017796, 0.02017796, 0.02018748, 0.02048809, + 0.02059442, 0.02059442, 0.02072253, 0.02090835, 0.02098159]) + drag + total_drag_coeff + CD0 |0.09287608| input unitless traj.climb.rhs_all.core_aerodynamics.Drag.CD0 + val: + array([0.02181828, 0.02157963, 0.02130564, 0.02122983, 0.02122983, + 0.02092983, 0.02062655, 0.02055053, 0.02055053, 0.02038073, + 0.02021645, 0.02017796, 0.02017796, 0.02018748, 0.02048809, + 0.02059442, 0.02059442, 0.02072253, 0.02090835, 0.02098159]) + CDI |0.19410682| input unitless traj.climb.rhs_all.core_aerodynamics.Drag.CDI + val: + array([0.13425286, 0.09210444, 0.05861387, 0.05154436, 0.05154436, + 0.03064913, 0.01809189, 0.01590923, 0.01590923, 0.01172832, + 0.00853495, 0.00800222, 0.00800222, 0.00731729, 0.00669708, + 0.00658197, 0.00658197, 0.00649204, 0.00642953, 0.00642535]) + FCD0 [0.93089003] input unitless traj.climb.rhs_all.aircraft:design:zero_lift_drag_coeff_factor + FCDI [0.90983938] input unitless traj.climb.rhs_all.aircraft:design:lift_dependent_drag_coeff_factor + CD_prescaled |0.24189295| output unitless traj.climb.rhs_all.core_aerodynamics.Drag.drag.CD_prescaled + val: + array([0.14245896, 0.10388851, 0.07316241, 0.06665972, 0.06665972, + 0.04736916, 0.03566177, 0.03360513, 0.03360513, 0.0296431 , + 0.02658473, 0.0260642 , 0.0260642 , 0.02544989, 0.02516542, + 0.02515968, 0.02515968, 0.02519711, 0.02531322, 0.02537759]) + simple_CD + aircraft:design:subsonic_drag_coeff_factor [1.] input unitless traj.climb.rhs_all.aircraft:design:subsonic_drag_coeff_factor + aircraft:design:supersonic_drag_coeff_factor [1.] input unitless traj.climb.rhs_all.aircraft:design:supersonic_drag_coeff_factor + mach |2.22189137| input unitless traj.climb.rhs_all.mach + val: + array([0.2 , 0.22168851, 0.25161423, 0.26108562, 0.26108562, + 0.30537972, 0.36649654, 0.38583981, 0.38583981, 0.43850111, + 0.51116297, 0.53416019, 0.53416019, 0.5784543 , 0.63957112, + 0.65891438, 0.65891438, 0.68060289, 0.71052861, 0.72 ]) + CD_prescaled |0.24189295| input unitless traj.climb.rhs_all.core_aerodynamics.Drag.drag.CD_prescaled + val: + array([0.14245896, 0.10388851, 0.07316241, 0.06665972, 0.06665972, + 0.04736916, 0.03566177, 0.03360513, 0.03360513, 0.0296431 , + 0.02658473, 0.0260642 , 0.0260642 , 0.02544989, 0.02516542, + 0.02515968, 0.02515968, 0.02519711, 0.02531322, 0.02537759]) + CD |0.24189295| output unitless traj.climb.rhs_all.core_aerodynamics.CD + val: + array([0.14245896, 0.10388851, 0.07316241, 0.06665972, 0.06665972, + 0.04736916, 0.03566177, 0.03360513, 0.03360513, 0.0296431 , + 0.02658473, 0.0260642 , 0.0260642 , 0.02544989, 0.02516542, + 0.02515968, 0.02515968, 0.02519711, 0.02531322, 0.02537759]) + simple_drag + aircraft:wing:area [127.2771648] input m**2 traj.climb.rhs_all.aircraft:wing:area + dynamic_pressure |34941.60514958| input N/m**2 traj.climb.rhs_all.core_aerodynamics.dynamic_pressure + val: + array([2837.09058373, 3320.92742596, 3998.4465899 , 4213.25847322, + 4213.25847322, 5204.91091948, 6490.73694453, 6867.56030763, + 6867.56030763, 7800.52010707, 8831.20540436, 9090.215421 , + 9090.215421 , 9495.31922842, 9852.66004282, 9918.29233157, + 9918.29233157, 9965.60365807, 9986.86376675, 9983.27821833]) + CD |0.24189295| input unitless traj.climb.rhs_all.core_aerodynamics.Drag.drag.CD + val: + array([0.14245896, 0.10388851, 0.07316241, 0.06665972, 0.06665972, + 0.04736916, 0.03566177, 0.03360513, 0.03360513, 0.0296431 , + 0.02658473, 0.0260642 , 0.0260642 , 0.02544989, 0.02516542, + 0.02515968, 0.02515968, 0.02519711, 0.02531322, 0.02537759]) + drag |150759.28928049| output N traj.climb.rhs_all.drag + val: + array([51441.48042457, 43911.41111041, 37233.15286355, 35746.38288226, + 35746.38288226, 31380.47324171, 29460.99199568, 29373.69267134, + 29373.69267134, 29430.50374299, 29881.51771429, 30155.67367994, + 30155.67367994, 30757.1359626 , 31557.90749055, 31760.88321635, + 31760.88321635, 31959.85759632, 32175.62183799, 32245.86305683]) + Buffet + mach |2.22189137| input unitless traj.climb.rhs_all.mach + val: + array([0.2 , 0.22168851, 0.25161423, 0.26108562, 0.26108562, + 0.30537972, 0.36649654, 0.38583981, 0.38583981, 0.43850111, + 0.51116297, 0.53416019, 0.53416019, 0.5784543 , 0.63957112, + 0.65891438, 0.65891438, 0.68060289, 0.71052861, 0.72 ]) + mission:design:mach [0.80017085] input unitless traj.climb.rhs_all.mission:design:mach + aircraft:wing:aspect_ratio [11.22091] input unitless traj.climb.rhs_all.aircraft:wing:aspect_ratio + aircraft:wing:max_camber_at_70_semispan [0.] input unitless traj.climb.rhs_all.aircraft:wing:max_camber_at_70_semispan + aircraft:wing:sweep [25.] input deg traj.climb.rhs_all.aircraft:wing:sweep + aircraft:wing:thickness_to_chord [0.13] input unitless traj.climb.rhs_all.aircraft:wing:thickness_to_chord + DELCLB |2.82576417| output unitless traj.climb.rhs_all.core_aerodynamics.Buffet.DELCLB + val: + array([0.86560792, 0.85224899, 0.83173953, 0.82475258, 0.82475258, + 0.78891304, 0.73090207, 0.71047393, 0.71047393, 0.64533429, + 0.55812083, 0.53350129, 0.53350129, 0.4823821 , 0.41244945, + 0.38579137, 0.38579137, 0.35159113, 0.29970276, 0.28257367]) + core_propulsion + turbofan_28k + interpolation + mach |2.22189137| input unitless traj.climb.rhs_all.mach + val: + array([0.2 , 0.22168851, 0.25161423, 0.26108562, 0.26108562, + 0.30537972, 0.36649654, 0.38583981, 0.38583981, 0.43850111, + 0.51116297, 0.53416019, 0.53416019, 0.5784543 , 0.63957112, + 0.65891438, 0.65891438, 0.68060289, 0.71052861, 0.72 ]) + altitude |87358.6369253| input ft traj.climb.rhs_all.altitude + val: + array([ 0. , 1334.67757163, 3176.26020893, 3759.11481713, + 3759.11481713, 6484.90577713, 10245.94096014, 11436.29573631, + 11436.29573631, 14676.99149614, 19148.49020934, 20563.70426369, + 20563.70426369, 23289.4952237 , 27050.5304067 , 28240.88518287, + 28240.88518287, 29575.5627545 , 31417.1453918 , 32000. ]) + throttle |2.27639903| input unitless traj.climb.rhs_all.throttle + val: + array([0.36272519, 0.34217892, 0.32721108, 0.32475961, 0.32475961, + 0.32505412, 0.34982841, 0.36112935, 0.36112935, 0.40082952, + 0.46816406, 0.49426945, 0.49426945, 0.54853485, 0.63668329, + 0.6672203 , 0.6672203 , 0.70468433, 0.75486115, 0.77136189]) + fuel_flow_rate_unscaled |11208.88451868| output lbm/h traj.climb.rhs_all.turbofan_28k.interpolation.fuel_flow_rate_unscaled + val: + array([3239.56199085, 2918.98793851, 2639.60346984, 2577.53239335, + 2577.53239335, 2393.40610099, 2299.95148918, 2296.43887466, + 2296.43887466, 2304.20682221, 2346.79843317, 2363.50900188, + 2363.50900188, 2407.78889133, 2460.8909312 , 2474.53935068, + 2474.53935068, 2484.43200533, 2500.59248016, 2507.76511382]) + nox_rate_unscaled |58.65166043| output lbm/h traj.climb.rhs_all.turbofan_28k.interpolation.nox_rate_unscaled + val: + array([13.84282768, 13.22353665, 12.59493128, 12.44304625, 12.44304625, + 12.0221227 , 12.15639189, 12.24459752, 12.24459752, 12.56052319, + 12.86332862, 13.12504521, 13.12504521, 13.37192625, 13.76383712, + 13.84749833, 13.84749833, 13.96635966, 14.09873028, 14.13201018]) + thrust_net_unscaled |24207.42074097| output lbf traj.climb.rhs_all.turbofan_28k.interpolation.thrust_net_unscaled + val: + array([8532.57300146, 7450.68156717, 6441.96803141, 6205.50413313, + 6205.50413313, 5447.41128948, 4968.24516058, 4892.23703914, + 4892.23703914, 4747.51070881, 4639.74635182, 4629.13254482, + 4629.13254482, 4625.89901783, 4633.63504935, 4633.44613673, + 4633.44613673, 4631.49947216, 4624.52153368, 4623.04453842]) + interp_max_throttles + mach |2.22189137| input unitless traj.climb.rhs_all.mach + val: + array([0.2 , 0.22168851, 0.25161423, 0.26108562, 0.26108562, + 0.30537972, 0.36649654, 0.38583981, 0.38583981, 0.43850111, + 0.51116297, 0.53416019, 0.53416019, 0.5784543 , 0.63957112, + 0.65891438, 0.65891438, 0.68060289, 0.71052861, 0.72 ]) + altitude |87358.6369253| input ft traj.climb.rhs_all.altitude + val: + array([ 0. , 1334.67757163, 3176.26020893, 3759.11481713, + 3759.11481713, 6484.90577713, 10245.94096014, 11436.29573631, + 11436.29573631, 14676.99149614, 19148.49020934, 20563.70426369, + 20563.70426369, 23289.4952237 , 27050.5304067 , 28240.88518287, + 28240.88518287, 29575.5627545 , 31417.1453918 , 32000. ]) + throttle_max |4.47213595| output unitless traj.climb.rhs_all.turbofan_28k.throttle_max + val: + array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + 1., 1., 1.]) + max_interpolation + mach |2.22189137| input unitless traj.climb.rhs_all.mach + val: + array([0.2 , 0.22168851, 0.25161423, 0.26108562, 0.26108562, + 0.30537972, 0.36649654, 0.38583981, 0.38583981, 0.43850111, + 0.51116297, 0.53416019, 0.53416019, 0.5784543 , 0.63957112, + 0.65891438, 0.65891438, 0.68060289, 0.71052861, 0.72 ]) + altitude |87358.6369253| input ft traj.climb.rhs_all.altitude + val: + array([ 0. , 1334.67757163, 3176.26020893, 3759.11481713, + 3759.11481713, 6484.90577713, 10245.94096014, 11436.29573631, + 11436.29573631, 14676.99149614, 19148.49020934, 20563.70426369, + 20563.70426369, 23289.4952237 , 27050.5304067 , 28240.88518287, + 28240.88518287, 29575.5627545 , 31417.1453918 , 32000. ]) + throttle_max |4.47213595| input unitless traj.climb.rhs_all.throttle_max + val: + array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + 1., 1., 1.]) + thrust_net_max_unscaled |68847.2855466| output lbf traj.climb.rhs_all.turbofan_28k.max_interpolation.thrust_net_max_unscaled + val: + array([26469. , 24792.97627383, 22635.23967936, 22005.94254328, + 22005.94254328, 19296.17450843, 16096.80803552, 15256.52557923, + 15256.52557923, 13082.84267052, 10678.74368018, 10014.48915139, + 10014.48915139, 8896.88333758, 7550.59501168, 7170.84981635, + 7170.84981635, 6751.56561794, 6254.90218295, 6107.972 ]) + engine_scaling + aircraft:engine:scale_factor [1.] input unitless traj.climb.rhs_all.aircraft:engine:scale_factor + mach |2.22189137| input unitless traj.climb.rhs_all.mach + val: + array([0.2 , 0.22168851, 0.25161423, 0.26108562, 0.26108562, + 0.30537972, 0.36649654, 0.38583981, 0.38583981, 0.43850111, + 0.51116297, 0.53416019, 0.53416019, 0.5784543 , 0.63957112, + 0.65891438, 0.65891438, 0.68060289, 0.71052861, 0.72 ]) + fuel_flow_rate_unscaled |11208.88451868| input lbm/h traj.climb.rhs_all.engine_scaling.fuel_flow_rate_unscaled + val: + array([3239.56199085, 2918.98793851, 2639.60346984, 2577.53239335, + 2577.53239335, 2393.40610099, 2299.95148918, 2296.43887466, + 2296.43887466, 2304.20682221, 2346.79843317, 2363.50900188, + 2363.50900188, 2407.78889133, 2460.8909312 , 2474.53935068, + 2474.53935068, 2484.43200533, 2500.59248016, 2507.76511382]) + nox_rate_unscaled |58.65166043| input lbm/h traj.climb.rhs_all.engine_scaling.nox_rate_unscaled + val: + array([13.84282768, 13.22353665, 12.59493128, 12.44304625, 12.44304625, + 12.0221227 , 12.15639189, 12.24459752, 12.24459752, 12.56052319, + 12.86332862, 13.12504521, 13.12504521, 13.37192625, 13.76383712, + 13.84749833, 13.84749833, 13.96635966, 14.09873028, 14.13201018]) + thrust_net_unscaled |24207.42074097| input lbf traj.climb.rhs_all.engine_scaling.thrust_net_unscaled + val: + array([8532.57300146, 7450.68156717, 6441.96803141, 6205.50413313, + 6205.50413313, 5447.41128948, 4968.24516058, 4892.23703914, + 4892.23703914, 4747.51070881, 4639.74635182, 4629.13254482, + 4629.13254482, 4625.89901783, 4633.63504935, 4633.44613673, + 4633.44613673, 4631.49947216, 4624.52153368, 4623.04453842]) + thrust_net_max_unscaled |68847.2855466| input lbf traj.climb.rhs_all.engine_scaling.thrust_net_max_unscaled + val: + array([26469. , 24792.97627383, 22635.23967936, 22005.94254328, + 22005.94254328, 19296.17450843, 16096.80803552, 15256.52557923, + 15256.52557923, 13082.84267052, 10678.74368018, 10014.48915139, + 10014.48915139, 8896.88333758, 7550.59501168, 7170.84981635, + 7170.84981635, 6751.56561794, 6254.90218295, 6107.972 ]) + fuel_flow_rate_negative |11208.88451868| output lbm/h traj.climb.rhs_all.turbofan_28k.fuel_flow_rate_negative + val: + array([-3239.56199085, -2918.98793851, -2639.60346984, -2577.53239335, + -2577.53239335, -2393.40610099, -2299.95148918, -2296.43887466, + -2296.43887466, -2304.20682221, -2346.79843317, -2363.50900188, + -2363.50900188, -2407.78889133, -2460.8909312 , -2474.53935068, + -2474.53935068, -2484.43200533, -2500.59248016, -2507.76511382]) + nox_rate |58.65166043| output lbm/h traj.climb.rhs_all.turbofan_28k.nox_rate + val: + array([13.84282768, 13.22353665, 12.59493128, 12.44304625, 12.44304625, + 12.0221227 , 12.15639189, 12.24459752, 12.24459752, 12.56052319, + 12.86332862, 13.12504521, 13.12504521, 13.37192625, 13.76383712, + 13.84749833, 13.84749833, 13.96635966, 14.09873028, 14.13201018]) + thrust_net |24207.42074097| output lbf traj.climb.rhs_all.turbofan_28k.thrust_net + val: + array([8532.57300146, 7450.68156717, 6441.96803141, 6205.50413313, + 6205.50413313, 5447.41128948, 4968.24516058, 4892.23703914, + 4892.23703914, 4747.51070881, 4639.74635182, 4629.13254482, + 4629.13254482, 4625.89901783, 4633.63504935, 4633.44613673, + 4633.44613673, 4631.49947216, 4624.52153368, 4623.04453842]) + thrust_net_max |68847.2855466| output lbf traj.climb.rhs_all.turbofan_28k.thrust_net_max + val: + array([26469. , 24792.97627383, 22635.23967936, 22005.94254328, + 22005.94254328, 19296.17450843, 16096.80803552, 15256.52557923, + 15256.52557923, 13082.84267052, 10678.74368018, 10014.48915139, + 10014.48915139, 8896.88333758, 7550.59501168, 7170.84981635, + 7170.84981635, 6751.56561794, 6254.90218295, 6107.972 ]) + vectorize_performance + thrust_net_0 |24207.42074097| input lbf traj.climb.rhs_all.vectorize_performance.thrust_net_0 + val: + array([8532.57300146, 7450.68156717, 6441.96803141, 6205.50413313, + 6205.50413313, 5447.41128948, 4968.24516058, 4892.23703914, + 4892.23703914, 4747.51070881, 4639.74635182, 4629.13254482, + 4629.13254482, 4625.89901783, 4633.63504935, 4633.44613673, + 4633.44613673, 4631.49947216, 4624.52153368, 4623.04453842]) + thrust_net_max_0 |68847.2855466| input lbf traj.climb.rhs_all.vectorize_performance.thrust_net_max_0 + val: + array([26469. , 24792.97627383, 22635.23967936, 22005.94254328, + 22005.94254328, 19296.17450843, 16096.80803552, 15256.52557923, + 15256.52557923, 13082.84267052, 10678.74368018, 10014.48915139, + 10014.48915139, 8896.88333758, 7550.59501168, 7170.84981635, + 7170.84981635, 6751.56561794, 6254.90218295, 6107.972 ]) + fuel_flow_rate_negative_0 |11208.88451868| input lbm/h traj.climb.rhs_all.vectorize_performance.fuel_flow_rate_negative_0 + val: + array([-3239.56199085, -2918.98793851, -2639.60346984, -2577.53239335, + -2577.53239335, -2393.40610099, -2299.95148918, -2296.43887466, + -2296.43887466, -2304.20682221, -2346.79843317, -2363.50900188, + -2363.50900188, -2407.78889133, -2460.8909312 , -2474.53935068, + -2474.53935068, -2484.43200533, -2500.59248016, -2507.76511382]) + electric_power_in_0 |0.0| input kW traj.climb.rhs_all.vectorize_performance.electric_power_in_0 + val: + array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., + 0., 0., 0.]) + nox_rate_0 |58.65166043| input lbm/h traj.climb.rhs_all.vectorize_performance.nox_rate_0 + val: + array([13.84282768, 13.22353665, 12.59493128, 12.44304625, 12.44304625, + 12.0221227 , 12.15639189, 12.24459752, 12.24459752, 12.56052319, + 12.86332862, 13.12504521, 13.12504521, 13.37192625, 13.76383712, + 13.84749833, 13.84749833, 13.96635966, 14.09873028, 14.13201018]) + t4_0 |0.0| input degR traj.climb.rhs_all.vectorize_performance.t4_0 + val: + array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., + 0., 0., 0.]) + shaft_power_0 |0.0| input hp traj.climb.rhs_all.vectorize_performance.shaft_power_0 + val: + array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., + 0., 0., 0.]) + shaft_power_max_0 |0.0| input hp traj.climb.rhs_all.vectorize_performance.shaft_power_max_0 + val: + array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., + 0., 0., 0.]) + thrust_net |24207.42074097| output lbf traj.climb.rhs_all.thrust_net + val: + array([[8532.57300146], + [7450.68156717], + [6441.96803141], + [6205.50413313], + [6205.50413313], + [5447.41128948], + [4968.24516058], + [4892.23703914], + [4892.23703914], + [4747.51070881], + [4639.74635182], + [4629.13254482], + [4629.13254482], + [4625.89901783], + [4633.63504935], + [4633.44613673], + [4633.44613673], + [4631.49947216], + [4624.52153368], + [4623.04453842]]) + thrust_net_max |68847.2855466| output lbf traj.climb.rhs_all.thrust_net_max + val: + array([[26469. ], + [24792.97627383], + [22635.23967936], + [22005.94254328], + [22005.94254328], + [19296.17450843], + [16096.80803552], + [15256.52557923], + [15256.52557923], + [13082.84267052], + [10678.74368018], + [10014.48915139], + [10014.48915139], + [ 8896.88333758], + [ 7550.59501168], + [ 7170.84981635], + [ 7170.84981635], + [ 6751.56561794], + [ 6254.90218295], + [ 6107.972 ]]) + fuel_flow_rate_negative |11208.88451868| output lbm/h traj.climb.rhs_all.fuel_flow_rate_negative + val: + array([[-3239.56199085], + [-2918.98793851], + [-2639.60346984], + [-2577.53239335], + [-2577.53239335], + [-2393.40610099], + [-2299.95148918], + [-2296.43887466], + [-2296.43887466], + [-2304.20682221], + [-2346.79843317], + [-2363.50900188], + [-2363.50900188], + [-2407.78889133], + [-2460.8909312 ], + [-2474.53935068], + [-2474.53935068], + [-2484.43200533], + [-2500.59248016], + [-2507.76511382]]) + electric_power_in |0.0| output kW traj.climb.rhs_all.electric_power_in + val: + array([[0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.]]) + nox_rate |58.65166043| output lbm/h traj.climb.rhs_all.nox_rate + val: + array([[13.84282768], + [13.22353665], + [12.59493128], + [12.44304625], + [12.44304625], + [12.0221227 ], + [12.15639189], + [12.24459752], + [12.24459752], + [12.56052319], + [12.86332862], + [13.12504521], + [13.12504521], + [13.37192625], + [13.76383712], + [13.84749833], + [13.84749833], + [13.96635966], + [14.09873028], + [14.13201018]]) + t4 |0.0| output degR traj.climb.rhs_all.t4 + val: + array([[0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.]]) + shaft_power |0.0| output hp traj.climb.rhs_all.shaft_power + val: + array([[0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.]]) + shaft_power_max |0.0| output hp traj.climb.rhs_all.shaft_power_max + val: + array([[0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.]]) + propulsion_sum + thrust_net |24207.42074097| input lbf traj.climb.rhs_all.thrust_net + val: + array([[8532.57300146], + [7450.68156717], + [6441.96803141], + [6205.50413313], + [6205.50413313], + [5447.41128948], + [4968.24516058], + [4892.23703914], + [4892.23703914], + [4747.51070881], + [4639.74635182], + [4629.13254482], + [4629.13254482], + [4625.89901783], + [4633.63504935], + [4633.44613673], + [4633.44613673], + [4631.49947216], + [4624.52153368], + [4623.04453842]]) + thrust_net_max |68847.2855466| input lbf traj.climb.rhs_all.thrust_net_max + val: + array([[26469. ], + [24792.97627383], + [22635.23967936], + [22005.94254328], + [22005.94254328], + [19296.17450843], + [16096.80803552], + [15256.52557923], + [15256.52557923], + [13082.84267052], + [10678.74368018], + [10014.48915139], + [10014.48915139], + [ 8896.88333758], + [ 7550.59501168], + [ 7170.84981635], + [ 7170.84981635], + [ 6751.56561794], + [ 6254.90218295], + [ 6107.972 ]]) + fuel_flow_rate_negative |11208.88451868| input lbm/h traj.climb.rhs_all.fuel_flow_rate_negative + val: + array([[-3239.56199085], + [-2918.98793851], + [-2639.60346984], + [-2577.53239335], + [-2577.53239335], + [-2393.40610099], + [-2299.95148918], + [-2296.43887466], + [-2296.43887466], + [-2304.20682221], + [-2346.79843317], + [-2363.50900188], + [-2363.50900188], + [-2407.78889133], + [-2460.8909312 ], + [-2474.53935068], + [-2474.53935068], + [-2484.43200533], + [-2500.59248016], + [-2507.76511382]]) + electric_power_in |0.0| input kW traj.climb.rhs_all.electric_power_in + val: + array([[0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.]]) + nox_rate |58.65166043| input lbm/h traj.climb.rhs_all.nox_rate + val: + array([[13.84282768], + [13.22353665], + [12.59493128], + [12.44304625], + [12.44304625], + [12.0221227 ], + [12.15639189], + [12.24459752], + [12.24459752], + [12.56052319], + [12.86332862], + [13.12504521], + [13.12504521], + [13.37192625], + [13.76383712], + [13.84749833], + [13.84749833], + [13.96635966], + [14.09873028], + [14.13201018]]) + thrust_net_total |48414.84148193| output lbf traj.climb.rhs_all.thrust_net_total + val: + array([17065.14600291, 14901.36313434, 12883.93606283, 12411.00826626, + 12411.00826626, 10894.82257897, 9936.49032117, 9784.47407829, + 9784.47407829, 9495.02141762, 9279.49270363, 9258.26508964, + 9258.26508964, 9251.79803565, 9267.2700987 , 9266.89227346, + 9266.89227346, 9262.99894433, 9249.04306736, 9246.08907684]) + thrust_net_max_total |137694.5710932| output lbf traj.climb.rhs_all.thrust_net_max_total + val: + array([52938. , 49585.95254766, 45270.47935872, 44011.88508656, + 44011.88508656, 38592.34901686, 32193.61607105, 30513.05115847, + 30513.05115847, 26165.68534103, 21357.48736037, 20028.97830279, + 20028.97830279, 17793.76667517, 15101.19002336, 14341.69963271, + 14341.69963271, 13503.13123587, 12509.8043659 , 12215.944 ]) + fuel_flow_rate_negative_total |22417.76903736| output lbm/h traj.climb.rhs_all.fuel_flow_rate_negative_total + val: + array([-6479.1239817 , -5837.97587703, -5279.20693967, -5155.06478669, + -5155.06478669, -4786.81220198, -4599.90297835, -4592.87774932, + -4592.87774932, -4608.41364442, -4693.59686634, -4727.01800377, + -4727.01800377, -4815.57778266, -4921.78186239, -4949.07870135, + -4949.07870135, -4968.86401067, -5001.18496031, -5015.53022764]) + electric_power_in_total |0.0| output kW traj.climb.rhs_all.electric_power_in_total + val: + array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., + 0., 0., 0.]) + nox_rate_total |117.30332085| output lbm/h traj.climb.rhs_all.nox_rate_total + val: + array([27.68565536, 26.4470733 , 25.18986255, 24.8860925 , 24.8860925 , + 24.0442454 , 24.31278379, 24.48919503, 24.48919503, 25.12104637, + 25.72665723, 26.25009041, 26.25009041, 26.74385251, 27.52767425, + 27.69499666, 27.69499666, 27.93271932, 28.19746055, 28.26402037]) + mission_EOM + required_thrust + drag |150759.28928049| input N traj.climb.rhs_all.drag + val: + array([51441.48042457, 43911.41111041, 37233.15286355, 35746.38288226, + 35746.38288226, 31380.47324171, 29460.99199568, 29373.69267134, + 29373.69267134, 29430.50374299, 29881.51771429, 30155.67367994, + 30155.67367994, 30757.1359626 , 31557.90749055, 31760.88321635, + 31760.88321635, 31959.85759632, 32175.62183799, 32245.86305683]) + altitude_rate |11.35922533| input m/s traj.climb.rhs_all.altitude_rate + val: + array([2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, + 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54]) + velocity |692.82893696| input m/s traj.climb.rhs_all.velocity + val: + array([ 68.0573727 , 75.09079389, 84.68111157, 87.6885407 , + 87.6885407 , 101.57433671, 120.24308114, 126.03147998, + 126.03147998, 141.4927097 , 162.09903383, 168.44210711, + 168.44210711, 180.41248453, 196.38747815, 201.31036538, + 201.31036538, 206.75274127, 214.12710705, 216.42809923]) + velocity_rate |0.19418617| input m/s**2 traj.climb.rhs_all.velocity_rate + val: + array([0.04608051, 0.04586862, 0.04557466, 0.04548121, 0.04548121, + 0.04504182, 0.04442857, 0.04423277, 0.04423277, 0.04369538, + 0.04294308, 0.0427023 , 0.0427023 , 0.04223472, 0.0415812 , + 0.04137226, 0.04137226, 0.04113671, 0.04080959, 0.04070552]) + mass |260111.77531753| input kg traj.climb.rhs_all.mass + val: + array([59377.14578909, 59253.2001355 , 59099.30211114, 59053.23865024, + 59053.23865024, 58849.04195155, 58583.91501949, 58501.0166128 , + 58501.0166128 , 58275.75043339, 57961.72209353, 57860.85002365, + 57860.85002365, 57664.1758047 , 57387.22609857, 57298.3740442 , + 57298.3740442 , 57198.30721763, 57059.51640479, 57015.39290411]) + thrust_required |215359.94460881| output N traj.climb.rhs_all.thrust_required + val: + array([75909.55139862, 66284.56566165, 57310.60294538, 55206.91529598, + 55206.91529598, 48462.58534184, 44199.71107353, 43523.50913536, + 43523.50913536, 42235.95955221, 41277.24006694, 41182.81493542, + 41182.81493542, 41154.04804606, 41222.87121142, 41221.19056101, + 41221.19056101, 41203.8721702 , 41141.79333655, 41128.65333204]) + groundspeed + altitude_rate |11.35922533| input m/s traj.climb.rhs_all.altitude_rate + val: + array([2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, + 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54]) + velocity |692.82893696| input m/s traj.climb.rhs_all.velocity + val: + array([ 68.0573727 , 75.09079389, 84.68111157, 87.6885407 , + 87.6885407 , 101.57433671, 120.24308114, 126.03147998, + 126.03147998, 141.4927097 , 162.09903383, 168.44210711, + 168.44210711, 180.41248453, 196.38747815, 201.31036538, + 201.31036538, 206.75274127, 214.12710705, 216.42809923]) + distance_rate |692.73581104| output m/s traj.climb.rhs_all.distance_rate + val: + array([ 68.00995794, 75.04782293, 84.6430095 , 87.65174596, + 87.65174596, 101.54257372, 120.21625082, 126.00588218, + 126.00588218, 141.46990952, 162.07913243, 168.42295523, + 168.42295523, 180.39460351, 196.37105177, 201.29434073, + 201.29434073, 206.73713847, 214.11204164, 216.413194 ]) + excess_specific_power + velocity |692.82893696| input m/s traj.climb.rhs_all.velocity + val: + array([ 68.0573727 , 75.09079389, 84.68111157, 87.6885407 , + 87.6885407 , 101.57433671, 120.24308114, 126.03147998, + 126.03147998, 141.4927097 , 162.09903383, 168.44210711, + 168.44210711, 180.41248453, 196.38747815, 201.31036538, + 201.31036538, 206.75274127, 214.12710705, 216.42809923]) + mass |260111.77531753| input kg traj.climb.rhs_all.mass + val: + array([59377.14578909, 59253.2001355 , 59099.30211114, 59053.23865024, + 59053.23865024, 58849.04195155, 58583.91501949, 58501.0166128 , + 58501.0166128 , 58275.75043339, 57961.72209353, 57860.85002365, + 57860.85002365, 57664.1758047 , 57387.22609857, 57298.3740442 , + 57298.3740442 , 57198.30721763, 57059.51640479, 57015.39290411]) + thrust_net_total |612495.9680934| input N traj.climb.rhs_all.thrust_net_max_total + val: + array([235479.95611956, 220569.3061708 , 201373.12503122, 195774.61877901, + 195774.61877901, 171667.32126336, 143204.33903321, 135728.81385526, + 135728.81385526, 116390.76723609, 95002.83702527, 89093.33431297, + 89093.33431297, 79150.61762572, 67173.43994963, 63795.05837376, + 63795.05837376, 60064.9203011 , 55646.38224237, 54339.22620951]) + drag |150759.28928049| input N traj.climb.rhs_all.drag + val: + array([51441.48042457, 43911.41111041, 37233.15286355, 35746.38288226, + 35746.38288226, 31380.47324171, 29460.99199568, 29373.69267134, + 29373.69267134, 29430.50374299, 29881.51771429, 30155.67367994, + 30155.67367994, 30757.1359626 , 31557.90749055, 31760.88321635, + 31760.88321635, 31959.85759632, 32175.62183799, 32245.86305683]) + specific_energy_rate |85.6710443| output m/s traj.climb.rhs_all.specific_energy_rate_excess + val: + array([21.51016857, 22.8290196 , 23.98268911, 24.23120792, 24.23120792, + 24.69112511, 23.80603311, 23.36433121, 23.36433121, 21.53011554, + 18.57127243, 17.49597197, 17.49597197, 15.43926748, 12.42846021, + 11.47669154, 11.47669154, 10.35933753, 8.98152426, 8.55190129]) + altitude_rate_max + specific_energy_rate |85.6710443| input m/s traj.climb.rhs_all.mission_EOM.specific_energy_rate_excess + val: + array([21.51016857, 22.8290196 , 23.98268911, 24.23120792, 24.23120792, + 24.69112511, 23.80603311, 23.36433121, 23.36433121, 21.53011554, + 18.57127243, 17.49597197, 17.49597197, 15.43926748, 12.42846021, + 11.47669154, 11.47669154, 10.35933753, 8.98152426, 8.55190129]) + velocity_rate |0.19418617| input m/s**2 traj.climb.rhs_all.velocity_rate + val: + array([0.04608051, 0.04586862, 0.04557466, 0.04548121, 0.04548121, + 0.04504182, 0.04442857, 0.04423277, 0.04423277, 0.04369538, + 0.04294308, 0.0427023 , 0.0427023 , 0.04223472, 0.0415812 , + 0.04137226, 0.04137226, 0.04113671, 0.04080959, 0.04070552]) + velocity |692.82893696| input m/s traj.climb.rhs_all.velocity + val: + array([ 68.0573727 , 75.09079389, 84.68111157, 87.6885407 , + 87.6885407 , 101.57433671, 120.24308114, 126.03147998, + 126.03147998, 141.4927097 , 162.09903383, 168.44210711, + 168.44210711, 180.41248453, 196.38747815, 201.31036538, + 201.31036538, 206.75274127, 214.12710705, 216.42809923]) + altitude_rate |83.18904841| output m/s traj.climb.rhs_all.altitude_rate_max + val: + array([21.19037347, 22.47779765, 23.58914868, 23.82452664, 23.82452664, + 24.22459546, 23.26127744, 22.79586784, 22.79586784, 20.89966812, + 17.86144478, 16.76250383, 16.76250383, 14.66227723, 11.5957571 , + 10.62740405, 10.62740405, 9.49205578, 8.0904515 , 7.65354991]) + throttle_balance + thrust_required |48414.84148193| input lbf traj.climb.rhs_all.thrust_required + val: + array([17065.14600291, 14901.36313434, 12883.93606283, 12411.00826626, + 12411.00826626, 10894.82257897, 9936.49032117, 9784.47407829, + 9784.47407829, 9495.02141762, 9279.49270363, 9258.26508964, + 9258.26508964, 9251.79803565, 9267.2700987 , 9266.89227346, + 9266.89227346, 9262.99894433, 9249.04306736, 9246.08907684]) + thrust_net_total |48414.84148193| input lbf traj.climb.rhs_all.thrust_net_total + val: + array([17065.14600291, 14901.36313434, 12883.93606283, 12411.00826626, + 12411.00826626, 10894.82257897, 9936.49032117, 9784.47407829, + 9784.47407829, 9495.02141762, 9279.49270363, 9258.26508964, + 9258.26508964, 9251.79803565, 9267.2700987 , 9266.89227346, + 9266.89227346, 9262.99894433, 9249.04306736, 9246.08907684]) + throttle |2.27639903| output unitless traj.climb.rhs_all.throttle + val: + array([0.36272519, 0.34217892, 0.32721108, 0.32475961, 0.32475961, + 0.32505412, 0.34982841, 0.36112935, 0.36112935, 0.40082952, + 0.46816406, 0.49426945, 0.49426945, 0.54853485, 0.63668329, + 0.6672203 , 0.6672203 , 0.70468433, 0.75486115, 0.77136189]) + initial_mass_residual_constraint + initial_mass [1.] input kg traj.climb.rhs_all.mission:summary:gross_mass + mass |260111.77531753| input kg traj.climb.rhs_all.mass + val: + array([59377.14578909, 59253.2001355 , 59099.30211114, 59053.23865024, + 59053.23865024, 58849.04195155, 58583.91501949, 58501.0166128 , + 58501.0166128 , 58275.75043339, 57961.72209353, 57860.85002365, + 57860.85002365, 57664.1758047 , 57387.22609857, 57298.3740442 , + 57298.3740442 , 57198.30721763, 57059.51640479, 57015.39290411]) + initial_mass_residual [-59476.14578909] output kg traj.climb.rhs_all.initial_mass_residual + timeseries + dt_dstau |1817.71161504| input s traj.climb.timeseries.dt_dstau + val: + array([225.54688903, 225.54688903, 225.54688903, 225.54688903, + 460.63085515, 460.63085515, 460.63085515, 460.63085515, + 547.64451164, 547.64451164, 547.64451164, 547.64451164, + 460.63085515, 460.63085515, 460.63085515, 460.63085515, + 225.54688903, 225.54688903, 225.54688903, 225.54688903]) + input_values:mach |2.22189137| input unitless traj.climb.timeseries.input_values:mach + val: + array([[0.2 ], + [0.22168851], + [0.25161423], + [0.26108562], + [0.26108562], + [0.30537972], + [0.36649654], + [0.38583981], + [0.38583981], + [0.43850111], + [0.51116297], + [0.53416019], + [0.53416019], + [0.5784543 ], + [0.63957112], + [0.65891438], + [0.65891438], + [0.68060289], + [0.71052861], + [0.72 ]]) + input_values:thrust_net_total |48414.84148193| input lbf traj.climb.timeseries.input_values:thrust_net_total + val: + array([[17065.14600291], + [14901.36313434], + [12883.93606283], + [12411.00826626], + [12411.00826626], + [10894.82257897], + [ 9936.49032117], + [ 9784.47407829], + [ 9784.47407829], + [ 9495.02141762], + [ 9279.49270363], + [ 9258.26508964], + [ 9258.26508964], + [ 9251.79803565], + [ 9267.2700987 ], + [ 9266.89227346], + [ 9266.89227346], + [ 9262.99894433], + [ 9249.04306736], + [ 9246.08907684]]) + input_values:drag |33892.0364495| input lbf traj.climb.timeseries.input_values:drag + val: + array([[11564.50483341], + [ 9871.67791123], + [ 8370.34573461], + [ 8036.10654684], + [ 8036.10654684], + [ 7054.61101592], + [ 6623.09446616], + [ 6603.46879734], + [ 6603.46879734], + [ 6616.2404343 ], + [ 6717.63240841], + [ 6779.26512122], + [ 6779.26512122], + [ 6914.47922116], + [ 7094.49982183], + [ 7140.13058017], + [ 7140.13058017], + [ 7184.86180019], + [ 7233.36753127], + [ 7249.15838542]]) + input_values:specific_energy_rate_excess |85.6710443| input m/s traj.climb.timeseries.input_values:specific_energy_rate_excess + val: + array([[21.51016857], + [22.8290196 ], + [23.98268911], + [24.23120792], + [24.23120792], + [24.69112511], + [23.80603311], + [23.36433121], + [23.36433121], + [21.53011554], + [18.57127243], + [17.49597197], + [17.49597197], + [15.43926748], + [12.42846021], + [11.47669154], + [11.47669154], + [10.35933753], + [ 8.98152426], + [ 8.55190129]]) + input_values:fuel_flow_rate_negative_total |22417.76903736| input lbm/h traj.climb.timeseries.input_values:fuel_flow_rate_negative_total + val: + array([[-6479.1239817 ], + [-5837.97587703], + [-5279.20693967], + [-5155.06478669], + [-5155.06478669], + [-4786.81220198], + [-4599.90297835], + [-4592.87774932], + [-4592.87774932], + [-4608.41364442], + [-4693.59686634], + [-4727.01800377], + [-4727.01800377], + [-4815.57778266], + [-4921.78186239], + [-4949.07870135], + [-4949.07870135], + [-4968.86401067], + [-5001.18496031], + [-5015.53022764]]) + input_values:electric_power_in_total |0.0| input kW traj.climb.timeseries.input_values:electric_power_in_total + val: + array([[0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.]]) + input_values:altitude_rate |37.26779962| input ft/s traj.climb.timeseries.input_values:altitude_rate + val: + array([[8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333]]) + input_values:throttle |2.27639903| input unitless traj.climb.timeseries.input_values:throttle + val: + array([[0.36272519], + [0.34217892], + [0.32721108], + [0.32475961], + [0.32475961], + [0.32505412], + [0.34982841], + [0.36112935], + [0.36112935], + [0.40082952], + [0.46816406], + [0.49426945], + [0.49426945], + [0.54853485], + [0.63668329], + [0.6672203 ], + [0.6672203 ], + [0.70468433], + [0.75486115], + [0.77136189]]) + input_values:velocity |692.82893696| input m/s traj.climb.timeseries.input_values:velocity + val: + array([[ 68.0573727 ], + [ 75.09079389], + [ 84.68111157], + [ 87.6885407 ], + [ 87.6885407 ], + [101.57433671], + [120.24308114], + [126.03147998], + [126.03147998], + [141.4927097 ], + [162.09903383], + [168.44210711], + [168.44210711], + [180.41248453], + [196.38747815], + [201.31036538], + [201.31036538], + [206.75274127], + [214.12710705], + [216.42809923]]) + input_values:altitude |87358.6369253| input ft traj.climb.timeseries.input_values:altitude + val: + array([[ 0. ], + [ 1334.67757163], + [ 3176.26020893], + [ 3759.11481713], + [ 3759.11481713], + [ 6484.90577713], + [10245.94096014], + [11436.29573631], + [11436.29573631], + [14676.99149614], + [19148.49020934], + [20563.70426369], + [20563.70426369], + [23289.4952237 ], + [27050.5304067 ], + [28240.88518287], + [28240.88518287], + [29575.5627545 ], + [31417.1453918 ], + [32000. ]]) + input_values:time |10483.03643104| input s traj.climb.timeseries.input_values:time + val: + array([[ 0. ], + [ 160.1613086 ], + [ 381.15122507], + [ 451.09377806], + [ 451.09377806], + [ 778.18869326], + [1229.51291522], + [1372.35548836], + [1372.35548836], + [1761.23897954], + [2297.81882512], + [2467.64451164], + [2467.64451164], + [2794.73942684], + [3246.0636488 ], + [3388.90622194], + [3388.90622194], + [3549.06753054], + [3770.05744702], + [3840. ]]) + input_values:time_phase |10483.03643104| input s traj.climb.timeseries.input_values:time_phase + val: + array([[ 0. ], + [ 160.1613086 ], + [ 381.15122507], + [ 451.09377806], + [ 451.09377806], + [ 778.18869326], + [1229.51291522], + [1372.35548836], + [1372.35548836], + [1761.23897954], + [2297.81882512], + [2467.64451164], + [2467.64451164], + [2794.73942684], + [3246.0636488 ], + [3388.90622194], + [3388.90622194], + [3549.06753054], + [3770.05744702], + [3840. ]]) + input_values:mach_rate |0.0006056| input unitless/s traj.climb.timeseries.input_values:mach_rate + val: + array([[0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542]]) + input_values:mass |260111.77531753| input kg traj.climb.timeseries.input_values:mass + val: + array([[59377.14578909], + [59253.2001355 ], + [59099.30211114], + [59053.23865024], + [59053.23865024], + [58849.04195155], + [58583.91501949], + [58501.0166128 ], + [58501.0166128 ], + [58275.75043339], + [57961.72209353], + [57860.85002365], + [57860.85002365], + [57664.1758047 ], + [57387.22609857], + [57298.3740442 ], + [57298.3740442 ], + [57198.30721763], + [57059.51640479], + [57015.39290411]]) + input_values:distance |1394968.35548323| input m traj.climb.timeseries.input_values:distance + val: + array([[1.00000000e+00], + [1.14581007e+04], + [2.91056018e+04], + [3.51310537e+04], + [3.51310537e+04], + [6.60814858e+04], + [1.16145544e+05], + [1.33731831e+05], + [1.33731831e+05], + [1.85754660e+05], + [2.67231556e+05], + [2.95296884e+05], + [2.95296884e+05], + [3.52354108e+05], + [4.37399478e+05], + [4.65802163e+05], + [4.65802163e+05], + [4.98478689e+05], + [5.44983286e+05], + [5.60039406e+05]]) + mach |2.22189137| output unitless traj.climb.timeseries.mach + val: + array([[0.2 ], + [0.22168851], + [0.25161423], + [0.26108562], + [0.26108562], + [0.30537972], + [0.36649654], + [0.38583981], + [0.38583981], + [0.43850111], + [0.51116297], + [0.53416019], + [0.53416019], + [0.5784543 ], + [0.63957112], + [0.65891438], + [0.65891438], + [0.68060289], + [0.71052861], + [0.72 ]]) + thrust_net_total |48414.84148193| output lbf traj.climb.timeseries.thrust_net_total + val: + array([[17065.14600291], + [14901.36313434], + [12883.93606283], + [12411.00826626], + [12411.00826626], + [10894.82257897], + [ 9936.49032117], + [ 9784.47407829], + [ 9784.47407829], + [ 9495.02141762], + [ 9279.49270363], + [ 9258.26508964], + [ 9258.26508964], + [ 9251.79803565], + [ 9267.2700987 ], + [ 9266.89227346], + [ 9266.89227346], + [ 9262.99894433], + [ 9249.04306736], + [ 9246.08907684]]) + drag |33892.0364495| output lbf traj.climb.timeseries.drag + val: + array([[11564.50483341], + [ 9871.67791123], + [ 8370.34573461], + [ 8036.10654684], + [ 8036.10654684], + [ 7054.61101592], + [ 6623.09446616], + [ 6603.46879734], + [ 6603.46879734], + [ 6616.2404343 ], + [ 6717.63240841], + [ 6779.26512122], + [ 6779.26512122], + [ 6914.47922116], + [ 7094.49982183], + [ 7140.13058017], + [ 7140.13058017], + [ 7184.86180019], + [ 7233.36753127], + [ 7249.15838542]]) + specific_energy_rate_excess |85.6710443| output m/s traj.climb.timeseries.specific_energy_rate_excess + val: + array([[21.51016857], + [22.8290196 ], + [23.98268911], + [24.23120792], + [24.23120792], + [24.69112511], + [23.80603311], + [23.36433121], + [23.36433121], + [21.53011554], + [18.57127243], + [17.49597197], + [17.49597197], + [15.43926748], + [12.42846021], + [11.47669154], + [11.47669154], + [10.35933753], + [ 8.98152426], + [ 8.55190129]]) + fuel_flow_rate_negative_total |22417.76903736| output lbm/h traj.climb.timeseries.fuel_flow_rate_negative_total + val: + array([[-6479.1239817 ], + [-5837.97587703], + [-5279.20693967], + [-5155.06478669], + [-5155.06478669], + [-4786.81220198], + [-4599.90297835], + [-4592.87774932], + [-4592.87774932], + [-4608.41364442], + [-4693.59686634], + [-4727.01800377], + [-4727.01800377], + [-4815.57778266], + [-4921.78186239], + [-4949.07870135], + [-4949.07870135], + [-4968.86401067], + [-5001.18496031], + [-5015.53022764]]) + electric_power_in_total |0.0| output kW traj.climb.timeseries.electric_power_in_total + val: + array([[0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.]]) + altitude_rate |37.26779962| output ft/s traj.climb.timeseries.altitude_rate + val: + array([[8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333]]) + throttle |2.27639903| output unitless traj.climb.timeseries.throttle + val: + array([[0.36272519], + [0.34217892], + [0.32721108], + [0.32475961], + [0.32475961], + [0.32505412], + [0.34982841], + [0.36112935], + [0.36112935], + [0.40082952], + [0.46816406], + [0.49426945], + [0.49426945], + [0.54853485], + [0.63668329], + [0.6672203 ], + [0.6672203 ], + [0.70468433], + [0.75486115], + [0.77136189]]) + velocity |692.82893696| output m/s traj.climb.timeseries.velocity + val: + array([[ 68.0573727 ], + [ 75.09079389], + [ 84.68111157], + [ 87.6885407 ], + [ 87.6885407 ], + [101.57433671], + [120.24308114], + [126.03147998], + [126.03147998], + [141.4927097 ], + [162.09903383], + [168.44210711], + [168.44210711], + [180.41248453], + [196.38747815], + [201.31036538], + [201.31036538], + [206.75274127], + [214.12710705], + [216.42809923]]) + altitude |87358.6369253| output ft traj.climb.timeseries.altitude + val: + array([[ 0. ], + [ 1334.67757163], + [ 3176.26020893], + [ 3759.11481713], + [ 3759.11481713], + [ 6484.90577713], + [10245.94096014], + [11436.29573631], + [11436.29573631], + [14676.99149614], + [19148.49020934], + [20563.70426369], + [20563.70426369], + [23289.4952237 ], + [27050.5304067 ], + [28240.88518287], + [28240.88518287], + [29575.5627545 ], + [31417.1453918 ], + [32000. ]]) + time |10483.03643104| output s traj.climb.timeseries.time + val: + array([[ 0. ], + [ 160.1613086 ], + [ 381.15122507], + [ 451.09377806], + [ 451.09377806], + [ 778.18869326], + [1229.51291522], + [1372.35548836], + [1372.35548836], + [1761.23897954], + [2297.81882512], + [2467.64451164], + [2467.64451164], + [2794.73942684], + [3246.0636488 ], + [3388.90622194], + [3388.90622194], + [3549.06753054], + [3770.05744702], + [3840. ]]) + time_phase |10483.03643104| output s traj.climb.timeseries.time_phase + val: + array([[ 0. ], + [ 160.1613086 ], + [ 381.15122507], + [ 451.09377806], + [ 451.09377806], + [ 778.18869326], + [1229.51291522], + [1372.35548836], + [1372.35548836], + [1761.23897954], + [2297.81882512], + [2467.64451164], + [2467.64451164], + [2794.73942684], + [3246.0636488 ], + [3388.90622194], + [3388.90622194], + [3549.06753054], + [3770.05744702], + [3840. ]]) + mach_rate |0.0006056| output unitless/s traj.climb.timeseries.mach_rate + val: + array([[0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542]]) + mass |260111.77531753| output kg traj.climb.timeseries.mass + val: + array([[59377.14578909], + [59253.2001355 ], + [59099.30211114], + [59053.23865024], + [59053.23865024], + [58849.04195155], + [58583.91501949], + [58501.0166128 ], + [58501.0166128 ], + [58275.75043339], + [57961.72209353], + [57860.85002365], + [57860.85002365], + [57664.1758047 ], + [57387.22609857], + [57298.3740442 ], + [57298.3740442 ], + [57198.30721763], + [57059.51640479], + [57015.39290411]]) + distance |1394968.35548323| output m traj.climb.timeseries.distance + val: + array([[1.00000000e+00], + [1.14581007e+04], + [2.91056018e+04], + [3.51310537e+04], + [3.51310537e+04], + [6.60814858e+04], + [1.16145544e+05], + [1.33731831e+05], + [1.33731831e+05], + [1.85754660e+05], + [2.67231556e+05], + [2.95296884e+05], + [2.95296884e+05], + [3.52354108e+05], + [4.37399478e+05], + [4.65802163e+05], + [4.65802163e+05], + [4.98478689e+05], + [5.44983286e+05], + [5.60039406e+05]]) + mission_bus_variables + dt_dstau |1817.71161504| input s traj.climb.mission_bus_variables.dt_dstau + val: + array([225.54688903, 225.54688903, 225.54688903, 225.54688903, + 460.63085515, 460.63085515, 460.63085515, 460.63085515, + 547.64451164, 547.64451164, 547.64451164, 547.64451164, + 460.63085515, 460.63085515, 460.63085515, 460.63085515, + 225.54688903, 225.54688903, 225.54688903, 225.54688903]) + input_values:mach |2.22189137| input unitless traj.climb.mission_bus_variables.input_values:mach + val: + array([[0.2 ], + [0.22168851], + [0.25161423], + [0.26108562], + [0.26108562], + [0.30537972], + [0.36649654], + [0.38583981], + [0.38583981], + [0.43850111], + [0.51116297], + [0.53416019], + [0.53416019], + [0.5784543 ], + [0.63957112], + [0.65891438], + [0.65891438], + [0.68060289], + [0.71052861], + [0.72 ]]) + input_values:thrust_net_total |48414.84148193| input lbf traj.climb.mission_bus_variables.input_values:thrust_net_total + val: + array([[17065.14600291], + [14901.36313434], + [12883.93606283], + [12411.00826626], + [12411.00826626], + [10894.82257897], + [ 9936.49032117], + [ 9784.47407829], + [ 9784.47407829], + [ 9495.02141762], + [ 9279.49270363], + [ 9258.26508964], + [ 9258.26508964], + [ 9251.79803565], + [ 9267.2700987 ], + [ 9266.89227346], + [ 9266.89227346], + [ 9262.99894433], + [ 9249.04306736], + [ 9246.08907684]]) + input_values:drag |33892.0364495| input lbf traj.climb.mission_bus_variables.input_values:drag + val: + array([[11564.50483341], + [ 9871.67791123], + [ 8370.34573461], + [ 8036.10654684], + [ 8036.10654684], + [ 7054.61101592], + [ 6623.09446616], + [ 6603.46879734], + [ 6603.46879734], + [ 6616.2404343 ], + [ 6717.63240841], + [ 6779.26512122], + [ 6779.26512122], + [ 6914.47922116], + [ 7094.49982183], + [ 7140.13058017], + [ 7140.13058017], + [ 7184.86180019], + [ 7233.36753127], + [ 7249.15838542]]) + input_values:specific_energy_rate_excess |85.6710443| input m/s traj.climb.mission_bus_variables.input_values:specific_energy_rate_excess + val: + array([[21.51016857], + [22.8290196 ], + [23.98268911], + [24.23120792], + [24.23120792], + [24.69112511], + [23.80603311], + [23.36433121], + [23.36433121], + [21.53011554], + [18.57127243], + [17.49597197], + [17.49597197], + [15.43926748], + [12.42846021], + [11.47669154], + [11.47669154], + [10.35933753], + [ 8.98152426], + [ 8.55190129]]) + input_values:fuel_flow_rate_negative_total |22417.76903736| input lbm/h traj.climb.mission_bus_variables.input_values:fuel_flow_rate_negative_total + val: + array([[-6479.1239817 ], + [-5837.97587703], + [-5279.20693967], + [-5155.06478669], + [-5155.06478669], + [-4786.81220198], + [-4599.90297835], + [-4592.87774932], + [-4592.87774932], + [-4608.41364442], + [-4693.59686634], + [-4727.01800377], + [-4727.01800377], + [-4815.57778266], + [-4921.78186239], + [-4949.07870135], + [-4949.07870135], + [-4968.86401067], + [-5001.18496031], + [-5015.53022764]]) + input_values:electric_power_in_total |0.0| input kW traj.climb.mission_bus_variables.input_values:electric_power_in_total + val: + array([[0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.]]) + input_values:altitude_rate |37.26779962| input ft/s traj.climb.mission_bus_variables.input_values:altitude_rate + val: + array([[8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333]]) + input_values:throttle |2.27639903| input unitless traj.climb.mission_bus_variables.input_values:throttle + val: + array([[0.36272519], + [0.34217892], + [0.32721108], + [0.32475961], + [0.32475961], + [0.32505412], + [0.34982841], + [0.36112935], + [0.36112935], + [0.40082952], + [0.46816406], + [0.49426945], + [0.49426945], + [0.54853485], + [0.63668329], + [0.6672203 ], + [0.6672203 ], + [0.70468433], + [0.75486115], + [0.77136189]]) + input_values:velocity |692.82893696| input m/s traj.climb.mission_bus_variables.input_values:velocity + val: + array([[ 68.0573727 ], + [ 75.09079389], + [ 84.68111157], + [ 87.6885407 ], + [ 87.6885407 ], + [101.57433671], + [120.24308114], + [126.03147998], + [126.03147998], + [141.4927097 ], + [162.09903383], + [168.44210711], + [168.44210711], + [180.41248453], + [196.38747815], + [201.31036538], + [201.31036538], + [206.75274127], + [214.12710705], + [216.42809923]]) + input_values:altitude |87358.6369253| input ft traj.climb.mission_bus_variables.input_values:altitude + val: + array([[ 0. ], + [ 1334.67757163], + [ 3176.26020893], + [ 3759.11481713], + [ 3759.11481713], + [ 6484.90577713], + [10245.94096014], + [11436.29573631], + [11436.29573631], + [14676.99149614], + [19148.49020934], + [20563.70426369], + [20563.70426369], + [23289.4952237 ], + [27050.5304067 ], + [28240.88518287], + [28240.88518287], + [29575.5627545 ], + [31417.1453918 ], + [32000. ]]) + input_values:time |10483.03643104| input s traj.climb.mission_bus_variables.input_values:time + val: + array([[ 0. ], + [ 160.1613086 ], + [ 381.15122507], + [ 451.09377806], + [ 451.09377806], + [ 778.18869326], + [1229.51291522], + [1372.35548836], + [1372.35548836], + [1761.23897954], + [2297.81882512], + [2467.64451164], + [2467.64451164], + [2794.73942684], + [3246.0636488 ], + [3388.90622194], + [3388.90622194], + [3549.06753054], + [3770.05744702], + [3840. ]]) + input_values:time_phase |10483.03643104| input s traj.climb.mission_bus_variables.input_values:time_phase + val: + array([[ 0. ], + [ 160.1613086 ], + [ 381.15122507], + [ 451.09377806], + [ 451.09377806], + [ 778.18869326], + [1229.51291522], + [1372.35548836], + [1372.35548836], + [1761.23897954], + [2297.81882512], + [2467.64451164], + [2467.64451164], + [2794.73942684], + [3246.0636488 ], + [3388.90622194], + [3388.90622194], + [3549.06753054], + [3770.05744702], + [3840. ]]) + input_values:mach_rate |0.0006056| input unitless/s traj.climb.mission_bus_variables.input_values:mach_rate + val: + array([[0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542]]) + input_values:mass |260111.77531753| input kg traj.climb.mission_bus_variables.input_values:mass + val: + array([[59377.14578909], + [59253.2001355 ], + [59099.30211114], + [59053.23865024], + [59053.23865024], + [58849.04195155], + [58583.91501949], + [58501.0166128 ], + [58501.0166128 ], + [58275.75043339], + [57961.72209353], + [57860.85002365], + [57860.85002365], + [57664.1758047 ], + [57387.22609857], + [57298.3740442 ], + [57298.3740442 ], + [57198.30721763], + [57059.51640479], + [57015.39290411]]) + input_values:distance |1394968.35548323| input m traj.climb.mission_bus_variables.input_values:distance + val: + array([[1.00000000e+00], + [1.14581007e+04], + [2.91056018e+04], + [3.51310537e+04], + [3.51310537e+04], + [6.60814858e+04], + [1.16145544e+05], + [1.33731831e+05], + [1.33731831e+05], + [1.85754660e+05], + [2.67231556e+05], + [2.95296884e+05], + [2.95296884e+05], + [3.52354108e+05], + [4.37399478e+05], + [4.65802163e+05], + [4.65802163e+05], + [4.98478689e+05], + [5.44983286e+05], + [5.60039406e+05]]) + mach |1.87763681| output unitless traj.climb.mission_bus_variables.mach + val: + array([[0.2 ], + [0.252], + [0.304], + [0.304], + [0.356], + [0.408], + [0.408], + [0.46 ], + [0.512], + [0.512], + [0.564], + [0.616], + [0.616], + [0.668], + [0.72 ]]) + thrust_net_total |40887.66800453| output lbf traj.climb.mission_bus_variables.thrust_net_total + val: + array([[17065.14600291], + [12863.43667775], + [10929.29459826], + [10929.29459826], + [10039.41837459], + [ 9649.57306885], + [ 9649.57306885], + [ 9408.40094249], + [ 9278.31316437], + [ 9278.31316437], + [ 9250.40031304], + [ 9262.11775109], + [ 9262.11775109], + [ 9266.65324415], + [ 9246.08907684]]) + drag |28622.67791387| output lbf traj.climb.mission_bus_variables.drag + val: + array([[11564.50483341], + [ 8355.69107042], + [ 7074.68337595], + [ 7074.68337595], + [ 6648.6263692 ], + [ 6604.61391842], + [ 6604.61391842], + [ 6633.79494003], + [ 6719.58769169], + [ 6719.58769169], + [ 6869.15471209], + [ 7029.61212988], + [ 7029.61212988], + [ 7160.62450818], + [ 7249.15838542]]) + specific_energy_rate_excess |76.1474751| output m/s traj.climb.mission_bus_variables.specific_energy_rate_excess + val: + array([[21.51016857], + [23.99370022], + [24.69468355], + [24.69468355], + [24.02998969], + [22.61667701], + [22.61667701], + [20.71522371], + [18.53345324], + [18.53345324], + [16.12920993], + [13.59739582], + [13.59739582], + [10.98938407], + [ 8.55190129]]) + fuel_flow_rate_negative_total |19107.36560966| output lbm/h traj.climb.mission_bus_variables.fuel_flow_rate_negative_total + val: + array([[-6479.1239817 ], + [-5273.77681527], + [-4794.84549506], + [-4794.84549506], + [-4612.12691124], + [-4592.77340524], + [-4592.77340524], + [-4628.15205094], + [-4694.79617454], + [-4694.79617454], + [-4787.33714298], + [-4883.93359025], + [-4883.93359025], + [-4957.61495291], + [-5015.53022764]]) + electric_power_in_total |0.0| output kW traj.climb.mission_bus_variables.electric_power_in_total + val: + array([[0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.]]) + altitude_rate |32.27486122| output ft/s traj.climb.mission_bus_variables.altitude_rate + val: + array([[8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333], + [8.33333333]]) + throttle |1.87968944| output unitless traj.climb.mission_bus_variables.throttle + val: + array([[0.36272519], + [0.32709417], + [0.32477473], + [0.32477473], + [0.34419414], + [0.37727971], + [0.37727971], + [0.41879527], + [0.46906644], + [0.46906644], + [0.52984264], + [0.60107542], + [0.60107542], + [0.68323756], + [0.77136189]]) + velocity |589.5380269| output m/s traj.climb.mission_bus_variables.velocity + val: + array([[ 68.0573727 ], + [ 84.80386775], + [101.14628752], + [101.14628752], + [117.07770966], + [132.59095385], + [132.59095385], + [147.67822143], + [162.33142405], + [162.33142405], + [176.54212679], + [190.30161455], + [190.30161455], + [203.60018377], + [216.42809923]]) + altitude |71911.05617358| output ft traj.climb.mission_bus_variables.altitude + val: + array([[ 0.], + [ 3200.], + [ 6400.], + [ 6400.], + [ 9600.], + [12800.], + [12800.], + [16000.], + [19200.], + [19200.], + [22400.], + [25600.], + [25600.], + [28800.], + [32000.]]) + time |8629.32674083| output s traj.climb.mission_bus_variables.time + val: + array([[ 0.], + [ 384.], + [ 768.], + [ 768.], + [1152.], + [1536.], + [1536.], + [1920.], + [2304.], + [2304.], + [2688.], + [3072.], + [3072.], + [3456.], + [3840.]]) + time_phase |8629.32674083| output s traj.climb.mission_bus_variables.time_phase + val: + array([[ 0.], + [ 384.], + [ 768.], + [ 768.], + [1152.], + [1536.], + [1536.], + [1920.], + [2304.], + [2304.], + [2688.], + [3072.], + [3072.], + [3456.], + [3840.]]) + mach_rate |0.00052447| output unitless/s traj.climb.mission_bus_variables.mach_rate + val: + array([[0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542], + [0.00013542]]) + mass |225349.72849892| output kg traj.climb.mission_bus_variables.mass + val: + array([[59377.14578909], + [59097.40804654], + [58855.1924873 ], + [58855.1924873 ], + [58628.85825225], + [58406.30989701], + [58406.30989701], + [58183.40151086], + [57958.06610101], + [57958.06610101], + [57728.75425743], + [57494.74886721], + [57494.74886721], + [57256.50306513], + [57015.39290411]]) + distance |1112101.93489637| output m traj.climb.mission_bus_variables.distance + val: + array([[1.00000000e+00], + [2.93469056e+04], + [6.50490806e+04], + [6.50490806e+04], + [1.06949844e+05], + [1.54889941e+05], + [1.54889941e+05], + [2.08706570e+05], + [2.68234114e+05], + [2.68234114e+05], + [3.33305139e+05], + [4.03746843e+05], + [4.03746843e+05], + [4.79384667e+05], + [5.60039406e+05]]) + collocation_constraint + dt_dstau |1574.18443538| input s traj.climb.collocation_constraint.dt_dstau + val: + array([225.54688903, 225.54688903, 225.54688903, 460.63085515, + 460.63085515, 460.63085515, 547.64451164, 547.64451164, + 547.64451164, 460.63085515, 460.63085515, 460.63085515, + 225.54688903, 225.54688903, 225.54688903]) + f_approx:mass |2.46548436| input kg/s traj.climb.collocation_constraint.f_approx:mass + val: + array([[-0.81635589], + [-0.73557259], + [-0.66516889], + [-0.64952724], + [-0.60312819], + [-0.57957803], + [-0.57869286], + [-0.58065035], + [-0.59138326], + [-0.59559425], + [-0.60675259], + [-0.62013408], + [-0.62357343], + [-0.62606633], + [-0.63013871]]) + f_computed:mass |2.46548436| input kg/s traj.climb.collocation_constraint.f_computed:mass + val: + array([[-0.81635589], + [-0.73557259], + [-0.66516889], + [-0.64952724], + [-0.60312819], + [-0.57957803], + [-0.57869286], + [-0.58065035], + [-0.59138326], + [-0.59559425], + [-0.60675259], + [-0.62013408], + [-0.62357343], + [-0.62606633], + [-0.63013871]]) + f_approx:distance |583.61135954| input m/s traj.climb.collocation_constraint.f_approx:distance + val: + array([[ 68.00995794], + [ 75.04782293], + [ 84.6430095 ], + [ 87.65174596], + [101.54257372], + [120.21625082], + [126.00588218], + [141.46990952], + [162.07913243], + [168.42295523], + [180.39460351], + [196.37105177], + [201.29434073], + [206.73713847], + [214.11204164]]) + f_computed:distance |583.61135954| input m/s traj.climb.collocation_constraint.f_computed:distance + val: + array([[ 68.00995794], + [ 75.04782293], + [ 84.6430095 ], + [ 87.65174596], + [101.54257372], + [120.21625082], + [126.00588218], + [141.46990952], + [162.07913243], + [168.42295523], + [180.39460351], + [196.37105177], + [201.29434073], + [206.73713847], + [214.11204164]]) + defects:mass |0.0| output kg traj.climb.collocation_constraint.defects:mass + val: + array([[ 5.27357878e-11], + [ 5.75936903e-13], + [-7.51222048e-12], + [ 2.42405013e-11], + [-5.42087160e-12], + [ 1.22736715e-12], + [-1.33761660e-12], + [-7.96489885e-12], + [ 1.25249555e-11], + [-1.68251581e-11], + [ 2.10698028e-11], + [-9.30753426e-12], + [-4.59747893e-11], + [ 1.18693084e-11], + [-7.61238342e-12]]) + defects:distance |0.0| output m traj.climb.collocation_constraint.defects:distance + val: + array([[-6.41042814e-12], + [ 0.00000000e+00], + [-6.41042814e-12], + [ 0.00000000e+00], + [ 6.54595816e-12], + [ 0.00000000e+00], + [ 2.33474898e-11], + [-1.55649932e-11], + [-1.86779918e-10], + [ 5.23676653e-11], + [ 1.70194912e-10], + [-1.57102996e-10], + [-2.69237982e-10], + [-1.02566850e-10], + [ 6.41042814e-12]]) + cruise + param_comp + t_initial [3840.] input s traj.cruise.t_initial + t_duration [10170.] input s traj.cruise.t_duration + parameters:aircraft:design:base_area [0.] input ft**2 traj.cruise.parameters:aircraft:design:base_area + parameters:aircraft:design:lift_dependent_drag_coeff_factor [0.90983938] input unitless traj.cruise.parameters:aircraft:design:lift_dependent_drag_coeff_factor + parameters:aircraft:design:subsonic_drag_coeff_factor [1.] input unitless traj.cruise.parameters:aircraft:design:subsonic_drag_coeff_factor + parameters:aircraft:design:supersonic_drag_coeff_factor [1.] input unitless traj.cruise.parameters:aircraft:design:supersonic_drag_coeff_factor + parameters:aircraft:design:zero_lift_drag_coeff_factor [0.93089003] input unitless traj.cruise.parameters:aircraft:design:zero_lift_drag_coeff_factor + parameters:aircraft:fuselage:characteristic_length [128.] input ft traj.cruise.parameters:aircraft:fuselage:characteristic_length + parameters:aircraft:fuselage:cross_section [127.67628894] input ft**2 traj.cruise.parameters:aircraft:fuselage:cross_section + parameters:aircraft:fuselage:diameter_to_wing_span [0.10826471] input unitless traj.cruise.parameters:aircraft:fuselage:diameter_to_wing_span + parameters:aircraft:fuselage:fineness [10.03921569] input unitless traj.cruise.parameters:aircraft:fuselage:fineness + parameters:aircraft:fuselage:laminar_flow_lower [0.] input unitless traj.cruise.parameters:aircraft:fuselage:laminar_flow_lower + parameters:aircraft:fuselage:laminar_flow_upper [0.] input unitless traj.cruise.parameters:aircraft:fuselage:laminar_flow_upper + parameters:aircraft:fuselage:length_to_diameter [10.03921569] input unitless traj.cruise.parameters:aircraft:fuselage:length_to_diameter + parameters:aircraft:fuselage:wetted_area [4158.62] input ft**2 traj.cruise.parameters:aircraft:fuselage:wetted_area + parameters:aircraft:horizontal_tail:characteristic_length [7.69198717] input ft traj.cruise.parameters:aircraft:horizontal_tail:characteristic_length + parameters:aircraft:horizontal_tail:fineness [0.125] input unitless traj.cruise.parameters:aircraft:horizontal_tail:fineness + parameters:aircraft:horizontal_tail:laminar_flow_lower [0.] input unitless traj.cruise.parameters:aircraft:horizontal_tail:laminar_flow_lower + parameters:aircraft:horizontal_tail:laminar_flow_upper [0.] input unitless traj.cruise.parameters:aircraft:horizontal_tail:laminar_flow_upper + parameters:aircraft:horizontal_tail:wetted_area [592.65] input ft**2 traj.cruise.parameters:aircraft:horizontal_tail:wetted_area + parameters:aircraft:vertical_tail:characteristic_length [12.73914103] input ft traj.cruise.parameters:aircraft:vertical_tail:characteristic_length + parameters:aircraft:vertical_tail:fineness [0.1195] input unitless traj.cruise.parameters:aircraft:vertical_tail:fineness + parameters:aircraft:vertical_tail:laminar_flow_lower [0.] input unitless traj.cruise.parameters:aircraft:vertical_tail:laminar_flow_lower + parameters:aircraft:vertical_tail:laminar_flow_upper [0.] input unitless traj.cruise.parameters:aircraft:vertical_tail:laminar_flow_upper + parameters:aircraft:vertical_tail:wetted_area [581.13] input ft**2 traj.cruise.parameters:aircraft:vertical_tail:wetted_area + parameters:aircraft:wing:area [1370.] input ft**2 traj.cruise.parameters:aircraft:wing:area + parameters:aircraft:wing:aspect_ratio [11.22091] input unitless traj.cruise.parameters:aircraft:wing:aspect_ratio + parameters:aircraft:wing:characteristic_length [10.49530819] input ft traj.cruise.parameters:aircraft:wing:characteristic_length + parameters:aircraft:wing:fineness [0.13] input unitless traj.cruise.parameters:aircraft:wing:fineness + parameters:aircraft:wing:laminar_flow_lower [0.] input unitless traj.cruise.parameters:aircraft:wing:laminar_flow_lower + parameters:aircraft:wing:laminar_flow_upper [0.] input unitless traj.cruise.parameters:aircraft:wing:laminar_flow_upper + parameters:aircraft:wing:max_camber_at_70_semispan [0.] input unitless traj.cruise.parameters:aircraft:wing:max_camber_at_70_semispan + parameters:aircraft:wing:span_efficiency_factor [1.] input unitless traj.cruise.parameters:aircraft:wing:span_efficiency_factor + parameters:aircraft:wing:sweep [25.] input deg traj.cruise.parameters:aircraft:wing:sweep + parameters:aircraft:wing:taper_ratio [0.278] input unitless traj.cruise.parameters:aircraft:wing:taper_ratio + parameters:aircraft:wing:thickness_to_chord [0.13] input unitless traj.cruise.parameters:aircraft:wing:thickness_to_chord + parameters:aircraft:wing:wetted_area [2396.56] input ft**2 traj.cruise.parameters:aircraft:wing:wetted_area + parameters:mission:design:lift_coefficient [0.56736557] input unitless traj.cruise.parameters:mission:design:lift_coefficient + parameters:mission:design:mach [0.80017085] input unitless traj.cruise.parameters:mission:design:mach + parameters:aircraft:nacelle:characteristic_length [12.3] input ft traj.cruise.parameters:aircraft:nacelle:characteristic_length + parameters:aircraft:nacelle:fineness [1.54911839] input unitless traj.cruise.parameters:aircraft:nacelle:fineness + parameters:aircraft:nacelle:laminar_flow_lower [0.] input unitless traj.cruise.parameters:aircraft:nacelle:laminar_flow_lower + parameters:aircraft:nacelle:laminar_flow_upper [0.] input unitless traj.cruise.parameters:aircraft:nacelle:laminar_flow_upper + parameters:aircraft:nacelle:wetted_area [273.4536] input ft**2 traj.cruise.parameters:aircraft:nacelle:wetted_area + parameters:aircraft:engine:scale_factor [1.] input unitless traj.cruise.parameters:aircraft:engine:scale_factor + t_initial_val [3840.] output s traj.cruise.t_initial_val + t_duration_val [10170.] output s traj.cruise.t_duration_val + parameter_vals:aircraft:design:base_area [[0.]] output ft**2 traj.cruise.parameter_vals:aircraft:design:base_area + parameter_vals:aircraft:design:lift_dependent_drag_coeff_factor [[0.90983938]] output unitless traj.cruise.parameter_vals:aircraft:design:lift_dependent_drag_coeff_factor + parameter_vals:aircraft:design:subsonic_drag_coeff_factor [[1.]] output unitless traj.cruise.parameter_vals:aircraft:design:subsonic_drag_coeff_factor + parameter_vals:aircraft:design:supersonic_drag_coeff_factor [[1.]] output unitless traj.cruise.parameter_vals:aircraft:design:supersonic_drag_coeff_factor + parameter_vals:aircraft:design:zero_lift_drag_coeff_factor [[0.93089003]] output unitless traj.cruise.parameter_vals:aircraft:design:zero_lift_drag_coeff_factor + parameter_vals:aircraft:fuselage:characteristic_length [[128.]] output ft traj.cruise.parameter_vals:aircraft:fuselage:characteristic_length + parameter_vals:aircraft:fuselage:cross_section [[127.67628894]] output ft**2 traj.cruise.parameter_vals:aircraft:fuselage:cross_section + parameter_vals:aircraft:fuselage:diameter_to_wing_span [[0.10826471]] output unitless traj.cruise.parameter_vals:aircraft:fuselage:diameter_to_wing_span + parameter_vals:aircraft:fuselage:fineness [[10.03921569]] output unitless traj.cruise.parameter_vals:aircraft:fuselage:fineness + parameter_vals:aircraft:fuselage:laminar_flow_lower [[0.]] output unitless traj.cruise.parameter_vals:aircraft:fuselage:laminar_flow_lower + parameter_vals:aircraft:fuselage:laminar_flow_upper [[0.]] output unitless traj.cruise.parameter_vals:aircraft:fuselage:laminar_flow_upper + parameter_vals:aircraft:fuselage:length_to_diameter [[10.03921569]] output unitless traj.cruise.parameter_vals:aircraft:fuselage:length_to_diameter + parameter_vals:aircraft:fuselage:wetted_area [[4158.62]] output ft**2 traj.cruise.parameter_vals:aircraft:fuselage:wetted_area + parameter_vals:aircraft:horizontal_tail:characteristic_length [[7.69198717]] output ft traj.cruise.parameter_vals:aircraft:horizontal_tail:characteristic_length + parameter_vals:aircraft:horizontal_tail:fineness [[0.125]] output unitless traj.cruise.parameter_vals:aircraft:horizontal_tail:fineness + parameter_vals:aircraft:horizontal_tail:laminar_flow_lower [[0.]] output unitless traj.cruise.parameter_vals:aircraft:horizontal_tail:laminar_flow_lower + parameter_vals:aircraft:horizontal_tail:laminar_flow_upper [[0.]] output unitless traj.cruise.parameter_vals:aircraft:horizontal_tail:laminar_flow_upper + parameter_vals:aircraft:horizontal_tail:wetted_area [[592.65]] output ft**2 traj.cruise.parameter_vals:aircraft:horizontal_tail:wetted_area + parameter_vals:aircraft:vertical_tail:characteristic_length [[12.73914103]] output ft traj.cruise.parameter_vals:aircraft:vertical_tail:characteristic_length + parameter_vals:aircraft:vertical_tail:fineness [[0.1195]] output unitless traj.cruise.parameter_vals:aircraft:vertical_tail:fineness + parameter_vals:aircraft:vertical_tail:laminar_flow_lower [[0.]] output unitless traj.cruise.parameter_vals:aircraft:vertical_tail:laminar_flow_lower + parameter_vals:aircraft:vertical_tail:laminar_flow_upper [[0.]] output unitless traj.cruise.parameter_vals:aircraft:vertical_tail:laminar_flow_upper + parameter_vals:aircraft:vertical_tail:wetted_area [[581.13]] output ft**2 traj.cruise.parameter_vals:aircraft:vertical_tail:wetted_area + parameter_vals:aircraft:wing:area [[1370.]] output ft**2 traj.cruise.parameter_vals:aircraft:wing:area + parameter_vals:aircraft:wing:aspect_ratio [[11.22091]] output unitless traj.cruise.parameter_vals:aircraft:wing:aspect_ratio + parameter_vals:aircraft:wing:characteristic_length [[10.49530819]] output ft traj.cruise.parameter_vals:aircraft:wing:characteristic_length + parameter_vals:aircraft:wing:fineness [[0.13]] output unitless traj.cruise.parameter_vals:aircraft:wing:fineness + parameter_vals:aircraft:wing:laminar_flow_lower [[0.]] output unitless traj.cruise.parameter_vals:aircraft:wing:laminar_flow_lower + parameter_vals:aircraft:wing:laminar_flow_upper [[0.]] output unitless traj.cruise.parameter_vals:aircraft:wing:laminar_flow_upper + parameter_vals:aircraft:wing:max_camber_at_70_semispan [[0.]] output unitless traj.cruise.parameter_vals:aircraft:wing:max_camber_at_70_semispan + parameter_vals:aircraft:wing:span_efficiency_factor [[1.]] output unitless traj.cruise.parameter_vals:aircraft:wing:span_efficiency_factor + parameter_vals:aircraft:wing:sweep [[25.]] output deg traj.cruise.parameter_vals:aircraft:wing:sweep + parameter_vals:aircraft:wing:taper_ratio [[0.278]] output unitless traj.cruise.parameter_vals:aircraft:wing:taper_ratio + parameter_vals:aircraft:wing:thickness_to_chord [[0.13]] output unitless traj.cruise.parameter_vals:aircraft:wing:thickness_to_chord + parameter_vals:aircraft:wing:wetted_area [[2396.56]] output ft**2 traj.cruise.parameter_vals:aircraft:wing:wetted_area + parameter_vals:mission:design:lift_coefficient [[0.56736557]] output unitless traj.cruise.parameter_vals:mission:design:lift_coefficient + parameter_vals:mission:design:mach [[0.80017085]] output unitless traj.cruise.parameter_vals:mission:design:mach + parameter_vals:aircraft:nacelle:characteristic_length [[12.3]] output ft traj.cruise.parameter_vals:aircraft:nacelle:characteristic_length + parameter_vals:aircraft:nacelle:fineness [[1.54911839]] output unitless traj.cruise.parameter_vals:aircraft:nacelle:fineness + parameter_vals:aircraft:nacelle:laminar_flow_lower [[0.]] output unitless traj.cruise.parameter_vals:aircraft:nacelle:laminar_flow_lower + parameter_vals:aircraft:nacelle:laminar_flow_upper [[0.]] output unitless traj.cruise.parameter_vals:aircraft:nacelle:laminar_flow_upper + parameter_vals:aircraft:nacelle:wetted_area [[273.4536]] output ft**2 traj.cruise.parameter_vals:aircraft:nacelle:wetted_area + parameter_vals:aircraft:engine:scale_factor [[1.]] output unitless traj.cruise.parameter_vals:aircraft:engine:scale_factor + time + t_initial [3840.] input s traj.cruise.t_initial + t_duration [10170.] input s traj.cruise.t_duration + t |43155.65216817| output s traj.cruise.t + val: + array([ 3840. , 4264.17721573, 4849.45519765, 5034.69367782, + 5034.69367782, 5900.9841173 , 7096.28811139, 7474.5977387 , + 7474.5977387 , 8504.53135987, 9925.62954466, 10375.4022613 , + 10375.4022613 , 11241.69270078, 12436.99669488, 12815.30632218, + 12815.30632218, 13239.48353791, 13824.76151983, 14010. ]) + t_phase |27763.66679782| output s traj.cruise.t_phase + val: + array([ 0. , 424.17721573, 1009.45519765, 1194.69367782, + 1194.69367782, 2060.9841173 , 3256.28811139, 3634.5977387 , + 3634.5977387 , 4664.53135987, 6085.62954466, 6535.4022613 , + 6535.4022613 , 7401.69270078, 8596.99669488, 8975.30632218, + 8975.30632218, 9399.48353791, 9984.76151983, 10170. ]) + dt_dstau |4814.09560547| output s traj.cruise.dt_dstau + val: + array([ 597.34683891, 597.34683891, 597.34683891, 597.34683891, + 1219.95203044, 1219.95203044, 1219.95203044, 1219.95203044, + 1450.4022613 , 1450.4022613 , 1450.4022613 , 1450.4022613 , + 1219.95203044, 1219.95203044, 1219.95203044, 1219.95203044, + 597.34683891, 597.34683891, 597.34683891, 597.34683891]) + control_comp + dt_dstau |4814.09560547| input s traj.cruise.control_comp.dt_dstau + val: + array([ 597.34683891, 597.34683891, 597.34683891, 597.34683891, + 1219.95203044, 1219.95203044, 1219.95203044, 1219.95203044, + 1450.4022613 , 1450.4022613 , 1450.4022613 , 1450.4022613 , + 1219.95203044, 1219.95203044, 1219.95203044, 1219.95203044, + 597.34683891, 597.34683891, 597.34683891, 597.34683891]) + t_duration [10170.] input s traj.cruise.control_comp.t_duration + controls:mach |1.44| input unitless traj.cruise.controls:mach + val: + array([[0.72], + [0.72], + [0.72], + [0.72]]) + controls:altitude |66018.17931449| input ft traj.cruise.controls:altitude + val: + array([[32000. ], + [32552.7864045], + [33447.2135955], + [34000. ]]) + control_values:mach |3.21993789| output unitless traj.cruise.control_values:mach + val: + array([[0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72]]) + control_rates:mach_rate |0.0| output unitless/s traj.cruise.control_rates:mach_rate + val: + array([[ 0.00000000e+00], + [ 8.73331779e-20], + [ 4.36665890e-20], + [ 0.00000000e+00], + [ 0.00000000e+00], + [ 3.27499417e-20], + [ 2.18332945e-20], + [ 0.00000000e+00], + [ 0.00000000e+00], + [-4.36665890e-20], + [-6.54998835e-20], + [-4.36665890e-20], + [-4.36665890e-20], + [-4.91249126e-20], + [-2.18332945e-20], + [ 8.73331779e-20], + [ 8.73331779e-20], + [-8.73331779e-20], + [ 0.00000000e+00], + [ 1.74666356e-19]]) + control_rates:mach_rate2 |0.0| output unitless/s**2 traj.cruise.control_rates:mach_rate2 + val: + array([[ 0.00000000e+00], + [-6.86986651e-23], + [ 0.00000000e+00], + [ 0.00000000e+00], + [ 0.00000000e+00], + [-3.43493325e-23], + [-3.43493325e-23], + [ 0.00000000e+00], + [ 0.00000000e+00], + [-8.58733313e-24], + [ 0.00000000e+00], + [ 0.00000000e+00], + [ 0.00000000e+00], + [ 3.43493325e-23], + [ 3.43493325e-23], + [ 3.43493325e-23], + [ 3.43493325e-23], + [ 6.86986651e-23], + [ 1.37397330e-22], + [ 6.86986651e-23]]) + control_boundary_values:mach |1.01823376| output unitless traj.cruise.control_comp.control_boundary_values:mach + val: + array([[0.72], + [0.72]]) + control_boundary_rates:mach_rate |0.0| output unitless/s traj.cruise.control_comp.control_boundary_rates:mach_rate + val: + array([[0.00000000e+00], + [1.74666356e-19]]) + control_boundary_rates:mach_rate2 |0.0| output unitless/s**2 traj.cruise.control_comp.control_boundary_rates:mach_rate2 + val: + array([[0.00000000e+00], + [6.86986651e-23]]) + control_values:altitude |147700.4084954| output ft traj.cruise.control_values:altitude + val: + array([[32000. ], + [32083.41734823], + [32198.51626306], + [32234.94467607], + [32234.94467607], + [32405.30661107], + [32640.37131001], + [32714.76848352], + [32714.76848352], + [32917.31196851], + [33196.78063808], + [33285.23151648], + [33285.23151648], + [33455.59345148], + [33690.65815042], + [33765.05532393], + [33765.05532393], + [33848.47267216], + [33963.57158699], + [34000. ]]) + control_rates:altitude_rate |0.8794761| output ft/s traj.cruise.control_rates:altitude_rate + val: + array([[0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683]]) + control_rates:altitude_rate2 |0.0| output ft/s**2 traj.cruise.control_rates:altitude_rate2 + val: + array([[-4.50223571e-18], + [-4.50223571e-18], + [ 0.00000000e+00], + [ 0.00000000e+00], + [ 0.00000000e+00], + [-2.25111786e-18], + [-2.25111786e-18], + [ 5.62779464e-19], + [ 5.62779464e-19], + [-1.40694866e-19], + [ 5.62779464e-19], + [ 1.12555893e-18], + [ 1.12555893e-18], + [ 1.12555893e-18], + [ 2.25111786e-18], + [ 4.50223571e-18], + [ 4.50223571e-18], + [ 2.25111786e-18], + [ 4.50223571e-18], + [ 4.50223571e-18]]) + control_boundary_values:altitude |46690.47011972| output ft traj.cruise.control_comp.control_boundary_values:altitude + val: + array([[32000.], + [34000.]]) + control_boundary_rates:altitude_rate |0.27811476| output ft/s traj.cruise.control_comp.control_boundary_rates:altitude_rate + val: + array([[0.19665683], + [0.19665683]]) + control_boundary_rates:altitude_rate2 |0.0| output ft/s**2 traj.cruise.control_comp.control_boundary_rates:altitude_rate2 + val: + array([[-4.50223571e-18], + [ 4.50223571e-18]]) + indep_states + initial_states:mass [[57015.39290411]] input kg traj.cruise.initial_states:mass + initial_states:distance [[560039.40638961]] input m traj.cruise.initial_states:distance + states:mass |217826.10552332| output kg traj.cruise.states:mass + val: + array([[57015.39290411], + [56797.93787223], + [56499.27092781], + [56405.0756841 ], + [55966.67143281], + [55367.45066061], + [55179.16707729], + [54669.88811206], + [53975.10803913], + [53757.11559708], + [53339.81352995], + [52769.53817769], + [52590.37433179], + [52390.24374586], + [52115.41253722], + [52028.74471935]]) + states:distance |7389061.26546158| output m traj.cruise.states:distance + val: + array([[ 560039.40638961], + [ 651826.45257603], + [ 778418.59972934], + [ 818471.23138883], + [1005697.02623753], + [1263799.66653641], + [1345432.48793709], + [1567538.74520054], + [1873673.16694925], + [1970484.63129816], + [2156842.41376365], + [2413746.32168934], + [2494999.4935999 ], + [2586072.02583254], + [2711677.86536452], + [2751418.23144865]]) + state_interp + dt_dstau |4169.12909058| input s traj.cruise.state_interp.dt_dstau + val: + array([ 597.34683891, 597.34683891, 597.34683891, 1219.95203044, + 1219.95203044, 1219.95203044, 1450.4022613 , 1450.4022613 , + 1450.4022613 , 1219.95203044, 1219.95203044, 1219.95203044, + 597.34683891, 597.34683891, 597.34683891]) + state_disc:mass |243577.62672176| input kg traj.cruise.state_interp.state_disc:mass + val: + array([[57015.39290411], + [56797.93787223], + [56499.27092781], + [56405.0756841 ], + [56405.0756841 ], + [55966.67143281], + [55367.45066061], + [55179.16707729], + [55179.16707729], + [54669.88811206], + [53975.10803913], + [53757.11559708], + [53757.11559708], + [53339.81352995], + [52769.53817769], + [52590.37433179], + [52590.37433179], + [52390.24374586], + [52115.41253722], + [52028.74471935]]) + state_disc:distance |8196715.33458363| input m traj.cruise.state_interp.state_disc:distance + val: + array([[ 560039.40638961], + [ 651826.45257603], + [ 778418.59972934], + [ 818471.23138883], + [ 818471.23138883], + [1005697.02623753], + [1263799.66653641], + [1345432.48793709], + [1345432.48793709], + [1567538.74520054], + [1873673.16694925], + [1970484.63129816], + [1970484.63129816], + [2156842.41376365], + [2413746.32168934], + [2494999.4935999 ], + [2494999.4935999 ], + [2586072.02583254], + [2711677.86536452], + [2751418.23144865]]) + staterate_col:mass |1.90369215| output kg/s traj.cruise.state_interp.staterate_col:mass + val: + array([[-0.51364159], + [-0.51166194], + [-0.50893815], + [-0.50807793], + [-0.50406681], + [-0.49856426], + [-0.49683045], + [-0.49212903], + [-0.48568691], + [-0.48365848], + [-0.47976777], + [-0.47443141], + [-0.47274987], + [-0.47086868], + [-0.46828035]]) + staterate_col:distance |834.68098413| output m/s traj.cruise.state_interp.staterate_col:distance + val: + array([[216.42809093], + [216.34878522], + [216.23931282], + [216.20465388], + [216.04249491], + [215.81855294], + [215.7476287 ], + [215.55442444], + [215.28756351], + [215.20303548], + [215.04013759], + [214.81517331], + [214.74392485], + [214.66401045], + [214.55369706]]) + rhs_all + atmosphere + standard_atmosphere + h |147700.4084954| input ft traj.cruise.rhs_all.altitude + val: + array([32000. , 32083.41734823, 32198.51626306, 32234.94467607, + 32234.94467607, 32405.30661107, 32640.37131001, 32714.76848352, + 32714.76848352, 32917.31196851, 33196.78063808, 33285.23151648, + 33285.23151648, 33455.59345148, 33690.65815042, 33765.05532393, + 33765.05532393, 33848.47267216, 33963.57158699, 34000. ]) + temp |1793.81389837| output degR traj.cruise.rhs_all.temperature + val: + array([404.72782123, 404.4312669 , 404.02208634, 403.89258303, + 403.89258303, 403.28695094, 402.45131848, 402.18684758, + 402.18684758, 401.46684514, 400.47341164, 400.15899887, + 400.15899887, 399.55342768, 398.71787925, 398.45343495, + 398.45343495, 398.15693073, 397.74781931, 397.61833789]) + pres |17.03521656| output psi traj.cruise.rhs_all.static_pressure + val: + array([3.99016779, 3.97482967, 3.95374201, 3.94708596, 3.94708596, + 3.91607491, 3.87360603, 3.86024318, 3.86024318, 3.8240572 , + 3.77459278, 3.75904314, 3.75904314, 3.72923595, 3.68842027, + 3.67557869, 3.67557869, 3.66122435, 3.64149559, 3.6352703 ]) + rho |0.00356213| output slug/ft**3 traj.cruise.rhs_all.density + val: + array([0.00082715, 0.00082457, 0.00082103, 0.00081991, 0.00081991, + 0.00081469, 0.00080753, 0.00080527, 0.00080527, 0.00079915, + 0.00079077, 0.00078813, 0.00078813, 0.00078307, 0.00077612, + 0.00077393, 0.00077393, 0.00077148, 0.00076812, 0.00076705]) + viscosity |1.37e-06| output lbf*s/ft**2 traj.cruise.rhs_all.viscosity + val: + array([3.08755112e-07, 3.08563223e-07, 3.08298345e-07, 3.08214487e-07, + 3.08214487e-07, 3.07822153e-07, 3.07280402e-07, 3.07108846e-07, + 3.07108846e-07, 3.06641579e-07, 3.05996367e-07, 3.05792045e-07, + 3.05792045e-07, 3.05398344e-07, 3.04854735e-07, 3.04682587e-07, + 3.04682587e-07, 3.04489508e-07, 3.04222996e-07, 3.04138620e-07]) + drhos_dh |1.3e-07| output slug/ft**4 traj.cruise.rhs_all.drhos_dh + val: + array([-3.10133821e-08, -3.09387152e-08, -3.08399518e-08, -3.08085662e-08, + -3.08085662e-08, -3.06609758e-08, -3.04551345e-08, -3.03894557e-08, + -3.03894557e-08, -3.02093550e-08, -2.99676306e-08, -2.98931906e-08, + -2.98931906e-08, -2.97485691e-08, -2.95463292e-08, -2.94816707e-08, + -2.94816707e-08, -2.94088010e-08, -2.93076103e-08, -2.92754279e-08]) + sos |4390.63170709| output ft/s traj.cruise.rhs_all.speed_of_sound + val: + array([986.20269773, 985.84132367, 985.34248836, 985.18455722, + 985.18455722, 984.44564389, 983.42520261, 983.10202055, + 983.10202055, 982.22164251, 981.00563142, 980.62046071, + 980.62046071, 979.87818034, 978.85308069, 978.52842124, + 978.52842124, 978.16427355, 977.66160614, 977.50246093]) + flight_conditions + density |0.00356213| input slug/ft**3 traj.cruise.rhs_all.density + val: + array([0.00082715, 0.00082457, 0.00082103, 0.00081991, 0.00081991, + 0.00081469, 0.00080753, 0.00080527, 0.00080527, 0.00079915, + 0.00079077, 0.00078813, 0.00078813, 0.00078307, 0.00077612, + 0.00077393, 0.00077393, 0.00077148, 0.00076812, 0.00076705]) + speed_of_sound |4390.63170709| input ft/s traj.cruise.rhs_all.speed_of_sound + val: + array([986.20269773, 985.84132367, 985.34248836, 985.18455722, + 985.18455722, 984.44564389, 983.42520261, 983.10202055, + 983.10202055, 982.22164251, 981.00563142, 980.62046071, + 980.62046071, 979.87818034, 978.85308069, 978.52842124, + 978.52842124, 978.16427355, 977.66160614, 977.50246093]) + mach |3.21993789| input unitless traj.cruise.rhs_all.mach + val: + array([0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, + 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72]) + dynamic_pressure |890.23908728| output lbf/ft**2 traj.cruise.rhs_all.dynamic_pressure + val: + array([208.52120555, 207.71950091, 206.61736786, 206.2695204 , + 206.2695204 , 204.64899564, 202.42988607, 201.73163473, + 201.73163473, 199.84066159, 197.25538564, 196.44275765, + 196.44275765, 194.88514212, 192.75234949, 192.08130474, + 192.08130474, 191.33118115, 190.30013108, 189.97476746]) + EAS |1829.84522618| output ft/s traj.cruise.rhs_all.EAS + val: + array([418.87520758, 418.06920419, 416.95861826, 416.60748832, + 416.60748832, 414.96775506, 412.71177312, 411.99936477, + 411.99936477, 410.06383776, 407.40276977, 406.56272029, + 406.56272029, 404.94767291, 402.72573493, 402.02410248, + 402.02410248, 401.23833427, 400.15577248, 399.8135451 ]) + velocity |3161.2548291| output ft/s traj.cruise.rhs_all.velocity + val: + array([710.06594237, 709.80575304, 709.44659162, 709.3328812 , + 709.3328812 , 708.8008636 , 708.06614588, 707.8334548 , + 707.8334548 , 707.19958261, 706.32405462, 706.04673171, + 706.04673171, 705.51228985, 704.7742181 , 704.54046329, + 704.54046329, 704.27827695, 703.91635642, 703.80177187]) + velocity_rate_comp + mach_rate |0.0| input unitless/s traj.cruise.rhs_all.mach_rate + val: + array([ 0.00000000e+00, 8.73331779e-20, 4.36665890e-20, 0.00000000e+00, + 0.00000000e+00, 3.27499417e-20, 2.18332945e-20, 0.00000000e+00, + 0.00000000e+00, -4.36665890e-20, -6.54998835e-20, -4.36665890e-20, + -4.36665890e-20, -4.91249126e-20, -2.18332945e-20, 8.73331779e-20, + 8.73331779e-20, -8.73331779e-20, 0.00000000e+00, 1.74666356e-19]) + sos |1338.26454432| input m/s traj.cruise.rhs_all.speed_of_sound + val: + array([300.59458227, 300.48443545, 300.33239045, 300.28425304, + 300.28425304, 300.05903226, 299.74800175, 299.64949586, + 299.64949586, 299.38115664, 299.01051646, 298.89311642, + 298.89311642, 298.66686937, 298.354419 , 298.25546279, + 298.25546279, 298.14447058, 297.99125755, 297.94275009]) + velocity_rate |0.0| output m/s**2 traj.cruise.rhs_all.velocity_rate + val: + array([ 0.00000000e+00, 2.62422607e-17, 1.31144910e-17, 0.00000000e+00, + 0.00000000e+00, 9.82691582e-18, 6.54448639e-18, 0.00000000e+00, + 0.00000000e+00, -1.30729539e-17, -1.95851540e-17, -1.30516429e-17, + -1.30516429e-17, -1.46719839e-17, -6.51405989e-18, 2.60475974e-17, + 2.60475974e-17, -2.60379041e-17, 0.00000000e+00, 5.20405744e-17]) + solver_sub + core_aerodynamics + Mux + aircraft:wing:wetted_area [2396.56] input ft**2 traj.cruise.rhs_all.aircraft:wing:wetted_area + aircraft:wing:fineness [0.13] input unitless traj.cruise.rhs_all.aircraft:wing:fineness + aircraft:wing:characteristic_length [10.49530819] input ft traj.cruise.rhs_all.aircraft:wing:characteristic_length + aircraft:wing:laminar_flow_upper [0.] input unitless traj.cruise.rhs_all.aircraft:wing:laminar_flow_upper + aircraft:wing:laminar_flow_lower [0.] input unitless traj.cruise.rhs_all.aircraft:wing:laminar_flow_lower + aircraft:horizontal_tail:wetted_area [592.65] input ft**2 traj.cruise.rhs_all.aircraft:horizontal_tail:wetted_area + aircraft:horizontal_tail:fineness [0.125] input unitless traj.cruise.rhs_all.aircraft:horizontal_tail:fineness + aircraft:horizontal_tail:characteristic_length [7.69198717] input ft traj.cruise.rhs_all.aircraft:horizontal_tail:characteristic_length + aircraft:horizontal_tail:laminar_flow_upper [0.] input unitless traj.cruise.rhs_all.aircraft:horizontal_tail:laminar_flow_upper + aircraft:horizontal_tail:laminar_flow_lower [0.] input unitless traj.cruise.rhs_all.aircraft:horizontal_tail:laminar_flow_lower + aircraft:vertical_tail:wetted_area [581.13] input ft**2 traj.cruise.rhs_all.aircraft:vertical_tail:wetted_area + aircraft:vertical_tail:fineness [0.1195] input unitless traj.cruise.rhs_all.aircraft:vertical_tail:fineness + aircraft:vertical_tail:characteristic_length [12.73914103] input ft traj.cruise.rhs_all.aircraft:vertical_tail:characteristic_length + aircraft:vertical_tail:laminar_flow_upper [0.] input unitless traj.cruise.rhs_all.aircraft:vertical_tail:laminar_flow_upper + aircraft:vertical_tail:laminar_flow_lower [0.] input unitless traj.cruise.rhs_all.aircraft:vertical_tail:laminar_flow_lower + aircraft:fuselage:wetted_area [4158.62] input ft**2 traj.cruise.rhs_all.aircraft:fuselage:wetted_area + aircraft:fuselage:fineness [10.03921569] input unitless traj.cruise.rhs_all.aircraft:fuselage:fineness + aircraft:fuselage:characteristic_length [128.] input ft traj.cruise.rhs_all.aircraft:fuselage:characteristic_length + aircraft:fuselage:laminar_flow_upper [0.] input unitless traj.cruise.rhs_all.aircraft:fuselage:laminar_flow_upper + aircraft:fuselage:laminar_flow_lower [0.] input unitless traj.cruise.rhs_all.aircraft:fuselage:laminar_flow_lower + aircraft:nacelle:wetted_area [273.4536] input ft**2 traj.cruise.rhs_all.aircraft:nacelle:wetted_area + aircraft:nacelle:fineness [1.54911839] input unitless traj.cruise.rhs_all.aircraft:nacelle:fineness + aircraft:nacelle:characteristic_length [12.3] input ft traj.cruise.rhs_all.aircraft:nacelle:characteristic_length + aircraft:nacelle:laminar_flow_upper [0.] input unitless traj.cruise.rhs_all.aircraft:nacelle:laminar_flow_upper + aircraft:nacelle:laminar_flow_lower [0.] input unitless traj.cruise.rhs_all.aircraft:nacelle:laminar_flow_lower + wetted_areas |4886.31967641| output ft**2 traj.cruise.rhs_all.core_aerodynamics.wetted_areas + val: + array([2396.56 , 592.65 , 581.13 , 4158.62 , 273.4536, 273.4536]) + fineness_ratios |10.2777523| output unitless traj.cruise.rhs_all.core_aerodynamics.fineness_ratios + val: + array([ 0.13 , 0.125 , 0.1195 , 10.03921569, 1.54911839, + 1.54911839]) + characteristic_lengths |130.45376144| output ft traj.cruise.rhs_all.core_aerodynamics.characteristic_lengths + val: + array([ 10.49530819, 7.69198717, 12.73914103, 128. , + 12.3 , 12.3 ]) + laminar_fractions_upper |0.0| output unitless traj.cruise.rhs_all.core_aerodynamics.laminar_fractions_upper + val: + array([0., 0., 0., 0., 0., 0.]) + laminar_fractions_lower |0.0| output unitless traj.cruise.rhs_all.core_aerodynamics.laminar_fractions_lower + val: + array([0., 0., 0., 0., 0., 0.]) + DynamicPressure + static_pressure |2453.07118165| input lbf/ft**2 traj.cruise.rhs_all.static_pressure + val: + array([574.58416126, 572.37547248, 569.33884949, 568.38037824, + 568.38037824, 563.91478575, 557.79926709, 555.8750171 , + 555.8750171 , 550.66423551, 543.5413597 , 541.30221159, + 541.30221159, 537.00997557, 531.13251762, 529.28333072, + 529.28333072, 527.21630621, 524.37536456, 523.4789226 ]) + mach |3.21993789| input unitless traj.cruise.rhs_all.mach + val: + array([0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, + 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72]) + dynamic_pressure |890.1704704| output lbf/ft**2 traj.cruise.rhs_all.core_aerodynamics.dynamic_pressure + val: + array([208.50510044, 207.70361145, 206.6016817 , 206.25387165, + 206.25387165, 204.63339745, 202.41419804, 201.7159262 , + 201.7159262 , 199.82503778, 197.24028861, 196.42774654, + 196.42774654, 194.87017994, 192.73736799, 192.06633505, + 192.06633505, 191.3162532 , 190.28533229, 189.96003143]) + lift + aircraft:wing:area [127.2771648] input m**2 traj.cruise.rhs_all.aircraft:wing:area + mass |243577.62672176| input kg traj.cruise.rhs_all.mass + val: + array([57015.39290411, 56797.93787223, 56499.27092781, 56405.0756841 , + 56405.0756841 , 55966.67143281, 55367.45066061, 55179.16707729, + 55179.16707729, 54669.88811206, 53975.10803913, 53757.11559708, + 53757.11559708, 53339.81352995, 52769.53817769, 52590.37433179, + 52590.37433179, 52390.24374586, 52115.41253722, 52028.74471935]) + dynamic_pressure |42621.59270473| input N/m**2 traj.cruise.rhs_all.core_aerodynamics.dynamic_pressure + val: + array([9983.27821833, 9944.90271819, 9892.14203622, 9875.48880103, + 9875.48880103, 9797.90007646, 9691.64423382, 9658.21079739, + 9658.21079739, 9567.67456994, 9443.91610993, 9405.01138535, + 9405.01138535, 9330.43469278, 9228.31510457, 9196.18587354, + 9196.18587354, 9160.27175995, 9110.91099999, 9095.33551064]) + cl |1.96928114| output unitless traj.cruise.rhs_all.core_aerodynamics.cl + val: + array([0.44003693, 0.44005019, 0.44007093, 0.44007811, 0.44007811, + 0.44011549, 0.4401769 , 0.44019859, 0.44019859, 0.44026278, + 0.44036377, 0.4403995 , 0.4403995 , 0.44047351, 0.44058637, + 0.44062456, 0.44062456, 0.44066874, 0.44073197, 0.44075252]) + lift |2388680.53309095| output N traj.cruise.rhs_all.lift + val: + array([559130.00282312, 556997.49743474, 554068.57524424, 553144.83545746, + 553144.83545746, 548845.55840659, 542969.21002082, 541122.77881849, + 541122.77881849, 536128.45825413, 529314.99325197, 527177.21767011, + 527177.21767011, 523084.88235346, 517492.39157025, 515735.39444086, + 515735.39444086, 513772.78383032, 511077.61035812, 510227.68940198]) + PressureDrag + mach |3.21993789| input unitless traj.cruise.rhs_all.mach + val: + array([0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, + 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72]) + lift |536996.74547487| input lbf traj.cruise.rhs_all.core_aerodynamics.lift + val: + array([125697.42485608, 125218.01857407, 124559.5706727 , 124351.90570776, + 124351.90570776, 123385.38977889, 122064.33411041, 121649.23986375, + 121649.23986375, 120526.47193737, 118994.74407302, 118514.15300439, + 118514.15300439, 117594.15942802, 116336.91748709, 115941.92881983, + 115941.92881983, 115500.71640323, 114894.81730412, 114703.74747245]) + static_pressure |2453.07118165| input lbf/ft**2 traj.cruise.rhs_all.static_pressure + val: + array([574.58416126, 572.37547248, 569.33884949, 568.38037824, + 568.38037824, 563.91478575, 557.79926709, 555.8750171 , + 555.8750171 , 550.66423551, 543.5413597 , 541.30221159, + 541.30221159, 537.00997557, 531.13251762, 529.28333072, + 529.28333072, 527.21630621, 524.37536456, 523.4789226 ]) + mission:design:lift_coefficient [0.56736557] input unitless traj.cruise.rhs_all.mission:design:lift_coefficient + mission:design:mach [0.80017085] input unitless traj.cruise.rhs_all.mission:design:mach + aircraft:wing:area [1370.] input ft**2 traj.cruise.rhs_all.aircraft:wing:area + aircraft:wing:aspect_ratio [11.22091] input unitless traj.cruise.rhs_all.aircraft:wing:aspect_ratio + aircraft:wing:max_camber_at_70_semispan [0.] input unitless traj.cruise.rhs_all.aircraft:wing:max_camber_at_70_semispan + aircraft:wing:sweep [25.] input deg traj.cruise.rhs_all.aircraft:wing:sweep + aircraft:wing:thickness_to_chord [0.13] input unitless traj.cruise.rhs_all.aircraft:wing:thickness_to_chord + CD |0.00417813| output unitless traj.cruise.rhs_all.core_aerodynamics.PressureDrag.CD + val: + array([0.00093247, 0.00093254, 0.00093267, 0.00093271, 0.00093271, + 0.00093292, 0.00093328, 0.00093341, 0.00093341, 0.00093378, + 0.00093437, 0.00093458, 0.00093458, 0.00093501, 0.00093566, + 0.00093589, 0.00093589, 0.00093614, 0.00093651, 0.00093663]) + InducedDrag + mach |3.21993789| input unitless traj.cruise.rhs_all.mach + val: + array([0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, + 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72]) + lift |536996.74547487| input lbf traj.cruise.rhs_all.core_aerodynamics.lift + val: + array([125697.42485608, 125218.01857407, 124559.5706727 , 124351.90570776, + 124351.90570776, 123385.38977889, 122064.33411041, 121649.23986375, + 121649.23986375, 120526.47193737, 118994.74407302, 118514.15300439, + 118514.15300439, 117594.15942802, 116336.91748709, 115941.92881983, + 115941.92881983, 115500.71640323, 114894.81730412, 114703.74747245]) + static_pressure |2453.07118165| input lbf/ft**2 traj.cruise.rhs_all.static_pressure + val: + array([574.58416126, 572.37547248, 569.33884949, 568.38037824, + 568.38037824, 563.91478575, 557.79926709, 555.8750171 , + 555.8750171 , 550.66423551, 543.5413597 , 541.30221159, + 541.30221159, 537.00997557, 531.13251762, 529.28333072, + 529.28333072, 527.21630621, 524.37536456, 523.4789226 ]) + aircraft:wing:area [1370.] input ft**2 traj.cruise.rhs_all.aircraft:wing:area + aircraft:wing:aspect_ratio [11.22091] input unitless traj.cruise.rhs_all.aircraft:wing:aspect_ratio + aircraft:wing:span_efficiency_factor [1.] input unitless traj.cruise.rhs_all.aircraft:wing:span_efficiency_factor + aircraft:wing:sweep [25.] input deg traj.cruise.rhs_all.aircraft:wing:sweep + aircraft:wing:taper_ratio [0.278] input unitless traj.cruise.rhs_all.aircraft:wing:taper_ratio + induced_drag_coeff |0.0245993| output unitless traj.cruise.rhs_all.core_aerodynamics.InducedDrag.induced_drag_coeff + val: + array([0.00549288, 0.00549321, 0.00549373, 0.00549391, 0.00549391, + 0.00549484, 0.00549638, 0.00549692, 0.00549692, 0.00549852, + 0.00550105, 0.00550194, 0.00550194, 0.00550379, 0.00550661, + 0.00550756, 0.00550756, 0.00550867, 0.00551025, 0.00551076]) + CompressibilityDrag + mach |3.21993789| input unitless traj.cruise.rhs_all.mach + val: + array([0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, + 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72]) + mission:design:mach [0.80017085] input unitless traj.cruise.rhs_all.mission:design:mach + aircraft:design:base_area [0.] input ft**2 traj.cruise.rhs_all.aircraft:design:base_area + aircraft:wing:area [1370.] input ft**2 traj.cruise.rhs_all.aircraft:wing:area + aircraft:wing:aspect_ratio [11.22091] input unitless traj.cruise.rhs_all.aircraft:wing:aspect_ratio + aircraft:wing:max_camber_at_70_semispan [0.] input unitless traj.cruise.rhs_all.aircraft:wing:max_camber_at_70_semispan + aircraft:wing:sweep [25.] input deg traj.cruise.rhs_all.aircraft:wing:sweep + aircraft:wing:taper_ratio [0.278] input unitless traj.cruise.rhs_all.aircraft:wing:taper_ratio + aircraft:wing:thickness_to_chord [0.13] input unitless traj.cruise.rhs_all.aircraft:wing:thickness_to_chord + aircraft:fuselage:cross_section [127.67628894] input ft**2 traj.cruise.rhs_all.aircraft:fuselage:cross_section + aircraft:fuselage:diameter_to_wing_span [0.10826471] input unitless traj.cruise.rhs_all.aircraft:fuselage:diameter_to_wing_span + aircraft:fuselage:length_to_diameter [10.03921569] input unitless traj.cruise.rhs_all.aircraft:fuselage:length_to_diameter + compress_drag_coeff |0.0042079| output unitless traj.cruise.rhs_all.core_aerodynamics.CompressibilityDrag.compress_drag_coeff + val: + array([0.00094091, 0.00094091, 0.00094091, 0.00094091, 0.00094091, + 0.00094091, 0.00094091, 0.00094091, 0.00094091, 0.00094091, + 0.00094091, 0.00094091, 0.00094091, 0.00094091, 0.00094091, + 0.00094091, 0.00094091, 0.00094091, 0.00094091, 0.00094091]) + SkinFrictionCoef + temperature |1793.81389837| input degR traj.cruise.rhs_all.temperature + val: + array([404.72782123, 404.4312669 , 404.02208634, 403.89258303, + 403.89258303, 403.28695094, 402.45131848, 402.18684758, + 402.18684758, 401.46684514, 400.47341164, 400.15899887, + 400.15899887, 399.55342768, 398.71787925, 398.45343495, + 398.45343495, 398.15693073, 397.74781931, 397.61833789]) + static_pressure |2453.07118165| input lbf/ft**2 traj.cruise.rhs_all.static_pressure + val: + array([574.58416126, 572.37547248, 569.33884949, 568.38037824, + 568.38037824, 563.91478575, 557.79926709, 555.8750171 , + 555.8750171 , 550.66423551, 543.5413597 , 541.30221159, + 541.30221159, 537.00997557, 531.13251762, 529.28333072, + 529.28333072, 527.21630621, 524.37536456, 523.4789226 ]) + mach |3.21993789| input unitless traj.cruise.rhs_all.mach + val: + array([0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, + 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72]) + characteristic_lengths |130.45376144| input ft traj.cruise.rhs_all.core_aerodynamics.characteristic_lengths + val: + array([ 10.49530819, 7.69198717, 12.73914103, 128. , + 12.3 , 12.3 ]) + cf_iter |0.02795227| output unitless traj.cruise.rhs_all.core_aerodynamics.SkinFrictionCoef.cf_iter + val: + array([[0.00266681, 0.00280109, 0.00258767, 0.00185688, 0.00260175, + 0.00260175], + [0.00266801, 0.00280238, 0.00258882, 0.0018576 , 0.00260291, + 0.00260291], + [0.00266967, 0.00280416, 0.00259041, 0.00185859, 0.00260451, + 0.00260451], + [0.0026702 , 0.00280472, 0.00259092, 0.0018589 , 0.00260502, + 0.00260502], + [0.0026702 , 0.00280472, 0.00259092, 0.0018589 , 0.00260502, + 0.00260502], + [0.00267266, 0.00280737, 0.00259328, 0.00186037, 0.0026074 , + 0.0026074 ], + [0.00267608, 0.00281103, 0.00259655, 0.0018624 , 0.0026107 , + 0.0026107 ], + [0.00267716, 0.0028122 , 0.00259759, 0.00186305, 0.00261175, + 0.00261175], + [0.00267716, 0.0028122 , 0.00259759, 0.00186305, 0.00261175, + 0.00261175], + [0.00268012, 0.00281537, 0.00260042, 0.00186481, 0.0026146 , + 0.0026146 ], + [0.00268421, 0.00281976, 0.00260435, 0.00186725, 0.00261855, + 0.00261855], + [0.00268551, 0.00282115, 0.00260559, 0.00186802, 0.00261981, + 0.00261981], + [0.00268551, 0.00282115, 0.00260559, 0.00186802, 0.00261981, + 0.00261981], + [0.00268802, 0.00282384, 0.00260799, 0.00186952, 0.00262223, + 0.00262223], + [0.0026915 , 0.00282757, 0.00261132, 0.00187158, 0.00262558, + 0.00262558], + [0.0026926 , 0.00282875, 0.00261238, 0.00187224, 0.00262665, + 0.00262665], + [0.0026926 , 0.00282875, 0.00261238, 0.00187224, 0.00262665, + 0.00262665], + [0.00269384, 0.00283008, 0.00261356, 0.00187297, 0.00262784, + 0.00262784], + [0.00269555, 0.00283191, 0.0026152 , 0.00187399, 0.00262949, + 0.00262949], + [0.00269609, 0.00283249, 0.00261572, 0.00187431, 0.00263002, + 0.00263002]]) + skin_friction_coeff |0.02645907| output unitless traj.cruise.rhs_all.core_aerodynamics.skin_friction_coeff + val: + array([[0.00252403, 0.00265084, 0.0024493 , 0.00175916, 0.0024626 , + 0.0024626 ], + [0.00252518, 0.00265207, 0.0024504 , 0.00175984, 0.0024637 , + 0.0024637 ], + [0.00252676, 0.00265376, 0.00245191, 0.00176079, 0.00246523, + 0.00246523], + [0.00252726, 0.0026543 , 0.00245239, 0.00176109, 0.00246571, + 0.00246571], + [0.00252726, 0.0026543 , 0.00245239, 0.00176109, 0.00246571, + 0.00246571], + [0.0025296 , 0.00265681, 0.00245464, 0.00176249, 0.00246798, + 0.00246798], + [0.00253285, 0.0026603 , 0.00245775, 0.00176444, 0.00247111, + 0.00247111], + [0.00253388, 0.0026614 , 0.00245874, 0.00176505, 0.00247211, + 0.00247211], + [0.00253388, 0.0026614 , 0.00245874, 0.00176505, 0.00247211, + 0.00247211], + [0.0025367 , 0.00266442, 0.00246144, 0.00176674, 0.00247482, + 0.00247482], + [0.00254059, 0.00266859, 0.00246517, 0.00176906, 0.00247858, + 0.00247858], + [0.00254182, 0.00266991, 0.00246635, 0.0017698 , 0.00247978, + 0.00247978], + [0.00254182, 0.00266991, 0.00246635, 0.0017698 , 0.00247978, + 0.00247978], + [0.00254421, 0.00267247, 0.00246864, 0.00177123, 0.00248208, + 0.00248208], + [0.00254752, 0.00267602, 0.0024718 , 0.0017732 , 0.00248527, + 0.00248527], + [0.00254856, 0.00267714, 0.00247281, 0.00177383, 0.00248628, + 0.00248628], + [0.00254856, 0.00267714, 0.00247281, 0.00177383, 0.00248628, + 0.00248628], + [0.00254974, 0.0026784 , 0.00247393, 0.00177453, 0.00248742, + 0.00248742], + [0.00255137, 0.00268014, 0.00247549, 0.00177551, 0.00248899, + 0.00248899], + [0.00255188, 0.0026807 , 0.00247599, 0.00177581, 0.00248949, + 0.00248949]]) + Re |1080455359.9739447| output unitless traj.cruise.rhs_all.core_aerodynamics.Re + val: + array([[2.01263640e+07, 1.47505658e+07, 2.44292579e+07, 2.45459643e+08, + 2.35871375e+07, 2.35871375e+07], + [2.00685447e+07, 1.47081901e+07, 2.43590771e+07, 2.44754482e+08, + 2.35193760e+07, 2.35193760e+07], + [1.99889596e+07, 1.46498624e+07, 2.42624772e+07, 2.43783868e+08, + 2.34261061e+07, 2.34261061e+07], + [1.99638172e+07, 1.46314356e+07, 2.42319595e+07, 2.43477233e+08, + 2.33966404e+07, 2.33966404e+07], + [1.99638172e+07, 1.46314356e+07, 2.42319595e+07, 2.43477233e+08, + 2.33966404e+07, 2.33966404e+07], + [1.98465360e+07, 1.45454805e+07, 2.40896043e+07, 2.42046880e+08, + 2.32591924e+07, 2.32591924e+07], + [1.96855499e+07, 1.44274941e+07, 2.38942003e+07, 2.40083506e+08, + 2.30705244e+07, 2.30705244e+07], + [1.96348075e+07, 1.43903052e+07, 2.38326096e+07, 2.39464656e+08, + 2.30110568e+07, 2.30110568e+07], + [1.96348075e+07, 1.43903052e+07, 2.38326096e+07, 2.39464656e+08, + 2.30110568e+07, 2.30110568e+07], + [1.94971908e+07, 1.42894462e+07, 2.36655712e+07, 2.37786292e+08, + 2.28497765e+07, 2.28497765e+07], + [1.93085792e+07, 1.41512132e+07, 2.34366357e+07, 2.35486000e+08, + 2.26287328e+07, 2.26287328e+07], + [1.92491598e+07, 1.41076648e+07, 2.33645127e+07, 2.34761325e+08, + 2.25590960e+07, 2.25590960e+07], + [1.92491598e+07, 1.41076648e+07, 2.33645127e+07, 2.34761325e+08, + 2.25590960e+07, 2.25590960e+07], + [1.91350858e+07, 1.40240603e+07, 2.32260504e+07, 2.33370087e+08, + 2.24254068e+07, 2.24254068e+07], + [1.89785178e+07, 1.39093120e+07, 2.30360091e+07, 2.31460596e+08, + 2.22419166e+07, 2.22419166e+07], + [1.89291719e+07, 1.38731464e+07, 2.29761133e+07, 2.30858776e+08, + 2.21840855e+07, 2.21840855e+07], + [1.89291719e+07, 1.38731464e+07, 2.29761133e+07, 2.30858776e+08, + 2.21840855e+07, 2.21840855e+07], + [1.88739646e+07, 1.38326851e+07, 2.29091031e+07, 2.30185472e+08, + 2.21193852e+07, 2.21193852e+07], + [1.87980046e+07, 1.37770142e+07, 2.28169033e+07, 2.29259069e+08, + 2.20303637e+07, 2.20303637e+07], + [1.87740162e+07, 1.37594332e+07, 2.27877863e+07, 2.28966508e+08, + 2.20022504e+07, 2.20022504e+07]]) + wall_temp |4767.00873853| output degR traj.cruise.rhs_all.core_aerodynamics.SkinFrictionCoef.wall_temp + val: + array([[439.28316759, 439.38550012, 439.2181017 , 438.36912071, + 439.22995416, 439.22995416], + [438.95927068, 439.06163127, 438.89418676, 438.04496127, + 438.90604251, 438.90604251], + [438.51236175, 438.61476117, 438.4472529 , 437.59768921, + 438.45911321, 438.45911321], + [438.37091718, 438.47332892, 438.30580042, 437.45612946, + 438.31766217, 438.31766217], + [438.37091718, 438.47332892, 438.30580042, 437.45612946, + 438.31766217, 438.31766217], + [437.7094387 , 437.81190818, 437.64428486, 436.79411101, + 437.65615339, 437.65615339], + [436.79674802, 436.89929743, 436.73154285, 435.88067283, + 436.74342075, 436.74342075], + [436.5078888 , 436.61046354, 436.44266736, 435.59157674, + 436.45454824, 436.45454824], + [436.5078888 , 436.61046354, 436.44266736, 435.59157674, + 436.45454824, 436.45454824], + [435.72149288, 435.82413657, 435.65622717, 434.80453602, + 435.66811613, 435.66811613], + [434.63645774, 434.73919648, 434.57113099, 433.71861181, + 434.58303111, 434.58303111], + [434.29305211, 434.39582105, 434.22770597, 433.37492366, + 434.23960963, 434.23960963], + [434.29305211, 434.39582105, 434.22770597, 433.37492366, + 434.23960963, 434.23960963], + [433.63163707, 433.73446435, 433.56625346, 432.71296292, + 433.57816397, 433.57816397], + [432.71903478, 432.82194279, 432.65359932, 431.79960555, + 432.6655193 , 432.6655193 ], + [432.43020376, 432.53313734, 432.36475188, 431.51053533, + 432.37667486, 432.37667486], + [432.43020376, 432.53313734, 432.36475188, 431.51053533, + 432.37667486, 432.37667486], + [432.10635676, 432.20931901, 432.04088647, 431.18642017, + 432.05281281, 432.05281281], + [431.65951951, 431.76252129, 431.59402384, 430.73921313, + 431.60595482, 431.60595482], + [431.51809847, 431.62111275, 431.45259477, 430.59767514, + 431.46452722, 431.46452722]]) + SkinFrictionDrag + skin_friction_coeff |0.02645907| input unitless traj.cruise.rhs_all.core_aerodynamics.skin_friction_coeff + val: + array([[0.00252403, 0.00265084, 0.0024493 , 0.00175916, 0.0024626 , + 0.0024626 ], + [0.00252518, 0.00265207, 0.0024504 , 0.00175984, 0.0024637 , + 0.0024637 ], + [0.00252676, 0.00265376, 0.00245191, 0.00176079, 0.00246523, + 0.00246523], + [0.00252726, 0.0026543 , 0.00245239, 0.00176109, 0.00246571, + 0.00246571], + [0.00252726, 0.0026543 , 0.00245239, 0.00176109, 0.00246571, + 0.00246571], + [0.0025296 , 0.00265681, 0.00245464, 0.00176249, 0.00246798, + 0.00246798], + [0.00253285, 0.0026603 , 0.00245775, 0.00176444, 0.00247111, + 0.00247111], + [0.00253388, 0.0026614 , 0.00245874, 0.00176505, 0.00247211, + 0.00247211], + [0.00253388, 0.0026614 , 0.00245874, 0.00176505, 0.00247211, + 0.00247211], + [0.0025367 , 0.00266442, 0.00246144, 0.00176674, 0.00247482, + 0.00247482], + [0.00254059, 0.00266859, 0.00246517, 0.00176906, 0.00247858, + 0.00247858], + [0.00254182, 0.00266991, 0.00246635, 0.0017698 , 0.00247978, + 0.00247978], + [0.00254182, 0.00266991, 0.00246635, 0.0017698 , 0.00247978, + 0.00247978], + [0.00254421, 0.00267247, 0.00246864, 0.00177123, 0.00248208, + 0.00248208], + [0.00254752, 0.00267602, 0.0024718 , 0.0017732 , 0.00248527, + 0.00248527], + [0.00254856, 0.00267714, 0.00247281, 0.00177383, 0.00248628, + 0.00248628], + [0.00254856, 0.00267714, 0.00247281, 0.00177383, 0.00248628, + 0.00248628], + [0.00254974, 0.0026784 , 0.00247393, 0.00177453, 0.00248742, + 0.00248742], + [0.00255137, 0.00268014, 0.00247549, 0.00177551, 0.00248899, + 0.00248899], + [0.00255188, 0.0026807 , 0.00247599, 0.00177581, 0.00248949, + 0.00248949]]) + Re |1080455359.9739447| input unitless traj.cruise.rhs_all.core_aerodynamics.Re + val: + array([[2.01263640e+07, 1.47505658e+07, 2.44292579e+07, 2.45459643e+08, + 2.35871375e+07, 2.35871375e+07], + [2.00685447e+07, 1.47081901e+07, 2.43590771e+07, 2.44754482e+08, + 2.35193760e+07, 2.35193760e+07], + [1.99889596e+07, 1.46498624e+07, 2.42624772e+07, 2.43783868e+08, + 2.34261061e+07, 2.34261061e+07], + [1.99638172e+07, 1.46314356e+07, 2.42319595e+07, 2.43477233e+08, + 2.33966404e+07, 2.33966404e+07], + [1.99638172e+07, 1.46314356e+07, 2.42319595e+07, 2.43477233e+08, + 2.33966404e+07, 2.33966404e+07], + [1.98465360e+07, 1.45454805e+07, 2.40896043e+07, 2.42046880e+08, + 2.32591924e+07, 2.32591924e+07], + [1.96855499e+07, 1.44274941e+07, 2.38942003e+07, 2.40083506e+08, + 2.30705244e+07, 2.30705244e+07], + [1.96348075e+07, 1.43903052e+07, 2.38326096e+07, 2.39464656e+08, + 2.30110568e+07, 2.30110568e+07], + [1.96348075e+07, 1.43903052e+07, 2.38326096e+07, 2.39464656e+08, + 2.30110568e+07, 2.30110568e+07], + [1.94971908e+07, 1.42894462e+07, 2.36655712e+07, 2.37786292e+08, + 2.28497765e+07, 2.28497765e+07], + [1.93085792e+07, 1.41512132e+07, 2.34366357e+07, 2.35486000e+08, + 2.26287328e+07, 2.26287328e+07], + [1.92491598e+07, 1.41076648e+07, 2.33645127e+07, 2.34761325e+08, + 2.25590960e+07, 2.25590960e+07], + [1.92491598e+07, 1.41076648e+07, 2.33645127e+07, 2.34761325e+08, + 2.25590960e+07, 2.25590960e+07], + [1.91350858e+07, 1.40240603e+07, 2.32260504e+07, 2.33370087e+08, + 2.24254068e+07, 2.24254068e+07], + [1.89785178e+07, 1.39093120e+07, 2.30360091e+07, 2.31460596e+08, + 2.22419166e+07, 2.22419166e+07], + [1.89291719e+07, 1.38731464e+07, 2.29761133e+07, 2.30858776e+08, + 2.21840855e+07, 2.21840855e+07], + [1.89291719e+07, 1.38731464e+07, 2.29761133e+07, 2.30858776e+08, + 2.21840855e+07, 2.21840855e+07], + [1.88739646e+07, 1.38326851e+07, 2.29091031e+07, 2.30185472e+08, + 2.21193852e+07, 2.21193852e+07], + [1.87980046e+07, 1.37770142e+07, 2.28169033e+07, 2.29259069e+08, + 2.20303637e+07, 2.20303637e+07], + [1.87740162e+07, 1.37594332e+07, 2.27877863e+07, 2.28966508e+08, + 2.20022504e+07, 2.20022504e+07]]) + fineness_ratios |10.2777523| input unitless traj.cruise.rhs_all.core_aerodynamics.fineness_ratios + val: + array([ 0.13 , 0.125 , 0.1195 , 10.03921569, 1.54911839, + 1.54911839]) + wetted_areas |4886.31967641| input ft**2 traj.cruise.rhs_all.core_aerodynamics.wetted_areas + val: + array([2396.56 , 592.65 , 581.13 , 4158.62 , 273.4536, 273.4536]) + laminar_fractions_upper |0.0| input unitless traj.cruise.rhs_all.core_aerodynamics.laminar_fractions_upper + val: + array([0., 0., 0., 0., 0., 0.]) + laminar_fractions_lower |0.0| input unitless traj.cruise.rhs_all.core_aerodynamics.laminar_fractions_lower + val: + array([0., 0., 0., 0., 0., 0.]) + aircraft:wing:area [1370.] input ft**2 traj.cruise.rhs_all.aircraft:wing:area + skin_friction_drag_coeff |0.09010481| output unitless traj.cruise.rhs_all.core_aerodynamics.SkinFrictionDrag.skin_friction_drag_coeff + val: + array([0.02004067, 0.02004935, 0.02006133, 0.02006513, 0.02006513, + 0.02008293, 0.02010757, 0.02011539, 0.02011539, 0.02013671, + 0.02016624, 0.02017562, 0.02017562, 0.02019371, 0.02021877, + 0.02022672, 0.02022672, 0.02023564, 0.02024797, 0.02025187]) + Drag + CDI + induced_drag_coeff |0.0245993| input unitless traj.cruise.rhs_all.core_aerodynamics.Drag.induced_drag_coeff + val: + array([0.00549288, 0.00549321, 0.00549373, 0.00549391, 0.00549391, + 0.00549484, 0.00549638, 0.00549692, 0.00549692, 0.00549852, + 0.00550105, 0.00550194, 0.00550194, 0.00550379, 0.00550661, + 0.00550756, 0.00550756, 0.00550867, 0.00551025, 0.00551076]) + pressure_drag_coeff |0.00417813| input unitless traj.cruise.rhs_all.core_aerodynamics.Drag.pressure_drag_coeff + val: + array([0.00093247, 0.00093254, 0.00093267, 0.00093271, 0.00093271, + 0.00093292, 0.00093328, 0.00093341, 0.00093341, 0.00093378, + 0.00093437, 0.00093458, 0.00093458, 0.00093501, 0.00093566, + 0.00093589, 0.00093589, 0.00093614, 0.00093651, 0.00093663]) + CDI |0.02877743| output unitless traj.cruise.rhs_all.core_aerodynamics.CDI + val: + array([0.00642535, 0.00642576, 0.0064264 , 0.00642662, 0.00642662, + 0.00642777, 0.00642966, 0.00643033, 0.00643033, 0.0064323 , + 0.00643541, 0.00643651, 0.00643651, 0.00643879, 0.00644227, + 0.00644345, 0.00644345, 0.00644481, 0.00644676, 0.00644739]) + CD0 + compress_drag_coeff |0.0042079| input unitless traj.cruise.rhs_all.core_aerodynamics.Drag.compress_drag_coeff + val: + array([0.00094091, 0.00094091, 0.00094091, 0.00094091, 0.00094091, + 0.00094091, 0.00094091, 0.00094091, 0.00094091, 0.00094091, + 0.00094091, 0.00094091, 0.00094091, 0.00094091, 0.00094091, + 0.00094091, 0.00094091, 0.00094091, 0.00094091, 0.00094091]) + skin_friction_drag_coeff |0.09010481| input unitless traj.cruise.rhs_all.core_aerodynamics.Drag.skin_friction_drag_coeff + val: + array([0.02004067, 0.02004935, 0.02006133, 0.02006513, 0.02006513, + 0.02008293, 0.02010757, 0.02011539, 0.02011539, 0.02013671, + 0.02016624, 0.02017562, 0.02017562, 0.02019371, 0.02021877, + 0.02022672, 0.02022672, 0.02023564, 0.02024797, 0.02025187]) + CD0 |0.09431269| output unitless traj.cruise.rhs_all.core_aerodynamics.CD0 + val: + array([0.02098159, 0.02099026, 0.02100225, 0.02100605, 0.02100605, + 0.02102385, 0.02104849, 0.0210563 , 0.0210563 , 0.02107763, + 0.02110716, 0.02111653, 0.02111653, 0.02113463, 0.02115968, + 0.02116763, 0.02116763, 0.02117655, 0.02118888, 0.02119279]) + drag + total_drag_coeff + CD0 |0.09431269| input unitless traj.cruise.rhs_all.core_aerodynamics.Drag.CD0 + val: + array([0.02098159, 0.02099026, 0.02100225, 0.02100605, 0.02100605, + 0.02102385, 0.02104849, 0.0210563 , 0.0210563 , 0.02107763, + 0.02110716, 0.02111653, 0.02111653, 0.02113463, 0.02115968, + 0.02116763, 0.02116763, 0.02117655, 0.02118888, 0.02119279]) + CDI |0.02877743| input unitless traj.cruise.rhs_all.core_aerodynamics.Drag.CDI + val: + array([0.00642535, 0.00642576, 0.0064264 , 0.00642662, 0.00642662, + 0.00642777, 0.00642966, 0.00643033, 0.00643033, 0.0064323 , + 0.00643541, 0.00643651, 0.00643651, 0.00643879, 0.00644227, + 0.00644345, 0.00644345, 0.00644481, 0.00644676, 0.00644739]) + FCD0 [0.93089003] input unitless traj.cruise.rhs_all.aircraft:design:zero_lift_drag_coeff_factor + FCDI [0.90983938] input unitless traj.cruise.rhs_all.aircraft:design:lift_dependent_drag_coeff_factor + CD_prescaled |0.11397753| output unitless traj.cruise.rhs_all.core_aerodynamics.Drag.drag.CD_prescaled + val: + array([0.02537759, 0.02538603, 0.02539777, 0.02540151, 0.02540151, + 0.02541912, 0.02544378, 0.02545167, 0.02545167, 0.02547332, + 0.02550363, 0.02551336, 0.02551336, 0.02553228, 0.02555877, + 0.02556724, 0.02556724, 0.02557679, 0.02559004, 0.02559425]) + simple_CD + aircraft:design:subsonic_drag_coeff_factor [1.] input unitless traj.cruise.rhs_all.aircraft:design:subsonic_drag_coeff_factor + aircraft:design:supersonic_drag_coeff_factor [1.] input unitless traj.cruise.rhs_all.aircraft:design:supersonic_drag_coeff_factor + mach |3.21993789| input unitless traj.cruise.rhs_all.mach + val: + array([0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, + 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72]) + CD_prescaled |0.11397753| input unitless traj.cruise.rhs_all.core_aerodynamics.Drag.drag.CD_prescaled + val: + array([0.02537759, 0.02538603, 0.02539777, 0.02540151, 0.02540151, + 0.02541912, 0.02544378, 0.02545167, 0.02545167, 0.02547332, + 0.02550363, 0.02551336, 0.02551336, 0.02553228, 0.02555877, + 0.02556724, 0.02556724, 0.02557679, 0.02559004, 0.02559425]) + CD |0.11397753| output unitless traj.cruise.rhs_all.core_aerodynamics.CD + val: + array([0.02537759, 0.02538603, 0.02539777, 0.02540151, 0.02540151, + 0.02541912, 0.02544378, 0.02545167, 0.02545167, 0.02547332, + 0.02550363, 0.02551336, 0.02551336, 0.02553228, 0.02555877, + 0.02556724, 0.02556724, 0.02557679, 0.02559004, 0.02559425]) + simple_drag + aircraft:wing:area [127.2771648] input m**2 traj.cruise.rhs_all.aircraft:wing:area + dynamic_pressure |42621.59270473| input N/m**2 traj.cruise.rhs_all.core_aerodynamics.dynamic_pressure + val: + array([9983.27821833, 9944.90271819, 9892.14203622, 9875.48880103, + 9875.48880103, 9797.90007646, 9691.64423382, 9658.21079739, + 9658.21079739, 9567.67456994, 9443.91610993, 9405.01138535, + 9405.01138535, 9330.43469278, 9228.31510457, 9196.18587354, + 9196.18587354, 9160.27175995, 9110.91099999, 9095.33551064]) + CD |0.11397753| input unitless traj.cruise.rhs_all.core_aerodynamics.Drag.drag.CD + val: + array([0.02537759, 0.02538603, 0.02539777, 0.02540151, 0.02540151, + 0.02541912, 0.02544378, 0.02545167, 0.02545167, 0.02547332, + 0.02550363, 0.02551336, 0.02551336, 0.02553228, 0.02555877, + 0.02556724, 0.02556724, 0.02557679, 0.02559004, 0.02559425]) + drag |138231.49046391| output N traj.cruise.rhs_all.drag + val: + array([32245.86305683, 32132.59930567, 31976.90699449, 31927.77231031, + 31927.77231031, 31698.89271539, 31385.54185499, 31286.96306422, + 31286.96306422, 31020.04336447, 30655.23779807, 30540.59717096, + 30540.59717096, 30320.89657307, 30020.15057154, 29925.54646903, + 29925.54646903, 29819.80551962, 29674.48430755, 29628.63095587]) + Buffet + mach |3.21993789| input unitless traj.cruise.rhs_all.mach + val: + array([0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, + 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72]) + mission:design:mach [0.80017085] input unitless traj.cruise.rhs_all.mission:design:mach + aircraft:wing:aspect_ratio [11.22091] input unitless traj.cruise.rhs_all.aircraft:wing:aspect_ratio + aircraft:wing:max_camber_at_70_semispan [0.] input unitless traj.cruise.rhs_all.aircraft:wing:max_camber_at_70_semispan + aircraft:wing:sweep [25.] input deg traj.cruise.rhs_all.aircraft:wing:sweep + aircraft:wing:thickness_to_chord [0.13] input unitless traj.cruise.rhs_all.aircraft:wing:thickness_to_chord + DELCLB |1.26370788| output unitless traj.cruise.rhs_all.core_aerodynamics.Buffet.DELCLB + val: + array([0.28257367, 0.28257367, 0.28257367, 0.28257367, 0.28257367, + 0.28257367, 0.28257367, 0.28257367, 0.28257367, 0.28257367, + 0.28257367, 0.28257367, 0.28257367, 0.28257367, 0.28257367, + 0.28257367, 0.28257367, 0.28257367, 0.28257367, 0.28257367]) + core_propulsion + turbofan_28k + interpolation + mach |3.21993789| input unitless traj.cruise.rhs_all.mach + val: + array([0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, + 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72]) + altitude |147700.4084954| input ft traj.cruise.rhs_all.altitude + val: + array([32000. , 32083.41734823, 32198.51626306, 32234.94467607, + 32234.94467607, 32405.30661107, 32640.37131001, 32714.76848352, + 32714.76848352, 32917.31196851, 33196.78063808, 33285.23151648, + 33285.23151648, 33455.59345148, 33690.65815042, 33765.05532393, + 33765.05532393, 33848.47267216, 33963.57158699, 34000. ]) + throttle |2.78644451| input unitless traj.cruise.rhs_all.throttle + val: + array([0.62030938, 0.62046836, 0.62070005, 0.62077638, 0.62077638, + 0.62115279, 0.62172604, 0.62192082, 0.62192082, 0.62248454, + 0.62334458, 0.62363676, 0.62363676, 0.6242272 , 0.62510335, + 0.62539589, 0.62539589, 0.62573279, 0.62621334, 0.62636927]) + fuel_flow_rate_unscaled |8698.65228821| output lbm/h traj.cruise.rhs_all.turbofan_28k.interpolation.fuel_flow_rate_unscaled + val: + array([2038.29455175, 2030.43868351, 2019.62980286, 2016.21617134, + 2016.21617134, 2000.29878137, 1978.46288981, 1971.58256237, + 1971.58256237, 1952.92584537, 1927.36144242, 1919.31195184, + 1919.31195184, 1903.87239807, 1882.69600876, 1876.02310243, + 1876.02310243, 1868.55792623, 1858.28661428, 1855.04280882]) + nox_rate_unscaled |53.10083024| output lbm/h traj.cruise.rhs_all.turbofan_28k.interpolation.nox_rate_unscaled + val: + array([12.26163399, 12.22868063, 12.18343233, 12.16916537, 12.16916537, + 12.10279735, 12.01221129, 11.98378873, 11.98378873, 11.90703657, + 11.80269729, 11.77005993, 11.77005993, 11.70594487, 11.61704483, + 11.5890778 , 11.5890778 , 11.55781859, 11.51486054, 11.50130677]) + thrust_net_unscaled |15612.52281263| output lbf traj.cruise.rhs_all.turbofan_28k.interpolation.thrust_net_unscaled + val: + array([3641.98550395, 3629.19412091, 3611.61113056, 3606.06215312, + 3606.06215312, 3580.21392177, 3544.8261912 , 3533.69340408, + 3533.69340408, 3503.5494743 , 3462.35123567, 3449.40469312, + 3449.40469312, 3424.59364544, 3390.63020633, 3379.94654122, + 3379.94654122, 3368.00520937, 3351.59410981, 3346.41590658]) + interp_max_throttles + mach |3.21993789| input unitless traj.cruise.rhs_all.mach + val: + array([0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, + 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72]) + altitude |147700.4084954| input ft traj.cruise.rhs_all.altitude + val: + array([32000. , 32083.41734823, 32198.51626306, 32234.94467607, + 32234.94467607, 32405.30661107, 32640.37131001, 32714.76848352, + 32714.76848352, 32917.31196851, 33196.78063808, 33285.23151648, + 33285.23151648, 33455.59345148, 33690.65815042, 33765.05532393, + 33765.05532393, 33848.47267216, 33963.57158699, 34000. ]) + throttle_max |4.47213595| output unitless traj.cruise.rhs_all.turbofan_28k.throttle_max + val: + array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + 1., 1., 1.]) + max_interpolation + mach |3.21993789| input unitless traj.cruise.rhs_all.mach + val: + array([0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, + 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72]) + altitude |147700.4084954| input ft traj.cruise.rhs_all.altitude + val: + array([32000. , 32083.41734823, 32198.51626306, 32234.94467607, + 32234.94467607, 32405.30661107, 32640.37131001, 32714.76848352, + 32714.76848352, 32917.31196851, 33196.78063808, 33285.23151648, + 33285.23151648, 33455.59345148, 33690.65815042, 33765.05532393, + 33765.05532393, 33848.47267216, 33963.57158699, 34000. ]) + throttle_max |4.47213595| input unitless traj.cruise.rhs_all.throttle_max + val: + array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + 1., 1., 1.]) + thrust_net_max_unscaled |26061.52151244| output lbf traj.cruise.rhs_all.turbofan_28k.max_interpolation.thrust_net_max_unscaled + val: + array([6107.972 , 6084.79332195, 6052.81147708, 6042.68933253, + 6042.68933253, 5995.35188382, 5930.03586632, 5909.3635701 , + 5909.3635701 , 5853.08402718, 5775.42974478, 5750.8524299 , + 5750.8524299 , 5703.5149812 , 5638.19896369, 5617.52666747, + 5617.52666747, 5594.34798942, 5562.36614455, 5552.244 ]) + engine_scaling + aircraft:engine:scale_factor [1.] input unitless traj.cruise.rhs_all.aircraft:engine:scale_factor + mach |3.21993789| input unitless traj.cruise.rhs_all.mach + val: + array([0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, + 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72]) + fuel_flow_rate_unscaled |8698.65228821| input lbm/h traj.cruise.rhs_all.engine_scaling.fuel_flow_rate_unscaled + val: + array([2038.29455175, 2030.43868351, 2019.62980286, 2016.21617134, + 2016.21617134, 2000.29878137, 1978.46288981, 1971.58256237, + 1971.58256237, 1952.92584537, 1927.36144242, 1919.31195184, + 1919.31195184, 1903.87239807, 1882.69600876, 1876.02310243, + 1876.02310243, 1868.55792623, 1858.28661428, 1855.04280882]) + nox_rate_unscaled |53.10083024| input lbm/h traj.cruise.rhs_all.engine_scaling.nox_rate_unscaled + val: + array([12.26163399, 12.22868063, 12.18343233, 12.16916537, 12.16916537, + 12.10279735, 12.01221129, 11.98378873, 11.98378873, 11.90703657, + 11.80269729, 11.77005993, 11.77005993, 11.70594487, 11.61704483, + 11.5890778 , 11.5890778 , 11.55781859, 11.51486054, 11.50130677]) + thrust_net_unscaled |15612.52281263| input lbf traj.cruise.rhs_all.engine_scaling.thrust_net_unscaled + val: + array([3641.98550395, 3629.19412091, 3611.61113056, 3606.06215312, + 3606.06215312, 3580.21392177, 3544.8261912 , 3533.69340408, + 3533.69340408, 3503.5494743 , 3462.35123567, 3449.40469312, + 3449.40469312, 3424.59364544, 3390.63020633, 3379.94654122, + 3379.94654122, 3368.00520937, 3351.59410981, 3346.41590658]) + thrust_net_max_unscaled |26061.52151244| input lbf traj.cruise.rhs_all.engine_scaling.thrust_net_max_unscaled + val: + array([6107.972 , 6084.79332195, 6052.81147708, 6042.68933253, + 6042.68933253, 5995.35188382, 5930.03586632, 5909.3635701 , + 5909.3635701 , 5853.08402718, 5775.42974478, 5750.8524299 , + 5750.8524299 , 5703.5149812 , 5638.19896369, 5617.52666747, + 5617.52666747, 5594.34798942, 5562.36614455, 5552.244 ]) + fuel_flow_rate_negative |8698.65228821| output lbm/h traj.cruise.rhs_all.turbofan_28k.fuel_flow_rate_negative + val: + array([-2038.29455175, -2030.43868351, -2019.62980286, -2016.21617134, + -2016.21617134, -2000.29878137, -1978.46288981, -1971.58256237, + -1971.58256237, -1952.92584537, -1927.36144242, -1919.31195184, + -1919.31195184, -1903.87239807, -1882.69600876, -1876.02310243, + -1876.02310243, -1868.55792623, -1858.28661428, -1855.04280882]) + nox_rate |53.10083024| output lbm/h traj.cruise.rhs_all.turbofan_28k.nox_rate + val: + array([12.26163399, 12.22868063, 12.18343233, 12.16916537, 12.16916537, + 12.10279735, 12.01221129, 11.98378873, 11.98378873, 11.90703657, + 11.80269729, 11.77005993, 11.77005993, 11.70594487, 11.61704483, + 11.5890778 , 11.5890778 , 11.55781859, 11.51486054, 11.50130677]) + thrust_net |15612.52281263| output lbf traj.cruise.rhs_all.turbofan_28k.thrust_net + val: + array([3641.98550395, 3629.19412091, 3611.61113056, 3606.06215312, + 3606.06215312, 3580.21392177, 3544.8261912 , 3533.69340408, + 3533.69340408, 3503.5494743 , 3462.35123567, 3449.40469312, + 3449.40469312, 3424.59364544, 3390.63020633, 3379.94654122, + 3379.94654122, 3368.00520937, 3351.59410981, 3346.41590658]) + thrust_net_max |26061.52151244| output lbf traj.cruise.rhs_all.turbofan_28k.thrust_net_max + val: + array([6107.972 , 6084.79332195, 6052.81147708, 6042.68933253, + 6042.68933253, 5995.35188382, 5930.03586632, 5909.3635701 , + 5909.3635701 , 5853.08402718, 5775.42974478, 5750.8524299 , + 5750.8524299 , 5703.5149812 , 5638.19896369, 5617.52666747, + 5617.52666747, 5594.34798942, 5562.36614455, 5552.244 ]) + vectorize_performance + thrust_net_0 |15612.52281263| input lbf traj.cruise.rhs_all.vectorize_performance.thrust_net_0 + val: + array([3641.98550395, 3629.19412091, 3611.61113056, 3606.06215312, + 3606.06215312, 3580.21392177, 3544.8261912 , 3533.69340408, + 3533.69340408, 3503.5494743 , 3462.35123567, 3449.40469312, + 3449.40469312, 3424.59364544, 3390.63020633, 3379.94654122, + 3379.94654122, 3368.00520937, 3351.59410981, 3346.41590658]) + thrust_net_max_0 |26061.52151244| input lbf traj.cruise.rhs_all.vectorize_performance.thrust_net_max_0 + val: + array([6107.972 , 6084.79332195, 6052.81147708, 6042.68933253, + 6042.68933253, 5995.35188382, 5930.03586632, 5909.3635701 , + 5909.3635701 , 5853.08402718, 5775.42974478, 5750.8524299 , + 5750.8524299 , 5703.5149812 , 5638.19896369, 5617.52666747, + 5617.52666747, 5594.34798942, 5562.36614455, 5552.244 ]) + fuel_flow_rate_negative_0 |8698.65228821| input lbm/h traj.cruise.rhs_all.vectorize_performance.fuel_flow_rate_negative_0 + val: + array([-2038.29455175, -2030.43868351, -2019.62980286, -2016.21617134, + -2016.21617134, -2000.29878137, -1978.46288981, -1971.58256237, + -1971.58256237, -1952.92584537, -1927.36144242, -1919.31195184, + -1919.31195184, -1903.87239807, -1882.69600876, -1876.02310243, + -1876.02310243, -1868.55792623, -1858.28661428, -1855.04280882]) + electric_power_in_0 |0.0| input kW traj.cruise.rhs_all.vectorize_performance.electric_power_in_0 + val: + array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., + 0., 0., 0.]) + nox_rate_0 |53.10083024| input lbm/h traj.cruise.rhs_all.vectorize_performance.nox_rate_0 + val: + array([12.26163399, 12.22868063, 12.18343233, 12.16916537, 12.16916537, + 12.10279735, 12.01221129, 11.98378873, 11.98378873, 11.90703657, + 11.80269729, 11.77005993, 11.77005993, 11.70594487, 11.61704483, + 11.5890778 , 11.5890778 , 11.55781859, 11.51486054, 11.50130677]) + t4_0 |0.0| input degR traj.cruise.rhs_all.vectorize_performance.t4_0 + val: + array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., + 0., 0., 0.]) + shaft_power_0 |0.0| input hp traj.cruise.rhs_all.vectorize_performance.shaft_power_0 + val: + array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., + 0., 0., 0.]) + shaft_power_max_0 |0.0| input hp traj.cruise.rhs_all.vectorize_performance.shaft_power_max_0 + val: + array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., + 0., 0., 0.]) + thrust_net |15612.52281263| output lbf traj.cruise.rhs_all.thrust_net + val: + array([[3641.98550395], + [3629.19412091], + [3611.61113056], + [3606.06215312], + [3606.06215312], + [3580.21392177], + [3544.8261912 ], + [3533.69340408], + [3533.69340408], + [3503.5494743 ], + [3462.35123567], + [3449.40469312], + [3449.40469312], + [3424.59364544], + [3390.63020633], + [3379.94654122], + [3379.94654122], + [3368.00520937], + [3351.59410981], + [3346.41590658]]) + thrust_net_max |26061.52151244| output lbf traj.cruise.rhs_all.thrust_net_max + val: + array([[6107.972 ], + [6084.79332195], + [6052.81147708], + [6042.68933253], + [6042.68933253], + [5995.35188382], + [5930.03586632], + [5909.3635701 ], + [5909.3635701 ], + [5853.08402718], + [5775.42974478], + [5750.8524299 ], + [5750.8524299 ], + [5703.5149812 ], + [5638.19896369], + [5617.52666747], + [5617.52666747], + [5594.34798942], + [5562.36614455], + [5552.244 ]]) + fuel_flow_rate_negative |8698.65228821| output lbm/h traj.cruise.rhs_all.fuel_flow_rate_negative + val: + array([[-2038.29455175], + [-2030.43868351], + [-2019.62980286], + [-2016.21617134], + [-2016.21617134], + [-2000.29878137], + [-1978.46288981], + [-1971.58256237], + [-1971.58256237], + [-1952.92584537], + [-1927.36144242], + [-1919.31195184], + [-1919.31195184], + [-1903.87239807], + [-1882.69600876], + [-1876.02310243], + [-1876.02310243], + [-1868.55792623], + [-1858.28661428], + [-1855.04280882]]) + electric_power_in |0.0| output kW traj.cruise.rhs_all.electric_power_in + val: + array([[0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.]]) + nox_rate |53.10083024| output lbm/h traj.cruise.rhs_all.nox_rate + val: + array([[12.26163399], + [12.22868063], + [12.18343233], + [12.16916537], + [12.16916537], + [12.10279735], + [12.01221129], + [11.98378873], + [11.98378873], + [11.90703657], + [11.80269729], + [11.77005993], + [11.77005993], + [11.70594487], + [11.61704483], + [11.5890778 ], + [11.5890778 ], + [11.55781859], + [11.51486054], + [11.50130677]]) + t4 |0.0| output degR traj.cruise.rhs_all.t4 + val: + array([[0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.]]) + shaft_power |0.0| output hp traj.cruise.rhs_all.shaft_power + val: + array([[0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.]]) + shaft_power_max |0.0| output hp traj.cruise.rhs_all.shaft_power_max + val: + array([[0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.]]) + propulsion_sum + thrust_net |15612.52281263| input lbf traj.cruise.rhs_all.thrust_net + val: + array([[3641.98550395], + [3629.19412091], + [3611.61113056], + [3606.06215312], + [3606.06215312], + [3580.21392177], + [3544.8261912 ], + [3533.69340408], + [3533.69340408], + [3503.5494743 ], + [3462.35123567], + [3449.40469312], + [3449.40469312], + [3424.59364544], + [3390.63020633], + [3379.94654122], + [3379.94654122], + [3368.00520937], + [3351.59410981], + [3346.41590658]]) + thrust_net_max |26061.52151244| input lbf traj.cruise.rhs_all.thrust_net_max + val: + array([[6107.972 ], + [6084.79332195], + [6052.81147708], + [6042.68933253], + [6042.68933253], + [5995.35188382], + [5930.03586632], + [5909.3635701 ], + [5909.3635701 ], + [5853.08402718], + [5775.42974478], + [5750.8524299 ], + [5750.8524299 ], + [5703.5149812 ], + [5638.19896369], + [5617.52666747], + [5617.52666747], + [5594.34798942], + [5562.36614455], + [5552.244 ]]) + fuel_flow_rate_negative |8698.65228821| input lbm/h traj.cruise.rhs_all.fuel_flow_rate_negative + val: + array([[-2038.29455175], + [-2030.43868351], + [-2019.62980286], + [-2016.21617134], + [-2016.21617134], + [-2000.29878137], + [-1978.46288981], + [-1971.58256237], + [-1971.58256237], + [-1952.92584537], + [-1927.36144242], + [-1919.31195184], + [-1919.31195184], + [-1903.87239807], + [-1882.69600876], + [-1876.02310243], + [-1876.02310243], + [-1868.55792623], + [-1858.28661428], + [-1855.04280882]]) + electric_power_in |0.0| input kW traj.cruise.rhs_all.electric_power_in + val: + array([[0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.]]) + nox_rate |53.10083024| input lbm/h traj.cruise.rhs_all.nox_rate + val: + array([[12.26163399], + [12.22868063], + [12.18343233], + [12.16916537], + [12.16916537], + [12.10279735], + [12.01221129], + [11.98378873], + [11.98378873], + [11.90703657], + [11.80269729], + [11.77005993], + [11.77005993], + [11.70594487], + [11.61704483], + [11.5890778 ], + [11.5890778 ], + [11.55781859], + [11.51486054], + [11.50130677]]) + thrust_net_total |31225.04562526| output lbf traj.cruise.rhs_all.thrust_net_total + val: + array([7283.97100791, 7258.38824181, 7223.22226111, 7212.12430625, + 7212.12430625, 7160.42784354, 7089.6523824 , 7067.38680815, + 7067.38680815, 7007.0989486 , 6924.70247135, 6898.80938625, + 6898.80938625, 6849.18729088, 6781.26041265, 6759.89308244, + 6759.89308244, 6736.01041873, 6703.18821962, 6692.83181316]) + thrust_net_max_total |52123.04302488| output lbf traj.cruise.rhs_all.thrust_net_max_total + val: + array([12215.944 , 12169.5866439 , 12105.62295416, 12085.37866506, + 12085.37866506, 11990.70376764, 11860.07173263, 11818.72714019, + 11818.72714019, 11706.16805436, 11550.85948956, 11501.70485981, + 11501.70485981, 11407.0299624 , 11276.39792738, 11235.05333494, + 11235.05333494, 11188.69597885, 11124.73228911, 11104.488 ]) + fuel_flow_rate_negative_total |17397.30457641| output lbm/h traj.cruise.rhs_all.fuel_flow_rate_negative_total + val: + array([-4076.58910351, -4060.87736702, -4039.25960572, -4032.43234269, + -4032.43234269, -4000.59756274, -3956.92577962, -3943.16512475, + -3943.16512475, -3905.85169075, -3854.72288485, -3838.62390368, + -3838.62390368, -3807.74479615, -3765.39201751, -3752.04620486, + -3752.04620486, -3737.11585247, -3716.57322856, -3710.08561764]) + electric_power_in_total |0.0| output kW traj.cruise.rhs_all.electric_power_in_total + val: + array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., + 0., 0., 0.]) + nox_rate_total |106.20166048| output lbm/h traj.cruise.rhs_all.nox_rate_total + val: + array([24.52326798, 24.45736125, 24.36686465, 24.33833074, 24.33833074, + 24.2055947 , 24.02442257, 23.96757746, 23.96757746, 23.81407315, + 23.60539459, 23.54011987, 23.54011987, 23.41188974, 23.23408966, + 23.17815561, 23.17815561, 23.11563718, 23.02972108, 23.00261354]) + mission_EOM + required_thrust + drag |138231.49046391| input N traj.cruise.rhs_all.drag + val: + array([32245.86305683, 32132.59930567, 31976.90699449, 31927.77231031, + 31927.77231031, 31698.89271539, 31385.54185499, 31286.96306422, + 31286.96306422, 31020.04336447, 30655.23779807, 30540.59717096, + 30540.59717096, 30320.89657307, 30020.15057154, 29925.54646903, + 29925.54646903, 29819.80551962, 29674.48430755, 29628.63095587]) + altitude_rate |0.26806431| input m/s traj.cruise.rhs_all.altitude_rate + val: + array([0.059941, 0.059941, 0.059941, 0.059941, 0.059941, 0.059941, + 0.059941, 0.059941, 0.059941, 0.059941, 0.059941, 0.059941, + 0.059941, 0.059941, 0.059941, 0.059941, 0.059941, 0.059941, + 0.059941, 0.059941]) + velocity |963.55047191| input m/s traj.cruise.rhs_all.velocity + val: + array([216.42809923, 216.34879353, 216.23932113, 216.20466219, + 216.20466219, 216.04250323, 215.81856126, 215.74763702, + 215.74763702, 215.55443278, 215.28757185, 215.20304383, + 215.20304383, 215.04014595, 214.81518168, 214.74393321, + 214.74393321, 214.66401882, 214.55370544, 214.51878007]) + velocity_rate |0.0| input m/s**2 traj.cruise.rhs_all.velocity_rate + val: + array([ 0.00000000e+00, 2.62422607e-17, 1.31144910e-17, 0.00000000e+00, + 0.00000000e+00, 9.82691582e-18, 6.54448639e-18, 0.00000000e+00, + 0.00000000e+00, -1.30729539e-17, -1.95851540e-17, -1.30516429e-17, + -1.30516429e-17, -1.46719839e-17, -6.51405989e-18, 2.60475974e-17, + 2.60475974e-17, -2.60379041e-17, 0.00000000e+00, 5.20405744e-17]) + mass |243577.62672176| input kg traj.cruise.rhs_all.mass + val: + array([57015.39290411, 56797.93787223, 56499.27092781, 56405.0756841 , + 56405.0756841 , 55966.67143281, 55367.45066061, 55179.16707729, + 55179.16707729, 54669.88811206, 53975.10803913, 53757.11559708, + 53757.11559708, 53339.81352995, 52769.53817769, 52590.37433179, + 52590.37433179, 52390.24374586, 52115.41253722, 52028.74471935]) + thrust_required |138895.92303576| output N traj.cruise.rhs_all.thrust_required + val: + array([32400.71731682, 32286.91950359, 32130.49342794, 32081.12726519, + 32081.12726519, 31851.16994206, 31536.34500569, 31437.30279692, + 31437.30279692, 31169.12903663, 30802.61124513, 30687.43306416, + 30687.43306416, 30466.70298674, 30164.54917842, 30069.50255821, + 30069.50255821, 29963.26717715, 29817.26676143, 29771.1991703 ]) + groundspeed + altitude_rate |0.26806431| input m/s traj.cruise.rhs_all.altitude_rate + val: + array([0.059941, 0.059941, 0.059941, 0.059941, 0.059941, 0.059941, + 0.059941, 0.059941, 0.059941, 0.059941, 0.059941, 0.059941, + 0.059941, 0.059941, 0.059941, 0.059941, 0.059941, 0.059941, + 0.059941, 0.059941]) + velocity |963.55047191| input m/s traj.cruise.rhs_all.velocity + val: + array([216.42809923, 216.34879353, 216.23932113, 216.20466219, + 216.20466219, 216.04250323, 215.81856126, 215.74763702, + 215.74763702, 215.55443278, 215.28757185, 215.20304383, + 215.20304383, 215.04014595, 214.81518168, 214.74393321, + 214.74393321, 214.66401882, 214.55370544, 214.51878007]) + distance_rate |963.55043462| output m/s traj.cruise.rhs_all.distance_rate + val: + array([216.42809093, 216.34878522, 216.23931282, 216.20465388, + 216.20465388, 216.04249491, 215.81855294, 215.7476287 , + 215.7476287 , 215.55442444, 215.28756351, 215.20303548, + 215.20303548, 215.04013759, 214.81517331, 214.74392485, + 214.74392485, 214.66401045, 214.55369706, 214.51877169]) + excess_specific_power + velocity |963.55047191| input m/s traj.cruise.rhs_all.velocity + val: + array([216.42809923, 216.34879353, 216.23932113, 216.20466219, + 216.20466219, 216.04250323, 215.81856126, 215.74763702, + 215.74763702, 215.55443278, 215.28757185, 215.20304383, + 215.20304383, 215.04014595, 214.81518168, 214.74393321, + 214.74393321, 214.66401882, 214.55370544, 214.51878007]) + mass |243577.62672176| input kg traj.cruise.rhs_all.mass + val: + array([57015.39290411, 56797.93787223, 56499.27092781, 56405.0756841 , + 56405.0756841 , 55966.67143281, 55367.45066061, 55179.16707729, + 55179.16707729, 54669.88811206, 53975.10803913, 53757.11559708, + 53757.11559708, 53339.81352995, 52769.53817769, 52590.37433179, + 52590.37433179, 52390.24374586, 52115.41253722, 52028.74471935]) + thrust_net_total |231854.84688348| input N traj.cruise.rhs_all.thrust_net_max_total + val: + array([54339.22620951, 54133.01841588, 53848.49374828, 53758.44266379, + 53758.44266379, 53337.30773824, 52756.22749584, 52572.31758588, + 52572.31758588, 52071.62982678, 51380.78291104, 51162.13222426, + 51162.13222426, 50740.99729871, 50159.91705631, 49976.00714635, + 49976.00714635, 49769.79935272, 49485.27468512, 49395.22360063]) + drag |138231.49046391| input N traj.cruise.rhs_all.drag + val: + array([32245.86305683, 32132.59930567, 31976.90699449, 31927.77231031, + 31927.77231031, 31698.89271539, 31385.54185499, 31286.96306422, + 31286.96306422, 31020.04336447, 30655.23779807, 30540.59717096, + 30540.59717096, 30320.89657307, 30020.15057154, 29925.54646903, + 29925.54646903, 29819.80551962, 29674.48430755, 29628.63095587]) + specific_energy_rate |37.75301942| output m/s traj.cruise.rhs_all.specific_energy_rate_excess + val: + array([8.55190129, 8.5453959 , 8.53594173, 8.53283337, 8.53283337, + 8.5175461 , 8.49438705, 8.48654893, 8.48654893, 8.46394686, + 8.42967295, 8.41807454, 8.41807454, 8.39470149, 8.36017624, + 8.34868973, 8.34868973, 8.33548601, 8.31669867, 8.31061392]) + altitude_rate_max + specific_energy_rate |37.75301942| input m/s traj.cruise.rhs_all.mission_EOM.specific_energy_rate_excess + val: + array([8.55190129, 8.5453959 , 8.53594173, 8.53283337, 8.53283337, + 8.5175461 , 8.49438705, 8.48654893, 8.48654893, 8.46394686, + 8.42967295, 8.41807454, 8.41807454, 8.39470149, 8.36017624, + 8.34868973, 8.34868973, 8.33548601, 8.31669867, 8.31061392]) + velocity_rate |0.0| input m/s**2 traj.cruise.rhs_all.velocity_rate + val: + array([ 0.00000000e+00, 2.62422607e-17, 1.31144910e-17, 0.00000000e+00, + 0.00000000e+00, 9.82691582e-18, 6.54448639e-18, 0.00000000e+00, + 0.00000000e+00, -1.30729539e-17, -1.95851540e-17, -1.30516429e-17, + -1.30516429e-17, -1.46719839e-17, -6.51405989e-18, 2.60475974e-17, + 2.60475974e-17, -2.60379041e-17, 0.00000000e+00, 5.20405744e-17]) + velocity |963.55047191| input m/s traj.cruise.rhs_all.velocity + val: + array([216.42809923, 216.34879353, 216.23932113, 216.20466219, + 216.20466219, 216.04250323, 215.81856126, 215.74763702, + 215.74763702, 215.55443278, 215.28757185, 215.20304383, + 215.20304383, 215.04014595, 214.81518168, 214.74393321, + 214.74393321, 214.66401882, 214.55370544, 214.51878007]) + altitude_rate |37.75301942| output m/s traj.cruise.rhs_all.altitude_rate_max + val: + array([8.55190129, 8.5453959 , 8.53594173, 8.53283337, 8.53283337, + 8.5175461 , 8.49438705, 8.48654893, 8.48654893, 8.46394686, + 8.42967295, 8.41807454, 8.41807454, 8.39470149, 8.36017624, + 8.34868973, 8.34868973, 8.33548601, 8.31669867, 8.31061392]) + throttle_balance + thrust_required |31225.04562526| input lbf traj.cruise.rhs_all.thrust_required + val: + array([7283.97100791, 7258.38824181, 7223.22226111, 7212.12430625, + 7212.12430625, 7160.42784354, 7089.6523824 , 7067.38680815, + 7067.38680815, 7007.0989486 , 6924.70247135, 6898.80938625, + 6898.80938625, 6849.18729088, 6781.26041265, 6759.89308244, + 6759.89308244, 6736.01041873, 6703.18821962, 6692.83181316]) + thrust_net_total |31225.04562526| input lbf traj.cruise.rhs_all.thrust_net_total + val: + array([7283.97100791, 7258.38824181, 7223.22226111, 7212.12430625, + 7212.12430625, 7160.42784354, 7089.6523824 , 7067.38680815, + 7067.38680815, 7007.0989486 , 6924.70247135, 6898.80938625, + 6898.80938625, 6849.18729088, 6781.26041265, 6759.89308244, + 6759.89308244, 6736.01041873, 6703.18821962, 6692.83181316]) + throttle |2.78644451| output unitless traj.cruise.rhs_all.throttle + val: + array([0.62030938, 0.62046836, 0.62070005, 0.62077638, 0.62077638, + 0.62115279, 0.62172604, 0.62192082, 0.62192082, 0.62248454, + 0.62334458, 0.62363676, 0.62363676, 0.6242272 , 0.62510335, + 0.62539589, 0.62539589, 0.62573279, 0.62621334, 0.62636927]) + initial_mass_residual_constraint + initial_mass [1.] input kg traj.cruise.rhs_all.mission:summary:gross_mass + mass |243577.62672176| input kg traj.cruise.rhs_all.mass + val: + array([57015.39290411, 56797.93787223, 56499.27092781, 56405.0756841 , + 56405.0756841 , 55966.67143281, 55367.45066061, 55179.16707729, + 55179.16707729, 54669.88811206, 53975.10803913, 53757.11559708, + 53757.11559708, 53339.81352995, 52769.53817769, 52590.37433179, + 52590.37433179, 52390.24374586, 52115.41253722, 52028.74471935]) + initial_mass_residual [-57114.39290411] output kg traj.cruise.rhs_all.initial_mass_residual + timeseries + dt_dstau |4814.09560547| input s traj.cruise.timeseries.dt_dstau + val: + array([ 597.34683891, 597.34683891, 597.34683891, 597.34683891, + 1219.95203044, 1219.95203044, 1219.95203044, 1219.95203044, + 1450.4022613 , 1450.4022613 , 1450.4022613 , 1450.4022613 , + 1219.95203044, 1219.95203044, 1219.95203044, 1219.95203044, + 597.34683891, 597.34683891, 597.34683891, 597.34683891]) + input_values:mach |3.21993789| input unitless traj.cruise.timeseries.input_values:mach + val: + array([[0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72]]) + input_values:thrust_net_total |31225.04562526| input lbf traj.cruise.timeseries.input_values:thrust_net_total + val: + array([[7283.97100791], + [7258.38824181], + [7223.22226111], + [7212.12430625], + [7212.12430625], + [7160.42784354], + [7089.6523824 ], + [7067.38680815], + [7067.38680815], + [7007.0989486 ], + [6924.70247135], + [6898.80938625], + [6898.80938625], + [6849.18729088], + [6781.26041265], + [6759.89308244], + [6759.89308244], + [6736.01041873], + [6703.18821962], + [6692.83181316]]) + input_values:drag |31075.67524118| input lbf traj.cruise.timeseries.input_values:drag + val: + array([[7249.15838542], + [7223.69568126], + [7188.69465737], + [7177.64874096], + [7177.64874096], + [7126.19456118], + [7055.75048551], + [7033.58909177], + [7033.58909177], + [6973.58315624], + [6891.57160251], + [6865.79936432], + [6865.79936432], + [6816.40870516], + [6748.79831449], + [6727.53046622], + [6727.53046622], + [6703.75895516], + [6671.0894471 ], + [6660.78120358]]) + input_values:specific_energy_rate_excess |37.75301942| input m/s traj.cruise.timeseries.input_values:specific_energy_rate_excess + val: + array([[8.55190129], + [8.5453959 ], + [8.53594173], + [8.53283337], + [8.53283337], + [8.5175461 ], + [8.49438705], + [8.48654893], + [8.48654893], + [8.46394686], + [8.42967295], + [8.41807454], + [8.41807454], + [8.39470149], + [8.36017624], + [8.34868973], + [8.34868973], + [8.33548601], + [8.31669867], + [8.31061392]]) + input_values:fuel_flow_rate_negative_total |17397.30457641| input lbm/h traj.cruise.timeseries.input_values:fuel_flow_rate_negative_total + val: + array([[-4076.58910351], + [-4060.87736702], + [-4039.25960572], + [-4032.43234269], + [-4032.43234269], + [-4000.59756274], + [-3956.92577962], + [-3943.16512475], + [-3943.16512475], + [-3905.85169075], + [-3854.72288485], + [-3838.62390368], + [-3838.62390368], + [-3807.74479615], + [-3765.39201751], + [-3752.04620486], + [-3752.04620486], + [-3737.11585247], + [-3716.57322856], + [-3710.08561764]]) + input_values:electric_power_in_total |0.0| input kW traj.cruise.timeseries.input_values:electric_power_in_total + val: + array([[0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.]]) + input_values:altitude_rate |0.8794761| input ft/s traj.cruise.timeseries.input_values:altitude_rate + val: + array([[0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683]]) + input_values:throttle |2.78644451| input unitless traj.cruise.timeseries.input_values:throttle + val: + array([[0.62030938], + [0.62046836], + [0.62070005], + [0.62077638], + [0.62077638], + [0.62115279], + [0.62172604], + [0.62192082], + [0.62192082], + [0.62248454], + [0.62334458], + [0.62363676], + [0.62363676], + [0.6242272 ], + [0.62510335], + [0.62539589], + [0.62539589], + [0.62573279], + [0.62621334], + [0.62636927]]) + input_values:velocity |963.55047191| input m/s traj.cruise.timeseries.input_values:velocity + val: + array([[216.42809923], + [216.34879353], + [216.23932113], + [216.20466219], + [216.20466219], + [216.04250323], + [215.81856126], + [215.74763702], + [215.74763702], + [215.55443278], + [215.28757185], + [215.20304383], + [215.20304383], + [215.04014595], + [214.81518168], + [214.74393321], + [214.74393321], + [214.66401882], + [214.55370544], + [214.51878007]]) + input_values:altitude |147700.4084954| input ft traj.cruise.timeseries.input_values:altitude + val: + array([[32000. ], + [32083.41734823], + [32198.51626306], + [32234.94467607], + [32234.94467607], + [32405.30661107], + [32640.37131001], + [32714.76848352], + [32714.76848352], + [32917.31196851], + [33196.78063808], + [33285.23151648], + [33285.23151648], + [33455.59345148], + [33690.65815042], + [33765.05532393], + [33765.05532393], + [33848.47267216], + [33963.57158699], + [34000. ]]) + input_values:time |43155.65216817| input s traj.cruise.timeseries.input_values:time + val: + array([[ 3840. ], + [ 4264.17721573], + [ 4849.45519765], + [ 5034.69367782], + [ 5034.69367782], + [ 5900.9841173 ], + [ 7096.28811139], + [ 7474.5977387 ], + [ 7474.5977387 ], + [ 8504.53135987], + [ 9925.62954466], + [10375.4022613 ], + [10375.4022613 ], + [11241.69270078], + [12436.99669488], + [12815.30632218], + [12815.30632218], + [13239.48353791], + [13824.76151983], + [14010. ]]) + input_values:time_phase |27763.66679782| input s traj.cruise.timeseries.input_values:time_phase + val: + array([[ 0. ], + [ 424.17721573], + [ 1009.45519765], + [ 1194.69367782], + [ 1194.69367782], + [ 2060.9841173 ], + [ 3256.28811139], + [ 3634.5977387 ], + [ 3634.5977387 ], + [ 4664.53135987], + [ 6085.62954466], + [ 6535.4022613 ], + [ 6535.4022613 ], + [ 7401.69270078], + [ 8596.99669488], + [ 8975.30632218], + [ 8975.30632218], + [ 9399.48353791], + [ 9984.76151983], + [10170. ]]) + input_values:mach_rate |0.0| input unitless/s traj.cruise.timeseries.input_values:mach_rate + val: + array([[ 0.00000000e+00], + [ 8.73331779e-20], + [ 4.36665890e-20], + [ 0.00000000e+00], + [ 0.00000000e+00], + [ 3.27499417e-20], + [ 2.18332945e-20], + [ 0.00000000e+00], + [ 0.00000000e+00], + [-4.36665890e-20], + [-6.54998835e-20], + [-4.36665890e-20], + [-4.36665890e-20], + [-4.91249126e-20], + [-2.18332945e-20], + [ 8.73331779e-20], + [ 8.73331779e-20], + [-8.73331779e-20], + [ 0.00000000e+00], + [ 1.74666356e-19]]) + input_values:mass |243577.62672176| input kg traj.cruise.timeseries.input_values:mass + val: + array([[57015.39290411], + [56797.93787223], + [56499.27092781], + [56405.0756841 ], + [56405.0756841 ], + [55966.67143281], + [55367.45066061], + [55179.16707729], + [55179.16707729], + [54669.88811206], + [53975.10803913], + [53757.11559708], + [53757.11559708], + [53339.81352995], + [52769.53817769], + [52590.37433179], + [52590.37433179], + [52390.24374586], + [52115.41253722], + [52028.74471935]]) + input_values:distance |8196715.33458363| input m traj.cruise.timeseries.input_values:distance + val: + array([[ 560039.40638961], + [ 651826.45257603], + [ 778418.59972934], + [ 818471.23138883], + [ 818471.23138883], + [1005697.02623753], + [1263799.66653641], + [1345432.48793709], + [1345432.48793709], + [1567538.74520054], + [1873673.16694925], + [1970484.63129816], + [1970484.63129816], + [2156842.41376365], + [2413746.32168934], + [2494999.4935999 ], + [2494999.4935999 ], + [2586072.02583254], + [2711677.86536452], + [2751418.23144865]]) + mach |3.21993789| output unitless traj.cruise.timeseries.mach + val: + array([[0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72]]) + thrust_net_total |31225.04562526| output lbf traj.cruise.timeseries.thrust_net_total + val: + array([[7283.97100791], + [7258.38824181], + [7223.22226111], + [7212.12430625], + [7212.12430625], + [7160.42784354], + [7089.6523824 ], + [7067.38680815], + [7067.38680815], + [7007.0989486 ], + [6924.70247135], + [6898.80938625], + [6898.80938625], + [6849.18729088], + [6781.26041265], + [6759.89308244], + [6759.89308244], + [6736.01041873], + [6703.18821962], + [6692.83181316]]) + drag |31075.67524118| output lbf traj.cruise.timeseries.drag + val: + array([[7249.15838542], + [7223.69568126], + [7188.69465737], + [7177.64874096], + [7177.64874096], + [7126.19456118], + [7055.75048551], + [7033.58909177], + [7033.58909177], + [6973.58315624], + [6891.57160251], + [6865.79936432], + [6865.79936432], + [6816.40870516], + [6748.79831449], + [6727.53046622], + [6727.53046622], + [6703.75895516], + [6671.0894471 ], + [6660.78120358]]) + specific_energy_rate_excess |37.75301942| output m/s traj.cruise.timeseries.specific_energy_rate_excess + val: + array([[8.55190129], + [8.5453959 ], + [8.53594173], + [8.53283337], + [8.53283337], + [8.5175461 ], + [8.49438705], + [8.48654893], + [8.48654893], + [8.46394686], + [8.42967295], + [8.41807454], + [8.41807454], + [8.39470149], + [8.36017624], + [8.34868973], + [8.34868973], + [8.33548601], + [8.31669867], + [8.31061392]]) + fuel_flow_rate_negative_total |17397.30457641| output lbm/h traj.cruise.timeseries.fuel_flow_rate_negative_total + val: + array([[-4076.58910351], + [-4060.87736702], + [-4039.25960572], + [-4032.43234269], + [-4032.43234269], + [-4000.59756274], + [-3956.92577962], + [-3943.16512475], + [-3943.16512475], + [-3905.85169075], + [-3854.72288485], + [-3838.62390368], + [-3838.62390368], + [-3807.74479615], + [-3765.39201751], + [-3752.04620486], + [-3752.04620486], + [-3737.11585247], + [-3716.57322856], + [-3710.08561764]]) + electric_power_in_total |0.0| output kW traj.cruise.timeseries.electric_power_in_total + val: + array([[0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.]]) + altitude_rate |0.8794761| output ft/s traj.cruise.timeseries.altitude_rate + val: + array([[0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683]]) + throttle |2.78644451| output unitless traj.cruise.timeseries.throttle + val: + array([[0.62030938], + [0.62046836], + [0.62070005], + [0.62077638], + [0.62077638], + [0.62115279], + [0.62172604], + [0.62192082], + [0.62192082], + [0.62248454], + [0.62334458], + [0.62363676], + [0.62363676], + [0.6242272 ], + [0.62510335], + [0.62539589], + [0.62539589], + [0.62573279], + [0.62621334], + [0.62636927]]) + velocity |963.55047191| output m/s traj.cruise.timeseries.velocity + val: + array([[216.42809923], + [216.34879353], + [216.23932113], + [216.20466219], + [216.20466219], + [216.04250323], + [215.81856126], + [215.74763702], + [215.74763702], + [215.55443278], + [215.28757185], + [215.20304383], + [215.20304383], + [215.04014595], + [214.81518168], + [214.74393321], + [214.74393321], + [214.66401882], + [214.55370544], + [214.51878007]]) + altitude |147700.4084954| output ft traj.cruise.timeseries.altitude + val: + array([[32000. ], + [32083.41734823], + [32198.51626306], + [32234.94467607], + [32234.94467607], + [32405.30661107], + [32640.37131001], + [32714.76848352], + [32714.76848352], + [32917.31196851], + [33196.78063808], + [33285.23151648], + [33285.23151648], + [33455.59345148], + [33690.65815042], + [33765.05532393], + [33765.05532393], + [33848.47267216], + [33963.57158699], + [34000. ]]) + time |43155.65216817| output s traj.cruise.timeseries.time + val: + array([[ 3840. ], + [ 4264.17721573], + [ 4849.45519765], + [ 5034.69367782], + [ 5034.69367782], + [ 5900.9841173 ], + [ 7096.28811139], + [ 7474.5977387 ], + [ 7474.5977387 ], + [ 8504.53135987], + [ 9925.62954466], + [10375.4022613 ], + [10375.4022613 ], + [11241.69270078], + [12436.99669488], + [12815.30632218], + [12815.30632218], + [13239.48353791], + [13824.76151983], + [14010. ]]) + time_phase |27763.66679782| output s traj.cruise.timeseries.time_phase + val: + array([[ 0. ], + [ 424.17721573], + [ 1009.45519765], + [ 1194.69367782], + [ 1194.69367782], + [ 2060.9841173 ], + [ 3256.28811139], + [ 3634.5977387 ], + [ 3634.5977387 ], + [ 4664.53135987], + [ 6085.62954466], + [ 6535.4022613 ], + [ 6535.4022613 ], + [ 7401.69270078], + [ 8596.99669488], + [ 8975.30632218], + [ 8975.30632218], + [ 9399.48353791], + [ 9984.76151983], + [10170. ]]) + mach_rate |0.0| output unitless/s traj.cruise.timeseries.mach_rate + val: + array([[ 0.00000000e+00], + [ 8.73331779e-20], + [ 4.36665890e-20], + [ 0.00000000e+00], + [ 0.00000000e+00], + [ 3.27499417e-20], + [ 2.18332945e-20], + [ 0.00000000e+00], + [ 0.00000000e+00], + [-4.36665890e-20], + [-6.54998835e-20], + [-4.36665890e-20], + [-4.36665890e-20], + [-4.91249126e-20], + [-2.18332945e-20], + [ 8.73331779e-20], + [ 8.73331779e-20], + [-8.73331779e-20], + [ 0.00000000e+00], + [ 1.74666356e-19]]) + mass |243577.62672176| output kg traj.cruise.timeseries.mass + val: + array([[57015.39290411], + [56797.93787223], + [56499.27092781], + [56405.0756841 ], + [56405.0756841 ], + [55966.67143281], + [55367.45066061], + [55179.16707729], + [55179.16707729], + [54669.88811206], + [53975.10803913], + [53757.11559708], + [53757.11559708], + [53339.81352995], + [52769.53817769], + [52590.37433179], + [52590.37433179], + [52390.24374586], + [52115.41253722], + [52028.74471935]]) + distance |8196715.33458363| output m traj.cruise.timeseries.distance + val: + array([[ 560039.40638961], + [ 651826.45257603], + [ 778418.59972934], + [ 818471.23138883], + [ 818471.23138883], + [1005697.02623753], + [1263799.66653641], + [1345432.48793709], + [1345432.48793709], + [1567538.74520054], + [1873673.16694925], + [1970484.63129816], + [1970484.63129816], + [2156842.41376365], + [2413746.32168934], + [2494999.4935999 ], + [2494999.4935999 ], + [2586072.02583254], + [2711677.86536452], + [2751418.23144865]]) + mission_bus_variables + dt_dstau |4814.09560547| input s traj.cruise.mission_bus_variables.dt_dstau + val: + array([ 597.34683891, 597.34683891, 597.34683891, 597.34683891, + 1219.95203044, 1219.95203044, 1219.95203044, 1219.95203044, + 1450.4022613 , 1450.4022613 , 1450.4022613 , 1450.4022613 , + 1219.95203044, 1219.95203044, 1219.95203044, 1219.95203044, + 597.34683891, 597.34683891, 597.34683891, 597.34683891]) + input_values:mach |3.21993789| input unitless traj.cruise.mission_bus_variables.input_values:mach + val: + array([[0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72]]) + input_values:thrust_net_total |31225.04562526| input lbf traj.cruise.mission_bus_variables.input_values:thrust_net_total + val: + array([[7283.97100791], + [7258.38824181], + [7223.22226111], + [7212.12430625], + [7212.12430625], + [7160.42784354], + [7089.6523824 ], + [7067.38680815], + [7067.38680815], + [7007.0989486 ], + [6924.70247135], + [6898.80938625], + [6898.80938625], + [6849.18729088], + [6781.26041265], + [6759.89308244], + [6759.89308244], + [6736.01041873], + [6703.18821962], + [6692.83181316]]) + input_values:drag |31075.67524118| input lbf traj.cruise.mission_bus_variables.input_values:drag + val: + array([[7249.15838542], + [7223.69568126], + [7188.69465737], + [7177.64874096], + [7177.64874096], + [7126.19456118], + [7055.75048551], + [7033.58909177], + [7033.58909177], + [6973.58315624], + [6891.57160251], + [6865.79936432], + [6865.79936432], + [6816.40870516], + [6748.79831449], + [6727.53046622], + [6727.53046622], + [6703.75895516], + [6671.0894471 ], + [6660.78120358]]) + input_values:specific_energy_rate_excess |37.75301942| input m/s traj.cruise.mission_bus_variables.input_values:specific_energy_rate_excess + val: + array([[8.55190129], + [8.5453959 ], + [8.53594173], + [8.53283337], + [8.53283337], + [8.5175461 ], + [8.49438705], + [8.48654893], + [8.48654893], + [8.46394686], + [8.42967295], + [8.41807454], + [8.41807454], + [8.39470149], + [8.36017624], + [8.34868973], + [8.34868973], + [8.33548601], + [8.31669867], + [8.31061392]]) + input_values:fuel_flow_rate_negative_total |17397.30457641| input lbm/h traj.cruise.mission_bus_variables.input_values:fuel_flow_rate_negative_total + val: + array([[-4076.58910351], + [-4060.87736702], + [-4039.25960572], + [-4032.43234269], + [-4032.43234269], + [-4000.59756274], + [-3956.92577962], + [-3943.16512475], + [-3943.16512475], + [-3905.85169075], + [-3854.72288485], + [-3838.62390368], + [-3838.62390368], + [-3807.74479615], + [-3765.39201751], + [-3752.04620486], + [-3752.04620486], + [-3737.11585247], + [-3716.57322856], + [-3710.08561764]]) + input_values:electric_power_in_total |0.0| input kW traj.cruise.mission_bus_variables.input_values:electric_power_in_total + val: + array([[0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.]]) + input_values:altitude_rate |0.8794761| input ft/s traj.cruise.mission_bus_variables.input_values:altitude_rate + val: + array([[0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683]]) + input_values:throttle |2.78644451| input unitless traj.cruise.mission_bus_variables.input_values:throttle + val: + array([[0.62030938], + [0.62046836], + [0.62070005], + [0.62077638], + [0.62077638], + [0.62115279], + [0.62172604], + [0.62192082], + [0.62192082], + [0.62248454], + [0.62334458], + [0.62363676], + [0.62363676], + [0.6242272 ], + [0.62510335], + [0.62539589], + [0.62539589], + [0.62573279], + [0.62621334], + [0.62636927]]) + input_values:velocity |963.55047191| input m/s traj.cruise.mission_bus_variables.input_values:velocity + val: + array([[216.42809923], + [216.34879353], + [216.23932113], + [216.20466219], + [216.20466219], + [216.04250323], + [215.81856126], + [215.74763702], + [215.74763702], + [215.55443278], + [215.28757185], + [215.20304383], + [215.20304383], + [215.04014595], + [214.81518168], + [214.74393321], + [214.74393321], + [214.66401882], + [214.55370544], + [214.51878007]]) + input_values:altitude |147700.4084954| input ft traj.cruise.mission_bus_variables.input_values:altitude + val: + array([[32000. ], + [32083.41734823], + [32198.51626306], + [32234.94467607], + [32234.94467607], + [32405.30661107], + [32640.37131001], + [32714.76848352], + [32714.76848352], + [32917.31196851], + [33196.78063808], + [33285.23151648], + [33285.23151648], + [33455.59345148], + [33690.65815042], + [33765.05532393], + [33765.05532393], + [33848.47267216], + [33963.57158699], + [34000. ]]) + input_values:time |43155.65216817| input s traj.cruise.mission_bus_variables.input_values:time + val: + array([[ 3840. ], + [ 4264.17721573], + [ 4849.45519765], + [ 5034.69367782], + [ 5034.69367782], + [ 5900.9841173 ], + [ 7096.28811139], + [ 7474.5977387 ], + [ 7474.5977387 ], + [ 8504.53135987], + [ 9925.62954466], + [10375.4022613 ], + [10375.4022613 ], + [11241.69270078], + [12436.99669488], + [12815.30632218], + [12815.30632218], + [13239.48353791], + [13824.76151983], + [14010. ]]) + input_values:time_phase |27763.66679782| input s traj.cruise.mission_bus_variables.input_values:time_phase + val: + array([[ 0. ], + [ 424.17721573], + [ 1009.45519765], + [ 1194.69367782], + [ 1194.69367782], + [ 2060.9841173 ], + [ 3256.28811139], + [ 3634.5977387 ], + [ 3634.5977387 ], + [ 4664.53135987], + [ 6085.62954466], + [ 6535.4022613 ], + [ 6535.4022613 ], + [ 7401.69270078], + [ 8596.99669488], + [ 8975.30632218], + [ 8975.30632218], + [ 9399.48353791], + [ 9984.76151983], + [10170. ]]) + input_values:mach_rate |0.0| input unitless/s traj.cruise.mission_bus_variables.input_values:mach_rate + val: + array([[ 0.00000000e+00], + [ 8.73331779e-20], + [ 4.36665890e-20], + [ 0.00000000e+00], + [ 0.00000000e+00], + [ 3.27499417e-20], + [ 2.18332945e-20], + [ 0.00000000e+00], + [ 0.00000000e+00], + [-4.36665890e-20], + [-6.54998835e-20], + [-4.36665890e-20], + [-4.36665890e-20], + [-4.91249126e-20], + [-2.18332945e-20], + [ 8.73331779e-20], + [ 8.73331779e-20], + [-8.73331779e-20], + [ 0.00000000e+00], + [ 1.74666356e-19]]) + input_values:mass |243577.62672176| input kg traj.cruise.mission_bus_variables.input_values:mass + val: + array([[57015.39290411], + [56797.93787223], + [56499.27092781], + [56405.0756841 ], + [56405.0756841 ], + [55966.67143281], + [55367.45066061], + [55179.16707729], + [55179.16707729], + [54669.88811206], + [53975.10803913], + [53757.11559708], + [53757.11559708], + [53339.81352995], + [52769.53817769], + [52590.37433179], + [52590.37433179], + [52390.24374586], + [52115.41253722], + [52028.74471935]]) + input_values:distance |8196715.33458363| input m traj.cruise.mission_bus_variables.input_values:distance + val: + array([[ 560039.40638961], + [ 651826.45257603], + [ 778418.59972934], + [ 818471.23138883], + [ 818471.23138883], + [1005697.02623753], + [1263799.66653641], + [1345432.48793709], + [1345432.48793709], + [1567538.74520054], + [1873673.16694925], + [1970484.63129816], + [1970484.63129816], + [2156842.41376365], + [2413746.32168934], + [2494999.4935999 ], + [2494999.4935999 ], + [2586072.02583254], + [2711677.86536452], + [2751418.23144865]]) + mach |2.78854801| output unitless traj.cruise.mission_bus_variables.mach + val: + array([[0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72], + [0.72]]) + thrust_net_total |27059.7506392| output lbf traj.cruise.mission_bus_variables.thrust_net_total + val: + array([[7283.97100791], + [7222.76993971], + [7162.03304682], + [7162.03304682], + [7101.76183506], + [7041.95764492], + [7041.95764492], + [6982.6259213 ], + [6923.75849779], + [6923.75849779], + [6865.34407699], + [6807.38342407], + [6807.38342407], + [6749.87860684], + [6692.83181316]]) + drag |26930.30868092| output lbf traj.cruise.mission_bus_variables.drag + val: + array([[7249.15838542], + [7188.2444571 ], + [7127.79224443], + [7127.79224443], + [7067.80326401], + [7008.27886715], + [7008.27886715], + [6949.22450959], + [6890.63203568], + [6890.63203568], + [6832.49015876], + [6774.79965532], + [6774.79965532], + [6717.56260424], + [6660.78120358]]) + specific_energy_rate_excess |32.71327904| output m/s traj.cruise.mission_bus_variables.specific_energy_rate_excess + val: + array([[8.55190129], + [8.53581622], + [8.5180411 ], + [8.5180411 ], + [8.49853731], + [8.47726597], + [8.47726597], + [8.45418023], + [8.42925716], + [8.42925716], + [8.4024794 ], + [8.37380788], + [8.37380788], + [8.34320043], + [8.31061392]]) + fuel_flow_rate_negative_total |15077.90378893| output lbm/h traj.cruise.mission_bus_variables.fuel_flow_rate_negative_total + val: + array([[-4076.58910351], + [-4038.98139242], + [-4001.58685424], + [-4001.58685424], + [-3964.40528187], + [-3927.43635038], + [-3927.43635038], + [-3890.68162598], + [-3854.13623888], + [-3854.13623888], + [-3817.80397591], + [-3781.69244616], + [-3781.69244616], + [-3745.78735803], + [-3710.08561764]]) + electric_power_in_total |0.0| output kW traj.cruise.mission_bus_variables.electric_power_in_total + val: + array([[0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.]]) + altitude_rate |0.76164864| output ft/s traj.cruise.mission_bus_variables.altitude_rate + val: + array([[0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683], + [0.19665683]]) + throttle |2.41264855| output unitless traj.cruise.mission_bus_variables.throttle + val: + array([[0.62030938], + [0.62070313], + [0.62114057], + [0.62114057], + [0.62162306], + [0.62215196], + [0.62215196], + [0.62272905], + [0.62335505], + [0.62335505], + [0.62403048], + [0.62475686], + [0.62475686], + [0.62553587], + [0.62636927]]) + velocity |834.53311829| output m/s traj.cruise.mission_bus_variables.velocity + val: + array([[216.42809923], + [216.23790957], + [216.04755612], + [216.04755612], + [215.85703846], + [215.66635615], + [215.66635615], + [215.47550876], + [215.28449584], + [215.28449584], + [215.09331695], + [214.90197166], + [214.90197166], + [214.71045951], + [214.51878007]]) + altitude |127828.79174896| output ft traj.cruise.mission_bus_variables.altitude + val: + array([[32000.], + [32200.], + [32400.], + [32400.], + [32600.], + [32800.], + [32800.], + [33000.], + [33200.], + [33200.], + [33400.], + [33600.], + [33600.], + [33800.], + [34000.]]) + time |36459.4561808| output s traj.cruise.mission_bus_variables.time + val: + array([[ 3840.], + [ 4857.], + [ 5874.], + [ 5874.], + [ 6891.], + [ 7908.], + [ 7908.], + [ 8925.], + [ 9942.], + [ 9942.], + [10959.], + [11976.], + [11976.], + [12993.], + [14010.]]) + time_phase |22854.23254017| output s traj.cruise.mission_bus_variables.time_phase + val: + array([[ 0.], + [ 1017.], + [ 2034.], + [ 2034.], + [ 3051.], + [ 4068.], + [ 4068.], + [ 5085.], + [ 6102.], + [ 6102.], + [ 7119.], + [ 8136.], + [ 8136.], + [ 9153.], + [10170.]]) + mach_rate |0.0| output unitless/s traj.cruise.mission_bus_variables.mach_rate + val: + array([[ 0.00000000e+00], + [ 4.21226452e-20], + [ 3.21535108e-20], + [ 3.21535108e-20], + [ 2.95885122e-20], + [-1.70675411e-20], + [-1.70675411e-20], + [-5.96326498e-20], + [-6.50288885e-20], + [-6.50288885e-20], + [-3.42111904e-20], + [-7.15043654e-20], + [-7.15043654e-20], + [ 4.28728963e-21], + [ 1.74666356e-19]]) + mass |211091.10966044| output kg traj.cruise.mission_bus_variables.mass + val: + array([[57015.39290411], + [56495.43122231], + [55980.27491257], + [55980.27491257], + [55469.89668958], + [54964.26925183], + [54964.26925183], + [54463.36530601], + [53967.15772816], + [53967.15772816], + [53475.6194842 ], + [52988.7226521 ], + [52988.7226521 ], + [52506.43974513], + [52028.74471935]]) + distance |6887901.12410551| output m traj.cruise.mission_bus_variables.distance + val: + array([[ 560039.40638961], + [ 780050.07727996], + [ 999867.2420398 ], + [ 999867.2420398 ], + [1219490.73383222], + [1438920.38552 ], + [1438920.38552 ], + [1658156.02936447], + [1877197.49721605], + [1877197.49721605], + [2096044.62065779], + [2314697.23052702], + [2314697.23052702], + [2533155.15743856], + [2751418.23144865]]) + collocation_constraint + dt_dstau |4169.12909058| input s traj.cruise.collocation_constraint.dt_dstau + val: + array([ 597.34683891, 597.34683891, 597.34683891, 1219.95203044, + 1219.95203044, 1219.95203044, 1450.4022613 , 1450.4022613 , + 1450.4022613 , 1219.95203044, 1219.95203044, 1219.95203044, + 597.34683891, 597.34683891, 597.34683891]) + f_approx:mass |1.90369215| input kg/s traj.cruise.collocation_constraint.f_approx:mass + val: + array([[-0.51364159], + [-0.51166194], + [-0.50893815], + [-0.50807793], + [-0.50406681], + [-0.49856426], + [-0.49683045], + [-0.49212903], + [-0.48568691], + [-0.48365848], + [-0.47976777], + [-0.47443141], + [-0.47274987], + [-0.47086868], + [-0.46828035]]) + f_computed:mass |1.90369215| input kg/s traj.cruise.collocation_constraint.f_computed:mass + val: + array([[-0.51364159], + [-0.51166194], + [-0.50893815], + [-0.50807793], + [-0.50406681], + [-0.49856426], + [-0.49683045], + [-0.49212903], + [-0.48568691], + [-0.48365848], + [-0.47976777], + [-0.47443141], + [-0.47274987], + [-0.47086868], + [-0.46828035]]) + f_approx:distance |834.68098413| input m/s traj.cruise.collocation_constraint.f_approx:distance + val: + array([[216.42809093], + [216.34878522], + [216.23931282], + [216.20465388], + [216.04249491], + [215.81855294], + [215.7476287 ], + [215.55442444], + [215.28756351], + [215.20303548], + [215.04013759], + [214.81517331], + [214.74392485], + [214.66401045], + [214.55369706]]) + f_computed:distance |834.68098413| input m/s traj.cruise.collocation_constraint.f_computed:distance + val: + array([[216.42809093], + [216.34878522], + [216.23931282], + [216.20465388], + [216.04249491], + [215.81855294], + [215.7476287 ], + [215.55442444], + [215.28756351], + [215.20303548], + [215.04013759], + [214.81517331], + [214.74392485], + [214.66401045], + [214.55369706]]) + defects:mass |0.0| output kg traj.cruise.collocation_constraint.defects:mass + val: + array([[ 2.58643404e-12], + [-6.63188214e-12], + [-1.45901407e-12], + [-2.50567484e-11], + [ 2.87136793e-11], + [-8.87144336e-12], + [ 9.56500371e-11], + [-9.17853892e-12], + [ 9.74213341e-12], + [ 3.56889363e-11], + [-6.43348946e-12], + [ 3.31832614e-12], + [ 7.45423553e-11], + [-2.18520517e-11], + [ 3.71385400e-12]]) + defects:distance |0.0| output m traj.cruise.collocation_constraint.defects:distance + val: + array([[-6.28171877e-10], + [ 2.88619511e-10], + [ 5.09328549e-11], + [-5.54769954e-10], + [-1.38692489e-10], + [-2.42711855e-10], + [ 2.18481432e-09], + [-4.12229116e-11], + [ 5.35897851e-10], + [-2.46179167e-09], + [ 5.89443076e-10], + [-4.85423710e-10], + [ 2.56362036e-09], + [ 5.94216640e-10], + [-1.44309755e-09]]) + descent + param_comp + t_initial [14010.] input s traj.descent.t_initial + t_duration [4548.94581634] input s traj.descent.t_duration + parameters:aircraft:design:base_area [0.] input ft**2 traj.descent.parameters:aircraft:design:base_area + parameters:aircraft:design:lift_dependent_drag_coeff_factor [0.90983938] input unitless traj.descent.parameters:aircraft:design:lift_dependent_drag_coeff_factor + parameters:aircraft:design:subsonic_drag_coeff_factor [1.] input unitless traj.descent.parameters:aircraft:design:subsonic_drag_coeff_factor + parameters:aircraft:design:supersonic_drag_coeff_factor [1.] input unitless traj.descent.parameters:aircraft:design:supersonic_drag_coeff_factor + parameters:aircraft:design:zero_lift_drag_coeff_factor [0.93089003] input unitless traj.descent.parameters:aircraft:design:zero_lift_drag_coeff_factor + parameters:aircraft:fuselage:characteristic_length [128.] input ft traj.descent.parameters:aircraft:fuselage:characteristic_length + parameters:aircraft:fuselage:cross_section [127.67628894] input ft**2 traj.descent.parameters:aircraft:fuselage:cross_section + parameters:aircraft:fuselage:diameter_to_wing_span [0.10826471] input unitless traj.descent.parameters:aircraft:fuselage:diameter_to_wing_span + parameters:aircraft:fuselage:fineness [10.03921569] input unitless traj.descent.parameters:aircraft:fuselage:fineness + parameters:aircraft:fuselage:laminar_flow_lower [0.] input unitless traj.descent.parameters:aircraft:fuselage:laminar_flow_lower + parameters:aircraft:fuselage:laminar_flow_upper [0.] input unitless traj.descent.parameters:aircraft:fuselage:laminar_flow_upper + parameters:aircraft:fuselage:length_to_diameter [10.03921569] input unitless traj.descent.parameters:aircraft:fuselage:length_to_diameter + parameters:aircraft:fuselage:wetted_area [4158.62] input ft**2 traj.descent.parameters:aircraft:fuselage:wetted_area + parameters:aircraft:horizontal_tail:characteristic_length [7.69198717] input ft traj.descent.parameters:aircraft:horizontal_tail:characteristic_length + parameters:aircraft:horizontal_tail:fineness [0.125] input unitless traj.descent.parameters:aircraft:horizontal_tail:fineness + parameters:aircraft:horizontal_tail:laminar_flow_lower [0.] input unitless traj.descent.parameters:aircraft:horizontal_tail:laminar_flow_lower + parameters:aircraft:horizontal_tail:laminar_flow_upper [0.] input unitless traj.descent.parameters:aircraft:horizontal_tail:laminar_flow_upper + parameters:aircraft:horizontal_tail:wetted_area [592.65] input ft**2 traj.descent.parameters:aircraft:horizontal_tail:wetted_area + parameters:aircraft:vertical_tail:characteristic_length [12.73914103] input ft traj.descent.parameters:aircraft:vertical_tail:characteristic_length + parameters:aircraft:vertical_tail:fineness [0.1195] input unitless traj.descent.parameters:aircraft:vertical_tail:fineness + parameters:aircraft:vertical_tail:laminar_flow_lower [0.] input unitless traj.descent.parameters:aircraft:vertical_tail:laminar_flow_lower + parameters:aircraft:vertical_tail:laminar_flow_upper [0.] input unitless traj.descent.parameters:aircraft:vertical_tail:laminar_flow_upper + parameters:aircraft:vertical_tail:wetted_area [581.13] input ft**2 traj.descent.parameters:aircraft:vertical_tail:wetted_area + parameters:aircraft:wing:area [1370.] input ft**2 traj.descent.parameters:aircraft:wing:area + parameters:aircraft:wing:aspect_ratio [11.22091] input unitless traj.descent.parameters:aircraft:wing:aspect_ratio + parameters:aircraft:wing:characteristic_length [10.49530819] input ft traj.descent.parameters:aircraft:wing:characteristic_length + parameters:aircraft:wing:fineness [0.13] input unitless traj.descent.parameters:aircraft:wing:fineness + parameters:aircraft:wing:laminar_flow_lower [0.] input unitless traj.descent.parameters:aircraft:wing:laminar_flow_lower + parameters:aircraft:wing:laminar_flow_upper [0.] input unitless traj.descent.parameters:aircraft:wing:laminar_flow_upper + parameters:aircraft:wing:max_camber_at_70_semispan [0.] input unitless traj.descent.parameters:aircraft:wing:max_camber_at_70_semispan + parameters:aircraft:wing:span_efficiency_factor [1.] input unitless traj.descent.parameters:aircraft:wing:span_efficiency_factor + parameters:aircraft:wing:sweep [25.] input deg traj.descent.parameters:aircraft:wing:sweep + parameters:aircraft:wing:taper_ratio [0.278] input unitless traj.descent.parameters:aircraft:wing:taper_ratio + parameters:aircraft:wing:thickness_to_chord [0.13] input unitless traj.descent.parameters:aircraft:wing:thickness_to_chord + parameters:aircraft:wing:wetted_area [2396.56] input ft**2 traj.descent.parameters:aircraft:wing:wetted_area + parameters:mission:design:lift_coefficient [0.56736557] input unitless traj.descent.parameters:mission:design:lift_coefficient + parameters:mission:design:mach [0.80017085] input unitless traj.descent.parameters:mission:design:mach + parameters:aircraft:nacelle:characteristic_length [12.3] input ft traj.descent.parameters:aircraft:nacelle:characteristic_length + parameters:aircraft:nacelle:fineness [1.54911839] input unitless traj.descent.parameters:aircraft:nacelle:fineness + parameters:aircraft:nacelle:laminar_flow_lower [0.] input unitless traj.descent.parameters:aircraft:nacelle:laminar_flow_lower + parameters:aircraft:nacelle:laminar_flow_upper [0.] input unitless traj.descent.parameters:aircraft:nacelle:laminar_flow_upper + parameters:aircraft:nacelle:wetted_area [273.4536] input ft**2 traj.descent.parameters:aircraft:nacelle:wetted_area + parameters:aircraft:engine:scale_factor [1.] input unitless traj.descent.parameters:aircraft:engine:scale_factor + t_initial_val [14010.] output s traj.descent.t_initial_val + t_duration_val [4548.94581634] output s traj.descent.t_duration_val + parameter_vals:aircraft:design:base_area [[0.]] output ft**2 traj.descent.parameter_vals:aircraft:design:base_area + parameter_vals:aircraft:design:lift_dependent_drag_coeff_factor [[0.90983938]] output unitless traj.descent.parameter_vals:aircraft:design:lift_dependent_drag_coeff_factor + parameter_vals:aircraft:design:subsonic_drag_coeff_factor [[1.]] output unitless traj.descent.parameter_vals:aircraft:design:subsonic_drag_coeff_factor + parameter_vals:aircraft:design:supersonic_drag_coeff_factor [[1.]] output unitless traj.descent.parameter_vals:aircraft:design:supersonic_drag_coeff_factor + parameter_vals:aircraft:design:zero_lift_drag_coeff_factor [[0.93089003]] output unitless traj.descent.parameter_vals:aircraft:design:zero_lift_drag_coeff_factor + parameter_vals:aircraft:fuselage:characteristic_length [[128.]] output ft traj.descent.parameter_vals:aircraft:fuselage:characteristic_length + parameter_vals:aircraft:fuselage:cross_section [[127.67628894]] output ft**2 traj.descent.parameter_vals:aircraft:fuselage:cross_section + parameter_vals:aircraft:fuselage:diameter_to_wing_span [[0.10826471]] output unitless traj.descent.parameter_vals:aircraft:fuselage:diameter_to_wing_span + parameter_vals:aircraft:fuselage:fineness [[10.03921569]] output unitless traj.descent.parameter_vals:aircraft:fuselage:fineness + parameter_vals:aircraft:fuselage:laminar_flow_lower [[0.]] output unitless traj.descent.parameter_vals:aircraft:fuselage:laminar_flow_lower + parameter_vals:aircraft:fuselage:laminar_flow_upper [[0.]] output unitless traj.descent.parameter_vals:aircraft:fuselage:laminar_flow_upper + parameter_vals:aircraft:fuselage:length_to_diameter [[10.03921569]] output unitless traj.descent.parameter_vals:aircraft:fuselage:length_to_diameter + parameter_vals:aircraft:fuselage:wetted_area [[4158.62]] output ft**2 traj.descent.parameter_vals:aircraft:fuselage:wetted_area + parameter_vals:aircraft:horizontal_tail:characteristic_length [[7.69198717]] output ft traj.descent.parameter_vals:aircraft:horizontal_tail:characteristic_length + parameter_vals:aircraft:horizontal_tail:fineness [[0.125]] output unitless traj.descent.parameter_vals:aircraft:horizontal_tail:fineness + parameter_vals:aircraft:horizontal_tail:laminar_flow_lower [[0.]] output unitless traj.descent.parameter_vals:aircraft:horizontal_tail:laminar_flow_lower + parameter_vals:aircraft:horizontal_tail:laminar_flow_upper [[0.]] output unitless traj.descent.parameter_vals:aircraft:horizontal_tail:laminar_flow_upper + parameter_vals:aircraft:horizontal_tail:wetted_area [[592.65]] output ft**2 traj.descent.parameter_vals:aircraft:horizontal_tail:wetted_area + parameter_vals:aircraft:vertical_tail:characteristic_length [[12.73914103]] output ft traj.descent.parameter_vals:aircraft:vertical_tail:characteristic_length + parameter_vals:aircraft:vertical_tail:fineness [[0.1195]] output unitless traj.descent.parameter_vals:aircraft:vertical_tail:fineness + parameter_vals:aircraft:vertical_tail:laminar_flow_lower [[0.]] output unitless traj.descent.parameter_vals:aircraft:vertical_tail:laminar_flow_lower + parameter_vals:aircraft:vertical_tail:laminar_flow_upper [[0.]] output unitless traj.descent.parameter_vals:aircraft:vertical_tail:laminar_flow_upper + parameter_vals:aircraft:vertical_tail:wetted_area [[581.13]] output ft**2 traj.descent.parameter_vals:aircraft:vertical_tail:wetted_area + parameter_vals:aircraft:wing:area [[1370.]] output ft**2 traj.descent.parameter_vals:aircraft:wing:area + parameter_vals:aircraft:wing:aspect_ratio [[11.22091]] output unitless traj.descent.parameter_vals:aircraft:wing:aspect_ratio + parameter_vals:aircraft:wing:characteristic_length [[10.49530819]] output ft traj.descent.parameter_vals:aircraft:wing:characteristic_length + parameter_vals:aircraft:wing:fineness [[0.13]] output unitless traj.descent.parameter_vals:aircraft:wing:fineness + parameter_vals:aircraft:wing:laminar_flow_lower [[0.]] output unitless traj.descent.parameter_vals:aircraft:wing:laminar_flow_lower + parameter_vals:aircraft:wing:laminar_flow_upper [[0.]] output unitless traj.descent.parameter_vals:aircraft:wing:laminar_flow_upper + parameter_vals:aircraft:wing:max_camber_at_70_semispan [[0.]] output unitless traj.descent.parameter_vals:aircraft:wing:max_camber_at_70_semispan + parameter_vals:aircraft:wing:span_efficiency_factor [[1.]] output unitless traj.descent.parameter_vals:aircraft:wing:span_efficiency_factor + parameter_vals:aircraft:wing:sweep [[25.]] output deg traj.descent.parameter_vals:aircraft:wing:sweep + parameter_vals:aircraft:wing:taper_ratio [[0.278]] output unitless traj.descent.parameter_vals:aircraft:wing:taper_ratio + parameter_vals:aircraft:wing:thickness_to_chord [[0.13]] output unitless traj.descent.parameter_vals:aircraft:wing:thickness_to_chord + parameter_vals:aircraft:wing:wetted_area [[2396.56]] output ft**2 traj.descent.parameter_vals:aircraft:wing:wetted_area + parameter_vals:mission:design:lift_coefficient [[0.56736557]] output unitless traj.descent.parameter_vals:mission:design:lift_coefficient + parameter_vals:mission:design:mach [[0.80017085]] output unitless traj.descent.parameter_vals:mission:design:mach + parameter_vals:aircraft:nacelle:characteristic_length [[12.3]] output ft traj.descent.parameter_vals:aircraft:nacelle:characteristic_length + parameter_vals:aircraft:nacelle:fineness [[1.54911839]] output unitless traj.descent.parameter_vals:aircraft:nacelle:fineness + parameter_vals:aircraft:nacelle:laminar_flow_lower [[0.]] output unitless traj.descent.parameter_vals:aircraft:nacelle:laminar_flow_lower + parameter_vals:aircraft:nacelle:laminar_flow_upper [[0.]] output unitless traj.descent.parameter_vals:aircraft:nacelle:laminar_flow_upper + parameter_vals:aircraft:nacelle:wetted_area [[273.4536]] output ft**2 traj.descent.parameter_vals:aircraft:nacelle:wetted_area + parameter_vals:aircraft:engine:scale_factor [[1.]] output unitless traj.descent.parameter_vals:aircraft:engine:scale_factor + time + t_initial [14010.] input s traj.descent.t_initial + t_duration [4548.94581634] input s traj.descent.t_duration + t |73347.98069351| output s traj.descent.t + val: + array([14010. , 14199.73049861, 14461.51986216, 14544.37530064, + 14544.37530064, 14931.85890638, 15466.50719578, 15635.72155138, + 15635.72155138, 16096.40122071, 16732.04513834, 16933.22426496, + 16933.22426496, 17320.7078707 , 17855.3561601 , 18024.5705157 , + 18024.5705157 , 18214.30101431, 18476.09037785, 18558.94581634]) + t_phase |12418.42831132| output s traj.descent.t_phase + val: + array([ 0. , 189.73049861, 451.51986216, 534.37530064, + 534.37530064, 921.85890638, 1456.50719578, 1625.72155138, + 1625.72155138, 2086.40122071, 2722.04513834, 2923.22426496, + 2923.22426496, 3310.7078707 , 3845.3561601 , 4014.5705157 , + 4014.5705157 , 4204.30101431, 4466.09037785, 4548.94581634]) + dt_dstau |2153.29990796| output s traj.descent.dt_dstau + val: + array([267.18765032, 267.18765032, 267.18765032, 267.18765032, + 545.67312537, 545.67312537, 545.67312537, 545.67312537, + 648.75135679, 648.75135679, 648.75135679, 648.75135679, + 545.67312537, 545.67312537, 545.67312537, 545.67312537, + 267.18765032, 267.18765032, 267.18765032, 267.18765032]) + control_comp + dt_dstau |2153.29990796| input s traj.descent.control_comp.dt_dstau + val: + array([267.18765032, 267.18765032, 267.18765032, 267.18765032, + 545.67312537, 545.67312537, 545.67312537, 545.67312537, + 648.75135679, 648.75135679, 648.75135679, 648.75135679, + 545.67312537, 545.67312537, 545.67312537, 545.67312537, + 267.18765032, 267.18765032, 267.18765032, 267.18765032]) + t_duration [4548.94581634] input s traj.descent.control_comp.t_duration + controls:mach |1.1154192| input unitless traj.descent.controls:mach + val: + array([[0.72 ], + [0.62049845], + [0.45950155], + [0.36 ]]) + controls:altitude |43169.43363075| input ft traj.descent.controls:altitude + val: + array([[34000. ], + [24740.82772462], + [ 9759.17227538], + [ 500. ]]) + control_values:mach |2.45889929| output unitless traj.descent.control_values:mach + val: + array([[0.72 ], + [0.70498488], + [0.68426707], + [0.67770996], + [0.67770996], + [0.64704481], + [0.60473316], + [0.59134167], + [0.59134167], + [0.55488385], + [0.50457949], + [0.48865833], + [0.48865833], + [0.45799318], + [0.41568153], + [0.40229004], + [0.40229004], + [0.38727492], + [0.36655711], + [0.36 ]]) + control_rates:mach_rate |0.00035392| output unitless/s traj.descent.control_rates:mach_rate + val: + array([[-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05]]) + control_rates:mach_rate2 |0.0| output unitless/s**2 traj.descent.control_rates:mach_rate2 + val: + array([[-3.43375003e-22], + [-5.15062504e-22], + [-1.71687501e-22], + [-1.71687501e-22], + [-1.71687501e-22], + [-1.71687501e-22], + [-2.57531252e-22], + [-8.58437507e-23], + [-8.58437507e-23], + [-8.58437507e-23], + [-2.14609377e-23], + [ 4.29218754e-23], + [ 4.29218754e-23], + [ 8.58437507e-23], + [ 0.00000000e+00], + [ 1.71687501e-22], + [ 1.71687501e-22], + [ 1.71687501e-22], + [ 3.43375003e-22], + [ 3.43375003e-22]]) + control_boundary_values:mach |0.80498447| output unitless traj.descent.control_comp.control_boundary_values:mach + val: + array([[0.72], + [0.36]]) + control_boundary_rates:mach_rate |0.00011192| output unitless/s traj.descent.control_comp.control_boundary_rates:mach_rate + val: + array([[-7.91392148e-05], + [-7.91392148e-05]]) + control_boundary_rates:mach_rate2 |0.0| output unitless/s**2 traj.descent.control_comp.control_boundary_rates:mach_rate2 + val: + array([[-3.43375003e-22], + [ 3.43375003e-22]]) + control_values:altitude |90819.35928076| output ft traj.descent.control_values:altitude + val: + array([[34000. ], + [32602.7594172 ], + [30674.85259378], + [30064.67667582], + [30064.67667582], + [27211.11426456], + [23273.78055735], + [22027.62790105], + [22027.62790105], + [18635.02452748], + [13953.9243121 ], + [12472.37209895], + [12472.37209895], + [ 9618.80968769], + [ 5681.47598048], + [ 4435.32332418], + [ 4435.32332418], + [ 3038.08274138], + [ 1110.17591796], + [ 500. ]]) + control_rates:altitude_rate |32.93434579| output ft/s traj.descent.control_rates:altitude_rate + val: + array([[-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436]]) + control_rates:altitude_rate2 |0.0| output ft/s**2 traj.descent.control_rates:altitude_rate2 + val: + array([[-1.12517121e-17], + [-1.68775681e-17], + [-5.62585605e-18], + [-5.62585605e-18], + [-5.62585605e-18], + [-5.62585605e-18], + [-8.43878407e-18], + [ 0.00000000e+00], + [ 0.00000000e+00], + [-1.40646401e-18], + [-3.51616003e-19], + [ 1.40646401e-18], + [ 1.40646401e-18], + [ 2.81292802e-18], + [ 0.00000000e+00], + [ 2.81292802e-18], + [ 2.81292802e-18], + [ 0.00000000e+00], + [ 5.62585605e-18], + [ 5.62585605e-18]]) + control_boundary_values:altitude |34003.67627184| output ft traj.descent.control_comp.control_boundary_values:altitude + val: + array([[34000.], + [ 500.]]) + control_boundary_rates:altitude_rate |10.41475459| output ft/s traj.descent.control_comp.control_boundary_rates:altitude_rate + val: + array([[-7.3643436], + [-7.3643436]]) + control_boundary_rates:altitude_rate2 |0.0| output ft/s**2 traj.descent.control_comp.control_boundary_rates:altitude_rate2 + val: + array([[-1.12517121e-17], + [ 5.62585605e-18]]) + indep_states + initial_states:mass [[52028.74471935]] input kg traj.descent.initial_states:mass + initial_states:distance [[2751418.23144865]] input m traj.descent.initial_states:distance + states:mass |204485.67328288| output kg traj.descent.states:mass + val: + array([[52028.74471935], + [51956.50719188], + [51855.82599664], + [51823.76601249], + [51672.54219645], + [51461.12266693], + [51393.8106793 ], + [51210.06984292], + [50956.67116637], + [50876.7919899 ], + [50724.57452871], + [50519.93012614], + [50456.90390387], + [50387.51580428], + [50293.8882617 ], + [50264.76158872]]) + states:distance |12756536.37582982| output m traj.descent.states:distance + val: + array([[2751418.23144865], + [2791817.41185045], + [2846561.44051968], + [2863642.02155273], + [2941914.82037522], + [3045428.93171548], + [3077070.29224964], + [3160390.83905457], + [3268342.75197541], + [3300756.63996977], + [3360741.81646801], + [3438080.96818847], + [3461214.38233449], + [3486369.12667608], + [3519699.62007001], + [3529912. ]]) + state_interp + dt_dstau |1864.81242226| input s traj.descent.state_interp.dt_dstau + val: + array([267.18765032, 267.18765032, 267.18765032, 545.67312537, + 545.67312537, 545.67312537, 648.75135679, 648.75135679, + 648.75135679, 545.67312537, 545.67312537, 545.67312537, + 267.18765032, 267.18765032, 267.18765032]) + state_disc:mass |228638.93848721| input kg traj.descent.state_interp.state_disc:mass + val: + array([[52028.74471935], + [51956.50719188], + [51855.82599664], + [51823.76601249], + [51823.76601249], + [51672.54219645], + [51461.12266693], + [51393.8106793 ], + [51393.8106793 ], + [51210.06984292], + [50956.67116637], + [50876.7919899 ], + [50876.7919899 ], + [50724.57452871], + [50519.93012614], + [50456.90390387], + [50456.90390387], + [50387.51580428], + [50293.8882617 ], + [50264.76158872]]) + state_disc:distance |14257384.99570313| input m traj.descent.state_interp.state_disc:distance + val: + array([[2751418.23144865], + [2791817.41185045], + [2846561.44051968], + [2863642.02155273], + [2863642.02155273], + [2941914.82037522], + [3045428.93171548], + [3077070.29224964], + [3077070.29224964], + [3160390.83905457], + [3268342.75197541], + [3300756.63996977], + [3300756.63996977], + [3360741.81646801], + [3438080.96818847], + [3461214.38233449], + [3461214.38233449], + [3486369.12667608], + [3519699.62007001], + [3529912. ]]) + staterate_col:mass |1.48954691| output kg/s traj.descent.state_interp.staterate_col:mass + val: + array([[-0.37884527], + [-0.38251468], + [-0.38644318], + [-0.38736247], + [-0.39287019], + [-0.3974122 ], + [-0.39825982], + [-0.39915285], + [-0.39760802], + [-0.39585232], + [-0.38930864], + [-0.37524796], + [-0.36913783], + [-0.36231144], + [-0.35299812]]) + staterate_col:distance |678.62402375| output m/s traj.descent.state_interp.staterate_col:distance + val: + array([[214.5070361 ], + [211.34098824], + [206.86850148], + [205.42809125], + [198.53527609], + [188.60727137], + [185.36616898], + [176.30605727], + [163.24787168], + [158.98300661], + [150.59309082], + [138.64324625], + [134.77225428], + [130.38185021], + [124.23737345]]) + rhs_all + atmosphere + standard_atmosphere + h |90819.35928076| input ft traj.descent.rhs_all.altitude + val: + array([34000. , 32602.7594172 , 30674.85259378, 30064.67667582, + 30064.67667582, 27211.11426456, 23273.78055735, 22027.62790105, + 22027.62790105, 18635.02452748, 13953.9243121 , 12472.37209895, + 12472.37209895, 9618.80968769, 5681.47598048, 4435.32332418, + 4435.32332418, 3038.08274138, 1110.17591796, 500. ]) + temp |2057.90503542| output degR traj.descent.rhs_all.temperature + val: + array([397.61833789, 402.58502389, 409.43912788, 411.60869197, + 411.60869197, 421.75760711, 435.76421298, 440.19835649, + 440.19835649, 452.27382677, 468.94157663, 474.21810376, + 474.21810376, 484.38346865, 498.41437443, 502.85599996, + 502.85599996, 507.83777076, 514.7113234 , 516.88704275]) + pres |40.67816643| output psi traj.descent.rhs_all.static_pressure + val: + array([ 3.6352703 , 3.88037611, 4.24043035, 4.35988134, 4.35988134, + 4.95530237, 5.88365723, 6.20522118, 6.20522118, 7.15363949, + 8.65234929, 9.17647506, 9.17647506, 10.25865618, 11.91976345, + 12.48876061, 12.48876061, 13.15282131, 14.11591336, 14.43234102]) + rho |0.00703051| output slug/ft**3 traj.descent.rhs_all.density + val: + array([0.00076705, 0.00080867, 0.00086891, 0.00088868, 0.00088868, + 0.00098574, 0.00113279, 0.00118267, 0.00118267, 0.00132703, + 0.00154799, 0.0016235 , 0.0016235 , 0.00177686, 0.00200646, + 0.00208368, 0.00208368, 0.00217294, 0.00230091, 0.00234259]) + viscosity |1.53e-06| output lbf*s/ft**2 traj.descent.rhs_all.viscosity + val: + array([3.04138620e-07, 3.07367116e-07, 3.11795581e-07, 3.13190984e-07, + 3.13190984e-07, 3.19675903e-07, 3.28517441e-07, 3.31290236e-07, + 3.31290236e-07, 3.38780681e-07, 3.48975867e-07, 3.52169371e-07, + 3.52169371e-07, 3.58276954e-07, 3.66611763e-07, 3.69227842e-07, + 3.69227842e-07, 3.72149488e-07, 3.76157667e-07, 3.77421833e-07]) + drhos_dh |2.2e-07| output slug/ft**4 traj.descent.rhs_all.drhos_dh + val: + array([-2.92754279e-08, -3.04882416e-08, -3.22109276e-08, -3.27621989e-08, + -3.27621989e-08, -3.54703549e-08, -3.94566362e-08, -4.07705940e-08, + -4.07705940e-08, -4.45375443e-08, -5.00972532e-08, -5.19550694e-08, + -5.19550694e-08, -5.56782862e-08, -6.11034075e-08, -6.28984502e-08, + -6.28984502e-08, -6.49319629e-08, -6.78347342e-08, -6.87819117e-08]) + sos |4693.86791488| output ft/s traj.descent.rhs_all.speed_of_sound + val: + array([ 977.50246093, 983.5885495 , 991.92612429, 994.55069512, + 994.55069512, 1006.73720555, 1023.31758488, 1028.51082041, + 1028.51082041, 1042.52237447, 1061.55873018, 1067.51434936, + 1067.51434936, 1078.89532956, 1094.40970637, 1099.27531289, + 1099.27531289, 1104.70712734, 1112.15807119, 1114.50617585]) + flight_conditions + density |0.00703051| input slug/ft**3 traj.descent.rhs_all.density + val: + array([0.00076705, 0.00080867, 0.00086891, 0.00088868, 0.00088868, + 0.00098574, 0.00113279, 0.00118267, 0.00118267, 0.00132703, + 0.00154799, 0.0016235 , 0.0016235 , 0.00177686, 0.00200646, + 0.00208368, 0.00208368, 0.00217294, 0.00230091, 0.00234259]) + speed_of_sound |4693.86791488| input ft/s traj.descent.rhs_all.speed_of_sound + val: + array([ 977.50246093, 983.5885495 , 991.92612429, 994.55069512, + 994.55069512, 1006.73720555, 1023.31758488, 1028.51082041, + 1028.51082041, 1042.52237447, 1061.55873018, 1067.51434936, + 1067.51434936, 1078.89532956, 1094.40970637, 1099.27531289, + 1099.27531289, 1104.70712734, 1112.15807119, 1114.50617585]) + mach |2.45889929| input unitless traj.descent.rhs_all.mach + val: + array([0.72 , 0.70498488, 0.68426707, 0.67770996, 0.67770996, + 0.64704481, 0.60473316, 0.59134167, 0.59134167, 0.55488385, + 0.50457949, 0.48865833, 0.48865833, 0.45799318, 0.41568153, + 0.40229004, 0.40229004, 0.38727492, 0.36655711, 0.36 ]) + dynamic_pressure |928.96258055| output lbf/ft**2 traj.descent.rhs_all.dynamic_pressure + val: + array([189.97476746, 194.41399439, 200.14980358, 201.86238278, + 201.86238278, 209.1379374 , 216.90403419, 218.74024951, + 218.74024951, 222.03734202, 222.06822194, 220.89198309, + 220.89198309, 216.92011004, 207.6264045 , 203.74806627, + 203.74806627, 198.86198706, 191.19926567, 188.55390789]) + EAS |1868.29888869| output ft/s traj.descent.rhs_all.EAS + val: + array([399.8135451 , 404.45788281, 410.38088776, 412.13285744, + 412.13285744, 419.49419246, 427.21191554, 429.01639983, + 429.01639983, 432.23760925, 432.267665 , 431.12133914, + 431.12133914, 427.22774666, 417.97550788, 414.05333815, + 414.05333815, 409.05850787, 401.09999123, 398.31559595]) + velocity |2531.95454473| output ft/s traj.descent.rhs_all.velocity + val: + array([703.80177187, 693.4150529 , 678.74238535, 674.01691012, + 674.01691012, 651.40408389, 618.83408108, 608.20130921, + 608.20130921, 578.47882434, 535.64075753, 521.64977604, + 521.64977604, 494.12670151, 454.92590439, 442.22751145, + 442.22751145, 427.82536327, 407.66945327, 401.22222331]) + velocity_rate_comp + mach_rate |0.00035392| input unitless/s traj.descent.rhs_all.mach_rate + val: + array([-7.91392148e-05, -7.91392148e-05, -7.91392148e-05, -7.91392148e-05, + -7.91392148e-05, -7.91392148e-05, -7.91392148e-05, -7.91392148e-05, + -7.91392148e-05, -7.91392148e-05, -7.91392148e-05, -7.91392148e-05, + -7.91392148e-05, -7.91392148e-05, -7.91392148e-05, -7.91392148e-05, + -7.91392148e-05, -7.91392148e-05, -7.91392148e-05, -7.91392148e-05]) + sos |1430.69094045| input m/s traj.descent.rhs_all.speed_of_sound + val: + array([297.94275009, 299.79778989, 302.33908268, 303.13905187, + 303.13905187, 306.85350025, 311.90719987, 313.49009806, + 313.49009806, 317.76081974, 323.56310096, 325.37837369, + 325.37837369, 328.84729645, 333.5760785 , 335.05911537, + 335.05911537, 336.71473241, 338.9857801 , 339.7014824 ]) + velocity_rate |0.11322376| output m/s**2 traj.descent.rhs_all.velocity_rate + val: + array([-0.02357896, -0.02372576, -0.02392688, -0.02399019, -0.02399019, + -0.02428415, -0.02468409, -0.02480936, -0.02480936, -0.02514734, + -0.02560653, -0.02575019, -0.02575019, -0.02602472, -0.02639895, + -0.02651632, -0.02651632, -0.02664734, -0.02682707, -0.02688371]) + solver_sub + core_aerodynamics + Mux + aircraft:wing:wetted_area [2396.56] input ft**2 traj.descent.rhs_all.aircraft:wing:wetted_area + aircraft:wing:fineness [0.13] input unitless traj.descent.rhs_all.aircraft:wing:fineness + aircraft:wing:characteristic_length [10.49530819] input ft traj.descent.rhs_all.aircraft:wing:characteristic_length + aircraft:wing:laminar_flow_upper [0.] input unitless traj.descent.rhs_all.aircraft:wing:laminar_flow_upper + aircraft:wing:laminar_flow_lower [0.] input unitless traj.descent.rhs_all.aircraft:wing:laminar_flow_lower + aircraft:horizontal_tail:wetted_area [592.65] input ft**2 traj.descent.rhs_all.aircraft:horizontal_tail:wetted_area + aircraft:horizontal_tail:fineness [0.125] input unitless traj.descent.rhs_all.aircraft:horizontal_tail:fineness + aircraft:horizontal_tail:characteristic_length [7.69198717] input ft traj.descent.rhs_all.aircraft:horizontal_tail:characteristic_length + aircraft:horizontal_tail:laminar_flow_upper [0.] input unitless traj.descent.rhs_all.aircraft:horizontal_tail:laminar_flow_upper + aircraft:horizontal_tail:laminar_flow_lower [0.] input unitless traj.descent.rhs_all.aircraft:horizontal_tail:laminar_flow_lower + aircraft:vertical_tail:wetted_area [581.13] input ft**2 traj.descent.rhs_all.aircraft:vertical_tail:wetted_area + aircraft:vertical_tail:fineness [0.1195] input unitless traj.descent.rhs_all.aircraft:vertical_tail:fineness + aircraft:vertical_tail:characteristic_length [12.73914103] input ft traj.descent.rhs_all.aircraft:vertical_tail:characteristic_length + aircraft:vertical_tail:laminar_flow_upper [0.] input unitless traj.descent.rhs_all.aircraft:vertical_tail:laminar_flow_upper + aircraft:vertical_tail:laminar_flow_lower [0.] input unitless traj.descent.rhs_all.aircraft:vertical_tail:laminar_flow_lower + aircraft:fuselage:wetted_area [4158.62] input ft**2 traj.descent.rhs_all.aircraft:fuselage:wetted_area + aircraft:fuselage:fineness [10.03921569] input unitless traj.descent.rhs_all.aircraft:fuselage:fineness + aircraft:fuselage:characteristic_length [128.] input ft traj.descent.rhs_all.aircraft:fuselage:characteristic_length + aircraft:fuselage:laminar_flow_upper [0.] input unitless traj.descent.rhs_all.aircraft:fuselage:laminar_flow_upper + aircraft:fuselage:laminar_flow_lower [0.] input unitless traj.descent.rhs_all.aircraft:fuselage:laminar_flow_lower + aircraft:nacelle:wetted_area [273.4536] input ft**2 traj.descent.rhs_all.aircraft:nacelle:wetted_area + aircraft:nacelle:fineness [1.54911839] input unitless traj.descent.rhs_all.aircraft:nacelle:fineness + aircraft:nacelle:characteristic_length [12.3] input ft traj.descent.rhs_all.aircraft:nacelle:characteristic_length + aircraft:nacelle:laminar_flow_upper [0.] input unitless traj.descent.rhs_all.aircraft:nacelle:laminar_flow_upper + aircraft:nacelle:laminar_flow_lower [0.] input unitless traj.descent.rhs_all.aircraft:nacelle:laminar_flow_lower + wetted_areas |4886.31967641| output ft**2 traj.descent.rhs_all.core_aerodynamics.wetted_areas + val: + array([2396.56 , 592.65 , 581.13 , 4158.62 , 273.4536, 273.4536]) + fineness_ratios |10.2777523| output unitless traj.descent.rhs_all.core_aerodynamics.fineness_ratios + val: + array([ 0.13 , 0.125 , 0.1195 , 10.03921569, 1.54911839, + 1.54911839]) + characteristic_lengths |130.45376144| output ft traj.descent.rhs_all.core_aerodynamics.characteristic_lengths + val: + array([ 10.49530819, 7.69198717, 12.73914103, 128. , + 12.3 , 12.3 ]) + laminar_fractions_upper |0.0| output unitless traj.descent.rhs_all.core_aerodynamics.laminar_fractions_upper + val: + array([0., 0., 0., 0., 0., 0.]) + laminar_fractions_lower |0.0| output unitless traj.descent.rhs_all.core_aerodynamics.laminar_fractions_lower + val: + array([0., 0., 0., 0., 0., 0.]) + DynamicPressure + static_pressure |5857.65596001| input lbf/ft**2 traj.descent.rhs_all.static_pressure + val: + array([ 523.4789226 , 558.77415991, 610.62196946, 627.82291255, + 627.82291255, 713.56354112, 847.24664051, 893.5518483 , + 893.5518483 , 1030.12408532, 1245.93829696, 1321.41240663, + 1321.41240663, 1477.24648833, 1716.44593554, 1798.38152578, + 1798.38152578, 1894.006267 , 2032.69152116, 2078.25710533]) + mach |2.45889929| input unitless traj.descent.rhs_all.mach + val: + array([0.72 , 0.70498488, 0.68426707, 0.67770996, 0.67770996, + 0.64704481, 0.60473316, 0.59134167, 0.59134167, 0.55488385, + 0.50457949, 0.48865833, 0.48865833, 0.45799318, 0.41568153, + 0.40229004, 0.40229004, 0.38727492, 0.36655711, 0.36 ]) + dynamic_pressure |928.89141001| output lbf/ft**2 traj.descent.rhs_all.core_aerodynamics.dynamic_pressure + val: + array([189.96003143, 194.39896856, 200.13440281, 201.84729598, + 201.84729598, 209.12184804, 216.88797219, 218.72315851, + 218.72315851, 222.01981902, 222.05152171, 220.87523658, + 220.87523658, 216.90473154, 207.61065114, 203.73161921, + 203.73161921, 198.84661178, 191.18456249, 188.5394846 ]) + lift + aircraft:wing:area [127.2771648] input m**2 traj.descent.rhs_all.aircraft:wing:area + mass |228638.93848721| input kg traj.descent.rhs_all.mass + val: + array([52028.74471935, 51956.50719188, 51855.82599664, 51823.76601249, + 51823.76601249, 51672.54219645, 51461.12266693, 51393.8106793 , + 51393.8106793 , 51210.06984292, 50956.67116637, 50876.7919899 , + 50876.7919899 , 50724.57452871, 50519.93012614, 50456.90390387, + 50456.90390387, 50387.51580428, 50293.8882617 , 50264.76158872]) + dynamic_pressure |44475.56132351| input N/m**2 traj.descent.rhs_all.core_aerodynamics.dynamic_pressure + val: + array([ 9095.33551064, 9307.87296998, 9582.48704743, 9664.50081633, + 9664.50081633, 10012.80825307, 10384.65228946, 10472.52148539, + 10472.52148539, 10630.36644494, 10631.88437784, 10575.56354086, + 10575.56354086, 10385.45473119, 9940.45175416, 9754.72270062, + 9754.72270062, 9520.82727965, 9153.9663749 , 9027.31936006]) + cl |1.78197778| output unitless traj.descent.rhs_all.core_aerodynamics.cl + val: + array([0.44075252, 0.43009033, 0.4169553 , 0.41316139, 0.41316139, + 0.39762539, 0.38181895, 0.37812008, 0.37812008, 0.3711738 , + 0.36928442, 0.3706691 , 0.3706691 , 0.37632501, 0.39158568, + 0.39854361, 0.39854361, 0.40777298, 0.42332711, 0.4290175 ]) + lift |2242182.04611564| output N traj.descent.rhs_all.lift + val: + array([510227.68940198, 509519.28125321, 508531.93600992, 508217.53496643, + 508217.53496643, 506734.53593078, 504661.21860166, 504001.11349819, + 504001.11349819, 502199.23142511, 499714.2392937 , 498930.89216773, + 498930.89216773, 497438.14880199, 495431.27277151, 494813.19666888, + 494813.19666888, 494132.73186204, 493214.55932157, 492928.92423401]) + PressureDrag + mach |2.45889929| input unitless traj.descent.rhs_all.mach + val: + array([0.72 , 0.70498488, 0.68426707, 0.67770996, 0.67770996, + 0.64704481, 0.60473316, 0.59134167, 0.59134167, 0.55488385, + 0.50457949, 0.48865833, 0.48865833, 0.45799318, 0.41568153, + 0.40229004, 0.40229004, 0.38727492, 0.36655711, 0.36 ]) + lift |504062.57548733| input lbf traj.descent.rhs_all.core_aerodynamics.lift + val: + array([114703.74747245, 114544.49098541, 114322.52694503, 114251.84677881, + 114251.84677881, 113918.45533334, 113452.35505637, 113303.95752588, + 113303.95752588, 112898.87832187, 112340.22986779, 112164.12642851, + 112164.12642851, 111828.5443705 , 111377.38069164, 111238.4316564 , + 111238.4316564 , 111085.45708252, 110879.04368433, 110814.83036225]) + static_pressure |5857.65596001| input lbf/ft**2 traj.descent.rhs_all.static_pressure + val: + array([ 523.4789226 , 558.77415991, 610.62196946, 627.82291255, + 627.82291255, 713.56354112, 847.24664051, 893.5518483 , + 893.5518483 , 1030.12408532, 1245.93829696, 1321.41240663, + 1321.41240663, 1477.24648833, 1716.44593554, 1798.38152578, + 1798.38152578, 1894.006267 , 2032.69152116, 2078.25710533]) + mission:design:lift_coefficient [0.56736557] input unitless traj.descent.rhs_all.mission:design:lift_coefficient + mission:design:mach [0.80017085] input unitless traj.descent.rhs_all.mission:design:mach + aircraft:wing:area [1370.] input ft**2 traj.descent.rhs_all.aircraft:wing:area + aircraft:wing:aspect_ratio [11.22091] input unitless traj.descent.rhs_all.aircraft:wing:aspect_ratio + aircraft:wing:max_camber_at_70_semispan [0.] input unitless traj.descent.rhs_all.aircraft:wing:max_camber_at_70_semispan + aircraft:wing:sweep [25.] input deg traj.descent.rhs_all.aircraft:wing:sweep + aircraft:wing:thickness_to_chord [0.13] input unitless traj.descent.rhs_all.aircraft:wing:thickness_to_chord + CD |0.0029774| output unitless traj.descent.rhs_all.core_aerodynamics.PressureDrag.CD + val: + array([0.00093663, 0.0008723 , 0.00079139, 0.00076681, 0.00076681, + 0.00065978, 0.0005458 , 0.00051791, 0.00051791, 0.00045833, + 0.00043096, 0.00043829, 0.00043829, 0.00047777, 0.00059396, + 0.00064705, 0.00064705, 0.00071638, 0.00082929, 0.00086917]) + InducedDrag + mach |2.45889929| input unitless traj.descent.rhs_all.mach + val: + array([0.72 , 0.70498488, 0.68426707, 0.67770996, 0.67770996, + 0.64704481, 0.60473316, 0.59134167, 0.59134167, 0.55488385, + 0.50457949, 0.48865833, 0.48865833, 0.45799318, 0.41568153, + 0.40229004, 0.40229004, 0.38727492, 0.36655711, 0.36 ]) + lift |504062.57548733| input lbf traj.descent.rhs_all.core_aerodynamics.lift + val: + array([114703.74747245, 114544.49098541, 114322.52694503, 114251.84677881, + 114251.84677881, 113918.45533334, 113452.35505637, 113303.95752588, + 113303.95752588, 112898.87832187, 112340.22986779, 112164.12642851, + 112164.12642851, 111828.5443705 , 111377.38069164, 111238.4316564 , + 111238.4316564 , 111085.45708252, 110879.04368433, 110814.83036225]) + static_pressure |5857.65596001| input lbf/ft**2 traj.descent.rhs_all.static_pressure + val: + array([ 523.4789226 , 558.77415991, 610.62196946, 627.82291255, + 627.82291255, 713.56354112, 847.24664051, 893.5518483 , + 893.5518483 , 1030.12408532, 1245.93829696, 1321.41240663, + 1321.41240663, 1477.24648833, 1716.44593554, 1798.38152578, + 1798.38152578, 1894.006267 , 2032.69152116, 2078.25710533]) + aircraft:wing:area [1370.] input ft**2 traj.descent.rhs_all.aircraft:wing:area + aircraft:wing:aspect_ratio [11.22091] input unitless traj.descent.rhs_all.aircraft:wing:aspect_ratio + aircraft:wing:span_efficiency_factor [1.] input unitless traj.descent.rhs_all.aircraft:wing:span_efficiency_factor + aircraft:wing:sweep [25.] input deg traj.descent.rhs_all.aircraft:wing:sweep + aircraft:wing:taper_ratio [0.278] input unitless traj.descent.rhs_all.aircraft:wing:taper_ratio + induced_drag_coeff |0.02027026| output unitless traj.descent.rhs_all.core_aerodynamics.InducedDrag.induced_drag_coeff + val: + array([0.00551076, 0.00524737, 0.00493175, 0.00484241, 0.00484241, + 0.00448508, 0.00413559, 0.00405585, 0.00405585, 0.0039082 , + 0.00386851, 0.00389758, 0.00389758, 0.00401743, 0.00434986, + 0.00450582, 0.00450582, 0.00471692, 0.00508363, 0.00522122]) + CompressibilityDrag + mach |2.45889929| input unitless traj.descent.rhs_all.mach + val: + array([0.72 , 0.70498488, 0.68426707, 0.67770996, 0.67770996, + 0.64704481, 0.60473316, 0.59134167, 0.59134167, 0.55488385, + 0.50457949, 0.48865833, 0.48865833, 0.45799318, 0.41568153, + 0.40229004, 0.40229004, 0.38727492, 0.36655711, 0.36 ]) + mission:design:mach [0.80017085] input unitless traj.descent.rhs_all.mission:design:mach + aircraft:design:base_area [0.] input ft**2 traj.descent.rhs_all.aircraft:design:base_area + aircraft:wing:area [1370.] input ft**2 traj.descent.rhs_all.aircraft:wing:area + aircraft:wing:aspect_ratio [11.22091] input unitless traj.descent.rhs_all.aircraft:wing:aspect_ratio + aircraft:wing:max_camber_at_70_semispan [0.] input unitless traj.descent.rhs_all.aircraft:wing:max_camber_at_70_semispan + aircraft:wing:sweep [25.] input deg traj.descent.rhs_all.aircraft:wing:sweep + aircraft:wing:taper_ratio [0.278] input unitless traj.descent.rhs_all.aircraft:wing:taper_ratio + aircraft:wing:thickness_to_chord [0.13] input unitless traj.descent.rhs_all.aircraft:wing:thickness_to_chord + aircraft:fuselage:cross_section [127.67628894] input ft**2 traj.descent.rhs_all.aircraft:fuselage:cross_section + aircraft:fuselage:diameter_to_wing_span [0.10826471] input unitless traj.descent.rhs_all.aircraft:fuselage:diameter_to_wing_span + aircraft:fuselage:length_to_diameter [10.03921569] input unitless traj.descent.rhs_all.aircraft:fuselage:length_to_diameter + compress_drag_coeff |0.00179297| output unitless traj.descent.rhs_all.core_aerodynamics.CompressibilityDrag.compress_drag_coeff + val: + array([0.00094091, 0.00082662, 0.00069503, 0.00065674, 0.00065674, + 0.00046614, 0.00021312, 0.00013737, 0.00013737, 0. , + 0. , 0. , 0. , 0. , 0. , + 0. , 0. , 0. , 0. , 0. ]) + SkinFrictionCoef + temperature |2057.90503542| input degR traj.descent.rhs_all.temperature + val: + array([397.61833789, 402.58502389, 409.43912788, 411.60869197, + 411.60869197, 421.75760711, 435.76421298, 440.19835649, + 440.19835649, 452.27382677, 468.94157663, 474.21810376, + 474.21810376, 484.38346865, 498.41437443, 502.85599996, + 502.85599996, 507.83777076, 514.7113234 , 516.88704275]) + static_pressure |5857.65596001| input lbf/ft**2 traj.descent.rhs_all.static_pressure + val: + array([ 523.4789226 , 558.77415991, 610.62196946, 627.82291255, + 627.82291255, 713.56354112, 847.24664051, 893.5518483 , + 893.5518483 , 1030.12408532, 1245.93829696, 1321.41240663, + 1321.41240663, 1477.24648833, 1716.44593554, 1798.38152578, + 1798.38152578, 1894.006267 , 2032.69152116, 2078.25710533]) + mach |2.45889929| input unitless traj.descent.rhs_all.mach + val: + array([0.72 , 0.70498488, 0.68426707, 0.67770996, 0.67770996, + 0.64704481, 0.60473316, 0.59134167, 0.59134167, 0.55488385, + 0.50457949, 0.48865833, 0.48865833, 0.45799318, 0.41568153, + 0.40229004, 0.40229004, 0.38727492, 0.36655711, 0.36 ]) + characteristic_lengths |130.45376144| input ft traj.descent.rhs_all.core_aerodynamics.characteristic_lengths + val: + array([ 10.49530819, 7.69198717, 12.73914103, 128. , + 12.3 , 12.3 ]) + cf_iter |0.02697932| output unitless traj.descent.rhs_all.core_aerodynamics.SkinFrictionCoef.cf_iter + val: + array([[0.00269609, 0.00283249, 0.00261572, 0.00187431, 0.00263002, + 0.00263002], + [0.0026826 , 0.00281803, 0.0026028 , 0.00186629, 0.002617 , + 0.002617 ], + [0.0026649 , 0.00279905, 0.00258585, 0.00185574, 0.00259991, + 0.00259991], + [0.00265952, 0.00279328, 0.00258069, 0.00185253, 0.00259471, + 0.00259471], + [0.00265952, 0.00279328, 0.00258069, 0.00185253, 0.00259471, + 0.00259471], + [0.00263571, 0.00276775, 0.00255788, 0.00183832, 0.00257172, + 0.00257172], + [0.0026065 , 0.00273644, 0.00252988, 0.00182084, 0.00254352, + 0.00254352], + [0.00259813, 0.00272747, 0.00252186, 0.00181583, 0.00253543, + 0.00253543], + [0.00259813, 0.00272747, 0.00252186, 0.00181583, 0.00253543, + 0.00253543], + [0.00257749, 0.00270535, 0.00250207, 0.00180345, 0.00251549, + 0.00251549], + [0.00255423, 0.00268044, 0.00247978, 0.00178947, 0.00249303, + 0.00249303], + [0.00254817, 0.00267395, 0.00247397, 0.00178582, 0.00248717, + 0.00248717], + [0.00254817, 0.00267395, 0.00247397, 0.00178582, 0.00248717, + 0.00248717], + [0.00253835, 0.00266344, 0.00246455, 0.00177991, 0.00247769, + 0.00247769], + [0.00252906, 0.00265349, 0.00245564, 0.0017743 , 0.00246871, + 0.00246871], + [0.00252722, 0.00265152, 0.00245388, 0.00177319, 0.00246693, + 0.00246693], + [0.00252722, 0.00265152, 0.00245388, 0.00177319, 0.00246693, + 0.00246693], + [0.00252583, 0.00265004, 0.00245255, 0.00177235, 0.00246559, + 0.00246559], + [0.00252516, 0.00264932, 0.0024519 , 0.00177194, 0.00246494, + 0.00246494], + [0.00252527, 0.00264944, 0.002452 , 0.001772 , 0.00246504, + 0.00246504]]) + skin_friction_coeff |0.02613897| output unitless traj.descent.rhs_all.core_aerodynamics.skin_friction_coeff + val: + array([[0.00255188, 0.0026807 , 0.00247599, 0.00177581, 0.00248949, + 0.00248949], + [0.00254494, 0.00267312, 0.0024694 , 0.00177225, 0.00248284, + 0.00248284], + [0.00253598, 0.00266334, 0.00246091, 0.00176767, 0.00247427, + 0.00247427], + [0.00253329, 0.00266041, 0.00245837, 0.0017663 , 0.00247169, + 0.00247169], + [0.00253329, 0.00266041, 0.00245837, 0.0017663 , 0.00247169, + 0.00247169], + [0.00252165, 0.0026477 , 0.00244735, 0.00176044, 0.00246057, + 0.00246057], + [0.00250813, 0.00263289, 0.00243457, 0.00175376, 0.00244766, + 0.00244766], + [0.00250446, 0.00262887, 0.00243111, 0.001752 , 0.00244416, + 0.00244416], + [0.00250446, 0.00262887, 0.00243111, 0.001752 , 0.00244416, + 0.00244416], + [0.00249601, 0.00261957, 0.00242315, 0.00174807, 0.00243611, + 0.00243611], + [0.00248817, 0.00261085, 0.00241581, 0.00174482, 0.00242869, + 0.00242869], + [0.00248667, 0.00260914, 0.00241442, 0.00174436, 0.00242728, + 0.00242728], + [0.00248667, 0.00260914, 0.00241442, 0.00174436, 0.00242728, + 0.00242728], + [0.00248519, 0.00260738, 0.00241311, 0.00174429, 0.00242593, + 0.00242593], + [0.00248652, 0.00260857, 0.00241451, 0.00174616, 0.00242732, + 0.00242732], + [0.00248784, 0.00260991, 0.00241581, 0.00174728, 0.00242863, + 0.00242863], + [0.00248784, 0.00260991, 0.00241581, 0.00174728, 0.00242863, + 0.00242863], + [0.00248987, 0.00261202, 0.0024178 , 0.00174886, 0.00243063, + 0.00243063], + [0.00249373, 0.00261604, 0.00242156, 0.00175167, 0.0024344 , + 0.0024344 ], + [0.00249522, 0.00261761, 0.00242301, 0.00175271, 0.00243586, + 0.00243586]]) + Re |1325371462.626787| output unitless traj.descent.rhs_all.core_aerodynamics.Re + val: + array([[1.87740162e+07, 1.37594332e+07, 2.27877863e+07, 2.28966508e+08, + 2.20022504e+07, 2.20022504e+07], + [1.93001769e+07, 1.41450551e+07, 2.34264369e+07, 2.35383525e+08, + 2.26188856e+07, 2.26188856e+07], + [2.00171471e+07, 1.46705210e+07, 2.42966911e+07, 2.44127642e+08, + 2.34591406e+07, 2.34591406e+07], + [2.02414357e+07, 1.48349015e+07, 2.45689311e+07, 2.46863048e+08, + 2.37219960e+07, 2.37219960e+07], + [2.02414357e+07, 1.48349015e+07, 2.45689311e+07, 2.46863048e+08, + 2.37219960e+07, 2.37219960e+07], + [2.12683033e+07, 1.55874905e+07, 2.58153368e+07, 2.59386649e+08, + 2.49254358e+07, 2.49254358e+07], + [2.26077276e+07, 1.65691514e+07, 2.74411218e+07, 2.75722169e+08, + 2.64951771e+07, 2.64951771e+07], + [2.30076545e+07, 1.68622569e+07, 2.79265506e+07, 2.80599647e+08, + 2.69638724e+07, 2.69638724e+07], + [2.30076545e+07, 1.68622569e+07, 2.79265506e+07, 2.80599647e+08, + 2.69638724e+07, 2.69638724e+07], + [2.40232164e+07, 1.76065599e+07, 2.91592335e+07, 2.92985365e+08, + 2.81540624e+07, 2.81540624e+07], + [2.52063871e+07, 1.84737030e+07, 3.05953588e+07, 3.07415227e+08, + 2.95406819e+07, 2.95406819e+07], + [2.55169120e+07, 1.87012860e+07, 3.09722721e+07, 3.11202366e+08, + 2.99046024e+07, 2.99046024e+07], + [2.55169120e+07, 1.87012860e+07, 3.09722721e+07, 3.11202366e+08, + 2.99046024e+07, 2.99046024e+07], + [2.60126988e+07, 1.90646470e+07, 3.15740551e+07, 3.17248945e+08, + 3.04856408e+07, 3.04856408e+07], + [2.64418484e+07, 1.93791697e+07, 3.20949542e+07, 3.22482821e+08, + 3.09885836e+07, 3.09885836e+07], + [2.65078276e+07, 1.94275257e+07, 3.21750394e+07, 3.23287499e+08, + 3.10659081e+07, 3.10659081e+07], + [2.65078276e+07, 1.94275257e+07, 3.21750394e+07, 3.23287499e+08, + 3.10659081e+07, 3.10659081e+07], + [2.65377461e+07, 1.94494529e+07, 3.22113543e+07, 3.23652383e+08, + 3.11009712e+07, 3.11009712e+07], + [2.64974101e+07, 1.94198908e+07, 3.21623947e+07, 3.23160448e+08, + 3.10536993e+07, 3.10536993e+07], + [2.64637059e+07, 1.93951890e+07, 3.21214847e+07, 3.22749394e+08, + 3.10141996e+07, 3.10141996e+07]]) + wall_temp |5259.05648112| output degR traj.descent.rhs_all.core_aerodynamics.SkinFrictionCoef.wall_temp + val: + array([[431.51809847, 431.62111275, 431.45259477, 430.59767514, + 431.46452722, 431.46452722], + [435.41657999, 435.51966045, 435.35103624, 434.49570326, + 435.36297587, 435.36297587], + [440.78626444, 440.88955317, 440.72059102, 439.86371601, + 440.73255412, 440.73255412], + [442.48389514, 442.58727866, 442.4181623 , 441.56055947, + 442.43013618, 442.43013618], + [442.48389514, 442.58727866, 442.4181623 , 441.56055947, + 442.43013618, 442.43013618], + [450.41582992, 450.51985322, 450.34969428, 449.4870573 , + 450.36174131, 450.36174131], + [461.3496913 , 461.45516136, 461.28264124, 460.40838221, + 461.29485454, 461.29485454], + [464.81144234, 464.91751935, 464.74400809, 463.86483597, + 464.75629127, 464.75629127], + [464.81144234, 464.91751935, 464.74400809, 463.86483597, + 464.75629127, 464.75629127], + [474.24868136, 474.35681485, 474.17994433, 473.28405316, + 474.19246456, 474.19246456], + [487.31995591, 487.43203244, 487.24871868, 486.32062011, + 487.26169396, 487.26169396], + [491.4740523 , 491.58768629, 491.40182709, 490.46097913, + 491.41498221, 491.41498221], + [491.4740523 , 491.58768629, 491.40182709, 490.46097913, + 491.41498221, 491.41498221], + [499.50540011, 499.62252492, 499.43096001, 498.46150476, + 499.44451833, 499.44451833], + [510.66352956, 510.78672108, 510.58523924, 509.56600731, + 510.59949851, 510.59949851], + [514.21572589, 514.34119425, 514.13599039, 513.09806622, + 514.15051278, 514.15051278], + [514.21572589, 514.34119425, 514.13599039, 513.09806622, + 514.15051278, 514.15051278], + [518.21255964, 518.34081825, 518.13105299, 517.07021675, + 518.14589784, 518.14589784], + [523.74947199, 523.88203852, 523.66523073, 522.56901372, + 523.68057346, 523.68057346], + [525.50771831, 525.64177125, 525.42253345, 524.3141074 , + 525.43804798, 525.43804798]]) + SkinFrictionDrag + skin_friction_coeff |0.02613897| input unitless traj.descent.rhs_all.core_aerodynamics.skin_friction_coeff + val: + array([[0.00255188, 0.0026807 , 0.00247599, 0.00177581, 0.00248949, + 0.00248949], + [0.00254494, 0.00267312, 0.0024694 , 0.00177225, 0.00248284, + 0.00248284], + [0.00253598, 0.00266334, 0.00246091, 0.00176767, 0.00247427, + 0.00247427], + [0.00253329, 0.00266041, 0.00245837, 0.0017663 , 0.00247169, + 0.00247169], + [0.00253329, 0.00266041, 0.00245837, 0.0017663 , 0.00247169, + 0.00247169], + [0.00252165, 0.0026477 , 0.00244735, 0.00176044, 0.00246057, + 0.00246057], + [0.00250813, 0.00263289, 0.00243457, 0.00175376, 0.00244766, + 0.00244766], + [0.00250446, 0.00262887, 0.00243111, 0.001752 , 0.00244416, + 0.00244416], + [0.00250446, 0.00262887, 0.00243111, 0.001752 , 0.00244416, + 0.00244416], + [0.00249601, 0.00261957, 0.00242315, 0.00174807, 0.00243611, + 0.00243611], + [0.00248817, 0.00261085, 0.00241581, 0.00174482, 0.00242869, + 0.00242869], + [0.00248667, 0.00260914, 0.00241442, 0.00174436, 0.00242728, + 0.00242728], + [0.00248667, 0.00260914, 0.00241442, 0.00174436, 0.00242728, + 0.00242728], + [0.00248519, 0.00260738, 0.00241311, 0.00174429, 0.00242593, + 0.00242593], + [0.00248652, 0.00260857, 0.00241451, 0.00174616, 0.00242732, + 0.00242732], + [0.00248784, 0.00260991, 0.00241581, 0.00174728, 0.00242863, + 0.00242863], + [0.00248784, 0.00260991, 0.00241581, 0.00174728, 0.00242863, + 0.00242863], + [0.00248987, 0.00261202, 0.0024178 , 0.00174886, 0.00243063, + 0.00243063], + [0.00249373, 0.00261604, 0.00242156, 0.00175167, 0.0024344 , + 0.0024344 ], + [0.00249522, 0.00261761, 0.00242301, 0.00175271, 0.00243586, + 0.00243586]]) + Re |1325371462.626787| input unitless traj.descent.rhs_all.core_aerodynamics.Re + val: + array([[1.87740162e+07, 1.37594332e+07, 2.27877863e+07, 2.28966508e+08, + 2.20022504e+07, 2.20022504e+07], + [1.93001769e+07, 1.41450551e+07, 2.34264369e+07, 2.35383525e+08, + 2.26188856e+07, 2.26188856e+07], + [2.00171471e+07, 1.46705210e+07, 2.42966911e+07, 2.44127642e+08, + 2.34591406e+07, 2.34591406e+07], + [2.02414357e+07, 1.48349015e+07, 2.45689311e+07, 2.46863048e+08, + 2.37219960e+07, 2.37219960e+07], + [2.02414357e+07, 1.48349015e+07, 2.45689311e+07, 2.46863048e+08, + 2.37219960e+07, 2.37219960e+07], + [2.12683033e+07, 1.55874905e+07, 2.58153368e+07, 2.59386649e+08, + 2.49254358e+07, 2.49254358e+07], + [2.26077276e+07, 1.65691514e+07, 2.74411218e+07, 2.75722169e+08, + 2.64951771e+07, 2.64951771e+07], + [2.30076545e+07, 1.68622569e+07, 2.79265506e+07, 2.80599647e+08, + 2.69638724e+07, 2.69638724e+07], + [2.30076545e+07, 1.68622569e+07, 2.79265506e+07, 2.80599647e+08, + 2.69638724e+07, 2.69638724e+07], + [2.40232164e+07, 1.76065599e+07, 2.91592335e+07, 2.92985365e+08, + 2.81540624e+07, 2.81540624e+07], + [2.52063871e+07, 1.84737030e+07, 3.05953588e+07, 3.07415227e+08, + 2.95406819e+07, 2.95406819e+07], + [2.55169120e+07, 1.87012860e+07, 3.09722721e+07, 3.11202366e+08, + 2.99046024e+07, 2.99046024e+07], + [2.55169120e+07, 1.87012860e+07, 3.09722721e+07, 3.11202366e+08, + 2.99046024e+07, 2.99046024e+07], + [2.60126988e+07, 1.90646470e+07, 3.15740551e+07, 3.17248945e+08, + 3.04856408e+07, 3.04856408e+07], + [2.64418484e+07, 1.93791697e+07, 3.20949542e+07, 3.22482821e+08, + 3.09885836e+07, 3.09885836e+07], + [2.65078276e+07, 1.94275257e+07, 3.21750394e+07, 3.23287499e+08, + 3.10659081e+07, 3.10659081e+07], + [2.65078276e+07, 1.94275257e+07, 3.21750394e+07, 3.23287499e+08, + 3.10659081e+07, 3.10659081e+07], + [2.65377461e+07, 1.94494529e+07, 3.22113543e+07, 3.23652383e+08, + 3.11009712e+07, 3.11009712e+07], + [2.64974101e+07, 1.94198908e+07, 3.21623947e+07, 3.23160448e+08, + 3.10536993e+07, 3.10536993e+07], + [2.64637059e+07, 1.93951890e+07, 3.21214847e+07, 3.22749394e+08, + 3.10141996e+07, 3.10141996e+07]]) + fineness_ratios |10.2777523| input unitless traj.descent.rhs_all.core_aerodynamics.fineness_ratios + val: + array([ 0.13 , 0.125 , 0.1195 , 10.03921569, 1.54911839, + 1.54911839]) + wetted_areas |4886.31967641| input ft**2 traj.descent.rhs_all.core_aerodynamics.wetted_areas + val: + array([2396.56 , 592.65 , 581.13 , 4158.62 , 273.4536, 273.4536]) + laminar_fractions_upper |0.0| input unitless traj.descent.rhs_all.core_aerodynamics.laminar_fractions_upper + val: + array([0., 0., 0., 0., 0., 0.]) + laminar_fractions_lower |0.0| input unitless traj.descent.rhs_all.core_aerodynamics.laminar_fractions_lower + val: + array([0., 0., 0., 0., 0., 0.]) + aircraft:wing:area [1370.] input ft**2 traj.descent.rhs_all.aircraft:wing:area + skin_friction_drag_coeff |0.08911326| output unitless traj.descent.rhs_all.core_aerodynamics.SkinFrictionDrag.skin_friction_drag_coeff + val: + array([0.02025187, 0.02020131, 0.02013615, 0.02011662, 0.02011662, + 0.02003231, 0.01993483, 0.01990857, 0.01990857, 0.0198485 , + 0.01979423, 0.01978438, 0.01978438, 0.01977612, 0.01979006, + 0.01980122, 0.01980122, 0.01981798, 0.01984902, 0.0198609 ]) + Drag + CDI + induced_drag_coeff |0.02027026| input unitless traj.descent.rhs_all.core_aerodynamics.Drag.induced_drag_coeff + val: + array([0.00551076, 0.00524737, 0.00493175, 0.00484241, 0.00484241, + 0.00448508, 0.00413559, 0.00405585, 0.00405585, 0.0039082 , + 0.00386851, 0.00389758, 0.00389758, 0.00401743, 0.00434986, + 0.00450582, 0.00450582, 0.00471692, 0.00508363, 0.00522122]) + pressure_drag_coeff |0.0029774| input unitless traj.descent.rhs_all.core_aerodynamics.Drag.pressure_drag_coeff + val: + array([0.00093663, 0.0008723 , 0.00079139, 0.00076681, 0.00076681, + 0.00065978, 0.0005458 , 0.00051791, 0.00051791, 0.00045833, + 0.00043096, 0.00043829, 0.00043829, 0.00047777, 0.00059396, + 0.00064705, 0.00064705, 0.00071638, 0.00082929, 0.00086917]) + CDI |0.02322507| output unitless traj.descent.rhs_all.core_aerodynamics.CDI + val: + array([0.00644739, 0.00611967, 0.00572314, 0.00560922, 0.00560922, + 0.00514486, 0.00468139, 0.00457376, 0.00457376, 0.00436653, + 0.00429947, 0.00433587, 0.00433587, 0.00449519, 0.00494382, + 0.00515287, 0.00515287, 0.00543331, 0.00591292, 0.00609039]) + CD0 + compress_drag_coeff |0.00179297| input unitless traj.descent.rhs_all.core_aerodynamics.Drag.compress_drag_coeff + val: + array([0.00094091, 0.00082662, 0.00069503, 0.00065674, 0.00065674, + 0.00046614, 0.00021312, 0.00013737, 0.00013737, 0. , + 0. , 0. , 0. , 0. , 0. , + 0. , 0. , 0. , 0. , 0. ]) + skin_friction_drag_coeff |0.08911326| input unitless traj.descent.rhs_all.core_aerodynamics.Drag.skin_friction_drag_coeff + val: + array([0.02025187, 0.02020131, 0.02013615, 0.02011662, 0.02011662, + 0.02003231, 0.01993483, 0.01990857, 0.01990857, 0.0198485 , + 0.01979423, 0.01978438, 0.01978438, 0.01977612, 0.01979006, + 0.01980122, 0.01980122, 0.01981798, 0.01984902, 0.0198609 ]) + CD0 |0.09019337| output unitless traj.descent.rhs_all.core_aerodynamics.CD0 + val: + array([0.02119279, 0.02102793, 0.02083118, 0.02077336, 0.02077336, + 0.02049845, 0.02014795, 0.02004594, 0.02004594, 0.0198485 , + 0.01979423, 0.01978438, 0.01978438, 0.01977612, 0.01979006, + 0.01980122, 0.01980122, 0.01981798, 0.01984902, 0.0198609 ]) + drag + total_drag_coeff + CD0 |0.09019337| input unitless traj.descent.rhs_all.core_aerodynamics.Drag.CD0 + val: + array([0.02119279, 0.02102793, 0.02083118, 0.02077336, 0.02077336, + 0.02049845, 0.02014795, 0.02004594, 0.02004594, 0.0198485 , + 0.01979423, 0.01978438, 0.01978438, 0.01977612, 0.01979006, + 0.01980122, 0.01980122, 0.01981798, 0.01984902, 0.0198609 ]) + CDI |0.02322507| input unitless traj.descent.rhs_all.core_aerodynamics.Drag.CDI + val: + array([0.00644739, 0.00611967, 0.00572314, 0.00560922, 0.00560922, + 0.00514486, 0.00468139, 0.00457376, 0.00457376, 0.00436653, + 0.00429947, 0.00433587, 0.00433587, 0.00449519, 0.00494382, + 0.00515287, 0.00515287, 0.00543331, 0.00591292, 0.00609039]) + FCD0 [0.93089003] input unitless traj.descent.rhs_all.aircraft:design:zero_lift_drag_coeff_factor + FCDI [0.90983938] input unitless traj.descent.rhs_all.aircraft:design:lift_dependent_drag_coeff_factor + CD_prescaled |0.1049794| output unitless traj.descent.rhs_all.core_aerodynamics.Drag.drag.CD_prescaled + val: + array([0.02559425, 0.0251426 , 0.02459867, 0.0244412 , 0.0244412 , + 0.0237628 , 0.02301483, 0.02282195, 0.02282195, 0.02244961, + 0.02233808, 0.02236203, 0.02236203, 0.0224993 , 0.02292045, + 0.02312104, 0.02312104, 0.0233918 , 0.02385706, 0.02402959]) + simple_CD + aircraft:design:subsonic_drag_coeff_factor [1.] input unitless traj.descent.rhs_all.aircraft:design:subsonic_drag_coeff_factor + aircraft:design:supersonic_drag_coeff_factor [1.] input unitless traj.descent.rhs_all.aircraft:design:supersonic_drag_coeff_factor + mach |2.45889929| input unitless traj.descent.rhs_all.mach + val: + array([0.72 , 0.70498488, 0.68426707, 0.67770996, 0.67770996, + 0.64704481, 0.60473316, 0.59134167, 0.59134167, 0.55488385, + 0.50457949, 0.48865833, 0.48865833, 0.45799318, 0.41568153, + 0.40229004, 0.40229004, 0.38727492, 0.36655711, 0.36 ]) + CD_prescaled |0.1049794| input unitless traj.descent.rhs_all.core_aerodynamics.Drag.drag.CD_prescaled + val: + array([0.02559425, 0.0251426 , 0.02459867, 0.0244412 , 0.0244412 , + 0.0237628 , 0.02301483, 0.02282195, 0.02282195, 0.02244961, + 0.02233808, 0.02236203, 0.02236203, 0.0224993 , 0.02292045, + 0.02312104, 0.02312104, 0.0233918 , 0.02385706, 0.02402959]) + CD |0.1049794| output unitless traj.descent.rhs_all.core_aerodynamics.CD + val: + array([0.02559425, 0.0251426 , 0.02459867, 0.0244412 , 0.0244412 , + 0.0237628 , 0.02301483, 0.02282195, 0.02282195, 0.02244961, + 0.02233808, 0.02236203, 0.02236203, 0.0224993 , 0.02292045, + 0.02312104, 0.02312104, 0.0233918 , 0.02385706, 0.02402959]) + simple_drag + aircraft:wing:area [127.2771648] input m**2 traj.descent.rhs_all.aircraft:wing:area + dynamic_pressure |44475.56132351| input N/m**2 traj.descent.rhs_all.core_aerodynamics.dynamic_pressure + val: + array([ 9095.33551064, 9307.87296998, 9582.48704743, 9664.50081633, + 9664.50081633, 10012.80825307, 10384.65228946, 10472.52148539, + 10472.52148539, 10630.36644494, 10631.88437784, 10575.56354086, + 10575.56354086, 10385.45473119, 9940.45175416, 9754.72270062, + 9754.72270062, 9520.82727965, 9153.9663749 , 9027.31936006]) + CD |0.1049794| input unitless traj.descent.rhs_all.core_aerodynamics.Drag.drag.CD + val: + array([0.02559425, 0.0251426 , 0.02459867, 0.0244412 , 0.0244412 , + 0.0237628 , 0.02301483, 0.02282195, 0.02282195, 0.02244961, + 0.02233808, 0.02236203, 0.02236203, 0.0224993 , 0.02292045, + 0.02312104, 0.02312104, 0.0233918 , 0.02385706, 0.02402959]) + drag |132386.47842047| output N traj.descent.rhs_all.drag + val: + array([29628.63095587, 29785.93321944, 30001.32401744, 30064.39827281, + 30064.39827281, 30283.35611481, 30419.37652939, 30419.67465515, + 30419.67465515, 30374.39124359, 30227.80491759, 30099.91140717, + 30099.91140717, 29740.27925815, 28998.78423975, 28706.00892746, + 28706.00892746, 28345.80074073, 27795.64338534, 27609.31432996]) + Buffet + mach |2.45889929| input unitless traj.descent.rhs_all.mach + val: + array([0.72 , 0.70498488, 0.68426707, 0.67770996, 0.67770996, + 0.64704481, 0.60473316, 0.59134167, 0.59134167, 0.55488385, + 0.50457949, 0.48865833, 0.48865833, 0.45799318, 0.41568153, + 0.40229004, 0.40229004, 0.38727492, 0.36655711, 0.36 ]) + mission:design:mach [0.80017085] input unitless traj.descent.rhs_all.mission:design:mach + aircraft:wing:aspect_ratio [11.22091] input unitless traj.descent.rhs_all.aircraft:wing:aspect_ratio + aircraft:wing:max_camber_at_70_semispan [0.] input unitless traj.descent.rhs_all.aircraft:wing:max_camber_at_70_semispan + aircraft:wing:sweep [25.] input deg traj.descent.rhs_all.aircraft:wing:sweep + aircraft:wing:thickness_to_chord [0.13] input unitless traj.descent.rhs_all.aircraft:wing:thickness_to_chord + DELCLB |2.44711534| output unitless traj.descent.rhs_all.core_aerodynamics.Buffet.DELCLB + val: + array([0.28257367, 0.30907612, 0.34536323, 0.35641629, 0.35641629, + 0.40257916, 0.45131983, 0.46659408, 0.46659408, 0.51019085, + 0.56492696, 0.58326658, 0.58326658, 0.62087321, 0.67452094, + 0.69192503, 0.69192503, 0.70891871, 0.73083965, 0.73753993]) + core_propulsion + turbofan_28k + interpolation + mach |2.45889929| input unitless traj.descent.rhs_all.mach + val: + array([0.72 , 0.70498488, 0.68426707, 0.67770996, 0.67770996, + 0.64704481, 0.60473316, 0.59134167, 0.59134167, 0.55488385, + 0.50457949, 0.48865833, 0.48865833, 0.45799318, 0.41568153, + 0.40229004, 0.40229004, 0.38727492, 0.36655711, 0.36 ]) + altitude |90819.35928076| input ft traj.descent.rhs_all.altitude + val: + array([34000. , 32602.7594172 , 30674.85259378, 30064.67667582, + 30064.67667582, 27211.11426456, 23273.78055735, 22027.62790105, + 22027.62790105, 18635.02452748, 13953.9243121 , 12472.37209895, + 12472.37209895, 9618.80968769, 5681.47598048, 4435.32332418, + 4435.32332418, 3038.08274138, 1110.17591796, 500. ]) + throttle |1.37898255| input unitless traj.descent.rhs_all.throttle + val: + array([0.49865618, 0.47293083, 0.44177524, 0.43279925, 0.43279925, + 0.3879603 , 0.33465308, 0.31905442, 0.31905442, 0.28076346, + 0.23449042, 0.21972804, 0.21972804, 0.19416101, 0.16162186, + 0.15241077, 0.15241077, 0.14229545, 0.12937745, 0.12545435]) + fuel_flow_rate_unscaled |6808.33095172| output lbm/h traj.descent.rhs_all.turbofan_28k.interpolation.fuel_flow_rate_unscaled + val: + array([1503.37955121, 1517.94092873, 1533.53048705, 1537.17850813, + 1537.17850813, 1559.03492417, 1577.0590553 , 1580.42268385, + 1580.42268385, 1583.96652651, 1577.8361375 , 1570.86895491, + 1570.86895491, 1544.90154793, 1489.1042658 , 1464.85730748, + 1464.85730748, 1437.76799322, 1400.80973616, 1392.60948422]) + nox_rate_unscaled |39.79090373| output lbm/h traj.descent.rhs_all.turbofan_28k.interpolation.nox_rate_unscaled + val: + array([9.35086631, 9.45404569, 9.51787795, 9.52279819, 9.52279819, + 9.34463144, 9.38766488, 9.41726059, 9.41726059, 9.30673318, + 9.06982852, 8.95934038, 8.95934038, 8.7569042 , 8.26810275, + 8.10558757, 8.10558757, 7.91353105, 7.59854458, 7.44959767]) + thrust_net_unscaled |10829.88540743| output lbf traj.descent.rhs_all.turbofan_28k.interpolation.thrust_net_unscaled + val: + array([2592.38405619, 2601.25619987, 2612.61858663, 2615.46381809, + 2615.46381809, 2618.99352049, 2601.42829759, 2590.02168952, + 2590.02168952, 2550.8318053 , 2478.80852562, 2444.37153188, + 2444.37153188, 2361.22340177, 2208.19330616, 2150.07646149, + 2150.07646149, 2079.18894078, 1971.20719177, 1934.52722757]) + interp_max_throttles + mach |2.45889929| input unitless traj.descent.rhs_all.mach + val: + array([0.72 , 0.70498488, 0.68426707, 0.67770996, 0.67770996, + 0.64704481, 0.60473316, 0.59134167, 0.59134167, 0.55488385, + 0.50457949, 0.48865833, 0.48865833, 0.45799318, 0.41568153, + 0.40229004, 0.40229004, 0.38727492, 0.36655711, 0.36 ]) + altitude |90819.35928076| input ft traj.descent.rhs_all.altitude + val: + array([34000. , 32602.7594172 , 30674.85259378, 30064.67667582, + 30064.67667582, 27211.11426456, 23273.78055735, 22027.62790105, + 22027.62790105, 18635.02452748, 13953.9243121 , 12472.37209895, + 12472.37209895, 9618.80968769, 5681.47598048, 4435.32332418, + 4435.32332418, 3038.08274138, 1110.17591796, 500. ]) + throttle_max |4.47213595| output unitless traj.descent.rhs_all.turbofan_28k.throttle_max + val: + array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + 1., 1., 1.]) + max_interpolation + mach |2.45889929| input unitless traj.descent.rhs_all.mach + val: + array([0.72 , 0.70498488, 0.68426707, 0.67770996, 0.67770996, + 0.64704481, 0.60473316, 0.59134167, 0.59134167, 0.55488385, + 0.50457949, 0.48865833, 0.48865833, 0.45799318, 0.41568153, + 0.40229004, 0.40229004, 0.38727492, 0.36655711, 0.36 ]) + altitude |90819.35928076| input ft traj.descent.rhs_all.altitude + val: + array([34000. , 32602.7594172 , 30674.85259378, 30064.67667582, + 30064.67667582, 27211.11426456, 23273.78055735, 22027.62790105, + 22027.62790105, 18635.02452748, 13953.9243121 , 12472.37209895, + 12472.37209895, 9618.80968769, 5681.47598048, 4435.32332418, + 4435.32332418, 3038.08274138, 1110.17591796, 500. ]) + throttle_max |4.47213595| input unitless traj.descent.rhs_all.throttle_max + val: + array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + 1., 1., 1.]) + thrust_net_max_unscaled |63857.67198423| output lbf traj.descent.rhs_all.turbofan_28k.max_interpolation.thrust_net_max_unscaled + val: + array([ 5552.244 , 5917.97201101, 6428.32524261, 6590.10881811, + 6590.10881811, 7500.11461522, 8893.43548808, 9386.73222571, + 9386.73222571, 10844.87696627, 13226.95369831, 14106.4081819 , + 14106.4081819 , 15866.98242317, 18765.32961914, 19751.11014998, + 19751.11014998, 20964.54618415, 22706.21234893, 23290.83 ]) + engine_scaling + aircraft:engine:scale_factor [1.] input unitless traj.descent.rhs_all.aircraft:engine:scale_factor + mach |2.45889929| input unitless traj.descent.rhs_all.mach + val: + array([0.72 , 0.70498488, 0.68426707, 0.67770996, 0.67770996, + 0.64704481, 0.60473316, 0.59134167, 0.59134167, 0.55488385, + 0.50457949, 0.48865833, 0.48865833, 0.45799318, 0.41568153, + 0.40229004, 0.40229004, 0.38727492, 0.36655711, 0.36 ]) + fuel_flow_rate_unscaled |6808.33095172| input lbm/h traj.descent.rhs_all.engine_scaling.fuel_flow_rate_unscaled + val: + array([1503.37955121, 1517.94092873, 1533.53048705, 1537.17850813, + 1537.17850813, 1559.03492417, 1577.0590553 , 1580.42268385, + 1580.42268385, 1583.96652651, 1577.8361375 , 1570.86895491, + 1570.86895491, 1544.90154793, 1489.1042658 , 1464.85730748, + 1464.85730748, 1437.76799322, 1400.80973616, 1392.60948422]) + nox_rate_unscaled |39.79090373| input lbm/h traj.descent.rhs_all.engine_scaling.nox_rate_unscaled + val: + array([9.35086631, 9.45404569, 9.51787795, 9.52279819, 9.52279819, + 9.34463144, 9.38766488, 9.41726059, 9.41726059, 9.30673318, + 9.06982852, 8.95934038, 8.95934038, 8.7569042 , 8.26810275, + 8.10558757, 8.10558757, 7.91353105, 7.59854458, 7.44959767]) + thrust_net_unscaled |10829.88540743| input lbf traj.descent.rhs_all.engine_scaling.thrust_net_unscaled + val: + array([2592.38405619, 2601.25619987, 2612.61858663, 2615.46381809, + 2615.46381809, 2618.99352049, 2601.42829759, 2590.02168952, + 2590.02168952, 2550.8318053 , 2478.80852562, 2444.37153188, + 2444.37153188, 2361.22340177, 2208.19330616, 2150.07646149, + 2150.07646149, 2079.18894078, 1971.20719177, 1934.52722757]) + thrust_net_max_unscaled |63857.67198423| input lbf traj.descent.rhs_all.engine_scaling.thrust_net_max_unscaled + val: + array([ 5552.244 , 5917.97201101, 6428.32524261, 6590.10881811, + 6590.10881811, 7500.11461522, 8893.43548808, 9386.73222571, + 9386.73222571, 10844.87696627, 13226.95369831, 14106.4081819 , + 14106.4081819 , 15866.98242317, 18765.32961914, 19751.11014998, + 19751.11014998, 20964.54618415, 22706.21234893, 23290.83 ]) + fuel_flow_rate_negative |6808.33095172| output lbm/h traj.descent.rhs_all.turbofan_28k.fuel_flow_rate_negative + val: + array([-1503.37955121, -1517.94092873, -1533.53048705, -1537.17850813, + -1537.17850813, -1559.03492417, -1577.0590553 , -1580.42268385, + -1580.42268385, -1583.96652651, -1577.8361375 , -1570.86895491, + -1570.86895491, -1544.90154793, -1489.1042658 , -1464.85730748, + -1464.85730748, -1437.76799322, -1400.80973616, -1392.60948422]) + nox_rate |39.79090373| output lbm/h traj.descent.rhs_all.turbofan_28k.nox_rate + val: + array([9.35086631, 9.45404569, 9.51787795, 9.52279819, 9.52279819, + 9.34463144, 9.38766488, 9.41726059, 9.41726059, 9.30673318, + 9.06982852, 8.95934038, 8.95934038, 8.7569042 , 8.26810275, + 8.10558757, 8.10558757, 7.91353105, 7.59854458, 7.44959767]) + thrust_net |10829.88540743| output lbf traj.descent.rhs_all.turbofan_28k.thrust_net + val: + array([2592.38405619, 2601.25619987, 2612.61858663, 2615.46381809, + 2615.46381809, 2618.99352049, 2601.42829759, 2590.02168952, + 2590.02168952, 2550.8318053 , 2478.80852562, 2444.37153188, + 2444.37153188, 2361.22340177, 2208.19330616, 2150.07646149, + 2150.07646149, 2079.18894078, 1971.20719177, 1934.52722757]) + thrust_net_max |63857.67198423| output lbf traj.descent.rhs_all.turbofan_28k.thrust_net_max + val: + array([ 5552.244 , 5917.97201101, 6428.32524261, 6590.10881811, + 6590.10881811, 7500.11461522, 8893.43548808, 9386.73222571, + 9386.73222571, 10844.87696627, 13226.95369831, 14106.4081819 , + 14106.4081819 , 15866.98242317, 18765.32961914, 19751.11014998, + 19751.11014998, 20964.54618415, 22706.21234893, 23290.83 ]) + vectorize_performance + thrust_net_0 |10829.88540743| input lbf traj.descent.rhs_all.vectorize_performance.thrust_net_0 + val: + array([2592.38405619, 2601.25619987, 2612.61858663, 2615.46381809, + 2615.46381809, 2618.99352049, 2601.42829759, 2590.02168952, + 2590.02168952, 2550.8318053 , 2478.80852562, 2444.37153188, + 2444.37153188, 2361.22340177, 2208.19330616, 2150.07646149, + 2150.07646149, 2079.18894078, 1971.20719177, 1934.52722757]) + thrust_net_max_0 |63857.67198423| input lbf traj.descent.rhs_all.vectorize_performance.thrust_net_max_0 + val: + array([ 5552.244 , 5917.97201101, 6428.32524261, 6590.10881811, + 6590.10881811, 7500.11461522, 8893.43548808, 9386.73222571, + 9386.73222571, 10844.87696627, 13226.95369831, 14106.4081819 , + 14106.4081819 , 15866.98242317, 18765.32961914, 19751.11014998, + 19751.11014998, 20964.54618415, 22706.21234893, 23290.83 ]) + fuel_flow_rate_negative_0 |6808.33095172| input lbm/h traj.descent.rhs_all.vectorize_performance.fuel_flow_rate_negative_0 + val: + array([-1503.37955121, -1517.94092873, -1533.53048705, -1537.17850813, + -1537.17850813, -1559.03492417, -1577.0590553 , -1580.42268385, + -1580.42268385, -1583.96652651, -1577.8361375 , -1570.86895491, + -1570.86895491, -1544.90154793, -1489.1042658 , -1464.85730748, + -1464.85730748, -1437.76799322, -1400.80973616, -1392.60948422]) + electric_power_in_0 |0.0| input kW traj.descent.rhs_all.vectorize_performance.electric_power_in_0 + val: + array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., + 0., 0., 0.]) + nox_rate_0 |39.79090373| input lbm/h traj.descent.rhs_all.vectorize_performance.nox_rate_0 + val: + array([9.35086631, 9.45404569, 9.51787795, 9.52279819, 9.52279819, + 9.34463144, 9.38766488, 9.41726059, 9.41726059, 9.30673318, + 9.06982852, 8.95934038, 8.95934038, 8.7569042 , 8.26810275, + 8.10558757, 8.10558757, 7.91353105, 7.59854458, 7.44959767]) + t4_0 |0.0| input degR traj.descent.rhs_all.vectorize_performance.t4_0 + val: + array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., + 0., 0., 0.]) + shaft_power_0 |0.0| input hp traj.descent.rhs_all.vectorize_performance.shaft_power_0 + val: + array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., + 0., 0., 0.]) + shaft_power_max_0 |0.0| input hp traj.descent.rhs_all.vectorize_performance.shaft_power_max_0 + val: + array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., + 0., 0., 0.]) + thrust_net |10829.88540743| output lbf traj.descent.rhs_all.thrust_net + val: + array([[2592.38405619], + [2601.25619987], + [2612.61858663], + [2615.46381809], + [2615.46381809], + [2618.99352049], + [2601.42829759], + [2590.02168952], + [2590.02168952], + [2550.8318053 ], + [2478.80852562], + [2444.37153188], + [2444.37153188], + [2361.22340177], + [2208.19330616], + [2150.07646149], + [2150.07646149], + [2079.18894078], + [1971.20719177], + [1934.52722757]]) + thrust_net_max |63857.67198423| output lbf traj.descent.rhs_all.thrust_net_max + val: + array([[ 5552.244 ], + [ 5917.97201101], + [ 6428.32524261], + [ 6590.10881811], + [ 6590.10881811], + [ 7500.11461522], + [ 8893.43548808], + [ 9386.73222571], + [ 9386.73222571], + [10844.87696627], + [13226.95369831], + [14106.4081819 ], + [14106.4081819 ], + [15866.98242317], + [18765.32961914], + [19751.11014998], + [19751.11014998], + [20964.54618415], + [22706.21234893], + [23290.83 ]]) + fuel_flow_rate_negative |6808.33095172| output lbm/h traj.descent.rhs_all.fuel_flow_rate_negative + val: + array([[-1503.37955121], + [-1517.94092873], + [-1533.53048705], + [-1537.17850813], + [-1537.17850813], + [-1559.03492417], + [-1577.0590553 ], + [-1580.42268385], + [-1580.42268385], + [-1583.96652651], + [-1577.8361375 ], + [-1570.86895491], + [-1570.86895491], + [-1544.90154793], + [-1489.1042658 ], + [-1464.85730748], + [-1464.85730748], + [-1437.76799322], + [-1400.80973616], + [-1392.60948422]]) + electric_power_in |0.0| output kW traj.descent.rhs_all.electric_power_in + val: + array([[0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.]]) + nox_rate |39.79090373| output lbm/h traj.descent.rhs_all.nox_rate + val: + array([[9.35086631], + [9.45404569], + [9.51787795], + [9.52279819], + [9.52279819], + [9.34463144], + [9.38766488], + [9.41726059], + [9.41726059], + [9.30673318], + [9.06982852], + [8.95934038], + [8.95934038], + [8.7569042 ], + [8.26810275], + [8.10558757], + [8.10558757], + [7.91353105], + [7.59854458], + [7.44959767]]) + t4 |0.0| output degR traj.descent.rhs_all.t4 + val: + array([[0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.]]) + shaft_power |0.0| output hp traj.descent.rhs_all.shaft_power + val: + array([[0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.]]) + shaft_power_max |0.0| output hp traj.descent.rhs_all.shaft_power_max + val: + array([[0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.]]) + propulsion_sum + thrust_net |10829.88540743| input lbf traj.descent.rhs_all.thrust_net + val: + array([[2592.38405619], + [2601.25619987], + [2612.61858663], + [2615.46381809], + [2615.46381809], + [2618.99352049], + [2601.42829759], + [2590.02168952], + [2590.02168952], + [2550.8318053 ], + [2478.80852562], + [2444.37153188], + [2444.37153188], + [2361.22340177], + [2208.19330616], + [2150.07646149], + [2150.07646149], + [2079.18894078], + [1971.20719177], + [1934.52722757]]) + thrust_net_max |63857.67198423| input lbf traj.descent.rhs_all.thrust_net_max + val: + array([[ 5552.244 ], + [ 5917.97201101], + [ 6428.32524261], + [ 6590.10881811], + [ 6590.10881811], + [ 7500.11461522], + [ 8893.43548808], + [ 9386.73222571], + [ 9386.73222571], + [10844.87696627], + [13226.95369831], + [14106.4081819 ], + [14106.4081819 ], + [15866.98242317], + [18765.32961914], + [19751.11014998], + [19751.11014998], + [20964.54618415], + [22706.21234893], + [23290.83 ]]) + fuel_flow_rate_negative |6808.33095172| input lbm/h traj.descent.rhs_all.fuel_flow_rate_negative + val: + array([[-1503.37955121], + [-1517.94092873], + [-1533.53048705], + [-1537.17850813], + [-1537.17850813], + [-1559.03492417], + [-1577.0590553 ], + [-1580.42268385], + [-1580.42268385], + [-1583.96652651], + [-1577.8361375 ], + [-1570.86895491], + [-1570.86895491], + [-1544.90154793], + [-1489.1042658 ], + [-1464.85730748], + [-1464.85730748], + [-1437.76799322], + [-1400.80973616], + [-1392.60948422]]) + electric_power_in |0.0| input kW traj.descent.rhs_all.electric_power_in + val: + array([[0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.]]) + nox_rate |39.79090373| input lbm/h traj.descent.rhs_all.nox_rate + val: + array([[9.35086631], + [9.45404569], + [9.51787795], + [9.52279819], + [9.52279819], + [9.34463144], + [9.38766488], + [9.41726059], + [9.41726059], + [9.30673318], + [9.06982852], + [8.95934038], + [8.95934038], + [8.7569042 ], + [8.26810275], + [8.10558757], + [8.10558757], + [7.91353105], + [7.59854458], + [7.44959767]]) + thrust_net_total |21659.77081486| output lbf traj.descent.rhs_all.thrust_net_total + val: + array([5184.76811238, 5202.51239973, 5225.23717327, 5230.92763617, + 5230.92763617, 5237.98704098, 5202.85659519, 5180.04337904, + 5180.04337904, 5101.6636106 , 4957.61705125, 4888.74306376, + 4888.74306376, 4722.44680354, 4416.38661232, 4300.15292299, + 4300.15292299, 4158.37788155, 3942.41438355, 3869.05445515]) + thrust_net_max_total |127715.34396845| output lbf traj.descent.rhs_all.thrust_net_max_total + val: + array([11104.488 , 11835.94402202, 12856.65048522, 13180.21763622, + 13180.21763622, 15000.22923043, 17786.87097616, 18773.46445142, + 18773.46445142, 21689.75393255, 26453.90739662, 28212.8163638 , + 28212.8163638 , 31733.96484634, 37530.65923828, 39502.22029996, + 39502.22029996, 41929.09236831, 45412.42469786, 46581.66 ]) + fuel_flow_rate_negative_total |13616.66190343| output lbm/h traj.descent.rhs_all.fuel_flow_rate_negative_total + val: + array([-3006.75910243, -3035.88185747, -3067.0609741 , -3074.35701626, + -3074.35701626, -3118.06984835, -3154.1181106 , -3160.84536771, + -3160.84536771, -3167.93305303, -3155.67227501, -3141.73790983, + -3141.73790983, -3089.80309587, -2978.2085316 , -2929.71461497, + -2929.71461497, -2875.53598644, -2801.61947232, -2785.21896845]) + electric_power_in_total |0.0| output kW traj.descent.rhs_all.electric_power_in_total + val: + array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., + 0., 0., 0.]) + nox_rate_total |79.58180746| output lbm/h traj.descent.rhs_all.nox_rate_total + val: + array([18.70173262, 18.90809138, 19.03575591, 19.04559638, 19.04559638, + 18.68926287, 18.77532976, 18.83452118, 18.83452118, 18.61346637, + 18.13965705, 17.91868076, 17.91868076, 17.5138084 , 16.53620549, + 16.21117515, 16.21117515, 15.8270621 , 15.19708917, 14.89919533]) + mission_EOM + required_thrust + drag |132386.47842047| input N traj.descent.rhs_all.drag + val: + array([29628.63095587, 29785.93321944, 30001.32401744, 30064.39827281, + 30064.39827281, 30283.35611481, 30419.37652939, 30419.67465515, + 30419.67465515, 30374.39124359, 30227.80491759, 30099.91140717, + 30099.91140717, 29740.27925815, 28998.78423975, 28706.00892746, + 28706.00892746, 28345.80074073, 27795.64338534, 27609.31432996]) + altitude_rate |10.0383886| input m/s traj.descent.rhs_all.altitude_rate + val: + array([-2.24465193, -2.24465193, -2.24465193, -2.24465193, -2.24465193, + -2.24465193, -2.24465193, -2.24465193, -2.24465193, -2.24465193, + -2.24465193, -2.24465193, -2.24465193, -2.24465193, -2.24465193, + -2.24465193, -2.24465193, -2.24465193, -2.24465193, -2.24465193]) + velocity |771.73974523| input m/s traj.descent.rhs_all.velocity + val: + array([214.51878007, 211.35290813, 206.88067906, 205.44035421, + 205.44035421, 198.54796477, 188.62062791, 185.37975905, + 185.37975905, 176.32034566, 163.26330289, 158.99885174, + 158.99885174, 150.60981862, 138.66141566, 134.79094549, + 134.79094549, 130.40117072, 124.25764936, 122.29253366]) + velocity_rate |0.11322376| input m/s**2 traj.descent.rhs_all.velocity_rate + val: + array([-0.02357896, -0.02372576, -0.02392688, -0.02399019, -0.02399019, + -0.02428415, -0.02468409, -0.02480936, -0.02480936, -0.02514734, + -0.02560653, -0.02575019, -0.02575019, -0.02602472, -0.02639895, + -0.02651632, -0.02651632, -0.02664734, -0.02682707, -0.02688371]) + mass |228638.93848721| input kg traj.descent.rhs_all.mass + val: + array([52028.74471935, 51956.50719188, 51855.82599664, 51823.76601249, + 51823.76601249, 51672.54219645, 51461.12266693, 51393.8106793 , + 51393.8106793 , 51210.06984292, 50956.67116637, 50876.7919899 , + 50876.7919899 , 50724.57452871, 50519.93012614, 50456.90390387, + 50456.90390387, 50387.51580428, 50293.8882617 , 50264.76158872]) + thrust_required |96347.46082289| output N traj.descent.rhs_all.thrust_required + val: + array([23062.9976122 , 23141.92813481, 23243.01296376, 23268.32540388, + 23268.32540388, 23299.72720096, 23143.45919248, 23041.98095119, + 23041.98095119, 22693.33037066, 22052.57935105, 21746.21259086, + 21746.21259086, 21006.48997083, 19645.06641118, 19128.03320134, + 19128.03320134, 18497.38639685, 17536.73289589, 17210.41167636]) + groundspeed + altitude_rate |10.0383886| input m/s traj.descent.rhs_all.altitude_rate + val: + array([-2.24465193, -2.24465193, -2.24465193, -2.24465193, -2.24465193, + -2.24465193, -2.24465193, -2.24465193, -2.24465193, -2.24465193, + -2.24465193, -2.24465193, -2.24465193, -2.24465193, -2.24465193, + -2.24465193, -2.24465193, -2.24465193, -2.24465193, -2.24465193]) + velocity |771.73974523| input m/s traj.descent.rhs_all.velocity + val: + array([214.51878007, 211.35290813, 206.88067906, 205.44035421, + 205.44035421, 198.54796477, 188.62062791, 185.37975905, + 185.37975905, 176.32034566, 163.26330289, 158.99885174, + 158.99885174, 150.60981862, 138.66141566, 134.79094549, + 134.79094549, 130.40117072, 124.25764936, 122.29253366]) + distance_rate |771.67445541| output m/s traj.descent.rhs_all.distance_rate + val: + array([214.5070361 , 211.34098824, 206.86850148, 205.42809125, + 205.42809125, 198.53527609, 188.60727137, 185.36616898, + 185.36616898, 176.30605727, 163.24787168, 158.98300661, + 158.98300661, 150.59309082, 138.64324625, 134.77225428, + 134.77225428, 130.38185021, 124.23737345, 122.27193189]) + excess_specific_power + velocity |771.73974523| input m/s traj.descent.rhs_all.velocity + val: + array([214.51878007, 211.35290813, 206.88067906, 205.44035421, + 205.44035421, 198.54796477, 188.62062791, 185.37975905, + 185.37975905, 176.32034566, 163.26330289, 158.99885174, + 158.99885174, 150.60981862, 138.66141566, 134.79094549, + 134.79094549, 130.40117072, 124.25764936, 122.29253366]) + mass |228638.93848721| input kg traj.descent.rhs_all.mass + val: + array([52028.74471935, 51956.50719188, 51855.82599664, 51823.76601249, + 51823.76601249, 51672.54219645, 51461.12266693, 51393.8106793 , + 51393.8106793 , 51210.06984292, 50956.67116637, 50876.7919899 , + 50876.7919899 , 50724.57452871, 50519.93012614, 50456.90390387, + 50456.90390387, 50387.51580428, 50293.8882617 , 50264.76158872]) + thrust_net_total |568106.15424621| input N traj.descent.rhs_all.thrust_net_max_total + val: + array([ 49395.22360063, 52648.90209187, 57189.23064916, 58628.52904574, + 58628.52904574, 66724.34396776, 79119.94402832, 83508.53045513, + 83508.53045513, 96480.83237524, 117672.84281513, 125496.85971055, + 125496.85971055, 141159.70851781, 166944.68983655, 175714.6303763 , + 175714.6303763 , 186509.89517967, 202004.52935762, 207205.54710749]) + drag |132386.47842047| input N traj.descent.rhs_all.drag + val: + array([29628.63095587, 29785.93321944, 30001.32401744, 30064.39827281, + 30064.39827281, 30283.35611481, 30419.37652939, 30419.67465515, + 30419.67465515, 30374.39124359, 30227.80491759, 30099.91140717, + 30099.91140717, 29740.27925815, 28998.78423975, 28706.00892746, + 28706.00892746, 28345.80074073, 27795.64338534, 27609.31432996]) + specific_energy_rate |128.60366435| output m/s traj.descent.rhs_all.specific_energy_rate_excess + val: + array([ 8.31061392, 9.4837529 , 11.06056904, 11.5466798 , 11.5466798 , + 14.27825313, 18.20217461, 19.52693959, 19.52693959, 23.20973395, + 28.56945948, 30.4010144 , 30.4010144 , 33.73456594, 38.60833097, + 40.04628659, 40.04628659, 41.73935818, 43.8891883 , 44.55668406]) + altitude_rate_max + specific_energy_rate |128.60366435| input m/s traj.descent.rhs_all.mission_EOM.specific_energy_rate_excess + val: + array([ 8.31061392, 9.4837529 , 11.06056904, 11.5466798 , 11.5466798 , + 14.27825313, 18.20217461, 19.52693959, 19.52693959, 23.20973395, + 28.56945948, 30.4010144 , 30.4010144 , 33.73456594, 38.60833097, + 40.04628659, 40.04628659, 41.73935818, 43.8891883 , 44.55668406]) + velocity_rate |0.11322376| input m/s**2 traj.descent.rhs_all.velocity_rate + val: + array([-0.02357896, -0.02372576, -0.02392688, -0.02399019, -0.02399019, + -0.02428415, -0.02468409, -0.02480936, -0.02480936, -0.02514734, + -0.02560653, -0.02575019, -0.02575019, -0.02602472, -0.02639895, + -0.02651632, -0.02651632, -0.02664734, -0.02682707, -0.02688371]) + velocity |771.73974523| input m/s traj.descent.rhs_all.velocity + val: + array([214.51878007, 211.35290813, 206.88067906, 205.44035421, + 205.44035421, 198.54796477, 188.62062791, 185.37975905, + 185.37975905, 176.32034566, 163.26330289, 158.99885174, + 158.99885174, 150.60981862, 138.66141566, 134.79094549, + 134.79094549, 130.40117072, 124.25764936, 122.29253366]) + altitude_rate |130.2418282| output m/s traj.descent.rhs_all.altitude_rate_max + val: + array([ 8.82639951, 9.99509048, 11.56532945, 12.04925228, 12.04925228, + 14.76991619, 18.67694721, 19.9959227 , 19.9959227 , 23.66187489, + 28.99576271, 30.81851176, 30.81851176, 34.13425165, 38.98159969, + 40.4107494 , 40.4107494 , 42.09369368, 44.22910749, 44.8919338 ]) + throttle_balance + thrust_required |21659.77081486| input lbf traj.descent.rhs_all.thrust_required + val: + array([5184.76811238, 5202.51239973, 5225.23717327, 5230.92763617, + 5230.92763617, 5237.98704098, 5202.85659519, 5180.04337904, + 5180.04337904, 5101.6636106 , 4957.61705125, 4888.74306376, + 4888.74306376, 4722.44680354, 4416.38661232, 4300.15292299, + 4300.15292299, 4158.37788155, 3942.41438355, 3869.05445515]) + thrust_net_total |21659.77081486| input lbf traj.descent.rhs_all.thrust_net_total + val: + array([5184.76811238, 5202.51239973, 5225.23717327, 5230.92763617, + 5230.92763617, 5237.98704098, 5202.85659519, 5180.04337904, + 5180.04337904, 5101.6636106 , 4957.61705125, 4888.74306376, + 4888.74306376, 4722.44680354, 4416.38661232, 4300.15292299, + 4300.15292299, 4158.37788155, 3942.41438355, 3869.05445515]) + throttle |1.37898255| output unitless traj.descent.rhs_all.throttle + val: + array([0.49865618, 0.47293083, 0.44177524, 0.43279925, 0.43279925, + 0.3879603 , 0.33465308, 0.31905442, 0.31905442, 0.28076346, + 0.23449042, 0.21972804, 0.21972804, 0.19416101, 0.16162186, + 0.15241077, 0.15241077, 0.14229545, 0.12937745, 0.12545435]) + initial_mass_residual_constraint + initial_mass [1.] input kg traj.descent.rhs_all.mission:summary:gross_mass + mass |228638.93848721| input kg traj.descent.rhs_all.mass + val: + array([52028.74471935, 51956.50719188, 51855.82599664, 51823.76601249, + 51823.76601249, 51672.54219645, 51461.12266693, 51393.8106793 , + 51393.8106793 , 51210.06984292, 50956.67116637, 50876.7919899 , + 50876.7919899 , 50724.57452871, 50519.93012614, 50456.90390387, + 50456.90390387, 50387.51580428, 50293.8882617 , 50264.76158872]) + initial_mass_residual [-52127.74471935] output kg traj.descent.rhs_all.initial_mass_residual + timeseries + dt_dstau |2153.29990796| input s traj.descent.timeseries.dt_dstau + val: + array([267.18765032, 267.18765032, 267.18765032, 267.18765032, + 545.67312537, 545.67312537, 545.67312537, 545.67312537, + 648.75135679, 648.75135679, 648.75135679, 648.75135679, + 545.67312537, 545.67312537, 545.67312537, 545.67312537, + 267.18765032, 267.18765032, 267.18765032, 267.18765032]) + input_values:mach |2.45889929| input unitless traj.descent.timeseries.input_values:mach + val: + array([[0.72 ], + [0.70498488], + [0.68426707], + [0.67770996], + [0.67770996], + [0.64704481], + [0.60473316], + [0.59134167], + [0.59134167], + [0.55488385], + [0.50457949], + [0.48865833], + [0.48865833], + [0.45799318], + [0.41568153], + [0.40229004], + [0.40229004], + [0.38727492], + [0.36655711], + [0.36 ]]) + input_values:thrust_net_total |21659.77081486| input lbf traj.descent.timeseries.input_values:thrust_net_total + val: + array([[5184.76811238], + [5202.51239973], + [5225.23717327], + [5230.92763617], + [5230.92763617], + [5237.98704098], + [5202.85659519], + [5180.04337904], + [5180.04337904], + [5101.6636106 ], + [4957.61705125], + [4888.74306376], + [4888.74306376], + [4722.44680354], + [4416.38661232], + [4300.15292299], + [4300.15292299], + [4158.37788155], + [3942.41438355], + [3869.05445515]]) + input_values:drag |29761.66426269| input lbf traj.descent.timeseries.input_values:drag + val: + array([[6660.78120358], + [6696.14415917], + [6744.56593677], + [6758.74559344], + [6758.74559344], + [6807.96927443], + [6838.54788004], + [6838.61490138], + [6838.61490138], + [6828.43478549], + [6795.48086851], + [6766.72926363], + [6766.72926363], + [6685.88074039], + [6519.18602917], + [6453.36752072], + [6453.36752072], + [6372.38949905], + [6248.70920558], + [6206.82076761]]) + input_values:specific_energy_rate_excess |128.60366435| input m/s traj.descent.timeseries.input_values:specific_energy_rate_excess + val: + array([[ 8.31061392], + [ 9.4837529 ], + [11.06056904], + [11.5466798 ], + [11.5466798 ], + [14.27825313], + [18.20217461], + [19.52693959], + [19.52693959], + [23.20973395], + [28.56945948], + [30.4010144 ], + [30.4010144 ], + [33.73456594], + [38.60833097], + [40.04628659], + [40.04628659], + [41.73935818], + [43.8891883 ], + [44.55668406]]) + input_values:fuel_flow_rate_negative_total |13616.66190343| input lbm/h traj.descent.timeseries.input_values:fuel_flow_rate_negative_total + val: + array([[-3006.75910243], + [-3035.88185747], + [-3067.0609741 ], + [-3074.35701626], + [-3074.35701626], + [-3118.06984835], + [-3154.1181106 ], + [-3160.84536771], + [-3160.84536771], + [-3167.93305303], + [-3155.67227501], + [-3141.73790983], + [-3141.73790983], + [-3089.80309587], + [-2978.2085316 ], + [-2929.71461497], + [-2929.71461497], + [-2875.53598644], + [-2801.61947232], + [-2785.21896845]]) + input_values:electric_power_in_total |0.0| input kW traj.descent.timeseries.input_values:electric_power_in_total + val: + array([[0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.]]) + input_values:altitude_rate |32.93434579| input ft/s traj.descent.timeseries.input_values:altitude_rate + val: + array([[-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436]]) + input_values:throttle |1.37898255| input unitless traj.descent.timeseries.input_values:throttle + val: + array([[0.49865618], + [0.47293083], + [0.44177524], + [0.43279925], + [0.43279925], + [0.3879603 ], + [0.33465308], + [0.31905442], + [0.31905442], + [0.28076346], + [0.23449042], + [0.21972804], + [0.21972804], + [0.19416101], + [0.16162186], + [0.15241077], + [0.15241077], + [0.14229545], + [0.12937745], + [0.12545435]]) + input_values:velocity |771.73974523| input m/s traj.descent.timeseries.input_values:velocity + val: + array([[214.51878007], + [211.35290813], + [206.88067906], + [205.44035421], + [205.44035421], + [198.54796477], + [188.62062791], + [185.37975905], + [185.37975905], + [176.32034566], + [163.26330289], + [158.99885174], + [158.99885174], + [150.60981862], + [138.66141566], + [134.79094549], + [134.79094549], + [130.40117072], + [124.25764936], + [122.29253366]]) + input_values:altitude |90819.35928076| input ft traj.descent.timeseries.input_values:altitude + val: + array([[34000. ], + [32602.7594172 ], + [30674.85259378], + [30064.67667582], + [30064.67667582], + [27211.11426456], + [23273.78055735], + [22027.62790105], + [22027.62790105], + [18635.02452748], + [13953.9243121 ], + [12472.37209895], + [12472.37209895], + [ 9618.80968769], + [ 5681.47598048], + [ 4435.32332418], + [ 4435.32332418], + [ 3038.08274138], + [ 1110.17591796], + [ 500. ]]) + input_values:time |73347.98069351| input s traj.descent.timeseries.input_values:time + val: + array([[14010. ], + [14199.73049861], + [14461.51986216], + [14544.37530064], + [14544.37530064], + [14931.85890638], + [15466.50719578], + [15635.72155138], + [15635.72155138], + [16096.40122071], + [16732.04513834], + [16933.22426496], + [16933.22426496], + [17320.7078707 ], + [17855.3561601 ], + [18024.5705157 ], + [18024.5705157 ], + [18214.30101431], + [18476.09037785], + [18558.94581634]]) + input_values:time_phase |12418.42831132| input s traj.descent.timeseries.input_values:time_phase + val: + array([[ 0. ], + [ 189.73049861], + [ 451.51986216], + [ 534.37530064], + [ 534.37530064], + [ 921.85890638], + [1456.50719578], + [1625.72155138], + [1625.72155138], + [2086.40122071], + [2722.04513834], + [2923.22426496], + [2923.22426496], + [3310.7078707 ], + [3845.3561601 ], + [4014.5705157 ], + [4014.5705157 ], + [4204.30101431], + [4466.09037785], + [4548.94581634]]) + input_values:mach_rate |0.00035392| input unitless/s traj.descent.timeseries.input_values:mach_rate + val: + array([[-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05]]) + input_values:mass |228638.93848721| input kg traj.descent.timeseries.input_values:mass + val: + array([[52028.74471935], + [51956.50719188], + [51855.82599664], + [51823.76601249], + [51823.76601249], + [51672.54219645], + [51461.12266693], + [51393.8106793 ], + [51393.8106793 ], + [51210.06984292], + [50956.67116637], + [50876.7919899 ], + [50876.7919899 ], + [50724.57452871], + [50519.93012614], + [50456.90390387], + [50456.90390387], + [50387.51580428], + [50293.8882617 ], + [50264.76158872]]) + input_values:distance |14257384.99570313| input m traj.descent.timeseries.input_values:distance + val: + array([[2751418.23144865], + [2791817.41185045], + [2846561.44051968], + [2863642.02155273], + [2863642.02155273], + [2941914.82037522], + [3045428.93171548], + [3077070.29224964], + [3077070.29224964], + [3160390.83905457], + [3268342.75197541], + [3300756.63996977], + [3300756.63996977], + [3360741.81646801], + [3438080.96818847], + [3461214.38233449], + [3461214.38233449], + [3486369.12667608], + [3519699.62007001], + [3529912. ]]) + mach |2.45889929| output unitless traj.descent.timeseries.mach + val: + array([[0.72 ], + [0.70498488], + [0.68426707], + [0.67770996], + [0.67770996], + [0.64704481], + [0.60473316], + [0.59134167], + [0.59134167], + [0.55488385], + [0.50457949], + [0.48865833], + [0.48865833], + [0.45799318], + [0.41568153], + [0.40229004], + [0.40229004], + [0.38727492], + [0.36655711], + [0.36 ]]) + thrust_net_total |21659.77081486| output lbf traj.descent.timeseries.thrust_net_total + val: + array([[5184.76811238], + [5202.51239973], + [5225.23717327], + [5230.92763617], + [5230.92763617], + [5237.98704098], + [5202.85659519], + [5180.04337904], + [5180.04337904], + [5101.6636106 ], + [4957.61705125], + [4888.74306376], + [4888.74306376], + [4722.44680354], + [4416.38661232], + [4300.15292299], + [4300.15292299], + [4158.37788155], + [3942.41438355], + [3869.05445515]]) + drag |29761.66426269| output lbf traj.descent.timeseries.drag + val: + array([[6660.78120358], + [6696.14415917], + [6744.56593677], + [6758.74559344], + [6758.74559344], + [6807.96927443], + [6838.54788004], + [6838.61490138], + [6838.61490138], + [6828.43478549], + [6795.48086851], + [6766.72926363], + [6766.72926363], + [6685.88074039], + [6519.18602917], + [6453.36752072], + [6453.36752072], + [6372.38949905], + [6248.70920558], + [6206.82076761]]) + specific_energy_rate_excess |128.60366435| output m/s traj.descent.timeseries.specific_energy_rate_excess + val: + array([[ 8.31061392], + [ 9.4837529 ], + [11.06056904], + [11.5466798 ], + [11.5466798 ], + [14.27825313], + [18.20217461], + [19.52693959], + [19.52693959], + [23.20973395], + [28.56945948], + [30.4010144 ], + [30.4010144 ], + [33.73456594], + [38.60833097], + [40.04628659], + [40.04628659], + [41.73935818], + [43.8891883 ], + [44.55668406]]) + fuel_flow_rate_negative_total |13616.66190343| output lbm/h traj.descent.timeseries.fuel_flow_rate_negative_total + val: + array([[-3006.75910243], + [-3035.88185747], + [-3067.0609741 ], + [-3074.35701626], + [-3074.35701626], + [-3118.06984835], + [-3154.1181106 ], + [-3160.84536771], + [-3160.84536771], + [-3167.93305303], + [-3155.67227501], + [-3141.73790983], + [-3141.73790983], + [-3089.80309587], + [-2978.2085316 ], + [-2929.71461497], + [-2929.71461497], + [-2875.53598644], + [-2801.61947232], + [-2785.21896845]]) + electric_power_in_total |0.0| output kW traj.descent.timeseries.electric_power_in_total + val: + array([[0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.]]) + altitude_rate |32.93434579| output ft/s traj.descent.timeseries.altitude_rate + val: + array([[-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436]]) + throttle |1.37898255| output unitless traj.descent.timeseries.throttle + val: + array([[0.49865618], + [0.47293083], + [0.44177524], + [0.43279925], + [0.43279925], + [0.3879603 ], + [0.33465308], + [0.31905442], + [0.31905442], + [0.28076346], + [0.23449042], + [0.21972804], + [0.21972804], + [0.19416101], + [0.16162186], + [0.15241077], + [0.15241077], + [0.14229545], + [0.12937745], + [0.12545435]]) + velocity |771.73974523| output m/s traj.descent.timeseries.velocity + val: + array([[214.51878007], + [211.35290813], + [206.88067906], + [205.44035421], + [205.44035421], + [198.54796477], + [188.62062791], + [185.37975905], + [185.37975905], + [176.32034566], + [163.26330289], + [158.99885174], + [158.99885174], + [150.60981862], + [138.66141566], + [134.79094549], + [134.79094549], + [130.40117072], + [124.25764936], + [122.29253366]]) + altitude |90819.35928076| output ft traj.descent.timeseries.altitude + val: + array([[34000. ], + [32602.7594172 ], + [30674.85259378], + [30064.67667582], + [30064.67667582], + [27211.11426456], + [23273.78055735], + [22027.62790105], + [22027.62790105], + [18635.02452748], + [13953.9243121 ], + [12472.37209895], + [12472.37209895], + [ 9618.80968769], + [ 5681.47598048], + [ 4435.32332418], + [ 4435.32332418], + [ 3038.08274138], + [ 1110.17591796], + [ 500. ]]) + time |73347.98069351| output s traj.descent.timeseries.time + val: + array([[14010. ], + [14199.73049861], + [14461.51986216], + [14544.37530064], + [14544.37530064], + [14931.85890638], + [15466.50719578], + [15635.72155138], + [15635.72155138], + [16096.40122071], + [16732.04513834], + [16933.22426496], + [16933.22426496], + [17320.7078707 ], + [17855.3561601 ], + [18024.5705157 ], + [18024.5705157 ], + [18214.30101431], + [18476.09037785], + [18558.94581634]]) + time_phase |12418.42831132| output s traj.descent.timeseries.time_phase + val: + array([[ 0. ], + [ 189.73049861], + [ 451.51986216], + [ 534.37530064], + [ 534.37530064], + [ 921.85890638], + [1456.50719578], + [1625.72155138], + [1625.72155138], + [2086.40122071], + [2722.04513834], + [2923.22426496], + [2923.22426496], + [3310.7078707 ], + [3845.3561601 ], + [4014.5705157 ], + [4014.5705157 ], + [4204.30101431], + [4466.09037785], + [4548.94581634]]) + mach_rate |0.00035392| output unitless/s traj.descent.timeseries.mach_rate + val: + array([[-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05]]) + mass |228638.93848721| output kg traj.descent.timeseries.mass + val: + array([[52028.74471935], + [51956.50719188], + [51855.82599664], + [51823.76601249], + [51823.76601249], + [51672.54219645], + [51461.12266693], + [51393.8106793 ], + [51393.8106793 ], + [51210.06984292], + [50956.67116637], + [50876.7919899 ], + [50876.7919899 ], + [50724.57452871], + [50519.93012614], + [50456.90390387], + [50456.90390387], + [50387.51580428], + [50293.8882617 ], + [50264.76158872]]) + distance |14257384.99570313| output m traj.descent.timeseries.distance + val: + array([[2751418.23144865], + [2791817.41185045], + [2846561.44051968], + [2863642.02155273], + [2863642.02155273], + [2941914.82037522], + [3045428.93171548], + [3077070.29224964], + [3077070.29224964], + [3160390.83905457], + [3268342.75197541], + [3300756.63996977], + [3300756.63996977], + [3360741.81646801], + [3438080.96818847], + [3461214.38233449], + [3461214.38233449], + [3486369.12667608], + [3519699.62007001], + [3529912. ]]) + mission_bus_variables + dt_dstau |2153.29990796| input s traj.descent.mission_bus_variables.dt_dstau + val: + array([267.18765032, 267.18765032, 267.18765032, 267.18765032, + 545.67312537, 545.67312537, 545.67312537, 545.67312537, + 648.75135679, 648.75135679, 648.75135679, 648.75135679, + 545.67312537, 545.67312537, 545.67312537, 545.67312537, + 267.18765032, 267.18765032, 267.18765032, 267.18765032]) + input_values:mach |2.45889929| input unitless traj.descent.mission_bus_variables.input_values:mach + val: + array([[0.72 ], + [0.70498488], + [0.68426707], + [0.67770996], + [0.67770996], + [0.64704481], + [0.60473316], + [0.59134167], + [0.59134167], + [0.55488385], + [0.50457949], + [0.48865833], + [0.48865833], + [0.45799318], + [0.41568153], + [0.40229004], + [0.40229004], + [0.38727492], + [0.36655711], + [0.36 ]]) + input_values:thrust_net_total |21659.77081486| input lbf traj.descent.mission_bus_variables.input_values:thrust_net_total + val: + array([[5184.76811238], + [5202.51239973], + [5225.23717327], + [5230.92763617], + [5230.92763617], + [5237.98704098], + [5202.85659519], + [5180.04337904], + [5180.04337904], + [5101.6636106 ], + [4957.61705125], + [4888.74306376], + [4888.74306376], + [4722.44680354], + [4416.38661232], + [4300.15292299], + [4300.15292299], + [4158.37788155], + [3942.41438355], + [3869.05445515]]) + input_values:drag |29761.66426269| input lbf traj.descent.mission_bus_variables.input_values:drag + val: + array([[6660.78120358], + [6696.14415917], + [6744.56593677], + [6758.74559344], + [6758.74559344], + [6807.96927443], + [6838.54788004], + [6838.61490138], + [6838.61490138], + [6828.43478549], + [6795.48086851], + [6766.72926363], + [6766.72926363], + [6685.88074039], + [6519.18602917], + [6453.36752072], + [6453.36752072], + [6372.38949905], + [6248.70920558], + [6206.82076761]]) + input_values:specific_energy_rate_excess |128.60366435| input m/s traj.descent.mission_bus_variables.input_values:specific_energy_rate_excess + val: + array([[ 8.31061392], + [ 9.4837529 ], + [11.06056904], + [11.5466798 ], + [11.5466798 ], + [14.27825313], + [18.20217461], + [19.52693959], + [19.52693959], + [23.20973395], + [28.56945948], + [30.4010144 ], + [30.4010144 ], + [33.73456594], + [38.60833097], + [40.04628659], + [40.04628659], + [41.73935818], + [43.8891883 ], + [44.55668406]]) + input_values:fuel_flow_rate_negative_total |13616.66190343| input lbm/h traj.descent.mission_bus_variables.input_values:fuel_flow_rate_negative_total + val: + array([[-3006.75910243], + [-3035.88185747], + [-3067.0609741 ], + [-3074.35701626], + [-3074.35701626], + [-3118.06984835], + [-3154.1181106 ], + [-3160.84536771], + [-3160.84536771], + [-3167.93305303], + [-3155.67227501], + [-3141.73790983], + [-3141.73790983], + [-3089.80309587], + [-2978.2085316 ], + [-2929.71461497], + [-2929.71461497], + [-2875.53598644], + [-2801.61947232], + [-2785.21896845]]) + input_values:electric_power_in_total |0.0| input kW traj.descent.mission_bus_variables.input_values:electric_power_in_total + val: + array([[0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.]]) + input_values:altitude_rate |32.93434579| input ft/s traj.descent.mission_bus_variables.input_values:altitude_rate + val: + array([[-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436]]) + input_values:throttle |1.37898255| input unitless traj.descent.mission_bus_variables.input_values:throttle + val: + array([[0.49865618], + [0.47293083], + [0.44177524], + [0.43279925], + [0.43279925], + [0.3879603 ], + [0.33465308], + [0.31905442], + [0.31905442], + [0.28076346], + [0.23449042], + [0.21972804], + [0.21972804], + [0.19416101], + [0.16162186], + [0.15241077], + [0.15241077], + [0.14229545], + [0.12937745], + [0.12545435]]) + input_values:velocity |771.73974523| input m/s traj.descent.mission_bus_variables.input_values:velocity + val: + array([[214.51878007], + [211.35290813], + [206.88067906], + [205.44035421], + [205.44035421], + [198.54796477], + [188.62062791], + [185.37975905], + [185.37975905], + [176.32034566], + [163.26330289], + [158.99885174], + [158.99885174], + [150.60981862], + [138.66141566], + [134.79094549], + [134.79094549], + [130.40117072], + [124.25764936], + [122.29253366]]) + input_values:altitude |90819.35928076| input ft traj.descent.mission_bus_variables.input_values:altitude + val: + array([[34000. ], + [32602.7594172 ], + [30674.85259378], + [30064.67667582], + [30064.67667582], + [27211.11426456], + [23273.78055735], + [22027.62790105], + [22027.62790105], + [18635.02452748], + [13953.9243121 ], + [12472.37209895], + [12472.37209895], + [ 9618.80968769], + [ 5681.47598048], + [ 4435.32332418], + [ 4435.32332418], + [ 3038.08274138], + [ 1110.17591796], + [ 500. ]]) + input_values:time |73347.98069351| input s traj.descent.mission_bus_variables.input_values:time + val: + array([[14010. ], + [14199.73049861], + [14461.51986216], + [14544.37530064], + [14544.37530064], + [14931.85890638], + [15466.50719578], + [15635.72155138], + [15635.72155138], + [16096.40122071], + [16732.04513834], + [16933.22426496], + [16933.22426496], + [17320.7078707 ], + [17855.3561601 ], + [18024.5705157 ], + [18024.5705157 ], + [18214.30101431], + [18476.09037785], + [18558.94581634]]) + input_values:time_phase |12418.42831132| input s traj.descent.mission_bus_variables.input_values:time_phase + val: + array([[ 0. ], + [ 189.73049861], + [ 451.51986216], + [ 534.37530064], + [ 534.37530064], + [ 921.85890638], + [1456.50719578], + [1625.72155138], + [1625.72155138], + [2086.40122071], + [2722.04513834], + [2923.22426496], + [2923.22426496], + [3310.7078707 ], + [3845.3561601 ], + [4014.5705157 ], + [4014.5705157 ], + [4204.30101431], + [4466.09037785], + [4548.94581634]]) + input_values:mach_rate |0.00035392| input unitless/s traj.descent.mission_bus_variables.input_values:mach_rate + val: + array([[-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05]]) + input_values:mass |228638.93848721| input kg traj.descent.mission_bus_variables.input_values:mass + val: + array([[52028.74471935], + [51956.50719188], + [51855.82599664], + [51823.76601249], + [51823.76601249], + [51672.54219645], + [51461.12266693], + [51393.8106793 ], + [51393.8106793 ], + [51210.06984292], + [50956.67116637], + [50876.7919899 ], + [50876.7919899 ], + [50724.57452871], + [50519.93012614], + [50456.90390387], + [50456.90390387], + [50387.51580428], + [50293.8882617 ], + [50264.76158872]]) + input_values:distance |14257384.99570313| input m traj.descent.mission_bus_variables.input_values:distance + val: + array([[2751418.23144865], + [2791817.41185045], + [2846561.44051968], + [2863642.02155273], + [2863642.02155273], + [2941914.82037522], + [3045428.93171548], + [3077070.29224964], + [3077070.29224964], + [3160390.83905457], + [3268342.75197541], + [3300756.63996977], + [3300756.63996977], + [3360741.81646801], + [3438080.96818847], + [3461214.38233449], + [3461214.38233449], + [3486369.12667608], + [3519699.62007001], + [3529912. ]]) + mach |2.13130946| output unitless traj.descent.mission_bus_variables.mach + val: + array([[0.72 ], + [0.684], + [0.648], + [0.648], + [0.612], + [0.576], + [0.576], + [0.54 ], + [0.504], + [0.504], + [0.468], + [0.432], + [0.432], + [0.396], + [0.36 ]]) + thrust_net_total |19003.91342407| output lbf traj.descent.mission_bus_variables.thrust_net_total + val: + array([[5184.76811238], + [5225.48807372], + [5238.16325545], + [5238.16325545], + [5212.81280251], + [5146.60278852], + [5146.60278852], + [5067.03275078], + [4955.36760416], + [4955.36760416], + [4781.69778451], + [4545.27003905], + [4545.27003905], + [4242.24945088], + [3869.05445515]]) + drag |25947.60606281| output lbf traj.descent.mission_bus_variables.drag + val: + array([[6660.78120358], + [6745.15915969], + [6806.7679329 ], + [6806.7679329 ], + [6836.52910852], + [6832.79516112], + [6832.79516112], + [6824.40689005], + [6794.64634346], + [6794.64634346], + [6715.9990443 ], + [6590.95312626], + [6590.95312626], + [6420.36076088], + [6206.82076761]]) + specific_energy_rate_excess |107.0223294| output m/s traj.descent.mission_bus_variables.specific_energy_rate_excess + val: + array([[ 8.31061392], + [11.08050322], + [14.19260943], + [14.19260943], + [17.5036815 ], + [21.0705639 ], + [21.0705639 ], + [24.74493902], + [28.63469861], + [28.63469861], + [32.59971581], + [36.75470499], + [36.75470499], + [40.7761994 ], + [44.55668406]]) + fuel_flow_rate_negative_total |11916.19897582| output lbm/h traj.descent.mission_bus_variables.fuel_flow_rate_negative_total + val: + array([[-3006.75910243], + [-3067.38415203], + [-3116.95375848], + [-3116.95375848], + [-3149.62176437], + [-3164.45318511], + [-3164.45318511], + [-3168.14998767], + [-3155.26963505], + [-3155.26963505], + [-3108.83228807], + [-3028.04915148], + [-3028.04915148], + [-2908.40713121], + [-2785.21896845]]) + electric_power_in_total |0.0| output kW traj.descent.mission_bus_variables.electric_power_in_total + val: + array([[0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.], + [0.]]) + altitude_rate |28.52198011| output ft/s traj.descent.mission_bus_variables.altitude_rate + val: + array([[-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436], + [-7.3643436]]) + throttle |1.1689564| output unitless traj.descent.mission_bus_variables.throttle + val: + array([[0.49865618], + [0.4414021 ], + [0.38926315], + [0.38926315], + [0.34330884], + [0.30209065], + [0.30209065], + [0.26670543], + [0.23396121], + [0.23396121], + [0.20239237], + [0.1736363 ], + [0.1736363 ], + [0.148078 ], + [0.12545435]]) + velocity |670.98612095| output m/s traj.descent.mission_bus_variables.velocity + val: + array([[214.51878007], + [206.82224691], + [198.76652705], + [198.76652705], + [190.35952306], + [181.60939417], + [181.60939417], + [172.52370169], + [163.10919058], + [163.10919058], + [153.37258632], + [143.32037213], + [143.32037213], + [132.95846386], + [122.29253366]]) + altitude |76956.88728113| output ft traj.descent.mission_bus_variables.altitude + val: + array([[34000.], + [30650.], + [27300.], + [27300.], + [23950.], + [20600.], + [20600.], + [17250.], + [13900.], + [13900.], + [10550.], + [ 7200.], + [ 7200.], + [ 3850.], + [ 500.]]) + time |63282.3960427| output s traj.descent.mission_bus_variables.time + val: + array([[14010. ], + [14464.89458163], + [14919.78916327], + [14919.78916327], + [15374.6837449 ], + [15829.57832653], + [15829.57832653], + [16284.47290817], + [16739.3674898 ], + [16739.3674898 ], + [17194.26207144], + [17649.15665307], + [17649.15665307], + [18104.0512347 ], + [18558.94581634]]) + time_phase |10222.48431654| output s traj.descent.mission_bus_variables.time_phase + val: + array([[ 0. ], + [ 454.89458163], + [ 909.78916327], + [ 909.78916327], + [1364.6837449 ], + [1819.57832653], + [1819.57832653], + [2274.47290817], + [2729.3674898 ], + [2729.3674898 ], + [3184.26207144], + [3639.15665307], + [3639.15665307], + [4094.0512347 ], + [4548.94581634]]) + mach_rate |0.0003065| output unitless/s traj.descent.mission_bus_variables.mach_rate + val: + array([[-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05], + [-7.91392148e-05]]) + mass |198067.91745372| output kg traj.descent.mission_bus_variables.mass + val: + array([[52028.74471935], + [51854.52178828], + [51677.2831748 ], + [51677.2831748 ], + [51497.59098981], + [51316.54407232], + [51316.54407232], + [51135.00751291], + [50953.7598743 ], + [50953.7598743 ], + [50773.96071216], + [50597.95134026], + [50597.95134026], + [50427.67859411], + [50264.76158872]]) + distance |12328970.76725104| output m traj.descent.mission_bus_variables.distance + val: + array([[2751418.23144865], + [2847259.46507397], + [2939517.23148407], + [2939517.23148407], + [3028030.38808647], + [3112640.21428723], + [3112640.21428723], + [3193192.91369784], + [3269537.54580838], + [3269537.54580838], + [3341525.02224903], + [3409011.24339885], + [3409011.24339885], + [3471853.40400242], + [3529912. ]]) + collocation_constraint + dt_dstau |1864.81242226| input s traj.descent.collocation_constraint.dt_dstau + val: + array([267.18765032, 267.18765032, 267.18765032, 545.67312537, + 545.67312537, 545.67312537, 648.75135679, 648.75135679, + 648.75135679, 545.67312537, 545.67312537, 545.67312537, + 267.18765032, 267.18765032, 267.18765032]) + f_approx:mass |1.48954691| input kg/s traj.descent.collocation_constraint.f_approx:mass + val: + array([[-0.37884527], + [-0.38251468], + [-0.38644318], + [-0.38736247], + [-0.39287019], + [-0.3974122 ], + [-0.39825982], + [-0.39915285], + [-0.39760802], + [-0.39585232], + [-0.38930864], + [-0.37524796], + [-0.36913783], + [-0.36231144], + [-0.35299812]]) + f_computed:mass |1.48954691| input kg/s traj.descent.collocation_constraint.f_computed:mass + val: + array([[-0.37884527], + [-0.38251468], + [-0.38644318], + [-0.38736247], + [-0.39287019], + [-0.3974122 ], + [-0.39825982], + [-0.39915285], + [-0.39760802], + [-0.39585232], + [-0.38930864], + [-0.37524796], + [-0.36913783], + [-0.36231144], + [-0.35299812]]) + f_approx:distance |678.62402375| input m/s traj.descent.collocation_constraint.f_approx:distance + val: + array([[214.5070361 ], + [211.34098824], + [206.86850148], + [205.42809125], + [198.53527609], + [188.60727137], + [185.36616898], + [176.30605727], + [163.24787168], + [158.98300661], + [150.59309082], + [138.64324625], + [134.77225428], + [130.38185021], + [124.23737345]]) + f_computed:distance |678.62402375| input m/s traj.descent.collocation_constraint.f_computed:distance + val: + array([[214.5070361 ], + [211.34098824], + [206.86850148], + [205.42809125], + [198.53527609], + [188.60727137], + [185.36616898], + [176.30605727], + [163.24787168], + [158.98300661], + [150.59309082], + [138.64324625], + [134.77225428], + [130.38185021], + [124.23737345]]) + defects:mass |0.0| output kg traj.descent.collocation_constraint.defects:mass + val: + array([[-2.19067075e-11], + [ 1.48318941e-12], + [ 2.28114531e-11], + [-1.22072502e-11], + [-9.39019245e-12], + [ 3.03212343e-11], + [-2.99267487e-11], + [ 4.32155216e-13], + [-3.70933227e-12], + [ 7.60302679e-12], + [ 3.30171283e-12], + [-5.78557019e-12], + [ 1.03823258e-12], + [-9.55173978e-12], + [-8.40968393e-12]]) + defects:distance |1e-08| output m traj.descent.collocation_constraint.defects:distance + val: + array([[ 9.03677642e-10], + [ 1.51878595e-10], + [-4.70823645e-10], + [-2.55897890e-09], + [ 3.41197186e-10], + [ 3.41197186e-10], + [ 2.93174099e-09], + [-1.16163322e-09], + [ 9.77246995e-10], + [ 1.79903971e-09], + [ 1.70598593e-10], + [ 1.39580667e-09], + [-1.52637988e-09], + [ 8.35332274e-11], + [ 3.79696488e-11]]) +post_mission + fuel_burned + initial_mass [130904.19882744] input lbm fuel_burned.initial_mass + mass_final [110814.83048032] input lbm fuel_burned.mass_final + fuel_burned [20089.36834711] output lbm mission:summary:fuel_burned + reserve_fuel + reserve_fuel_additional [3000.] input lbm aircraft:design:reserve_fuel_additional + reserve_fuel_burned [0.] input lbm mission:summary:reserve_fuel_burned + reserve_fuel_frac_mass [0.] input lbm reserve_fuel_frac_mass + reserve_fuel [3000.] output lbm mission:design:reserve_fuel + fuel_calc + fuel_burned [20089.36834711] input lbm mission:summary:fuel_burned + fuel_margin [0.] input unitless aircraft:fuel:fuel_margin + reserve_fuel [3000.] input lbm mission:design:reserve_fuel + overall_fuel [23089.36834711] output lbm mission:summary:total_fuel_mass + mass_constraint + initial_mass [130904.19882744] input lbm mission:summary:gross_mass + operating_empty_mass [69789.83048032] input lbm aircraft:design:operating_mass + overall_fuel [23089.36834711] input lbm mission:summary:total_fuel_mass + payload_mass [38025.] input lbm aircraft:crew_and_payload:total_payload_mass + mass_resid [0.] output lbm mission:constraints:mass_residual +link_climb_mass + lhs:mass [130904.19882744] input lbm link_climb_mass.lhs:mass + rhs:mass [130904.19882744] input lbm mission:summary:gross_mass + mass [-1.45519152e-11] output None link_climb_mass.mass +range_constraint + actual_range [1906.] input nmi mission:summary:range + target_range [1906.] input nmi target_range + range_resid [2.27373675e-13] output nmi mission:constraints:range_residual +gtow_constraint + lhs:GTOW [130904.19882744] input lbm mission:design:gross_mass + rhs:GTOW [130904.19882744] input lbm mission:summary:gross_mass + GTOW [0.] output None gtow_constraint.GTOW +fuel_obj + ascent_duration [0.] input s mission:takeoff:ascent_duration + overall_fuel [23089.36834711] input lbm mission:summary:total_fuel_mass + reg_objective [2.30893683] output unitless mission:objectives:fuel +range_obj + actual_range [1906.] input nmi mission:summary:range + ascent_duration [0.] input s mission:takeoff:ascent_duration + reg_objective [-1.906] output unitless mission:objectives:range + + +Wing Mass [2.24666] +Horizontal Tail Mass [0.] +Fuselage Mass [5209.12373908] +done diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..7b3b31033 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,94 @@ +[build-system] +requires = ["hatchling", "numpy>=2.0"] +build-backend = "hatchling.build" + +[project] +name = "aviary" +dynamic = ["version"] +readme = "README.md" +license = "Apache-2.0" +dependencies = [ + "dymos>=1.8.1", + "hvplot", + "importlib_resources", + "matplotlib", + "numpy<2", + "openmdao>=3.36.0", + "pandas", + "panel>=1.0.0", + "parameterized", + "simupy", +] + +[project.optional-dependencies] +all = [ + "ambiance", + "itables", + "myst-nb", + "openaerostruct", + "pre-commit", + "sphinx_book_theme==1.1.0", + "testflo", +] +examples = [ + "ambiance", + "itables", + "openaerostruct", +] +test = [ + "myst-nb", + "pre-commit", + "sphinx_book_theme==1.1.0", + "testflo", +] + +[project.scripts] +aviary = "aviary.interface.cmd_entry_points:aviary_cmd" + +[project.entry-points.openmdao_report] +aviary_reports = "aviary.interface.reports:register_custom_reports" + +[tool.hatch.version] +path = "aviary/__init__.py" + +[tool.hatch.build.targets.sdist] +include = [ + "/aviary", +] + +[tool.ruff] +line-length = 100 + +[tool.ruff.format] +quote-style = "single" + +[tool.ruff.lint] +# isort, pydocstyle +extend-select = ["I", "D"] +# disabling these rules will help current Aviary code pass a pre-commit lint check +extend-ignore = [ + "D100", + "D101", + "D102", + "D103", + "D104", + "D105", + "D106", + "D204", + "D205", + "D401", + "D404", +] + +[tool.ruff.lint.isort] +split-on-trailing-comma = false + +[tool.ruff.lint.pydocstyle] +convention = "numpy" + +[tool.ruff.lint.per-file-ignores] +# Ignore `F401` (unused import) in api and doc files. +# Ignore `I001` (sort and format imports) in api. +# Ignore `E402` (module import not at top of file) for doc cells. +"api.py" = ["F401", "I001"] +"*.ipynb" = ["F401", "E402"] \ No newline at end of file From 1e44c6a095532b2fec3048893541c1ee06d8c84c Mon Sep 17 00:00:00 2001 From: Seth Zoppelt Date: Thu, 3 Jul 2025 13:41:08 +0000 Subject: [PATCH 079/147] Final updates. --- aviary/mission/sixdof/six_dof_ODE.py | 24 +++++++++++++++------- aviary/subsystems/mass/simple_mass/tail.py | 10 +++++++-- aviary/subsystems/mass/simple_mass/wing.py | 6 ++++-- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/aviary/mission/sixdof/six_dof_ODE.py b/aviary/mission/sixdof/six_dof_ODE.py index 75e59e6ab..4658dd12f 100644 --- a/aviary/mission/sixdof/six_dof_ODE.py +++ b/aviary/mission/sixdof/six_dof_ODE.py @@ -5,6 +5,7 @@ from aviary.variable_info.enums import AnalysisScheme, SpeedType, ThrottleAllocation from aviary.variable_info.variables import Aircraft, Dynamic, Mission +from aviary.constants import GRAV_METRIC_FLOPS from aviary.mission.sixdof.six_dof_EOM import SixDOF_EOM from aviary.mission.sixdof.force_component_calc import ForceComponentResolver @@ -48,18 +49,27 @@ def setup(self): ) T_vert_comp = om.ExecComp( - 'T_z = ...', - # variables + units etc. -- see energy_ODE.py line 60, - promotes_inputs=[...], - promotes_outputs=[...] - ) + 'T_z = cos(roll) * cos(pitch) * mass * g', + roll = {'units': 'rad', 'shape': (nn,)}, + pitch = {'units': 'rad', 'shape': (nn,)}, + mass = {'units': 'kg', 'shape': (nn,)}, + g = {'val': GRAV_METRIC_FLOPS, 'units': 'm/s**2'}, + promotes_inputs=[ + ('roll', 'roll'), + ('pitch', 'pitch'), + ('mass', 'mass'), + ], + promotes_outputs=[ + ('T_z', 'T_z'), + ] + ) # body-relative CS comp = om.BalanceComp( name=Dynamic.Vehicle.Propulsion.THROTTLE, units='unitless', val=np.ones((nn,)), - lhs_name='thrust_required', - rhs_name= 'T_z', + lhs_name='T_z', + rhs_name= Dynamic.Vehicle.Propulsion.THRUST_TOTAL, eq_units='N', normalize=False, ) diff --git a/aviary/subsystems/mass/simple_mass/tail.py b/aviary/subsystems/mass/simple_mass/tail.py index 788408585..6af8804c5 100644 --- a/aviary/subsystems/mass/simple_mass/tail.py +++ b/aviary/subsystems/mass/simple_mass/tail.py @@ -169,12 +169,18 @@ def compute_primal(self, thickness_dist = self.airfoil_thickness(x_points, max_thickness) if tail_type == 'horizontal': - total_mass, _ = quadgk(lambda x: density * self.airfoil_thickness(x, max_thickness) * (aircraft__horizontal_tail__root_chord - (aircraft__horizontal_tail__root_chord - tip_chord_tail) * (x / aircraft__horizontal_tail__span)) * aircraft__horizontal_tail__span, [0, 1], epsabs=1e-9, epsrel=1e-9) + total_mass, _ = quadgk( + lambda x: density * self.airfoil_thickness(x, max_thickness) * ( + aircraft__horizontal_tail__root_chord - (aircraft__horizontal_tail__root_chord - tip_chord_tail) * (x / aircraft__horizontal_tail__span) + ) * aircraft__horizontal_tail__span, [0, 1], epsabs=1e-9, epsrel=1e-9) aircraft__horizontal_tail__mass = total_mass elif tail_type == 'vertical': - total_mass, _ = quadgk(lambda x: density * self.airfoil_thickness(x, max_thickness) * (aircraft__vertical_tail__root_chord - (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span)) * aircraft__vertical_tail__span, [0, 1], epsabs=1e-9, epsrel=1e-9) + total_mass, _ = quadgk( + lambda x: density * self.airfoil_thickness(x, max_thickness) * ( + aircraft__vertical_tail__root_chord - (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span) + ) * aircraft__vertical_tail__span, [0, 1], epsabs=1e-9, epsrel=1e-9) aircraft__vertical_tail__mass = total_mass diff --git a/aviary/subsystems/mass/simple_mass/wing.py b/aviary/subsystems/mass/simple_mass/wing.py index 5052eb981..120e73479 100644 --- a/aviary/subsystems/mass/simple_mass/wing.py +++ b/aviary/subsystems/mass/simple_mass/wing.py @@ -101,7 +101,8 @@ def compute_primal(self, aircraft__wing__span, aircraft__wing__root_chord, tip_c x_points = jnp.linspace(0, 1, n_points) dx = 1 / (n_points - 1) - weight_function = lambda x: density * self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span)) * aircraft__wing__span + weight_function = lambda x: density * self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - + (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span)) * aircraft__wing__span aircraft__wing__mass, _ = quadgk(weight_function, [0, 1], epsabs=1e-9, epsrel=1e-9) @@ -167,7 +168,8 @@ def extract_airfoil_features(self, x_coords, y_coords): n_points = 10 # = num_sections x = jnp.linspace(0, 1, n_points) max_thickness_chord_ratio = 0.12 - thickness_dist = 5 * max_thickness_chord_ratio * (0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) + thickness_dist = 5 * max_thickness_chord_ratio * ( + 0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) # Setup the problem prob.setup() From 807a2293e6629d6e09c943795e2a05fb772dfbd6 Mon Sep 17 00:00:00 2001 From: Seth Zoppelt Date: Thu, 3 Jul 2025 13:45:25 +0000 Subject: [PATCH 080/147] Final Updates. --- aviary/subsystems/mass/simple_mass/tail.py | 6 ++++-- aviary/subsystems/mass/simple_mass/wing.py | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/tail.py b/aviary/subsystems/mass/simple_mass/tail.py index 6af8804c5..f9bac747e 100644 --- a/aviary/subsystems/mass/simple_mass/tail.py +++ b/aviary/subsystems/mass/simple_mass/tail.py @@ -172,7 +172,8 @@ def compute_primal(self, total_mass, _ = quadgk( lambda x: density * self.airfoil_thickness(x, max_thickness) * ( aircraft__horizontal_tail__root_chord - (aircraft__horizontal_tail__root_chord - tip_chord_tail) * (x / aircraft__horizontal_tail__span) - ) * aircraft__horizontal_tail__span, [0, 1], epsabs=1e-9, epsrel=1e-9) + ) * aircraft__horizontal_tail__span, [0, 1], epsabs=1e-9, epsrel=1e-9 + ) aircraft__horizontal_tail__mass = total_mass @@ -180,7 +181,8 @@ def compute_primal(self, total_mass, _ = quadgk( lambda x: density * self.airfoil_thickness(x, max_thickness) * ( aircraft__vertical_tail__root_chord - (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span) - ) * aircraft__vertical_tail__span, [0, 1], epsabs=1e-9, epsrel=1e-9) + ) * aircraft__vertical_tail__span, [0, 1], epsabs=1e-9, epsrel=1e-9 + ) aircraft__vertical_tail__mass = total_mass diff --git a/aviary/subsystems/mass/simple_mass/wing.py b/aviary/subsystems/mass/simple_mass/wing.py index 120e73479..8057c995e 100644 --- a/aviary/subsystems/mass/simple_mass/wing.py +++ b/aviary/subsystems/mass/simple_mass/wing.py @@ -102,7 +102,8 @@ def compute_primal(self, aircraft__wing__span, aircraft__wing__root_chord, tip_c dx = 1 / (n_points - 1) weight_function = lambda x: density * self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - - (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span)) * aircraft__wing__span + (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span) + ) * aircraft__wing__span aircraft__wing__mass, _ = quadgk(weight_function, [0, 1], epsabs=1e-9, epsrel=1e-9) From b2c9fd3a675c54389435cb700eac49b5cdc06c38 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 09:49:05 -0400 Subject: [PATCH 081/147] Delete aviary/subsystems/mass/simple_mass/Clark_Y.dat --- .../subsystems/mass/simple_mass/Clark_Y.dat | 122 ------------------ 1 file changed, 122 deletions(-) delete mode 100644 aviary/subsystems/mass/simple_mass/Clark_Y.dat diff --git a/aviary/subsystems/mass/simple_mass/Clark_Y.dat b/aviary/subsystems/mass/simple_mass/Clark_Y.dat deleted file mode 100644 index 3649ca4e2..000000000 --- a/aviary/subsystems/mass/simple_mass/Clark_Y.dat +++ /dev/null @@ -1,122 +0,0 @@ -0.0000000 0.0000000 -0.0005000 0.0023390 -0.0010000 0.0037271 -0.0020000 0.0058025 -0.0040000 0.0089238 -0.0080000 0.0137350 -0.0120000 0.0178581 -0.0200000 0.0253735 -0.0300000 0.0330215 -0.0400000 0.0391283 -0.0500000 0.0442753 -0.0600000 0.0487571 -0.0800000 0.0564308 -0.1000000 0.0629981 -0.1200000 0.0686204 -0.1400000 0.0734360 -0.1600000 0.0775707 -0.1800000 0.0810687 -0.2000000 0.0839202 -0.2200000 0.0861433 -0.2400000 0.0878308 -0.2600000 0.0890840 -0.2800000 0.0900016 -0.3000000 0.0906804 -0.3200000 0.0911857 -0.3400000 0.0915079 -0.3600000 0.0916266 -0.3800000 0.0915212 -0.4000000 0.0911712 -0.4200000 0.0905657 -0.4400000 0.0897175 -0.4600000 0.0886427 -0.4800000 0.0873572 -0.5000000 0.0858772 -0.5200000 0.0842145 -0.5400000 0.0823712 -0.5600000 0.0803480 -0.5800000 0.0781451 -0.6000000 0.0757633 -0.6200000 0.0732055 -0.6400000 0.0704822 -0.6600000 0.0676046 -0.6800000 0.0645843 -0.7000000 0.0614329 -0.7200000 0.0581599 -0.7400000 0.0547675 -0.7600000 0.0512565 -0.7800000 0.0476281 -0.8000000 0.0438836 -0.8200000 0.0400245 -0.8400000 0.0360536 -0.8600000 0.0319740 -0.8800000 0.0277891 -0.9000000 0.0235025 -0.9200000 0.0191156 -0.9400000 0.0146239 -0.9600000 0.0100232 -0.9700000 0.0076868 -0.9800000 0.0053335 -0.9900000 0.0029690 -1.0000000 0.0005993 -0.0000000 0.0000000 -0.0005000 -.0046700 -0.0010000 -.0059418 -0.0020000 -.0078113 -0.0040000 -.0105126 -0.0080000 -.0142862 -0.0120000 -.0169733 -0.0200000 -.0202723 -0.0300000 -.0226056 -0.0400000 -.0245211 -0.0500000 -.0260452 -0.0600000 -.0271277 -0.0800000 -.0284595 -0.1000000 -.0293786 -0.1200000 -.0299633 -0.1400000 -.0302404 -0.1600000 -.0302546 -0.1800000 -.0300490 -0.2000000 -.0296656 -0.2200000 -.0291445 -0.2400000 -.0285181 -0.2600000 -.0278164 -0.2800000 -.0270696 -0.3000000 -.0263079 -0.3200000 -.0255565 -0.3400000 -.0248176 -0.3600000 -.0240870 -0.3800000 -.0233606 -0.4000000 -.0226341 -0.4200000 -.0219042 -0.4400000 -.0211708 -0.4600000 -.0204353 -0.4800000 -.0196986 -0.5000000 -.0189619 -0.5200000 -.0182262 -0.5400000 -.0174914 -0.5600000 -.0167572 -0.5800000 -.0160232 -0.6000000 -.0152893 -0.6200000 -.0145551 -0.6400000 -.0138207 -0.6600000 -.0130862 -0.6800000 -.0123515 -0.7000000 -.0116169 -0.7200000 -.0108823 -0.7400000 -.0101478 -0.7600000 -.0094133 -0.7800000 -.0086788 -0.8000000 -.0079443 -0.8200000 -.0072098 -0.8400000 -.0064753 -0.8600000 -.0057408 -0.8800000 -.0050063 -0.9000000 -.0042718 -0.9200000 -.0035373 -0.9400000 -.0028028 -0.9600000 -.0020683 -0.9700000 -.0017011 -0.9800000 -.0013339 -0.9900000 -.0009666 -1.0000000 -.0005993 \ No newline at end of file From 966232c172aaf96d566fa30803212648870d4488 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 09:49:13 -0400 Subject: [PATCH 082/147] Delete aviary/subsystems/mass/simple_mass/Custom_Fuselage.dat --- .../mass/simple_mass/Custom_Fuselage.dat | 179 ------------------ 1 file changed, 179 deletions(-) delete mode 100644 aviary/subsystems/mass/simple_mass/Custom_Fuselage.dat diff --git a/aviary/subsystems/mass/simple_mass/Custom_Fuselage.dat b/aviary/subsystems/mass/simple_mass/Custom_Fuselage.dat deleted file mode 100644 index ce85fe585..000000000 --- a/aviary/subsystems/mass/simple_mass/Custom_Fuselage.dat +++ /dev/null @@ -1,179 +0,0 @@ -0.0 0.5 -0.5 0.45 -1.0 0.4 -1.5 0.6 -2.0 0.3 -2.5 0.35 - -class CenterOfGravity3D(om.ExplicitComponent): - def initialize(self): - self.options.declare('num_sections', types=int, default=50) - self.options.declare('airfoil_type', types=str, default='2412') - self.options.declare('material', default='metal', values=['wood', 'metal', 'carbon_fiber']) - self.options.declare('airfoil_data_file', default=None, types=str) - - def setup(self): - num_sections = self.options['num_sections'] - - # Inputs - self.add_input('span', val=10.0, units='m') - self.add_input('root_chord', val=2.0, units='m') - self.add_input('tip_chord', val=1.0, units='m') - self.add_input('twist', val=np.zeros(num_sections), units='deg') - self.add_input('thickness', val=0.2, units='m') - - # Outputs - self.add_output('center_of_gravity_x', val=0.0, units='m') - self.add_output('center_of_gravity_y', val=0.0, units='m') - self.add_output('center_of_gravity_z', val=0.0, units='m') - self.add_output('total_weight', val=0.0, units='kg') - self.add_output('x_coords', val=np.zeros(num_sections), units='m') - self.add_output('y_coords', val=np.zeros(num_sections), units='m') - self.add_output('z_coords', val=np.zeros(num_sections), units='m') - - def setup_partials(self): - num_sections = self.options['num_sections'] - - self.declare_partials(of=['center_of_gravity_x', 'center_of_gravity_y', 'center_of_gravity_z'], - wrt=['span', 'root_chord', 'tip_chord', 'thickness']) - self.declare_partials(of='total_weight', wrt=['span', 'root_chord', 'tip_chord', 'thickness']) - self.declare_partials(of='x_coords', wrt=['twist'], rows=np.arange(num_sections), cols=np.arange(num_sections)) - self.declare_partials(of='y_coords', wrt=['span'], rows=np.arange(num_sections), cols=np.arange(num_sections)) - self.declare_partials(of='z_coords', wrt=['twist'], rows=np.arange(num_sections), cols=np.arange(num_sections)) - - def compute_partials(self, inputs, partials): - """Compute the analytical derivatives of outputs with respect to inputs.""" - span = inputs['span'] - root_chord = inputs['root_chord'] - tip_chord = inputs['tip_chord'] - thickness = inputs['thickness'] - num_sections = self.options['num_sections'] - - # Compute section locations along the span - span_locations = np.linspace(0, span, num_sections) - chord_lengths = root_chord - (root_chord - tip_chord) * (span_locations / span) - dchord_dspan = (tip_chord - root_chord) / span # Chord gradient w.r.t. span - - # Compute derivatives of total weight - total_weight = np.sum(chord_lengths * thickness * (span / num_sections)) - d_weight_dspan = np.sum(dchord_dspan * thickness * (span / num_sections)) + np.sum(chord_lengths * thickness / num_sections) - d_weight_droot_chord = np.sum(thickness * (span / num_sections)) - d_weight_dtip_chord = np.sum(thickness * (span / num_sections) * (span_locations / span)) - d_weight_dthickness = np.sum(chord_lengths * (span / num_sections)) - - partials['total_weight', 'span'] = d_weight_dspan - partials['total_weight', 'root_chord'] = d_weight_droot_chord - partials['total_weight', 'tip_chord'] = d_weight_dtip_chord - partials['total_weight', 'thickness'] = d_weight_dthickness - - # Compute derivatives of center of gravity coordinates - centroid_xs = chord_lengths / 4 # Approximate centroid of airfoil section - centroid_ys = span_locations - centroid_zs = np.zeros_like(span_locations) # Assuming zero camber - - total_moment_x = np.sum(centroid_xs * chord_lengths * thickness * (span / num_sections)) - total_moment_y = np.sum(centroid_ys * chord_lengths * thickness * (span / num_sections)) - total_moment_z = np.sum(centroid_zs * chord_lengths * thickness * (span / num_sections)) - - partials['center_of_gravity_x', 'span'] = (np.sum(dchord_dspan * centroid_xs * thickness * (span / num_sections)) - - total_moment_x / total_weight * d_weight_dspan) / total_weight - partials['center_of_gravity_x', 'root_chord'] = (np.sum(centroid_xs * thickness * (span / num_sections)) - - total_moment_x / total_weight * d_weight_droot_chord) / total_weight - partials['center_of_gravity_x', 'tip_chord'] = (np.sum(centroid_xs * thickness * (span / num_sections) * (span_locations / span)) - - total_moment_x / total_weight * d_weight_dtip_chord) / total_weight - partials['center_of_gravity_x', 'thickness'] = (np.sum(centroid_xs * chord_lengths * (span / num_sections)) - - total_moment_x / total_weight * d_weight_dthickness) / total_weight - - partials['center_of_gravity_y', 'span'] = (np.sum(dchord_dspan * centroid_ys * thickness * (span / num_sections)) - - total_moment_y / total_weight * d_weight_dspan) / total_weight - partials['center_of_gravity_y', 'root_chord'] = (np.sum(centroid_ys * thickness * (span / num_sections)) - - total_moment_y / total_weight * d_weight_droot_chord) / total_weight - partials['center_of_gravity_y', 'tip_chord'] = (np.sum(centroid_ys * thickness * (span / num_sections) * (span_locations / span)) - - total_moment_y / total_weight * d_weight_dtip_chord) / total_weight - partials['center_of_gravity_y', 'thickness'] = (np.sum(centroid_ys * chord_lengths * (span / num_sections)) - - total_moment_y / total_weight * d_weight_dthickness) / total_weight - - partials['center_of_gravity_z', 'span'] = 0 # No camber means no variation - partials['center_of_gravity_z', 'root_chord'] = 0 - partials['center_of_gravity_z', 'tip_chord'] = 0 - partials['center_of_gravity_z', 'thickness'] = 0 - - # Compute derivatives of x_coords and z_coords w.r.t. twist - twist = np.radians(inputs['twist']) - for i in range(num_sections): - partials['x_coords', 'twist'][i] = -centroid_xs[i] * np.sin(twist[i]) - partials['z_coords', 'twist'][i] = centroid_xs[i] * np.cos(twist[i]) - - -def compute_partials(self, inputs, partials): - """Compute the analytical derivatives of outputs with respect to inputs.""" - span = inputs['span'] - root_chord = inputs['root_chord'] - tip_chord = inputs['tip_chord'] - thickness = inputs['thickness'] - twist = np.radians(inputs['twist']) # Convert twist from degrees to radians - num_sections = self.options['num_sections'] - - # Spanwise locations - span_locations = np.linspace(0, span, num_sections) - - # Chord length variation (linear taper) - chord_lengths = root_chord - (root_chord - tip_chord) * (span_locations / span) - dchord_dspan = (tip_chord - root_chord) / span # Chord gradient w.r.t. span - - # Compute centroid locations - centroid_xs = chord_lengths / 4 # Approximate centroid X-location (quarter chord) - centroid_ys = span_locations # The spanwise locations - centroid_zs = np.zeros_like(span_locations) # Assume zero camber for now - - # Compute rotated centroid due to twist - rotated_xs = centroid_xs * np.cos(twist) - centroid_zs * np.sin(twist) - rotated_zs = centroid_xs * np.sin(twist) + centroid_zs * np.cos(twist) - - # Compute weight of each section - section_areas = chord_lengths * thickness # Simple approximation - section_volumes = section_areas * (span / num_sections) # Volume of each section - section_weights = section_volumes # Assuming uniform density - - # Compute total weight - total_weight = np.sum(section_weights) - - # Compute moments for CoG - total_moment_x = np.sum(rotated_xs * section_weights) - total_moment_y = np.sum(centroid_ys * section_weights) - total_moment_z = np.sum(rotated_zs * section_weights) - - # Compute derivatives of weight - d_weight_dspan = np.sum(dchord_dspan * thickness * (span / num_sections)) + np.sum(chord_lengths * thickness / num_sections) - d_weight_droot_chord = np.sum(thickness * (span / num_sections)) - d_weight_dtip_chord = np.sum(thickness * (span / num_sections) * (span_locations / span)) - d_weight_dthickness = np.sum(chord_lengths * (span / num_sections)) - - # Compute derivatives of moments - d_moment_x_dspan = np.sum((dchord_dspan / 4) * np.cos(twist) * section_weights) - d_moment_y_dspan = np.sum(centroid_ys * (section_weights / span)) # dY/dspan is straightforward - d_moment_z_dspan = np.sum((dchord_dspan / 4) * np.sin(twist) * section_weights) - - # Compute partials for CoG X - partials['center_of_gravity_x', 'span'] = (d_moment_x_dspan - total_moment_x / total_weight * d_weight_dspan) / total_weight - partials['center_of_gravity_x', 'root_chord'] = (np.sum(thickness * (span / num_sections) / 4) - total_moment_x / total_weight * d_weight_droot_chord) / total_weight - partials['center_of_gravity_x', 'tip_chord'] = (np.sum(thickness * (span / num_sections) * (span_locations / span) / 4) - total_moment_x / total_weight * d_weight_dtip_chord) / total_weight - partials['center_of_gravity_x', 'thickness'] = (np.sum(chord_lengths * (span / num_sections) / 4) - total_moment_x / total_weight * d_weight_dthickness) / total_weight - - # Compute partials for CoG Y - partials['center_of_gravity_y', 'span'] = (d_moment_y_dspan - total_moment_y / total_weight * d_weight_dspan) / total_weight - partials['center_of_gravity_y', 'root_chord'] = -total_moment_y / total_weight * d_weight_droot_chord / total_weight - partials['center_of_gravity_y', 'tip_chord'] = -total_moment_y / total_weight * d_weight_dtip_chord / total_weight - partials['center_of_gravity_y', 'thickness'] = -total_moment_y / total_weight * d_weight_dthickness / total_weight - - # Compute partials for CoG Z - partials['center_of_gravity_z', 'span'] = (d_moment_z_dspan - total_moment_z / total_weight * d_weight_dspan) / total_weight - partials['center_of_gravity_z', 'root_chord'] = (np.sum(thickness * (span / num_sections) / 4 * np.sin(twist)) - total_moment_z / total_weight * d_weight_droot_chord) / total_weight - partials['center_of_gravity_z', 'tip_chord'] = (np.sum(thickness * (span / num_sections) * (span_locations / span) / 4 * np.sin(twist)) - total_moment_z / total_weight * d_weight_dtip_chord) / total_weight - partials['center_of_gravity_z', 'thickness'] = (np.sum(chord_lengths * (span / num_sections) / 4 * np.sin(twist)) - total_moment_z / total_weight * d_weight_dthickness) / total_weight - - # Compute derivatives of x_coords and z_coords w.r.t. twist - for i in range(num_sections): - partials['x_coords', 'twist'][i] = -centroid_xs[i] * np.sin(twist[i]) # dx/dtwist - partials['z_coords', 'twist'][i] = centroid_xs[i] * np.cos(twist[i]) # dz/dtwist - From 0abf857378b1c5a0d257c9122a20c55c1fa5cd4c Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 09:49:20 -0400 Subject: [PATCH 083/147] Delete aviary/subsystems/mass/simple_mass/airfoil_data_test.dat --- .../mass/simple_mass/airfoil_data_test.dat | 124 ------------------ 1 file changed, 124 deletions(-) delete mode 100644 aviary/subsystems/mass/simple_mass/airfoil_data_test.dat diff --git a/aviary/subsystems/mass/simple_mass/airfoil_data_test.dat b/aviary/subsystems/mass/simple_mass/airfoil_data_test.dat deleted file mode 100644 index 2e2249c98..000000000 --- a/aviary/subsystems/mass/simple_mass/airfoil_data_test.dat +++ /dev/null @@ -1,124 +0,0 @@ - 0.00000 0.00001 - 0.00050 0.00430 - 0.00100 0.00600 - 0.00200 0.00903 - 0.00300 0.01127 - 0.00500 0.01490 - 0.00750 0.01861 - 0.01000 0.02180 - 0.02000 0.03186 - 0.03000 0.03967 - 0.04000 0.04688 - 0.05000 0.05192 - 0.06000 0.05698 - 0.07000 0.06110 - 0.08000 0.06562 - 0.09000 0.06937 - 0.10000 0.07280 - 0.12000 0.07886 - 0.14000 0.08401 - 0.16000 0.08839 - 0.18000 0.09211 - 0.20000 0.09525 - 0.22000 0.09786 - 0.24000 0.10000 - 0.26000 0.10173 - 0.28000 0.10313 - 0.30000 0.10418 - 0.34000 0.10542 - 0.36000 0.10632 - 0.38000 0.10687 - 0.40000 0.10700 - 0.44000 0.10656 - 0.46000 0.10600 - 0.48000 0.10526 - 0.50000 0.10423 - 0.54000 0.10154 - 0.56000 0.09965 - 0.58000 0.09795 - 0.60000 0.09587 - 0.64000 0.09125 - 0.66000 0.08872 - 0.68000 0.08605 - 0.70000 0.08322 - 0.74000 0.07789 - 0.76000 0.07477 - 0.78000 0.07028 - 0.80000 0.06668 - 0.82000 0.06262 - 0.84000 0.05834 - 0.86000 0.05368 - 0.88000 0.04856 - 0.90000 0.04299 - 0.91000 0.03997 - 0.92000 0.03686 - 0.93000 0.03364 - 0.94000 0.03032 - 0.95000 0.02689 - 0.96000 0.02335 - 0.97000 0.01968 - 0.98000 0.01570 - 0.99000 0.01171 - 1.00000 0.00720 - 0.00000 0.00000 - 0.00050 -0.00377 - 0.00100 -0.00519 - 0.00200 -0.00709 - 0.00300 -0.00842 - 0.00500 -0.01044 - 0.00750 -0.01230 - 0.01000 -0.01376 - 0.02000 -0.01767 - 0.03000 -0.02006 - 0.04000 -0.02109 - 0.05000 -0.02283 - 0.06000 -0.02353 - 0.07000 -0.02417 - 0.08000 -0.02450 - 0.09000 -0.02466 - 0.10000 -0.02469 - 0.12000 -0.02440 - 0.14000 -0.02374 - 0.16000 -0.02279 - 0.18000 -0.02159 - 0.20000 -0.02030 - 0.22000 -0.01901 - 0.24000 -0.01786 - 0.26000 -0.01688 - 0.28000 -0.01607 - 0.30000 -0.01536 - 0.34000 -0.01389 - 0.36000 -0.01344 - 0.38000 -0.01279 - 0.40000 -0.01216 - 0.44000 -0.01105 - 0.46000 -0.01060 - 0.48000 -0.01020 - 0.50000 -0.00985 - 0.54000 -0.00919 - 0.56000 -0.00888 - 0.58000 -0.00856 - 0.60000 -0.00824 - 0.64000 -0.00756 - 0.66000 -0.00721 - 0.68000 -0.00687 - 0.70000 -0.00658 - 0.74000 -0.00619 - 0.76000 -0.00611 - 0.78000 -0.00609 - 0.80000 -0.00611 - 0.82000 -0.00614 - 0.84000 -0.00621 - 0.86000 -0.00633 - 0.88000 -0.00653 - 0.90000 -0.00683 - 0.91000 -0.00701 - 0.92000 -0.00721 - 0.93000 -0.00742 - 0.94000 -0.00753 - 0.95000 -0.00785 - 0.96000 -0.00807 - 0.97000 -0.00829 - 0.98000 -0.00882 - 0.99000 -0.00976 - 1.00000 -0.01070 \ No newline at end of file From faa5486673e531c8e5e0bf457925182b7a51ca12 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 09:49:32 -0400 Subject: [PATCH 084/147] Delete aviary/subsystems/mass/simple_mass/six_dof_EOM.py --- .../mass/simple_mass/six_dof_EOM.py | 405 ------------------ 1 file changed, 405 deletions(-) delete mode 100644 aviary/subsystems/mass/simple_mass/six_dof_EOM.py diff --git a/aviary/subsystems/mass/simple_mass/six_dof_EOM.py b/aviary/subsystems/mass/simple_mass/six_dof_EOM.py deleted file mode 100644 index 735d140fc..000000000 --- a/aviary/subsystems/mass/simple_mass/six_dof_EOM.py +++ /dev/null @@ -1,405 +0,0 @@ -import numpy as np -import openmdao.api as om - -class SixDOF_EOM(om.ExplicitComponent): - """ - Six DOF EOM component, with particular emphasis for rotorcraft. - ASSUMPTIONS: - - Assume Flat Earth model (particularly for rotorcraft) - - Earth is the internal f.o.r. - - Gravity is constant and normal to the tangent plane (Earth's surface) -- g = (0 0 G)^T - - (aircraft) mass is constant - - aircraft is a rigid body - - Symmetry in the xz plane (for moment of inertia matrix -- J_xy = J_yx = J_zy = J_yz = 0) - - Reference: https://youtu.be/hr_PqdkG6XY?si=_hFAZZMnk58eV9GJ - - """ - - def setup(self): - self.add_input( - 'mass', - val=0.0, - units='kg', - desc="mass -- assume constant" - ) - - self.add_input( - 'axial_vel', - val=0.0, - units='m/s', # meters per second - desc="axial velocity of CM wrt inertial CS resolved in aircraft body fixed CS" - ) - - self.add_input( - 'lat_vel', - val=0.0, - units='m/s', - desc="lateral velocity of CM wrt inertial CS resolved in aircraft body fixed CS" - ) - - self.add_input( - 'vert_vel', - val=0.0, - units='m/s', - desc="vertical velocity of CM wrt inertial CS resolved in aircraft body fixed CS" - ) - - self.add_input( - 'roll_ang_vel', - val=0.0, - units='rad/s', # radians per second - desc="roll angular velocity of body fixed CS wrt intertial CS" - ) - - self.add_input( - 'pitch_ang_vel', - val=0.0, - units='rad/s', - desc="pitch angular velocity of body fixed CS wrt intertial CS" - ) - - self.add_input( - 'yaw_ang_vel', - val=0.0, - units='rad/s', - desc="yaw angular velocity of body fixed CS wrt intertial CS" - ) - - self.add_input( - 'roll', - val=0.0, - units='rad', # radians - desc="roll angle" - ) - - self.add_input( - 'pitch', - val=0.0, - units='rad', - desc="pitch angle" - ) - - self.add_input( - 'yaw', - val=0.0, - units='rad', - desc="yaw angle" - ) - - self.add_input( - 'x', - val=0.0, - units='m', - desc="x-axis position of aircraft resolved in North-East-Down (NED) CS" - ) - - self.add_input( - 'y', - val=0.0, - units='m', - desc="y-axis position of aircraft resolved in NED CS" - ) - - self.add_input( - 'z', - val=0.0, - units='m', - desc="z-axis position of aircraft resolved in NED CS" - ) - - self.add_input( - 'time', - val=0.0, - desc="scalar time in seconds" - ) - - self.add_input( - 'g', - val=9.81, - units='m/s**2', - desc="acceleration due to gravity" - ) - - self.add_input( - 'Fx_ext', - val=0.0, - units='N', - desc="external forces in the x direciton" - ) - - self.add_input( - 'Fy_ext', - val=0.0, - units='N', - desc="external forces in the y direction" - ) - - self.add_input( - 'Fz_ext', - val=0.0, - units='N', - desc="external forces in the z direction" - ) - - self.add_input( - 'lx_ext', - val=0.0, - units='kg*m**2/s**2', # kg times m^2 / s^2 - desc="external moments in the x direction" - ) - - self.add_input( - 'ly_ext', - val=0.0, - units='kg*m**2/s**2', - desc="external moments in the y direction" - ) - - self.add_input( - 'lz_ext', - val=0.0, - units='kg*m**2/s**2', - desc="external moments in the z direction" - ) - - # Below are the necessary components for the moment of inertia matrix (J) - # Only xx, yy, zz, and xz are needed (xy and yz are 0 with assumptions) - # For now, these are separated. - # TODO: Rewrite J and EOM in matrix form - - self.add_input( - 'J_xz', - val=0.0, - units='kg*m**2', - desc="x-z (top right and bottom left corner of 3x3 matrix, assuming symmetry) " \ - "component" - ) - - self.add_input( - 'J_xx', - val=0.0, - units='kg*m**2', - desc="first diag component" - ) - - self.add_input( - 'J_yy', - val=0.0, - units='kg*m**2', - desc="second diag component" - ) - - self.add_input( - 'J_zz', - val=0.0, - units='kg*m**2', - desc="third diag component" - ) - - # Outputs - - self.add_output( - 'dx_accel', - val=0.0, - units='m/s**2', # meters per seconds squared - desc="x-axis (roll-axis) velocity equation, " \ - "state: axial_vel" - ) - - self.add_output( - 'dy_accel', - val=0.0, - units='m/s**2', - desc="y-axis (pitch axis) velocity equation, " \ - "state: lat_vel" - ) - - self.add_output( - 'dz_accel', - val=0.0, - units='m/s**2', - desc="z-axis (yaw axis) velocity equation, " \ - "state: vert_vel" - ) - - self.add_output( - 'roll_accel', - val=0.0, - units='rad/s**2', # radians per second squared - desc="roll equation, " \ - "state: roll_ang_vel" - ) - - self.add_output( - 'pitch_accel', - val=0.0, - units='rad/s**2', - desc="pitch equation, " \ - "state: pitch_ang_vel" - ) - - self.add_output( - 'yaw_accel', - val=0.0, - units='rad/s**2', - desc="yaw equation, " \ - "state: yaw_ang_vel" - ) - - self.add_output( - 'roll_angle_rate_eq', - val=0.0, - units='rad/s', - desc="Euler angular roll rate" - ) - - self.add_output( - 'pitch_angle_rate_eq', - val=0.0, - units='rad/s', - desc="Euler angular pitch rate" - ) - - self.add_output( - 'yaw_angle_rate_eq', - val=0.0, - units='rad/s', - desc="Euler angular yaw rate" - ) - - self.add_output( - 'dx_dt', - val=0.0, - units='m/s', - desc="x-position derivative of aircraft COM wrt point in NED CS" - ) - - self.add_output( - 'dy_dt', - val=0.0, - units='m/s', - desc="y-position derivative of aircraft COM wrt point in NED CS" - ) - - self.add_output( - 'dz_dt', - val=0.0, - units='m/s', - desc="z-position derivative of aircraft COM wrt point in NED CS" - ) - - def compute(self, inputs, outputs): - """ - Compute function for EOM. - TODO: Same as above, potentially rewrite equations for \ - matrix form, and add potential assymetry to moment \ - of inertia matrix. - - """ - - # inputs - - mass = inputs['mass'] - axial_vel = inputs['axial_vel'] # u - lat_vel = inputs['lat_vel'] # v - vert_vel = inputs['vert_vel'] # w - roll_ang_vel = inputs['roll_ang_vel'] # p - pitch_ang_vel = inputs['pitch_ang_vel'] # q - yaw_ang_vel = inputs['yaw_ang_vel'] # r - roll = inputs['roll'] # phi - pitch = inputs['pitch'] # theta - yaw = inputs['yaw'] # psi - x = inputs['x'] # p1 - y = inputs['y'] # p2 - z = inputs['z'] # p3 - time = inputs['time'] - g = inputs['g'] - Fx_ext = inputs['Fx_ext'] - Fy_ext = inputs['Fy_ext'] - Fz_ext = inputs['Fz_ext'] - lx_ext = inputs['lx_ext'] # l - ly_ext = inputs['ly_ext'] # m - lz_ext = inputs['lz_ext'] # n - J_xz = inputs['J_xz'] - J_xx = inputs['J_xx'] - J_yy = inputs['J_yy'] - J_zz = inputs['J_zz'] - - # Resolve gravity in body coordinate system -- denoted with subscript 'b' - gx_b = -np.sin(pitch) * g - gy_b = np.sin(roll) * np.cos(pitch) * g - gz_b = np.cos(roll) * np.cos(pitch) * g - - # TODO: could add external forces and moments here if needed - - # Denominator for roll and yaw rate equations - Den = J_xx * J_zz - J_xz**2 - - # roll-axis velocity equation - - dx_accel = 1 / mass * Fx_ext + gx_b - vert_vel * pitch_ang_vel + lat_vel * yaw_ang_vel - - # pitch-axis velocity equation - - dy_accel = 1 / mass * Fy_ext + gy_b - axial_vel * yaw_ang_vel + vert_vel * roll_ang_vel - - # yaw-axis velocity equation - - dz_accel = 1 / mass * Fz_ext + gz_b - lat_vel * roll_ang_vel + axial_vel * pitch_ang_vel - - # Roll equation - - roll_accel = (J_xz * (J_xx - J_yy + J_zz) * roll_ang_vel * pitch_ang_vel - - (J_zz * (J_zz - J_yy) + J_xz**2) * pitch_ang_vel * yaw_ang_vel + - J_zz * lx_ext + - J_xz * lz_ext) / Den - - # Pitch equation - - pitch_accel = ((J_zz - J_xx) * roll_ang_vel * yaw_ang_vel - - J_xz * (roll_ang_vel**2 - yaw_ang_vel**2) + ly_ext) / J_yy - - # Yaw equation - - yaw_accel = ((J_xx * (J_xx - J_yy) + J_xz**2) * roll_ang_vel * pitch_ang_vel + - J_xz * (J_xx - J_yy + J_zz) * pitch_ang_vel * yaw_ang_vel + - J_xz * lx_ext + - J_xz * lz_ext) / Den - - # Kinematic equations - - roll_angle_rate_eq = roll_ang_vel + np.sin(roll) * np.tan(pitch) * pitch_ang_vel + \ - np.cos(roll) * np.tan(pitch) * yaw_ang_vel - - pitch_angle_rate_eq = np.cos(roll) * pitch_ang_vel - np.sin(roll) * yaw_ang_vel - - yaw_angle_rate_eq = np.sin(roll) / np.cos(pitch) * pitch_ang_vel + \ - np.cos(roll) / np.cos(pitch) * yaw_ang_vel - - # Position equations - - dx_dt = np.cos(pitch) * np.cos(yaw) * axial_vel + \ - (-np.cos(roll) * np.sin(yaw) + np.sin(roll) * np.sin(pitch) * np.cos(yaw)) * lat_vel + \ - (np.sin(roll) * np.sin(yaw) + np.cos(roll) * np.sin(pitch) * np.cos(yaw)) * vert_vel - - dy_dt = np.cos(pitch) * np.sin(yaw) * axial_vel + \ - (np.cos(roll) * np.cos(yaw) + np.sin(roll) * np.sin(pitch) * np.sin(yaw)) * lat_vel + \ - (-np.sin(roll) * np.cos(yaw) + np.cos(roll) * np.sin(pitch) * np.sin(yaw)) * vert_vel - - dz_dt = -np.sin(pitch) * axial_vel + \ - np.sin(roll) * np.cos(pitch) * lat_vel + \ - np.cos(roll) * np.cos(pitch) * vert_vel - - outputs['dx_accel'] = dx_accel - outputs['dy_accel'] = dy_accel - outputs['dz_accel'] = dz_accel - outputs['roll_accel'] = roll_accel - outputs['pitch_accel'] = pitch_accel - outputs['yaw_accel'] = yaw_accel - outputs['roll_angle_rate_eq'] = roll_angle_rate_eq - outputs['pitch_angle_rate_eq'] = pitch_angle_rate_eq - outputs['yaw_angle_rate_eq'] = yaw_angle_rate_eq - outputs['dx_dt'] = dx_dt - outputs['dy_dt'] = dy_dt - outputs['dz_dt'] = dz_dt \ No newline at end of file From ae7b2183db6457ddebde8b8ad8db04fd78c9ce1f Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 09:49:51 -0400 Subject: [PATCH 085/147] Delete aviary/mission/sixdof directory --- aviary/mission/sixdof/force_component_calc.py | 261 ------ aviary/mission/sixdof/plottest.py | 10 - aviary/mission/sixdof/six_dof_EOM.py | 740 ------------------ aviary/mission/sixdof/six_dof_ODE.py | 167 ---- aviary/mission/sixdof/test_mission_6dof.py | 186 ----- 5 files changed, 1364 deletions(-) delete mode 100644 aviary/mission/sixdof/force_component_calc.py delete mode 100644 aviary/mission/sixdof/plottest.py delete mode 100644 aviary/mission/sixdof/six_dof_EOM.py delete mode 100644 aviary/mission/sixdof/six_dof_ODE.py delete mode 100644 aviary/mission/sixdof/test_mission_6dof.py diff --git a/aviary/mission/sixdof/force_component_calc.py b/aviary/mission/sixdof/force_component_calc.py deleted file mode 100644 index 8b43dee3f..000000000 --- a/aviary/mission/sixdof/force_component_calc.py +++ /dev/null @@ -1,261 +0,0 @@ -import numpy as np -import openmdao.api as om - - -class ForceComponentResolver(om.ExplicitComponent): - """ - This class will resolve forces (thrust, drag, lift, etc.) into their - respective x,y,z components for the 6 DOF equations of motion. - - This class assumes that the total force is given and needs to be resolved - into the separate components. - - """ - - def initialize(self): - self.options.declare('num_nodes', types=int) - - def setup(self): - nn = self.options['num_nodes'] - - # inputs - - self.add_input( - 'u', - val=np.zeros(nn), - units='m/s', - desc="axial velocity" - ) - - self.add_input( - 'v', - val=np.zeros(nn), - units='m/s', - desc="lateral velocity" - ) - - self.add_input( - 'w', - val=np.zeros(nn), - units='m/s', - desc="vertical velocity" - ) - - self.add_input( - 'drag', - val=np.zeros(nn), - units='N', - desc="Drag vector (unresolved)" - ) - - self.add_input( - 'thrust', - val=np.zeros(nn), - units='N', - desc="Thrust vector (unresolved)" - ) - - self.add_input( - 'lift', - val=np.zeros(nn), - units='N', - desc="Lift vector (unresolved)" - ) - - self.add_input( - 'side', - val=np.zeros(nn), - units='N', - desc="Side vector (unresolved)" - ) - - # self.add_input( - # 'true_air_speed', - # val=np.zeros(nn), - # units='m/s', - # desc="True air speed" - # ) # This is an aviary variable - - # outputs - - self.add_output( - 'Fx', - val=np.zeros(nn), - units='N', - desc="x-comp of final force" - ) - - self.add_output( - 'Fy', - val=np.zeros(nn), - units='N', - desc="y-comp of final force" - ) - - self.add_output( - 'Fz', - val=np.zeros(nn), - units='N', - desc="z-comp of final force" - ) - - ar = np.arange(nn) - - self.declare_partials(of='Fx', wrt='u', rows=ar, cols=ar) - self.declare_partials(of='Fx', wrt='v', rows=ar, cols=ar) - self.declare_partials(of='Fx', wrt='w', rows=ar, cols=ar) - self.declare_partials(of='Fx', wrt='drag', rows=ar, cols=ar) - self.declare_partials(of='Fx', wrt='lift', rows=ar, cols=ar) - self.declare_partials(of='Fx', wrt='side', rows=ar, cols=ar) - - self.declare_partials(of='Fy', wrt='u', rows=ar, cols=ar) - self.declare_partials(of='Fy', wrt='v', rows=ar, cols=ar) - self.declare_partials(of='Fy', wrt='w', rows=ar, cols=ar) - self.declare_partials(of='Fy', wrt='drag', rows=ar, cols=ar) - self.declare_partials(of='Fy', wrt='lift', rows=ar, cols=ar) - self.declare_partials(of='Fy', wrt='side', rows=ar, cols=ar) - - self.declare_partials(of='Fz', wrt='u', rows=ar, cols=ar) - self.declare_partials(of='Fz', wrt='v', rows=ar, cols=ar) - self.declare_partials(of='Fz', wrt='w', rows=ar, cols=ar) - self.declare_partials(of='Fz', wrt='drag', rows=ar, cols=ar) - self.declare_partials(of='Fz', wrt='lift', rows=ar, cols=ar) - self.declare_partials(of='Fz', wrt='side', rows=ar, cols=ar) - - def compute(self, inputs, outputs): - - u = inputs['u'] - v = inputs['v'] - w = inputs['w'] - D = inputs['drag'] - T = inputs['thrust'] - L = inputs['lift'] - S = inputs['side'] # side force -- assume 0 for now - - nn = self.options['num_nodes'] - - # true air speed - - V = np.sqrt(u**2 + v**2 + w**2) - - # flight path angle - - # divide by zero checks - if np.any(u == 0): - u[u == 0] = 1e-4 - gamma = np.arctan(w / u) - else: - gamma = np.arctan(w / u) - - # side slip angle - - # divide by zero checks - if ((np.any(u != 0) or np.any(w != 0))) : - beta = np.arctan(v / np.sqrt(u**2 + w**2)) - else: - u[u == 0] = 1.0e-4 - beta = np.arctan(v / np.sqrt(u**2 + w**2)) - - - - - # some trig needed - - cos_a = np.cos(gamma) - cos_b = np.cos(beta) - sin_a = np.sin(gamma) - sin_b = np.sin(beta) - - outputs['Fx'] = -(cos_a * cos_b * D - cos_a * sin_b * S - sin_a * L) - outputs['Fy'] = -(sin_b * D + cos_b * S) - outputs['Fz'] = -(sin_a * cos_b * D + sin_a * sin_b * S + cos_a * L) - - def compute_partials(self, inputs, J): - - u = inputs['u'] - v = inputs['v'] - w = inputs['w'] - D = inputs['drag'] - T = inputs['thrust'] - L = inputs['lift'] - S = inputs['side'] # side force -- assume 0 for now - - V = np.sqrt(u**2 + v**2 + w**2) - - # divide by zero checks - if u == 0: - u = 1e-4 - gamma = np.arctan(w / u) - else: - gamma = np.arctan(w / u) - - # side slip angle - - # divide by zero checks - if ((u != 0 or w != 0)) : - beta = np.arctan(v / np.sqrt(u**2 + w**2)) - else: - u = 1.0e-4 - beta = np.arctan(v / np.sqrt(u**2 + w**2)) - - # note: d/dx arctan(a/x) = -a / (x^2 + a^2) - # note: d/dx arctan(a / sqrt(b^2 + x^2)) = - ax / ((b^2 + x^2 + a^2) * sqrt(b^2 + x^2)) - # note: d/dx arctan(x / sqrt(a^2 + b^2)) = sqrt(a^2 + b^2) / (a^2 + b^2 + x^2) - # note: d/dx arctan(x/a) = a / (a^2 + x^2) - - J['Fx', 'u'] = np.cos(gamma) * np.sin(beta) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * D + \ - np.cos(beta) * np.sin(gamma) * (-w / (w**2 + u**2)) * D + \ - (np.cos(gamma) * np.cos(beta) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * S - np.sin(beta) * np.sin(gamma) * (-w / (w**2 + u**2)) * S) + \ - (np.cos(gamma) * (-w / (w**2 + u**2)) * L) - J['Fx', 'v'] = np.cos(gamma) * np.sin(beta) * (np.sqrt(w**2 + u**2) / V**2) * D + np.cos(gamma) * np.cos(beta) * (np.sqrt(w**2 + u**2) / V**2) * S - J['Fx', 'w'] = np.cos(gamma) * np.sin(beta) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) * D + np.sin(gamma) * np.cos(beta) * (u / (w**2 + u**2)) * D + \ - np.cos(gamma) * np.cos(beta) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) * S - np.sin(gamma) * np.sin(beta) * (u / (w**2 + u**2)) * S + \ - np.cos(gamma) * (u / (w**2 + u**2)) * L - J['Fx', 'drag'] = -np.cos(gamma) * np.cos(beta) - J['Fx', 'lift'] = np.sin(gamma) - J['Fx', 'side'] = np.cos(gamma) * np.sin(beta) - - J['Fy', 'u'] = -np.cos(beta) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * D + np.sin(beta) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * S - J['Fy', 'v'] = -np.cos(beta) * (np.sqrt(w**2 + u**2) / V**2) * D + np.sin(beta) * (np.sqrt(w**2 + u**2) / V**2) * S - J['Fy', 'w'] = -np.cos(beta) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) * D + np.sin(beta) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) * S - J['Fy', 'drag'] = -np.sin(beta) - J['Fy', 'side'] = -np.cos(beta) - - J['Fz', 'u'] = np.sin(gamma) * np.sin(beta) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * D - np.cos(gamma) * np.cos(beta) * (-w / (w**2 + u**2)) * D - \ - np.sin(gamma) * np.cos(beta) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * S - np.cos(gamma) * np.sin(beta) * (-w / (w**2 + u**2)) * S + \ - np.sin(gamma) * (-w / (w**2 + u**2)) * L - J['Fz', 'v'] = np.sin(gamma) * np.sin(beta) * (np.sqrt(w**2 + u**2) / V**2) * D - np.sin(gamma) * np.cos(beta) * (np.sqrt(w**2 + u**2) / V**2) * S - J['Fz', 'w'] = np.sin(gamma) * np.sin(beta) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) * D - np.cos(gamma) * np.cos(beta) * (u / (w**2 + u**2)) * D - \ - np.sin(gamma) * np.cos(beta) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) * S - np.cos(gamma) * np.sin(beta) * (u / (w**2 + u**2)) * S + \ - np.sin(gamma) * (u / (w**2 + u**2)) * L - J['Fz', 'drag'] = -np.sin(gamma) * np.cos(beta) - J['Fz', 'lift'] = -np.cos(gamma) - J['Fz', 'side'] = -np.sin(gamma) * np.sin(beta) - -if __name__ == "__main__": - p = om.Problem() - p.model = om.Group() - des_vars = p.model.add_subsystem('des_vars', om.IndepVarComp(), promotes=['*']) - - des_vars.add_output('u', 0.5, units='m/s') - des_vars.add_output('v', 0.6, units='m/s') - des_vars.add_output('w', 0.7, units='m/s') - des_vars.add_output('drag', 50, units='N') - des_vars.add_output('thrust', 50, units='N') - des_vars.add_output('lift', 60, units='N') - des_vars.add_output('side', 70, units='N') - - p.model.add_subsystem('ForceComponentResolver', ForceComponentResolver(num_nodes=1), promotes=['*']) - - p.setup(check=False, force_alloc_complex=True) - - p.run_model() - - p.check_partials(compact_print=True, show_only_incorrect=True, method='cs') - - - - - - - diff --git a/aviary/mission/sixdof/plottest.py b/aviary/mission/sixdof/plottest.py deleted file mode 100644 index f406812d7..000000000 --- a/aviary/mission/sixdof/plottest.py +++ /dev/null @@ -1,10 +0,0 @@ -# importing mplot3d toolkits, numpy and matplotlib -from mpl_toolkits import mplot3d -import numpy as np -import matplotlib.pyplot as plt - -x = np.linspace(0, 10, 100) -y = x+2 - -plt.plot(x, y) -plt.show() \ No newline at end of file diff --git a/aviary/mission/sixdof/six_dof_EOM.py b/aviary/mission/sixdof/six_dof_EOM.py deleted file mode 100644 index 4b6040ce6..000000000 --- a/aviary/mission/sixdof/six_dof_EOM.py +++ /dev/null @@ -1,740 +0,0 @@ -import numpy as np -import openmdao.api as om - -class SixDOF_EOM(om.ExplicitComponent): - """ - Six DOF EOM component, with particular emphasis for rotorcraft. - ASSUMPTIONS: - - Assume Flat Earth model (particularly for rotorcraft) - - Earth is the internal f.o.r. - - Gravity is constant and normal to the tangent plane (Earth's surface) -- g = (0 0 G)^T - - (aircraft) mass is constant - - aircraft is a rigid body - - Symmetry in the xz plane (for moment of inertia matrix -- J_xy = J_yx = J_zy = J_yz = 0) - - Reference: https://youtu.be/hr_PqdkG6XY?si=_hFAZZMnk58eV9GJ - - """ - - def initialize(self): - self.options.declare('num_nodes', types=int) - - def setup(self): - nn = self.options['num_nodes'] - - self.add_input( - 'mass', - val=np.zeros(nn), - units='kg', - desc="mass -- assume constant" - ) - - self.add_input( - 'axial_vel', - val=np.zeros(nn), - units='m/s', # meters per second - desc="axial velocity of CM wrt inertial CS resolved in aircraft body fixed CS" - ) - - self.add_input( - 'lat_vel', - val=np.zeros(nn), - units='m/s', - desc="lateral velocity of CM wrt inertial CS resolved in aircraft body fixed CS" - ) - - self.add_input( - 'vert_vel', - val=np.zeros(nn), - units='m/s', - desc="vertical velocity of CM wrt inertial CS resolved in aircraft body fixed CS" - ) - - self.add_input( - 'roll_ang_vel', - val=np.zeros(nn), - units='rad/s', # radians per second - desc="roll angular velocity of body fixed CS wrt intertial CS" - ) - - self.add_input( - 'pitch_ang_vel', - val=np.zeros(nn), - units='rad/s', - desc="pitch angular velocity of body fixed CS wrt intertial CS" - ) - - self.add_input( - 'yaw_ang_vel', - val=np.zeros(nn), - units='rad/s', - desc="yaw angular velocity of body fixed CS wrt intertial CS" - ) - - self.add_input( - 'roll', - val=np.zeros(nn), - units='rad', # radians - desc="roll angle" - ) - - self.add_input( - 'pitch', - val=np.zeros(nn), - units='rad', - desc="pitch angle" - ) - - self.add_input( - 'yaw', - val=np.zeros(nn), - units='rad', - desc="yaw angle" - ) - - self.add_input( - 'x', - val=np.zeros(nn), - units='m', - desc="x-axis position of aircraft resolved in North-East-Down (NED) CS" - ) - - self.add_input( - 'y', - val=np.zeros(nn), - units='m', - desc="y-axis position of aircraft resolved in NED CS" - ) - - self.add_input( - 'z', - val=np.zeros(nn), - units='m', - desc="z-axis position of aircraft resolved in NED CS" - ) - - self.add_input( - 'g', - val=9.81, - units='m/s**2', - desc="acceleration due to gravity" - ) - - self.add_input( - 'Fx', - val=np.zeros(nn), - units='N', - desc="external forces in the x direciton" - ) - - self.add_input( - 'Fy', - val=np.zeros(nn), - units='N', - desc="external forces in the y direction" - ) - - self.add_input( - 'Fz', - val=np.zeros(nn), - units='N', - desc="external forces in the z direction" - ) - - self.add_input( - 'lx_ext', - val=np.zeros(nn), - units='kg*m**2/s**2', # kg times m^2 / s^2 - desc="external moments in the x direction" - ) - - self.add_input( - 'ly_ext', - val=np.zeros(nn), - units='kg*m**2/s**2', - desc="external moments in the y direction" - ) - - self.add_input( - 'lz_ext', - val=np.zeros(nn), - units='kg*m**2/s**2', - desc="external moments in the z direction" - ) - - # Below are the necessary components for the moment of inertia matrix (J) - # Only xx, yy, zz, and xz are needed (xy and yz are 0 with assumptions) - # For now, these are separated. - # TODO: Rewrite J and EOM in matrix form - - self.add_input( - 'J_xz', - val=np.zeros(1), - units='kg*m**2', - desc="x-z (top right and bottom left corner of 3x3 matrix, assuming symmetry) " \ - "component" - ) - - self.add_input( - 'J_xx', - val=np.zeros(1), - units='kg*m**2', - desc="first diag component" - ) - - self.add_input( - 'J_yy', - val=np.zeros(1), - units='kg*m**2', - desc="second diag component" - ) - - self.add_input( - 'J_zz', - val=np.zeros(1), - units='kg*m**2', - desc="third diag component" - ) - - # Outputs - - self.add_output( - 'dx_accel', - val=np.zeros(nn), - units='m/s**2', # meters per seconds squared - desc="x-axis (roll-axis) velocity equation, " \ - "state: axial_vel", - tags=['dymos.state_rate_source:axial_vel', 'dymos.state_units:m/s'] - ) - - self.add_output( - 'dy_accel', - val=np.zeros(nn), - units='m/s**2', - desc="y-axis (pitch axis) velocity equation, " \ - "state: lat_vel", - tags=['dymos.state_rate_source:lat_vel', 'dymos.state_units:m/s'] - ) - - self.add_output( - 'dz_accel', - val=np.zeros(nn), - units='m/s**2', - desc="z-axis (yaw axis) velocity equation, " \ - "state: vert_vel", - tags=['dymos.state_rate_source:vert_vel', 'dymos.state_units:m/s'] - ) - - self.add_output( - 'roll_accel', - val=np.zeros(nn), - units='rad/s**2', # radians per second squared - desc="roll equation, " \ - "state: roll_ang_vel", - tags=['dymos.state_rate_source:roll_ang_vel', 'dymos.state_units:rad/s'] - ) - - self.add_output( - 'pitch_accel', - val=np.zeros(nn), - units='rad/s**2', - desc="pitch equation, " \ - "state: pitch_ang_vel", - tags=['dymos.state_rate_source:pitch_ang_vel', 'dymos.state_units:rad/s'] - ) - - self.add_output( - 'yaw_accel', - val=np.zeros(nn), - units='rad/s**2', - desc="yaw equation, " \ - "state: yaw_ang_vel", - tags=['dymos.state_rate_source:yaw_ang_vel', 'dymos.state_units:rad/s'] - ) - - self.add_output( - 'roll_angle_rate_eq', - val=np.zeros(nn), - units='rad/s', - desc="Euler angular roll rate", - tags=['dymos.state_rate_source:roll', 'dymos.state_units:rad'] - ) - - self.add_output( - 'pitch_angle_rate_eq', - val=np.zeros(nn), - units='rad/s', - desc="Euler angular pitch rate", - tags=['dymos.state_rate_source:pitch', 'dymos.state_units:rad'] - ) - - self.add_output( - 'yaw_angle_rate_eq', - val=np.zeros(nn), - units='rad/s', - desc="Euler angular yaw rate", - tags=['dymos.state_rate_source:yaw', 'dymos.state_units:rad'] - ) - - self.add_output( - 'dx_dt', - val=np.zeros(nn), - units='m/s', - desc="x-position derivative of aircraft COM wrt point in NED CS", - tags=['dymos.state_rate_source:x', 'dymos.state_units:m'] - ) - - self.add_output( - 'dy_dt', - val=np.zeros(nn), - units='m/s', - desc="y-position derivative of aircraft COM wrt point in NED CS", - tags=['dymos.state_rate_source:y', 'dymos.state_units:m'] - ) - - self.add_output( - 'dz_dt', - val=np.zeros(nn), - units='m/s', - desc="z-position derivative of aircraft COM wrt point in NED CS", - tags=['dymos.state_rate_source:z', 'dymos.state_units:m'] - ) - - ar = np.arange(nn) - self.declare_partials(of='dx_accel', wrt='mass', rows=ar, cols=ar) - self.declare_partials(of='dx_accel', wrt='Fx', rows=ar, cols=ar) - self.declare_partials(of='dx_accel', wrt='lat_vel', rows=ar, cols=ar) - self.declare_partials(of='dx_accel', wrt='vert_vel', rows=ar, cols=ar) - self.declare_partials(of='dx_accel', wrt='yaw_ang_vel', rows=ar, cols=ar) - self.declare_partials(of='dx_accel', wrt='pitch_ang_vel', rows=ar, cols=ar) - self.declare_partials(of='dx_accel', wrt='g') - self.declare_partials(of='dx_accel', wrt='pitch', rows=ar, cols=ar) - - self.declare_partials(of='dy_accel', wrt='mass', rows=ar, cols=ar) - self.declare_partials(of='dy_accel', wrt='Fy', rows=ar, cols=ar) - self.declare_partials(of='dy_accel', wrt='axial_vel', rows=ar, cols=ar) - self.declare_partials(of='dy_accel', wrt='vert_vel', rows=ar, cols=ar) - self.declare_partials(of='dy_accel', wrt='yaw_ang_vel', rows=ar, cols=ar) - self.declare_partials(of='dy_accel', wrt='roll_ang_vel', rows=ar, cols=ar) - self.declare_partials(of='dy_accel', wrt='g') - self.declare_partials(of='dy_accel', wrt='roll', rows=ar, cols=ar) - self.declare_partials(of='dy_accel', wrt='pitch', rows=ar, cols=ar) - - self.declare_partials(of='dz_accel', wrt='mass', rows=ar, cols=ar) - self.declare_partials(of='dz_accel', wrt='Fz', rows=ar, cols=ar) - self.declare_partials(of='dz_accel', wrt='lat_vel', rows=ar, cols=ar) - self.declare_partials(of='dz_accel', wrt='axial_vel', rows=ar, cols=ar) - self.declare_partials(of='dz_accel', wrt='roll_ang_vel', rows=ar, cols=ar) - self.declare_partials(of='dz_accel', wrt='pitch_ang_vel', rows=ar, cols=ar) - self.declare_partials(of='dz_accel', wrt='g') - self.declare_partials(of='dz_accel', wrt='roll', rows=ar, cols=ar) - self.declare_partials(of='dz_accel', wrt='pitch', rows=ar, cols=ar) - - self.declare_partials(of='roll_accel', wrt='J_xz') - self.declare_partials(of='roll_accel', wrt='J_xx') - self.declare_partials(of='roll_accel', wrt='J_yy') - self.declare_partials(of='roll_accel', wrt='J_zz') - self.declare_partials(of='roll_accel', wrt='roll_ang_vel', rows=ar, cols=ar) - self.declare_partials(of='roll_accel', wrt='pitch_ang_vel', rows=ar, cols=ar) - self.declare_partials(of='roll_accel', wrt='yaw_ang_vel', rows=ar, cols=ar) - self.declare_partials(of='roll_accel', wrt='lx_ext', rows=ar, cols=ar) - self.declare_partials(of='roll_accel', wrt='lz_ext', rows=ar, cols=ar) - - self.declare_partials(of='pitch_accel', wrt='J_xz') - self.declare_partials(of='pitch_accel', wrt='J_xx') - self.declare_partials(of='pitch_accel', wrt='J_yy') - self.declare_partials(of='pitch_accel', wrt='J_zz') - self.declare_partials(of='pitch_accel', wrt='roll_ang_vel', rows=ar, cols=ar) - self.declare_partials(of='pitch_accel', wrt='yaw_ang_vel', rows=ar, cols=ar) - self.declare_partials(of='pitch_accel', wrt='ly_ext', rows=ar, cols=ar) - - self.declare_partials(of='yaw_accel', wrt='J_xz') - self.declare_partials(of='yaw_accel', wrt='J_xx') - self.declare_partials(of='yaw_accel', wrt='J_yy') - self.declare_partials(of='yaw_accel', wrt='J_zz') - self.declare_partials(of='yaw_accel', wrt='roll_ang_vel', rows=ar, cols=ar) - self.declare_partials(of='yaw_accel', wrt='pitch_ang_vel', rows=ar, cols=ar) - self.declare_partials(of='yaw_accel', wrt='yaw_ang_vel', rows=ar, cols=ar) - self.declare_partials(of='yaw_accel', wrt='lx_ext', rows=ar, cols=ar) - self.declare_partials(of='yaw_accel', wrt='lz_ext', rows=ar, cols=ar) - - self.declare_partials(of='roll_angle_rate_eq', wrt='roll_ang_vel', rows=ar, cols=ar) - self.declare_partials(of='roll_angle_rate_eq', wrt='pitch_ang_vel', rows=ar, cols=ar) - self.declare_partials(of='roll_angle_rate_eq', wrt='yaw_ang_vel', rows=ar, cols=ar) - self.declare_partials(of='roll_angle_rate_eq', wrt='roll', rows=ar, cols=ar) - self.declare_partials(of='roll_angle_rate_eq', wrt='pitch', rows=ar, cols=ar) - - self.declare_partials(of='pitch_angle_rate_eq', wrt='pitch_ang_vel', rows=ar, cols=ar) - self.declare_partials(of='pitch_angle_rate_eq', wrt='yaw_ang_vel', rows=ar, cols=ar) - self.declare_partials(of='pitch_angle_rate_eq', wrt='roll', rows=ar, cols=ar) - - self.declare_partials(of='yaw_angle_rate_eq', wrt='pitch_ang_vel', rows=ar, cols=ar) - self.declare_partials(of='yaw_angle_rate_eq', wrt='yaw_ang_vel', rows=ar, cols=ar) - self.declare_partials(of='yaw_angle_rate_eq', wrt='roll', rows=ar, cols=ar) - self.declare_partials(of='yaw_angle_rate_eq', wrt='pitch', rows=ar, cols=ar) - - self.declare_partials(of='dx_dt', wrt='axial_vel', rows=ar, cols=ar) - self.declare_partials(of='dx_dt', wrt='lat_vel', rows=ar, cols=ar) - self.declare_partials(of='dx_dt', wrt='vert_vel', rows=ar, cols=ar) - self.declare_partials(of='dx_dt', wrt='roll', rows=ar, cols=ar) - self.declare_partials(of='dx_dt', wrt='pitch', rows=ar, cols=ar) - self.declare_partials(of='dx_dt', wrt='yaw', rows=ar, cols=ar) - - self.declare_partials(of='dy_dt', wrt='axial_vel', rows=ar, cols=ar) - self.declare_partials(of='dy_dt', wrt='lat_vel', rows=ar, cols=ar) - self.declare_partials(of='dy_dt', wrt='vert_vel', rows=ar, cols=ar) - self.declare_partials(of='dy_dt', wrt='roll', rows=ar, cols=ar) - self.declare_partials(of='dy_dt', wrt='pitch', rows=ar, cols=ar) - self.declare_partials(of='dy_dt', wrt='yaw', rows=ar, cols=ar) - - self.declare_partials(of='dz_dt', wrt='axial_vel', rows=ar, cols=ar) - self.declare_partials(of='dz_dt', wrt='lat_vel', rows=ar, cols=ar) - self.declare_partials(of='dz_dt', wrt='vert_vel', rows=ar, cols=ar) - self.declare_partials(of='dz_dt', wrt='roll', rows=ar, cols=ar) - self.declare_partials(of='dz_dt', wrt='pitch', rows=ar, cols=ar) - - - def compute(self, inputs, outputs): - """ - Compute function for EOM. - TODO: Same as above, potentially rewrite equations for \ - matrix form, and add potential assymetry to moment \ - of inertia matrix. - - """ - - # inputs - - mass = inputs['mass'] - axial_vel = inputs['axial_vel'] # u - lat_vel = inputs['lat_vel'] # v - vert_vel = inputs['vert_vel'] # w - roll_ang_vel = inputs['roll_ang_vel'] # p - pitch_ang_vel = inputs['pitch_ang_vel'] # q - yaw_ang_vel = inputs['yaw_ang_vel'] # r - roll = inputs['roll'] # phi - pitch = inputs['pitch'] # theta - yaw = inputs['yaw'] # psi - x = inputs['x'] # p1 - y = inputs['y'] # p2 - z = inputs['z'] # p3 - # time = inputs['time'] - g = inputs['g'] - Fx = inputs['Fx'] - Fy = inputs['Fy'] - Fz = inputs['Fz'] - lx_ext = inputs['lx_ext'] # l - ly_ext = inputs['ly_ext'] # m - lz_ext = inputs['lz_ext'] # n - J_xz = inputs['J_xz'] - J_xx = inputs['J_xx'] - J_yy = inputs['J_yy'] - J_zz = inputs['J_zz'] - - # Resolve gravity in body coordinate system -- denoted with subscript 'b' - gx_b = -np.sin(pitch) * g - gy_b = np.sin(roll) * np.cos(pitch) * g - gz_b = np.cos(roll) * np.cos(pitch) * g - - # TODO: could add external forces and moments here if needed - - # Denominator for roll and yaw rate equations - Den = J_xx * J_zz - J_xz**2 - - # roll-axis velocity equation - - dx_accel = 1 / mass * Fx + gx_b - vert_vel * pitch_ang_vel + lat_vel * yaw_ang_vel - - # pitch-axis velocity equation - - dy_accel = 1 / mass * Fy + gy_b - axial_vel * yaw_ang_vel + vert_vel * roll_ang_vel - - # yaw-axis velocity equation - - dz_accel = 1 / mass * Fz + gz_b - lat_vel * roll_ang_vel + axial_vel * pitch_ang_vel - - # Roll equation - - roll_accel = (J_xz * (J_xx - J_yy + J_zz) * roll_ang_vel * pitch_ang_vel - - (J_zz * (J_zz - J_yy) + J_xz**2) * pitch_ang_vel * yaw_ang_vel + - J_zz * lx_ext + - J_xz * lz_ext) / Den - - # Pitch equation - - pitch_accel = ((J_zz - J_xx) * roll_ang_vel * yaw_ang_vel - - J_xz * (roll_ang_vel**2 - yaw_ang_vel**2) + ly_ext) / J_yy - - # Yaw equation - - yaw_accel = ((J_xx * (J_xx - J_yy) + J_xz**2) * roll_ang_vel * pitch_ang_vel + - J_xz * (J_xx - J_yy + J_zz) * pitch_ang_vel * yaw_ang_vel + - J_xz * lx_ext + - J_xz * lz_ext) / Den - - # Kinematic equations - - roll_angle_rate_eq = roll_ang_vel + np.sin(roll) * np.tan(pitch) * pitch_ang_vel + \ - np.cos(roll) * np.tan(pitch) * yaw_ang_vel - - pitch_angle_rate_eq = np.cos(roll) * pitch_ang_vel - np.sin(roll) * yaw_ang_vel - - yaw_angle_rate_eq = np.sin(roll) / np.cos(pitch) * pitch_ang_vel + \ - np.cos(roll) / np.cos(pitch) * yaw_ang_vel - - # Position equations - - dx_dt = np.cos(pitch) * np.cos(yaw) * axial_vel + \ - (-np.cos(roll) * np.sin(yaw) + np.sin(roll) * np.sin(pitch) * np.cos(yaw)) * lat_vel + \ - (np.sin(roll) * np.sin(yaw) + np.cos(roll) * np.sin(pitch) * np.cos(yaw)) * vert_vel - - dy_dt = np.cos(pitch) * np.sin(yaw) * axial_vel + \ - (np.cos(roll) * np.cos(yaw) + np.sin(roll) * np.sin(pitch) * np.sin(yaw)) * lat_vel + \ - (-np.sin(roll) * np.cos(yaw) + np.cos(roll) * np.sin(pitch) * np.sin(yaw)) * vert_vel - - dz_dt = -np.sin(pitch) * axial_vel + \ - np.sin(roll) * np.cos(pitch) * lat_vel + \ - np.cos(roll) * np.cos(pitch) * vert_vel - - outputs['dx_accel'] = dx_accel - outputs['dy_accel'] = dy_accel - outputs['dz_accel'] = dz_accel - outputs['roll_accel'] = roll_accel - outputs['pitch_accel'] = pitch_accel - outputs['yaw_accel'] = yaw_accel - outputs['roll_angle_rate_eq'] = roll_angle_rate_eq - outputs['pitch_angle_rate_eq'] = pitch_angle_rate_eq - outputs['yaw_angle_rate_eq'] = yaw_angle_rate_eq - outputs['dx_dt'] = dx_dt - outputs['dy_dt'] = dy_dt - outputs['dz_dt'] = dz_dt - - - def compute_partials(self, inputs, J): - mass = inputs['mass'] - axial_vel = inputs['axial_vel'] # u - lat_vel = inputs['lat_vel'] # v - vert_vel = inputs['vert_vel'] # w - roll_ang_vel = inputs['roll_ang_vel'] # p - pitch_ang_vel = inputs['pitch_ang_vel'] # q - yaw_ang_vel = inputs['yaw_ang_vel'] # r - roll = inputs['roll'] # phi - pitch = inputs['pitch'] # theta - yaw = inputs['yaw'] # psi - x = inputs['x'] # p1 - y = inputs['y'] # p2 - z = inputs['z'] # p3 - # time = inputs['time'] - g = inputs['g'] - Fx = inputs['Fx'] - Fy = inputs['Fy'] - Fz = inputs['Fz'] - lx_ext = inputs['lx_ext'] # l - ly_ext = inputs['ly_ext'] # m - lz_ext = inputs['lz_ext'] # n - J_xz = inputs['J_xz'] - J_xx = inputs['J_xx'] - J_yy = inputs['J_yy'] - J_zz = inputs['J_zz'] - - # for roll and yaw - Den = J_xx * J_zz - J_xz**2 - - J['dx_accel', 'mass'] = -Fx / mass**2 - J['dx_accel', 'Fx'] = 1 / mass - J['dx_accel', 'lat_vel'] = yaw_ang_vel - J['dx_accel', 'vert_vel'] = -pitch_ang_vel - J['dx_accel', 'yaw_ang_vel'] = lat_vel - J['dx_accel', 'pitch_ang_vel'] = -vert_vel - J['dx_accel', 'g'] = -np.sin(pitch) - J['dx_accel', 'pitch'] = -np.cos(pitch) * g - - J['dy_accel', 'mass'] = -Fy / mass**2 - J['dy_accel', 'Fy'] = 1 / mass - J['dy_accel', 'axial_vel'] = -yaw_ang_vel - J['dy_accel', 'vert_vel'] = roll_ang_vel - J['dy_accel', 'yaw_ang_vel'] = -axial_vel - J['dy_accel', 'roll_ang_vel'] = vert_vel - J['dy_accel', 'g'] = np.sin(roll) * np.cos(pitch) - J['dy_accel', 'roll'] = np.cos(roll) * np.cos(pitch) * g - J['dy_accel', 'pitch'] = -np.sin(roll) * np.sin(pitch) * g - - J['dz_accel', 'mass'] = -Fz / mass**2 - J['dz_accel', 'Fz'] = 1 / mass - J['dz_accel', 'lat_vel'] = -roll_ang_vel - J['dz_accel', 'axial_vel'] = pitch_ang_vel - J['dz_accel', 'roll_ang_vel'] = -lat_vel - J['dz_accel', 'pitch_ang_vel'] = axial_vel - J['dz_accel', 'g'] = np.cos(roll) * np.cos(pitch) - J['dz_accel', 'roll'] = -np.sin(roll) * np.cos(pitch) * g - J['dz_accel', 'pitch'] = -np.cos(roll) * np.sin(pitch) * g - - J['roll_accel', 'J_xz'] = (Den * ( - (J_xx - J_yy + J_zz) * roll_ang_vel * pitch_ang_vel - 2 * J_xz * pitch_ang_vel * yaw_ang_vel + lz_ext) - ( - J_xz * (J_xx - J_yy + J_zz) * roll_ang_vel * pitch_ang_vel - - (J_zz * (J_zz - J_yy) + J_xz**2) * pitch_ang_vel * yaw_ang_vel + - J_zz * lx_ext + - J_xz * lz_ext) * -2 * J_xz) / Den**2 - J['roll_accel', 'J_xx'] = (Den * ( - J_xz * roll_ang_vel * pitch_ang_vel - ) - (J_xz * (J_xx - J_yy + J_zz) * roll_ang_vel * pitch_ang_vel - - (J_zz * (J_zz - J_yy) + J_xz**2) * pitch_ang_vel * yaw_ang_vel + - J_zz * lx_ext + - J_xz * lz_ext) * J_zz) / Den**2 - J['roll_accel', 'J_yy'] = (-J_xz * roll_ang_vel * pitch_ang_vel + J_zz * pitch_ang_vel * yaw_ang_vel) / Den - J['roll_accel', 'J_zz'] = (Den * ( - J_xz * roll_ang_vel * pitch_ang_vel - 2 * J_zz * pitch_ang_vel * yaw_ang_vel + J_yy * pitch_ang_vel * yaw_ang_vel + lx_ext - ) - (J_xz * (J_xx - J_yy + J_zz) * roll_ang_vel * pitch_ang_vel - - (J_zz * (J_zz - J_yy) + J_xz**2) * pitch_ang_vel * yaw_ang_vel + - J_zz * lx_ext + - J_xz * lz_ext) * J_xx) / Den**2 - J['roll_accel', 'roll_ang_vel'] = (J_xz * (J_xx - J_yy + J_zz) * pitch_ang_vel) / Den - J['roll_accel', 'pitch_ang_vel'] = (J_xz * (J_xx - J_yy + J_zz) * roll_ang_vel - (J_zz * (J_zz - J_yy) + J_xz**2) * yaw_ang_vel) / Den - J['roll_accel', 'yaw_ang_vel'] = -((J_zz * (J_zz - J_yy) + J_xz**2) * pitch_ang_vel) / Den - J['roll_accel', 'lx_ext'] = J_zz / Den - J['roll_accel', 'lz_ext'] = J_xz / Den - - J['pitch_accel', 'J_xz'] = -(roll_ang_vel**2 - yaw_ang_vel**2) / J_yy - J['pitch_accel', 'J_xx'] = -(roll_ang_vel * yaw_ang_vel) / J_yy - J['pitch_accel', 'J_yy'] = -((J_zz - J_xx) * roll_ang_vel * yaw_ang_vel - - J_xz * (roll_ang_vel**2 - yaw_ang_vel**2) + ly_ext) / J_yy**2 - J['pitch_accel', 'J_zz'] = roll_ang_vel * yaw_ang_vel / J_yy - J['pitch_accel', 'roll_ang_vel'] = ((J_zz - J_xx) * yaw_ang_vel - 2 * J_xz * roll_ang_vel) / J_yy - J['pitch_accel', 'yaw_ang_vel'] = ((J_zz - J_xx) * roll_ang_vel + 2 * J_xz * yaw_ang_vel) / J_yy - J['pitch_accel', 'ly_ext'] = 1 / J_yy - - J['yaw_accel', 'J_xz'] = (Den * ( - 2 * J_xz * roll_ang_vel * pitch_ang_vel + (J_xx - J_yy + J_zz) * pitch_ang_vel * yaw_ang_vel + lx_ext + lz_ext - ) - ((J_xx * (J_xx - J_yy) + J_xz**2) * roll_ang_vel * pitch_ang_vel + - J_xz * (J_xx - J_yy + J_zz) * pitch_ang_vel * yaw_ang_vel + - J_xz * lx_ext + - J_xz * lz_ext) * -2 * J_xz) / Den**2 - J['yaw_accel', 'J_xx'] = (Den * ( - 2 * J_xx * roll_ang_vel * pitch_ang_vel - J_yy * roll_ang_vel * pitch_ang_vel + J_xz * pitch_ang_vel * yaw_ang_vel - ) - ((J_xx * (J_xx - J_yy) + J_xz**2) * roll_ang_vel * pitch_ang_vel + - J_xz * (J_xx - J_yy + J_zz) * pitch_ang_vel * yaw_ang_vel + - J_xz * lx_ext + - J_xz * lz_ext) * J_zz) / Den**2 - J['yaw_accel', 'J_yy'] = (-J_xx * roll_ang_vel * pitch_ang_vel - J_xz * pitch_ang_vel * yaw_ang_vel) / Den - J['yaw_accel', 'J_zz'] = (Den * ( - J_xz * pitch_ang_vel * yaw_ang_vel - ) - ((J_xx * (J_xx - J_yy) + J_xz**2) * roll_ang_vel * pitch_ang_vel + - J_xz * (J_xx - J_yy + J_zz) * pitch_ang_vel * yaw_ang_vel + - J_xz * lx_ext + - J_xz * lz_ext) * J_xx) / Den**2 - J['yaw_accel', 'roll_ang_vel'] = ((J_xx * (J_xx - J_yy) + J_xz**2) * pitch_ang_vel) / Den - J['yaw_accel', 'pitch_ang_vel'] = ((J_xx * (J_xx - J_yy) + J_xz**2) * roll_ang_vel + J_xz * (J_xx - J_yy + J_zz) * yaw_ang_vel) / Den - J['yaw_accel', 'yaw_ang_vel'] = (J_xz * (J_xx - J_yy + J_zz) * pitch_ang_vel) / Den - J['yaw_accel', 'lx_ext'] = J_xz / Den - J['yaw_accel', 'lz_ext'] = J_xz / Den - - J['roll_angle_rate_eq', 'roll_ang_vel'] = 1 - J['roll_angle_rate_eq', 'pitch_ang_vel'] = np.sin(roll) * np.tan(pitch) - J['roll_angle_rate_eq', 'yaw_ang_vel'] = np.cos(roll) * np.tan(pitch) - J['roll_angle_rate_eq', 'roll'] = np.cos(roll) * np.tan(pitch) * pitch_ang_vel - np.sin(roll) * np.tan(pitch) * yaw_ang_vel - J['roll_angle_rate_eq', 'pitch'] = np.sin(roll) * (1 / np.cos(pitch)**2) * pitch_ang_vel + np.cos(roll) * (1 / np.cos(pitch)**2) * yaw_ang_vel - - J['pitch_angle_rate_eq', 'pitch_ang_vel'] = np.cos(roll) - J['pitch_angle_rate_eq', 'yaw_ang_vel'] = -np.sin(roll) - J['pitch_angle_rate_eq', 'roll'] = -np.sin(roll) * pitch_ang_vel - np.cos(roll) * yaw_ang_vel - - J['yaw_angle_rate_eq', 'pitch_ang_vel'] = np.sin(roll) / np.cos(pitch) - J['yaw_angle_rate_eq', 'yaw_ang_vel'] = np.cos(roll) / np.cos(pitch) - J['yaw_angle_rate_eq', 'roll'] = np.cos(roll) / np.cos(pitch) * pitch_ang_vel - np.sin(roll) / np.cos(pitch) * yaw_ang_vel - J['yaw_angle_rate_eq', 'pitch'] = np.sin(roll) * (np.tan(pitch) / np.cos(pitch)) * pitch_ang_vel + np.cos(roll) * (np.tan(pitch) / np.cos(pitch)) * yaw_ang_vel - - # note: d/dx tan(x) = sec^2(x) = 1 / cos^2(x) - # note: d/dx 1 / cos(x) = d/dx sec(x) = sec(x)tan(x) = tan(x) / cos(x) - - J['dx_dt', 'axial_vel'] = np.cos(pitch) * np.cos(yaw) - J['dx_dt', 'lat_vel'] = -np.cos(roll) * np.sin(yaw) + np.sin(roll) * np.sin(pitch) * np.cos(yaw) - J['dx_dt', 'vert_vel'] = np.sin(roll) * np.sin(yaw) + np.cos(roll) * np.sin(pitch) * np.cos(yaw) - J['dx_dt', 'roll'] = (np.sin(roll) * np.sin(yaw) + np.cos(roll) * np.sin(pitch) * np.cos(yaw)) * lat_vel + \ - (np.cos(roll) * np.sin(yaw) - np.sin(roll) * np.sin(pitch) * np.cos(yaw)) * vert_vel - J['dx_dt', 'pitch'] = -np.sin(pitch) * np.cos(yaw) * axial_vel + \ - np.sin(roll) * np.cos(pitch) * np.cos(yaw) * lat_vel + \ - np.cos(roll) * np.cos(pitch) * np.cos(yaw) * vert_vel - J['dx_dt', 'yaw'] = -np.cos(pitch) * np.sin(yaw) * axial_vel + \ - (-np.cos(roll) * np.cos(yaw) - np.sin(roll) * np.sin(pitch) * np.sin(yaw)) * lat_vel + \ - (np.sin(roll) * np.cos(yaw) - np.cos(roll) * np.sin(pitch) * np.sin(yaw)) * vert_vel - - J['dy_dt', 'axial_vel'] = np.cos(pitch) * np.sin(yaw) - J['dy_dt', 'lat_vel'] = np.cos(roll) * np.cos(yaw) + np.sin(roll) * np.sin(pitch) * np.sin(yaw) - J['dy_dt', 'vert_vel'] = -np.sin(roll) * np.cos(yaw) + np.cos(roll) * np.sin(pitch) * np.sin(yaw) - J['dy_dt', 'roll'] = (-np.sin(roll) * np.cos(yaw) + np.cos(roll) * np.sin(pitch) * np.sin(yaw)) * lat_vel + \ - (-np.cos(roll) * np.cos(yaw) - np.sin(roll) * np.sin(pitch) * np.sin(yaw)) * vert_vel - J['dy_dt', 'pitch'] = -np.sin(pitch) * np.sin(yaw) * axial_vel + \ - np.sin(roll) * np.cos(pitch) * np.sin(yaw) * lat_vel + \ - np.cos(roll) * np.cos(pitch) * np.sin(yaw) * vert_vel - J['dy_dt', 'yaw'] = np.cos(pitch) * np.cos(yaw) * axial_vel + \ - (-np.cos(roll) * np.sin(yaw) + np.sin(roll) * np.sin(pitch) * np.cos(yaw)) * lat_vel + \ - (np.sin(roll) * np.sin(yaw) + np.cos(roll) * np.sin(pitch) * np.cos(yaw)) * vert_vel - - J['dz_dt', 'axial_vel'] = -np.sin(pitch) - J['dz_dt', 'lat_vel'] = np.sin(roll) * np.cos(pitch) - J['dz_dt', 'vert_vel'] = np.cos(roll) * np.cos(pitch) - J['dz_dt', 'roll'] = np.cos(roll) * np.cos(pitch) * lat_vel - \ - np.sin(roll) * np.cos(pitch) * vert_vel - J['dz_dt', 'pitch'] = -np.cos(pitch) * axial_vel - \ - np.sin(roll) * np.sin(pitch) * lat_vel - \ - np.cos(roll) * np.sin(pitch) * vert_vel - - - - - -if __name__ == "__main__": - - p = om.Problem() - p.model = om.Group() - des_vars = p.model.add_subsystem('des_vars', om.IndepVarComp(), promotes=['*']) - - des_vars.add_output('mass', 3.0, units='kg') - des_vars.add_output('axial_vel', 0.1, units='m/s') - des_vars.add_output('lat_vel', 0.7, units='m/s') - des_vars.add_output('vert_vel', 0.12, units='m/s') - des_vars.add_output('roll_ang_vel', 0.1, units='rad/s') - des_vars.add_output('pitch_ang_vel', 0.9, units='rad/s') - des_vars.add_output('yaw_ang_vel', 0.12, units='rad/s') - des_vars.add_output('roll', 0.9, units='rad') - des_vars.add_output('pitch', 0.19, units='rad') - des_vars.add_output('yaw', 0.70, units='rad') - des_vars.add_output('g', 9.81, units='m/s**2') - des_vars.add_output('Fx', 0.1, units='N') - des_vars.add_output('Fy', 0.9, units='N') - des_vars.add_output('Fz', 0.12, units='N') - des_vars.add_output('lx_ext', 3.0, units='N*m') - des_vars.add_output('ly_ext', 4.0, units='N*m') - des_vars.add_output('lz_ext', 5.0, units='N*m') - des_vars.add_output('J_xz', 9.0, units='kg*m**2') - des_vars.add_output('J_xx', 50.0, units='kg*m**2') - des_vars.add_output('J_yy', 51.0, units='kg*m**2') - des_vars.add_output('J_zz', 52.0, units='kg*m**2') - - p.model.add_subsystem('SixDOF_EOM', SixDOF_EOM(num_nodes=1), promotes=['*']) - - p.setup(check=False, force_alloc_complex=True) - - p.run_model() - - dx_accel = p.get_val('dx_accel') - dy_accel = p.get_val('dy_accel') - dz_accel = p.get_val('dz_accel') - roll_accel = p.get_val('roll_accel') - pitch_accel = p.get_val('pitch_accel') - yaw_accel = p.get_val('yaw_accel') - roll_angle_rate_eq = p.get_val('roll_angle_rate_eq') - pitch_angle_rate_eq = p.get_val('pitch_angle_rate_eq') - yaw_angle_rate_eq = p.get_val('yaw_angle_rate_eq') - dx_dt = p.get_val('dx_dt') - dy_dt = p.get_val('dy_dt') - dz_dt = p.get_val('dz_dt') - - print(f"Accelerations in x,y,z: {dx_accel}, {dy_accel}, {dz_accel}") - print(f"Euler angle accels in roll, pitch, yaw: {roll_accel}, {pitch_accel}, {yaw_accel}") - print(f"Euler angular rates: {roll_angle_rate_eq}, {pitch_angle_rate_eq}, {yaw_angle_rate_eq}") - print(f"velocities: {dx_dt}, {dy_dt}, {dz_dt}") - - p.check_partials(compact_print=True, show_only_incorrect=True, method='cs') - - diff --git a/aviary/mission/sixdof/six_dof_ODE.py b/aviary/mission/sixdof/six_dof_ODE.py deleted file mode 100644 index 4658dd12f..000000000 --- a/aviary/mission/sixdof/six_dof_ODE.py +++ /dev/null @@ -1,167 +0,0 @@ -import numpy as np -import openmdao.api as om - -from aviary.mission.base_ode import BaseODE as _BaseODE - -from aviary.variable_info.enums import AnalysisScheme, SpeedType, ThrottleAllocation -from aviary.variable_info.variables import Aircraft, Dynamic, Mission -from aviary.constants import GRAV_METRIC_FLOPS - -from aviary.mission.sixdof.six_dof_EOM import SixDOF_EOM -from aviary.mission.sixdof.force_component_calc import ForceComponentResolver - -class SixDOF_ODE(_BaseODE): - - def initialize(self): - super().initialize() - - def setup(self): - options = self.options - nn = options['num_nodes'] - analysis_scheme = options['analysis_scheme'] - - self.add_subsystem( - 'true_airspeed_comp', - subsys=om.ExecComp( - 'true_airspeed = (axial_vel**2 + lat_vel**2 + vert_vel**2)**0.5', - true_airspeed = {'units': 'm/s', 'shape': (nn,)}, - axial_vel = {'units': 'm/s', 'shape': (nn,)}, - lat_vel = {'units': 'm/s', 'shape': (nn,)}, - vert_vel = {'units': 'm/s', 'shape': (nn,)}, - has_diag_partials=True - ), - promotes_inputs=[ - 'axial_vel', - 'lat_vel', - 'vert_vel', - ], - promotes_outputs=[ - 'true_airspeed' - ] - ) - - self.add_atmosphere(input_speed_type=SpeedType.TAS) - - sub1 = self.add_subsystem( - 'solver_sub', - om.Group(), - promotes=['*'] - ) - - T_vert_comp = om.ExecComp( - 'T_z = cos(roll) * cos(pitch) * mass * g', - roll = {'units': 'rad', 'shape': (nn,)}, - pitch = {'units': 'rad', 'shape': (nn,)}, - mass = {'units': 'kg', 'shape': (nn,)}, - g = {'val': GRAV_METRIC_FLOPS, 'units': 'm/s**2'}, - promotes_inputs=[ - ('roll', 'roll'), - ('pitch', 'pitch'), - ('mass', 'mass'), - ], - promotes_outputs=[ - ('T_z', 'T_z'), - ] - ) # body-relative CS - - comp = om.BalanceComp( - name=Dynamic.Vehicle.Propulsion.THROTTLE, - units='unitless', - val=np.ones((nn,)), - lhs_name='T_z', - rhs_name= Dynamic.Vehicle.Propulsion.THRUST_TOTAL, - eq_units='N', - normalize=False, - ) - - sub1.add_subsystem( - 'throttle_balance', - subsys=comp, - promotes_inputs=['*'], - promotes_outputs=['*'], - ) - - self.add_core_subsystems(solver_group=sub1) - - self.add_external_subsystems(solver_group=sub1) - - self.add_subsystem( - 'sum_forces_comp', - ForceComponentResolver(num_nodes=nn), - promotes_inputs=[ - 'u', - 'v', - 'w', - 'drag', - 'lift', - 'side', - 'thrust', - ], - promotes_outputs=[ - 'Fx', - 'Fy', - 'Fz', - ] - ) - - self.add_subsystem( - 'SixDOF_EOM', - SixDOF_EOM(num_nodes=nn), - promotes_inputs=[ - 'mass', - 'axial_vel', - 'lat_vel', - 'vert_vel', - 'roll_ang_vel', - 'pitch_ang_vel', - 'yaw_ang_vel', - 'roll', - 'pitch', - 'yaw', - 'g', - 'Fx_ext', - 'Fy_ext', - 'Fz_ext', - 'lx_ext', - 'ly_ext', - 'lz_ext', - 'J_xz', - 'J_xx', - 'J_yy', - 'J_zz' - ], - promotes_outputs=[ - 'dx_accel', - 'dy_accel', - 'dz_accel', - 'roll_accel', - 'pitch_accel', - 'yaw_accel', - 'roll_angle_rate_eq', - 'pitch_angle_rate_eq', - 'yaw_angle_rate_eq', - 'dx_dt', - 'dy_dt', - 'dz_dt' - ] - ) - - # self.set_input_defaults(Dynamic.Atmosphere.MACH, val=np.ones(nn), units='unitless') - # self.set_input_defaults(Dynamic.Vehicle.MASS, val=np.ones(nn), units='kg') - # self.set_input_defaults(Dynamic.Mission.VELOCITY, val=np.ones(nn), units='m/s') - # self.set_input_defaults(Dynamic.Mission.ALTITUDE, val=np.ones(nn), units='m') - # self.set_input_defaults(Dynamic.Mission.ALTITUDE_RATE, val=np.ones(nn), units='m/s') - - print_level = 0 if analysis_scheme is AnalysisScheme.SHOOTING else 2 - - sub1.nonlinear_solver = om.NewtonSolver( - solve_subsystems=True, - atol=1.0e-10, - rtol=1.0e-10, - ) - sub1.nonlinear_solver.linesearch = om.BoundsEnforceLS() - sub1.linear_solver = om.DirectSolver(assemble_jac=True) - sub1.nonlinear_solver.options['err_on_non_converge'] = True - sub1.nonlinear_solver.options['iprint'] = print_level - - self.options['auto_order'] = True \ No newline at end of file diff --git a/aviary/mission/sixdof/test_mission_6dof.py b/aviary/mission/sixdof/test_mission_6dof.py deleted file mode 100644 index 9a2ef1754..000000000 --- a/aviary/mission/sixdof/test_mission_6dof.py +++ /dev/null @@ -1,186 +0,0 @@ -import matplotlib.pyplot as plt - -import numpy as np - -import openmdao.api as om -import dymos as dm - -from openmdao.api import Group - -from dymos.models.atmosphere.atmos_1976 import USatm1976Comp - -from aviary.mission.sixdof.six_dof_EOM import SixDOF_EOM -from aviary.mission.sixdof.force_component_calc import ForceComponentResolver - -from openmdao.utils.general_utils import set_pyoptsparse_opt -OPT, OPTIMIZER = set_pyoptsparse_opt('SNOPT') -if OPTIMIZER: - from openmdao.drivers.pyoptsparse_driver import pyOptSparseDriver - -class vtolODE(Group): - - def initialize(self): - self.options.declare('num_nodes', types=int) - - def setup(self): - nn = self.options['num_nodes'] - - self.add_subsystem('USatm1976comp', USatm1976Comp(num_nodes=nn), - promotes_inputs=['*'], - promotes_outputs=['rho']) - - self.add_subsystem('ForceComponents', ForceComponentResolver(num_nodes=nn), - promotes_inputs=['*'], - promotes_outputs=['*']) - - self.add_subsystem('SixDOF_EOM', SixDOF_EOM(num_nodes=nn), - promotes_inputs=['*'], - promotes_outputs=['*']) - -def sixdof_test(): - p = om.Problem() - - - traj = dm.Trajectory() - phase = dm.Phase(ode_class=vtolODE, - transcription=dm.Radau(num_segments=10, order=3) - ) - - p.model.add_subsystem('traj', traj) - - # SETUP - - traj.add_phase(name='main_phase', phase=phase) - - phase.set_time_options(fix_initial=True, fix_duration=False, units='s') - - phase.add_state('axial_vel', fix_initial=True, rate_source='dx_accel', targets=['axial_vel'], lower=0, upper=100, units='m/s') - phase.add_state('lat_vel', fix_initial=True, rate_source='dy_accel', targets=['lat_vel'], lower=0, upper=100, units='m/s') - phase.add_state('vert_vel', fix_initial=True, rate_source='dz_accel', targets=['vert_vel'], lower=0, upper=100, units='m/s') - phase.add_state('roll_ang_vel', fix_initial=True, rate_source='roll_accel', targets=['roll_ang_vel'], lower=0, upper=100, units='rad/s') - phase.add_state('pitch_ang_vel', fix_initial=True, rate_source='pitch_accel', targets=['pitch_ang_vel'], lower=0, upper=100, units='rad/s') - phase.add_state('yaw_ang_vel', fix_initial=True, rate_source='yaw_accel', targets=['yaw_ang_vel'], lower=0, upper=100, units='rad/s') - phase.add_state('roll', fix_initial=True, rate_source='roll_angle_rate_eq', targets=['roll'], lower=0, upper=np.pi, units='rad') - phase.add_state('pitch', fix_initial=True, rate_source='pitch_angle_rate_eq', targets=['pitch'], lower=0, upper=np.pi, units='rad') - phase.add_state('yaw', fix_initial=True, rate_source='yaw_angle_rate_eq', targets=['yaw'], lower=0, upper=np.pi, units='rad') - phase.add_state('x', fix_initial=True, rate_source='dx_dt', targets=['x'],lower=0, upper=100, units='m') - phase.add_state('y', fix_initial=True, rate_source='dy_dt', targets=['y'], lower=0, upper=100, units='m') - phase.add_state('z', fix_initial=True, rate_source='dz_dt', targets=['z'], lower=0, upper=100, units='m') - phase.add_state('energy', fix_initial=True, rate_source='dE_dt', targets=['energy'], lower=0, upper=300, units='J') - - phase.add_control('Fx_ext', targets=['Fx_ext'], opt=True, units='N') - phase.add_control('Fy_ext', targets=['Fy_ext'], opt=True, units='N') - phase.add_control('Fz_ext', targets=['Fz_ext'], opt=True, units='N') - phase.add_control('lx_ext', targets=['lx_ext'], opt=True, units='N*m') - phase.add_control('ly_ext', targets=['ly_ext'], opt=True, units='N*m') - phase.add_control('lz_ext', targets=['lz_ext'], opt=True, units='N*m') - phase.add_control('power', targets=['power'], opt=True, units='W') - - phase.add_parameter('mass', units='kg', targets=['mass'], opt=False) - phase.add_parameter('J_xx', units='kg * m**2', targets=['J_xx'], opt=False) - phase.add_parameter('J_yy', units='kg * m**2', targets=['J_yy'], opt=False) - phase.add_parameter('J_zz', units='kg * m**2', targets=['J_zz'], opt=False) - phase.add_parameter('J_xz', units='kg * m**2', targets=['J_xz'], opt=False) - - phase.add_boundary_constraint('z', loc='final', equals=33, units='m') - phase.add_path_constraint('x', lower=0, upper=0.1, units='m') - phase.add_path_constraint('y', lower=0, upper=0.1, units='m') - - phase.add_objective('energy', loc='final', units='J') # minimize energy - - p.driver = om.pyOptSparseDriver() - p.driver.options["optimizer"] = "IPOPT" - - p.driver.opt_settings['mu_init'] = 1e-1 - p.driver.opt_settings['max_iter'] = 600 - p.driver.opt_settings['constr_viol_tol'] = 1e-6 - p.driver.opt_settings['compl_inf_tol'] = 1e-6 - p.driver.opt_settings['tol'] = 1e-5 - p.driver.opt_settings['print_level'] = 3 - p.driver.opt_settings['nlp_scaling_method'] = 'gradient-based' - p.driver.opt_settings['alpha_for_y'] = 'safer-min-dual-infeas' - p.driver.opt_settings['mu_strategy'] = 'monotone' - p.driver.opt_settings['bound_mult_init_method'] = 'mu-based' - p.driver.options['print_results'] = False - - p.driver.declare_coloring() - - p.setup() - - phase.set_time_val(initial=0, duration=60, units='s') - phase.set_state_val('axial_vel', vals=[0, 0], units='m/s') - phase.set_state_val('lat_vel', vals=[0, 0], units='m/s') - phase.set_state_val('vert_vel', vals=[10, 10], units='m/s') - phase.set_state_val('roll_ang_vel', vals=[0, 0], units='rad/s') - phase.set_state_val('pitch_ang_vel', vals=[0, 0], units='rad/s') - phase.set_state_val('yaw_ang_vel', vals=[0, 0], units='rad/s') - phase.set_state_val('roll', vals=[0, 0], units='rad') - phase.set_state_val('pitch', vals=[0, 0], units='rad') - phase.set_state_val('yaw', vals=[0, 0], units='rad') - phase.set_state_val('x', vals=[0, 0], units='m') - phase.set_state_val('y', vals=[0, 0], units='m') - phase.set_state_val('z', vals=[0, 33], units='m') - phase.set_state_val('energy', vals=[0, 300], units='J') - - phase.set_control_val('Fx_ext', vals=[0, 0], units='N') - phase.set_control_val('Fy_ext', vals=[0, 0], units='N') - phase.set_control_val('Fz_ext', vals=[10, 10], units='N') - phase.set_control_val('lx_ext', vals=[0, 0], units='N*m') - phase.set_control_val('ly_ext', vals=[0, 0], units='N*m') - phase.set_control_val('lz_ext', vals=[0, 0], units='N*m') - phase.set_control_val('power', vals=[0, 300], units='W') - - phase.set_parameter_val('mass', val=10, units='kg') - phase.set_parameter_val('J_xx', val=16, units='kg*m**2') # assume a sphere of 10 kg with radius = 2 - phase.set_parameter_val('J_yy', val=16, units='kg*m**2') - phase.set_parameter_val('J_zz', val=16, units='kg*m**2') - phase.set_parameter_val('J_xz', val=0, units='kg*m**2') - - - p.final_setup() - - p.run_model() - - dm.run_problem(p, run_driver=True, simulate=True, make_plots=True) - - exp_out = traj.simulate() - - p_sol = p - p_sim = exp_out - - x_traj = p_sol.get_val('traj.main_phase.timeseries.x') - x_sim = p_sim.get_val('traj.main_phase.timeseries.x') - y_traj = p_sol.get_val('traj.main_phase.timeseries.y') - y_sim = p_sim.get_val('traj.main_phase.timeseries.y') - z_traj = p_sol.get_val('traj.main_phase.timeseries.z') - z_sim = p_sim.get_val('traj.main_phase.timeseries.z') - t_traj = p_sol.get_val('traj.main_phase.timeseries.time') - t_sim = p_sim.get_val('traj.main_phase.timeseries.time') - - - - - - - # plt.plot(t_traj, z_traj, marker='o', ms=4, linestyle='None', label='solution') - # plt.plot(t_sim, z_sim, marker=None, linestyle='-', label='simulation') - # plt.legend(fontsize=12) - # plt.xlabel('t (s)', fontsize=12) - # plt.ylabel('z (m)', fontsize=12) - # plt.xticks(fontsize=12) - # plt.yticks(fontsize=12) - # plt.title('Trajectory of Vertical Take Off vs. Time', fontsize=12) - # plt.show() - # plt.savefig('./TrajPlots_Largerfontt.pdf') - - - - - -if __name__ == "__main__": - sixdof_test() - - - - - From 38c67c513ce89a7871a644b6e68afd1e4e3d8639 Mon Sep 17 00:00:00 2001 From: Seth Zoppelt Date: Thu, 3 Jul 2025 14:02:57 +0000 Subject: [PATCH 086/147] Updates. --- aviary/subsystems/mass/simple_mass/fuselage.py | 2 +- aviary/subsystems/mass/simple_mass/tail.py | 2 +- aviary/subsystems/mass/simple_mass/wing.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/fuselage.py b/aviary/subsystems/mass/simple_mass/fuselage.py index 94fad1c5f..cc7ecbd65 100644 --- a/aviary/subsystems/mass/simple_mass/fuselage.py +++ b/aviary/subsystems/mass/simple_mass/fuselage.py @@ -22,7 +22,7 @@ Debug = True -class FuselageMassAndCOG(om.JaxExplicitComponent): +class FuselageMass(om.JaxExplicitComponent): def initialize(self): self.options.declare('num_sections', types=int, diff --git a/aviary/subsystems/mass/simple_mass/tail.py b/aviary/subsystems/mass/simple_mass/tail.py index f9bac747e..a72b3dd52 100644 --- a/aviary/subsystems/mass/simple_mass/tail.py +++ b/aviary/subsystems/mass/simple_mass/tail.py @@ -21,7 +21,7 @@ Debug = True # set to enable printing -class TailMassAndCOG(om.JaxExplicitComponent): +class TailMass(om.JaxExplicitComponent): def initialize(self): #self.options['default_shape'] = () # Sets the default shape to scalar diff --git a/aviary/subsystems/mass/simple_mass/wing.py b/aviary/subsystems/mass/simple_mass/wing.py index 8057c995e..47f59141c 100644 --- a/aviary/subsystems/mass/simple_mass/wing.py +++ b/aviary/subsystems/mass/simple_mass/wing.py @@ -22,7 +22,7 @@ Debug = False -class WingMassAndCOG(om.JaxExplicitComponent): +class WingMass(om.JaxExplicitComponent): def initialize(self): self.options.declare('num_sections', types=int, From a3761082cea7abecb89e1974c4a8eee0841d0a01 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:10:45 -0400 Subject: [PATCH 087/147] Delete aviary/docs/examples/fuselage_out directory --- aviary/docs/examples/fuselage_out/.openmdao_out | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 aviary/docs/examples/fuselage_out/.openmdao_out diff --git a/aviary/docs/examples/fuselage_out/.openmdao_out b/aviary/docs/examples/fuselage_out/.openmdao_out deleted file mode 100644 index e69de29bb..000000000 From 38e8226cf03d15dd8d9661e9a51d93d278bf493f Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:10:51 -0400 Subject: [PATCH 088/147] Delete aviary/docs/examples/tail_out directory --- aviary/docs/examples/tail_out/.openmdao_out | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 aviary/docs/examples/tail_out/.openmdao_out diff --git a/aviary/docs/examples/tail_out/.openmdao_out b/aviary/docs/examples/tail_out/.openmdao_out deleted file mode 100644 index e69de29bb..000000000 From 1d91038c5b46b7b8e614d21321e904467dd552e5 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:10:57 -0400 Subject: [PATCH 089/147] Delete aviary/docs/examples/wing_out directory --- aviary/docs/examples/wing_out/.openmdao_out | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 aviary/docs/examples/wing_out/.openmdao_out diff --git a/aviary/docs/examples/wing_out/.openmdao_out b/aviary/docs/examples/wing_out/.openmdao_out deleted file mode 100644 index e69de29bb..000000000 From 46bc71f3aa661daca185d7411fe096cb14f97b58 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:11:04 -0400 Subject: [PATCH 090/147] Delete aviary/docs/examples/test_out directory --- aviary/docs/examples/test_out/.openmdao_out | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 aviary/docs/examples/test_out/.openmdao_out diff --git a/aviary/docs/examples/test_out/.openmdao_out b/aviary/docs/examples/test_out/.openmdao_out deleted file mode 100644 index e69de29bb..000000000 From dc001918228ac1f7f07cb62030419462b6667332 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:11:10 -0400 Subject: [PATCH 091/147] Delete aviary/docs/examples/test_wing_out directory --- aviary/docs/examples/test_wing_out/.openmdao_out | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 aviary/docs/examples/test_wing_out/.openmdao_out diff --git a/aviary/docs/examples/test_wing_out/.openmdao_out b/aviary/docs/examples/test_wing_out/.openmdao_out deleted file mode 100644 index e69de29bb..000000000 From efaa01372a6f81fea56abea739133fb73a0f9a18 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:11:16 -0400 Subject: [PATCH 092/147] Delete aviary/docs/examples/test_wing2_out directory --- aviary/docs/examples/test_wing2_out/.openmdao_out | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 aviary/docs/examples/test_wing2_out/.openmdao_out diff --git a/aviary/docs/examples/test_wing2_out/.openmdao_out b/aviary/docs/examples/test_wing2_out/.openmdao_out deleted file mode 100644 index e69de29bb..000000000 From 55753ed6620e399dd34a3d7454f58bc0c64f65ee Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:11:23 -0400 Subject: [PATCH 093/147] Delete aviary/docs/examples/test_fuselage_out directory --- aviary/docs/examples/test_fuselage_out/.openmdao_out | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 aviary/docs/examples/test_fuselage_out/.openmdao_out diff --git a/aviary/docs/examples/test_fuselage_out/.openmdao_out b/aviary/docs/examples/test_fuselage_out/.openmdao_out deleted file mode 100644 index e69de29bb..000000000 From 8a7bfa9f6f47b48a30b15fa6627f66907774b369 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:11:29 -0400 Subject: [PATCH 094/147] Delete aviary/docs/examples/test_tail_out directory --- aviary/docs/examples/test_tail_out/.openmdao_out | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 aviary/docs/examples/test_tail_out/.openmdao_out diff --git a/aviary/docs/examples/test_tail_out/.openmdao_out b/aviary/docs/examples/test_tail_out/.openmdao_out deleted file mode 100644 index e69de29bb..000000000 From fa47930bab2b55ffe4aa37fa7dc6595a05310710 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:11:34 -0400 Subject: [PATCH 095/147] Delete aviary/docs/examples/test_fuselage_dbf_out directory --- aviary/docs/examples/test_fuselage_dbf_out/.openmdao_out | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 aviary/docs/examples/test_fuselage_dbf_out/.openmdao_out diff --git a/aviary/docs/examples/test_fuselage_dbf_out/.openmdao_out b/aviary/docs/examples/test_fuselage_dbf_out/.openmdao_out deleted file mode 100644 index e69de29bb..000000000 From 95609352e9d400ed1a6f57d92ca007ae3fa1d3d8 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:11:40 -0400 Subject: [PATCH 096/147] Delete aviary/docs/examples/test_tail2_out directory --- aviary/docs/examples/test_tail2_out/.openmdao_out | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 aviary/docs/examples/test_tail2_out/.openmdao_out diff --git a/aviary/docs/examples/test_tail2_out/.openmdao_out b/aviary/docs/examples/test_tail2_out/.openmdao_out deleted file mode 100644 index e69de29bb..000000000 From 62057926e49725277a2b0ce9732ef2639e3ac97b Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:11:46 -0400 Subject: [PATCH 097/147] Delete aviary/docs/examples/test_fuselage2_out directory --- aviary/docs/examples/test_fuselage2_out/.openmdao_out | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 aviary/docs/examples/test_fuselage2_out/.openmdao_out diff --git a/aviary/docs/examples/test_fuselage2_out/.openmdao_out b/aviary/docs/examples/test_fuselage2_out/.openmdao_out deleted file mode 100644 index e69de29bb..000000000 From 13d3b17ac88afb93c496460a143911080caf970e Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:11:55 -0400 Subject: [PATCH 098/147] Delete aviary/docs/examples/six_dof_ODE.py --- aviary/docs/examples/six_dof_ODE.py | 112 ---------------------------- 1 file changed, 112 deletions(-) delete mode 100644 aviary/docs/examples/six_dof_ODE.py diff --git a/aviary/docs/examples/six_dof_ODE.py b/aviary/docs/examples/six_dof_ODE.py deleted file mode 100644 index f73190597..000000000 --- a/aviary/docs/examples/six_dof_ODE.py +++ /dev/null @@ -1,112 +0,0 @@ -import numpy as np -import openmdao.api as om - -# Here will import the 6dof equations of motion - -from aviary.mission.base_ode import BaseODE as _BaseODE - -from aviary.variable_info.enums import AnalysisScheme, SpeedType, ThrottleAllocation -from aviary.variable_info.variables import Aircraft, Dynamic, Mission - -from aviary.mission.sixdof.six_dof_EOM import SixDOF_EOM - -class SixDOF_ODE(_BaseODE): - - def initialize(self): - super().initialize() - - def setup(self): - options = self.options - nn = options['num_nodes'] - analysis_scheme = options['analysis_scheme'] - self.add_atmosphere(input_speed_type=SpeedType.MACH) - - self.add_subsystem( - name='veclocity_rate_comp', - subsys=om.ExecComp( - 'velocity_rate = mach_rate * sos', - mach_rate = {'units': 'unitless/s', 'shape': (nn,)}, - sos={'units': 'm/s', 'shape': (nn,)}, - velocity_rate={'units': 'm/s**2', 'shape': (nn,)}, - has_diag_partials=True, - ), - promotes_inputs=[ - ('mach_rate', Dynamic.Atmosphere.MACH_RATE), - ('sos', Dynamic.Atmosphere.SPEED_OF_SOUND), - ], - promotes_outputs=[ - 'velocity_rate', Dynamic.Mission.VELOCITY_RATE - ], - ) - - sub1 = self.add_subsystem( - 'solver_sub', - om.Group(), - promotes=['*'] - ) - - self.add_core_subsystems(solver_group=sub1) - - self.add_external_subsystems(solver_group=sub1) - - sub1.add_subsystem( - name='SixDOF_EOM', - subsys=SixDOF_EOM(num_nodes=nn), - promotes_inputs=[ - 'mass', - 'axial_vel', - 'lat_vel', - 'vert_vel', - 'roll_ang_vel', - 'pitch_ang_vel', - 'yaw_ang_vel', - 'roll', - 'pitch', - 'yaw', - 'g', - 'Fx_ext', - 'Fy_ext', - 'Fz_ext', - 'lx_ext', - 'ly_ext', - 'lz_ext', - 'J_xz', - 'J_xx', - 'J_yy', - 'J_zz', - ], - promotes_outputs=[ - 'dx_accel', - 'dy_accel', - 'dz_accel', - 'roll_accel', - 'pitch_accel', - 'yaw_accel', - 'roll_angle_rate_eq', - 'pitch_angle_rate_eq', - 'yaw_angle_rate_eq', - 'dx_dt', - 'dy_dt', - 'dz_dt', - ] - ) - - self.set_input_defaults(Dynamic.Atmosphere.MACH, val=np.ones(nn), units='unitless') - self.set_input_defaults(Dynamic.Vehicle.MASS, val=np.ones(nn), units='kg') - self.set_input_defaults(Dynamic.Mission.VELOCITY, val=np.ones(nn), units='m/s') - self.set_input_defaults(Dynamic.Mission.ALTITUDE, val=np.ones(nn), units='m') - self.set_input_defaults(Dynamic.Mission.ALTITUDE_RATE, val=np.ones(nn), units='m/s') - - print_level = 0 if analysis_scheme is AnalysisScheme.SHOOTING else 2 - - sub1.nonlinear_solver = om.NewtonSolver( - solve_subsystems=True, - atol=1.0e-10, - rtol=1.0e-10, - ) - sub1.nonlinear_solver.linesearch = om.BoundsEnforceLS() - sub1.linear_solver = om.DirectSolver(assemble_jac=True) - sub1.nonlinear_solver.options['err_on_non_converge'] = True - sub1.nonlinear_solver.options['iprint'] = print_level - - self.options['auto_order'] = True \ No newline at end of file From a0c5cbefce88052623eec455b31d31798b0e59c5 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:13:40 -0400 Subject: [PATCH 099/147] Delete pyproject_renamed --- pyproject_renamed | 89 ----------------------------------------------- 1 file changed, 89 deletions(-) delete mode 100644 pyproject_renamed diff --git a/pyproject_renamed b/pyproject_renamed deleted file mode 100644 index 86a77e3c5..000000000 --- a/pyproject_renamed +++ /dev/null @@ -1,89 +0,0 @@ -[build-system] -requires = ["hatchling", "numpy>=2.0"] -build-backend = "hatchling.build" - -[project] -name = "aviary" -dynamic = ["version"] -readme = "README.md" -license = "Apache-2.0" -requires_python = ">=3.9" -dependencies = [ - "dymos>=1.8.1", - "hvplot", - "importlib_resources", - "matplotlib", - "numpy<2", - "openmdao>=3.37.0", - "pandas", - "panel>=1.0.0", - "parameterized", - "simupy", -] - -[project.optional-dependencies] -docs = [ - "jupyter-book", - "itables" -] -dev = [ - "pre-commit", - "testflo", - "ambiance", - "openaerostruct", -] -all = [ - "aviary[docs]", - "aviary[dev]", -] - -[project.scripts] -aviary = "aviary.interface.cmd_entry_points:aviary_cmd" - -[project.entry-points.openmdao_report] -aviary_reports = "aviary.interface.reports:register_custom_reports" - -[tool.hatch.version] -path = "aviary/__init__.py" - -[tool.hatch.build.targets.sdist] -include = [ - "/aviary", -] - -[tool.ruff] -line-length = 100 - -[tool.ruff.format] -quote-style = "single" - -[tool.ruff.lint] -# isort, pydocstyle -extend-select = ["I", "D"] -# disabling these rules help current Aviary code pass a lint check -extend-ignore = [ - "D100", - "D101", - "D102", - "D103", - "D104", - "D105", - "D106", - "D204", - "D205", - "D401", - "D404", -] - -[tool.ruff.lint.isort] -split-on-trailing-comma = false - -[tool.ruff.lint.pydocstyle] -convention = "numpy" - -[tool.ruff.lint.per-file-ignores] -# Ignore `F401` (unused import) in api and doc files. -# Ignore `I001` (sort and format imports) in api. -# Ignore `E402` (module import not at top of file) for doc cells. -"api.py" = ["F401", "I001"] -"*.ipynb" = ["F401", "E402"] \ No newline at end of file From f16ceea63adb01b4ea5ff03256422c2d8f1284ee Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:13:59 -0400 Subject: [PATCH 100/147] Delete aviary/subsystems/mass/simple_mass/test/test_mass_subsystem.py --- .../simple_mass/test/test_mass_subsystem.py | 77 ------------------- 1 file changed, 77 deletions(-) delete mode 100644 aviary/subsystems/mass/simple_mass/test/test_mass_subsystem.py diff --git a/aviary/subsystems/mass/simple_mass/test/test_mass_subsystem.py b/aviary/subsystems/mass/simple_mass/test/test_mass_subsystem.py deleted file mode 100644 index 728fcb384..000000000 --- a/aviary/subsystems/mass/simple_mass/test/test_mass_subsystem.py +++ /dev/null @@ -1,77 +0,0 @@ -""" -Run the a mission with a simple external component that computes the wing -and horizontal tail mass. -""" - -from copy import deepcopy - -import aviary.api as av -from aviary.subsystems.mass.simple_mass.mass_builder import MassBuilderBase -from aviary.variable_info.variables import Aircraft - -import jax.numpy as jnp - -phase_info = deepcopy(av.default_height_energy_phase_info) -# Here we just add the simple weight system to only the pre-mission -phase_info['pre_mission']['external_subsystems'] = [MassBuilderBase()] - -if __name__ == '__main__': - prob = av.AviaryProblem() - - n_points = 10 # = num_sections - x = jnp.linspace(0, 1, n_points) - max_thickness_chord_ratio = 0.12 - thickness_dist = 5 * max_thickness_chord_ratio * (0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) - - # Load aircraft and options data from user - # Allow for user overrides here - prob.load_inputs('models/test_aircraft/aircraft_for_bench_FwFm.csv', phase_info) - prob.aviary_inputs.set_val(Aircraft.HorizontalTail.SPAN, val=1.0, units='m') - prob.aviary_inputs.set_val(Aircraft.HorizontalTail.ROOT_CHORD, val=1.0, units='m') - prob.aviary_inputs.set_val(Aircraft.Wing.SPAN, 3.74904, units='m') - prob.aviary_inputs.set_val(Aircraft.Wing.ROOT_CHORD, 0.40005, units='m') - prob.aviary_inputs.set_val(Aircraft.Fuselage.LENGTH, 2.5, units='m') - - - # Preprocess inputs - prob.check_and_preprocess_inputs() - - prob.add_pre_mission_systems() - - prob.add_phases() - - prob.add_post_mission_systems() - - # Link phases and variables - prob.link_phases() - - prob.add_driver('IPOPT') - - prob.add_design_variables() - - prob.add_objective() - - prob.setup() - - prob.set_val('pre_mission.simple_mass.tip_chord_tail', 0.5) - prob.set_val('pre_mission.simple_mass.thickness_ratio', 0.12) - prob.set_val('pre_mission.simple_mass.skin_thickness', 0.002) - prob.set_val('pre_mission.simple_mass.tip_chord', 0.100076) - prob.set_val('pre_mission.simple_mass.thickness_dist', thickness_dist) - prob.set_val('pre_mission.simple_mass.base_diameter', 0.5) - prob.set_val('pre_mission.simple_mass.tip_diameter', 0.3) - prob.set_val('pre_mission.simple_mass.curvature', 0.0) - prob.set_val('pre_mission.simple_mass.thickness', 0.05) - - prob.set_initial_guesses() - - prob.run_aviary_problem(suppress_solver_print=True) - - #prob.model.list_vars(units=True, print_arrays=True) - - #print('Engine Mass', prob.get_val(av.Aircraft.Engine.MASS)) - print('Wing Mass', prob.get_val(av.Aircraft.Wing.MASS)) - print('Horizontal Tail Mass', prob.get_val(av.Aircraft.HorizontalTail.MASS)) - print('Fuselage Mass', prob.get_val(av.Aircraft.Fuselage.MASS)) - - print('done') From 35960b8f155bf05707691ad8634fbc57f5a76596 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:14:08 -0400 Subject: [PATCH 101/147] Delete aviary/subsystems/mass/simple_mass/test/test.py --- aviary/subsystems/mass/simple_mass/test/test.py | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 aviary/subsystems/mass/simple_mass/test/test.py diff --git a/aviary/subsystems/mass/simple_mass/test/test.py b/aviary/subsystems/mass/simple_mass/test/test.py deleted file mode 100644 index 58b9244da..000000000 --- a/aviary/subsystems/mass/simple_mass/test/test.py +++ /dev/null @@ -1,3 +0,0 @@ -import os -print('path = '+ str(os.getcwd())) - From 0a0fbf3087856c55a86b60a30dbbb73c0bdef8b1 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:15:43 -0400 Subject: [PATCH 102/147] Delete out.txt --- out.txt | 10142 ------------------------------------------------------ 1 file changed, 10142 deletions(-) delete mode 100644 out.txt diff --git a/out.txt b/out.txt deleted file mode 100644 index 2081ffa93..000000000 --- a/out.txt +++ /dev/null @@ -1,10142 +0,0 @@ -Optimization terminated successfully (Exit mode 0) - Current function value: 2.308936834711119 - Iterations: 7 - Function evaluations: 7 - Gradient evaluations: 7 -Optimization Complete ------------------------------------ -1718 Variables(s) in 'model' - -varname val io units prom_name ------------------------------------------------------------------------ ------------------------ ------ ------------- -------------------------------------------------------------------------------- -pre_mission - simple_mass - Wing - aircraft:wing:span [35.914584] input m aircraft:wing:span - aircraft:wing:root_chord [0.] input m aircraft:wing:root_chord - tip_chord [1.] input m pre_mission.simple_mass.tip_chord - twist |0.0| input deg pre_mission.simple_mass.twist - val: - array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]) - thickness_dist |0.31622777| input m pre_mission.simple_mass.thickness_dist - val: - array([0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]) - aircraft:wing:mass [2.24666] output kg aircraft:wing:mass - Fuselage - aircraft:fuselage:length [39.0144] input m aircraft:fuselage:length - base_diameter [0.4] input m pre_mission.simple_mass.base_diameter - tip_diameter [0.2] input m pre_mission.simple_mass.tip_diameter - curvature [0.] input m pre_mission.simple_mass.curvature - thickness [0.05] input m pre_mission.simple_mass.thickness - y_offset [0.] input m pre_mission.simple_mass.y_offset - z_offset [0.] input m pre_mission.simple_mass.z_offset - is_hollow [1.] input None pre_mission.simple_mass.is_hollow - aircraft:fuselage:mass [5209.12373908] output kg aircraft:fuselage:mass - Tail - aircraft:horizontal_tail:span [0.] input m aircraft:horizontal_tail:span - aircraft:horizontal_tail:root_chord [0.] input m aircraft:horizontal_tail:root_chord - aircraft:vertical_tail:span [0.] input m aircraft:vertical_tail:span - aircraft:vertical_tail:root_chord [0.] input m aircraft:vertical_tail:root_chord - tip_chord_tail [0.8] input m pre_mission.simple_mass.tip_chord_tail - thickness_ratio [0.12] input None pre_mission.simple_mass.thickness_ratio - skin_thickness [0.002] input m pre_mission.simple_mass.skin_thickness - twist_tail |0.0| input deg pre_mission.simple_mass.twist_tail - val: - array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]) - aircraft:horizontal_tail:mass [0.] output kg aircraft:horizontal_tail:mass - aircraft:vertical_tail:mass [0.] output kg aircraft:vertical_tail:mass - core_propulsion - turbofan_28k - aircraft:engine:scale_factor [1.] input unitless aircraft:engine:scale_factor - aircraft:engine:scaled_sls_thrust [28928.1] output lbf aircraft:engine:scaled_sls_thrust - propulsion_sum - aircraft:engine:scaled_sls_thrust [28928.1] input lbf aircraft:engine:scaled_sls_thrust - aircraft:propulsion:total_scaled_sls_thrust [57856.2] output lbf aircraft:propulsion:total_scaled_sls_thrust - core_subsystems - core_geometry - fuselage_prelim - aircraft:fuselage:length [128.] input ft aircraft:fuselage:length - aircraft:fuselage:max_height [13.17] input ft aircraft:fuselage:max_height - aircraft:fuselage:max_width [12.33] input ft aircraft:fuselage:max_width - aircraft:fuselage:avg_diameter [12.75] output ft aircraft:fuselage:avg_diameter - aircraft:fuselage:planform_area [1578.24] output ft**2 pre_mission.AUTO_OVERRIDE:aircraft:fuselage:planform_area - wing_prelim - aircraft:wing:area [1370.] input ft**2 aircraft:wing:area - aircraft:wing:glove_and_bat [134.] input ft**2 aircraft:wing:glove_and_bat - aircraft:wing:span [117.83] input ft aircraft:wing:span - aircraft:wing:aspect_ratio [11.232936] output unitless pre_mission.AUTO_OVERRIDE:aircraft:wing:aspect_ratio - prelim - aircraft:fuselage:avg_diameter [12.75] input ft aircraft:fuselage:avg_diameter - aircraft:fuselage:max_width [12.33] input ft aircraft:fuselage:max_width - aircraft:horizontal_tail:area [355.] input ft**2 aircraft:horizontal_tail:area - aircraft:horizontal_tail:aspect_ratio [6.] input unitless aircraft:horizontal_tail:aspect_ratio - aircraft:horizontal_tail:taper_ratio [0.22] input unitless aircraft:horizontal_tail:taper_ratio - aircraft:horizontal_tail:thickness_to_chord [0.125] input unitless aircraft:horizontal_tail:thickness_to_chord - aircraft:vertical_tail:area [284.] input ft**2 aircraft:vertical_tail:area - aircraft:vertical_tail:aspect_ratio [1.75] input unitless aircraft:vertical_tail:aspect_ratio - aircraft:vertical_tail:taper_ratio [0.33] input unitless aircraft:vertical_tail:taper_ratio - aircraft:vertical_tail:thickness_to_chord [0.1195] input unitless aircraft:vertical_tail:thickness_to_chord - aircraft:wing:area [1370.] input ft**2 aircraft:wing:area - aircraft:wing:glove_and_bat [134.] input ft**2 aircraft:wing:glove_and_bat - aircraft:wing:span [117.83] input ft aircraft:wing:span - aircraft:wing:taper_ratio [0.278] input unitless aircraft:wing:taper_ratio - aircraft:wing:thickness_to_chord [0.13] input unitless aircraft:wing:thickness_to_chord - prep_geom:_Names:CROOT [16.415788] output unitless pre_mission.prelim.prep_geom:_Names:CROOT - prep_geom:_Names:CROOTB [15.13330021] output unitless pre_mission.prelim.prep_geom:_Names:CROOTB - prep_geom:_Names:CROTM [0.92187473] output unitless pre_mission.prelim.prep_geom:_Names:CROTM - prep_geom:_Names:CROTVT [19.15660306] output unitless pre_mission.prelim.prep_geom:_Names:CROTVT - prep_geom:_Names:CRTHTB [13.50207305] output unitless pre_mission.prelim.prep_geom:_Names:CRTHTB - prep_geom:_Names:SPANHT [46.15192304] output unitless pre_mission.prelim.prep_geom:_Names:SPANHT - prep_geom:_Names:SPANVT [22.29349681] output unitless pre_mission.prelim.prep_geom:_Names:SPANVT - prep_geom:_Names:XDX [12.75] output unitless pre_mission.prelim.prep_geom:_Names:XDX - prep_geom:_Names:XMULT [2.05031] output unitless pre_mission.prelim.prep_geom:_Names:XMULT - prep_geom:_Names:XMULTH [2.048375] output unitless pre_mission.prelim.prep_geom:_Names:XMULTH - prep_geom:_Names:XMULTV [2.0462465] output unitless pre_mission.prelim.prep_geom:_Names:XMULTV - wing - prep_geom:_Names:CROOT [16.415788] input unitless pre_mission.wing.prep_geom:_Names:CROOT - prep_geom:_Names:CROOTB [15.13330021] input unitless pre_mission.wing.prep_geom:_Names:CROOTB - prep_geom:_Names:XDX [12.75] input unitless pre_mission.wing.prep_geom:_Names:XDX - prep_geom:_Names:XMULT [2.05031] input unitless pre_mission.wing.prep_geom:_Names:XMULT - aircraft:wing:area [1370.] input ft**2 aircraft:wing:area - aircraft:wing:wetted_area_scaler [1.] input unitless aircraft:wing:wetted_area_scaler - aircraft:wing:wetted_area [2396.55520449] output ft**2 pre_mission.AUTO_OVERRIDE:aircraft:wing:wetted_area - tail - prep_geom:_Names:XMULTH [2.048375] input unitless pre_mission.tail.prep_geom:_Names:XMULTH - prep_geom:_Names:XMULTV [2.0462465] input unitless pre_mission.tail.prep_geom:_Names:XMULTV - aircraft:horizontal_tail:area [355.] input ft**2 aircraft:horizontal_tail:area - aircraft:horizontal_tail:vertical_tail_fraction [0.] input unitless aircraft:horizontal_tail:vertical_tail_fraction - aircraft:horizontal_tail:wetted_area_scaler [1.] input unitless aircraft:horizontal_tail:wetted_area_scaler - aircraft:vertical_tail:area [284.] input ft**2 aircraft:vertical_tail:area - aircraft:vertical_tail:wetted_area_scaler [1.] input unitless aircraft:vertical_tail:wetted_area_scaler - aircraft:horizontal_tail:wetted_area [592.64609688] output ft**2 pre_mission.AUTO_OVERRIDE:aircraft:horizontal_tail:wetted_area - aircraft:vertical_tail:wetted_area [581.134006] output ft**2 pre_mission.AUTO_OVERRIDE:aircraft:vertical_tail:wetted_area - fuselage - prep_geom:_Names:CROOTB [15.13330021] input unitless pre_mission.fuselage.prep_geom:_Names:CROOTB - prep_geom:_Names:CROTVT [19.15660306] input unitless pre_mission.fuselage.prep_geom:_Names:CROTVT - prep_geom:_Names:CRTHTB [13.50207305] input unitless pre_mission.fuselage.prep_geom:_Names:CRTHTB - aircraft:fuselage:avg_diameter [12.75] input ft aircraft:fuselage:avg_diameter - aircraft:fuselage:length [128.] input ft aircraft:fuselage:length - aircraft:fuselage:wetted_area_scaler [1.] input unitless aircraft:fuselage:wetted_area_scaler - aircraft:horizontal_tail:thickness_to_chord [0.125] input unitless aircraft:horizontal_tail:thickness_to_chord - aircraft:horizontal_tail:vertical_tail_fraction [0.] input unitless aircraft:horizontal_tail:vertical_tail_fraction - aircraft:vertical_tail:thickness_to_chord [0.1195] input unitless aircraft:vertical_tail:thickness_to_chord - aircraft:wing:area [1370.] input ft**2 aircraft:wing:area - aircraft:wing:aspect_ratio [11.22091] input unitless aircraft:wing:aspect_ratio - aircraft:wing:glove_and_bat [134.] input ft**2 aircraft:wing:glove_and_bat - aircraft:wing:thickness_to_chord [0.13] input unitless aircraft:wing:thickness_to_chord - aircraft:fuselage:cross_section [127.67628894] output ft**2 aircraft:fuselage:cross_section - aircraft:fuselage:diameter_to_wing_span [0.10826471] output unitless aircraft:fuselage:diameter_to_wing_span - aircraft:fuselage:length_to_diameter [10.03921569] output unitless aircraft:fuselage:length_to_diameter - aircraft:fuselage:wetted_area [4158.62066062] output ft**2 pre_mission.AUTO_OVERRIDE:aircraft:fuselage:wetted_area - nacelles - aircraft:nacelle:avg_diameter [7.94] input ft aircraft:nacelle:avg_diameter - aircraft:nacelle:avg_length [12.3] input ft aircraft:nacelle:avg_length - aircraft:nacelle:wetted_area_scaler [1.] input unitless aircraft:nacelle:wetted_area_scaler - aircraft:nacelle:total_wetted_area [546.9072] output ft**2 aircraft:nacelle:total_wetted_area - aircraft:nacelle:wetted_area [273.4536] output ft**2 aircraft:nacelle:wetted_area - canard - aircraft:canard:area [0.] input ft**2 aircraft:canard:area - aircraft:canard:thickness_to_chord [0.] input unitless aircraft:canard:thickness_to_chord - aircraft:canard:wetted_area_scaler [1.] input unitless aircraft:canard:wetted_area_scaler - aircraft:canard:wetted_area [0.] output ft**2 aircraft:canard:wetted_area - characteristic_lengths - prep_geom:_Names:CROOT [16.415788] input unitless pre_mission.characteristic_lengths.prep_geom:_Names:CROOT - aircraft:canard:area [0.] input ft**2 aircraft:canard:area - aircraft:canard:aspect_ratio [0.] input unitless aircraft:canard:aspect_ratio - aircraft:canard:thickness_to_chord [0.] input unitless aircraft:canard:thickness_to_chord - aircraft:fuselage:avg_diameter [12.75] input ft aircraft:fuselage:avg_diameter - aircraft:fuselage:length [128.] input ft aircraft:fuselage:length - aircraft:horizontal_tail:area [355.] input ft**2 aircraft:horizontal_tail:area - aircraft:horizontal_tail:aspect_ratio [6.] input unitless aircraft:horizontal_tail:aspect_ratio - aircraft:horizontal_tail:thickness_to_chord [0.125] input unitless aircraft:horizontal_tail:thickness_to_chord - aircraft:nacelle:avg_diameter [7.94] input ft aircraft:nacelle:avg_diameter - aircraft:nacelle:avg_length [12.3] input ft aircraft:nacelle:avg_length - aircraft:vertical_tail:area [284.] input ft**2 aircraft:vertical_tail:area - aircraft:vertical_tail:aspect_ratio [1.75] input unitless aircraft:vertical_tail:aspect_ratio - aircraft:vertical_tail:thickness_to_chord [0.1195] input unitless aircraft:vertical_tail:thickness_to_chord - aircraft:wing:area [1370.] input ft**2 aircraft:wing:area - aircraft:wing:aspect_ratio [11.22091] input unitless aircraft:wing:aspect_ratio - aircraft:wing:glove_and_bat [134.] input ft**2 aircraft:wing:glove_and_bat - aircraft:wing:taper_ratio [0.278] input unitless aircraft:wing:taper_ratio - aircraft:wing:thickness_to_chord [0.13] input unitless aircraft:wing:thickness_to_chord - aircraft:canard:characteristic_length [0.] output ft aircraft:canard:characteristic_length - aircraft:canard:fineness [0.] output unitless aircraft:canard:fineness - aircraft:fuselage:characteristic_length [128.] output ft aircraft:fuselage:characteristic_length - aircraft:fuselage:fineness [10.03921569] output unitless aircraft:fuselage:fineness - aircraft:horizontal_tail:characteristic_length [7.69198717] output ft aircraft:horizontal_tail:characteristic_length - aircraft:horizontal_tail:fineness [0.125] output unitless aircraft:horizontal_tail:fineness - aircraft:nacelle:characteristic_length [12.3] output ft aircraft:nacelle:characteristic_length - aircraft:nacelle:fineness [1.54911839] output unitless aircraft:nacelle:fineness - aircraft:vertical_tail:characteristic_length [12.73914103] output ft aircraft:vertical_tail:characteristic_length - aircraft:vertical_tail:fineness [0.1195] output unitless aircraft:vertical_tail:fineness - aircraft:wing:characteristic_length [10.49530819] output ft aircraft:wing:characteristic_length - aircraft:wing:fineness [0.13] output unitless aircraft:wing:fineness - total_wetted_area - aircraft:canard:wetted_area [0.] input ft**2 aircraft:canard:wetted_area - aircraft:fuselage:wetted_area [4158.62] input ft**2 aircraft:fuselage:wetted_area - aircraft:horizontal_tail:wetted_area [592.65] input ft**2 aircraft:horizontal_tail:wetted_area - aircraft:nacelle:total_wetted_area [546.9072] input ft**2 aircraft:nacelle:total_wetted_area - aircraft:vertical_tail:wetted_area [581.13] input ft**2 aircraft:vertical_tail:wetted_area - aircraft:wing:wetted_area [2396.56] input ft**2 aircraft:wing:wetted_area - aircraft:design:total_wetted_area [8275.8672] output ft**2 aircraft:design:total_wetted_area - core_aerodynamics - aircraft:wing:aspect_ratio [11.22091] input unitless aircraft:wing:aspect_ratio - aircraft:wing:max_camber_at_70_semispan [0.] input unitless aircraft:wing:max_camber_at_70_semispan - aircraft:wing:sweep [25.] input deg aircraft:wing:sweep - aircraft:wing:thickness_to_chord [0.13] input unitless aircraft:wing:thickness_to_chord - mission:design:mach [0.80017085] output unitless mission:design:mach - mission:design:lift_coefficient [0.56736557] output unitless mission:design:lift_coefficient - core_mass - cargo - aircraft:crew_and_payload:wing_cargo [0.] input lbm aircraft:crew_and_payload:wing_cargo - aircraft:crew_and_payload:misc_cargo [0.] input lbm aircraft:crew_and_payload:misc_cargo - aircraft:crew_and_payload:passenger_mass [30420.] output lbm aircraft:crew_and_payload:passenger_mass - aircraft:crew_and_payload:baggage_mass [7605.] output lbm aircraft:crew_and_payload:baggage_mass - aircraft:crew_and_payload:passenger_payload_mass [38025.] output lbm aircraft:crew_and_payload:passenger_payload_mass - aircraft:crew_and_payload:cargo_mass [0.] output lbm aircraft:crew_and_payload:cargo_mass - aircraft:crew_and_payload:total_payload_mass [38025.] output lbm aircraft:crew_and_payload:total_payload_mass - cargo_containers - aircraft:crew_and_payload:cargo_container_mass_scaler [1.] input unitless aircraft:crew_and_payload:cargo_container_mass_scaler - aircraft:crew_and_payload:cargo_mass [0.] input lbm aircraft:crew_and_payload:cargo_mass - aircraft:crew_and_payload:baggage_mass [7605.] input lbm aircraft:crew_and_payload:baggage_mass - aircraft:crew_and_payload:cargo_container_mass [1474.31956451] output lbm aircraft:crew_and_payload:cargo_container_mass - engine_controls - aircraft:propulsion:total_scaled_sls_thrust [57856.2] input lbf aircraft:propulsion:total_scaled_sls_thrust - aircraft:propulsion:total_engine_controls_mass [88.44296603] output lbm aircraft:propulsion:total_engine_controls_mass - avionics - aircraft:avionics:mass_scaler [1.2] input unitless aircraft:avionics:mass_scaler - aircraft:fuselage:planform_area [1578.24] input ft**2 aircraft:fuselage:planform_area - mission:design:range [3500.] input nmi mission:design:range - aircraft:avionics:mass [1652.64869221] output lbm aircraft:avionics:mass - fuel_capacity_group - wing_fuel_capacity - aircraft:fuel:density_ratio [1.] input unitless aircraft:fuel:density_ratio - aircraft:fuel:wing_ref_capacity [0.] input lbm aircraft:fuel:wing_ref_capacity - aircraft:fuel:wing_ref_capacity_area [0.] input unitless aircraft:fuel:wing_ref_capacity_area - aircraft:fuel:wing_ref_capacity_term_A [0.] input unitless aircraft:fuel:wing_ref_capacity_term_A - aircraft:fuel:wing_ref_capacity_term_B [0.] input unitless aircraft:fuel:wing_ref_capacity_term_B - aircraft:fuel:capacity_factor [1.] input unitless aircraft:fuel:capacity_factor - aircraft:wing:area [1370.] input ft**2 aircraft:wing:area - aircraft:wing:span [117.83] input ft aircraft:wing:span - aircraft:wing:taper_ratio [0.278] input unitless aircraft:wing:taper_ratio - aircraft:wing:thickness_to_chord [0.13] input unitless aircraft:wing:thickness_to_chord - aircraft:fuel:wing_fuel_capacity [1718.292967] output lbm aircraft:fuel:wing_fuel_capacity - fuselage_fuel_capacity - aircraft:fuel:total_capacity [45694.] input lbm aircraft:fuel:total_capacity - aircraft:fuel:wing_fuel_capacity [1718.292967] input lbm aircraft:fuel:wing_fuel_capacity - aircraft:fuel:fuselage_fuel_capacity [43975.707033] output lbm pre_mission.AUTO_OVERRIDE:aircraft:fuel:fuselage_fuel_capacity - auxiliary_fuel_capacity - aircraft:fuel:total_capacity [45694.] input lbm aircraft:fuel:total_capacity - aircraft:fuel:wing_fuel_capacity [1718.292967] input lbm aircraft:fuel:wing_fuel_capacity - aircraft:fuel:fuselage_fuel_capacity [0.] input lbm aircraft:fuel:fuselage_fuel_capacity - aircraft:fuel:auxiliary_fuel_capacity [43975.707033] output lbm pre_mission.AUTO_OVERRIDE:aircraft:fuel:auxiliary_fuel_capacity - total_fuel_capacity - aircraft:fuel:wing_fuel_capacity [1718.292967] input lbm aircraft:fuel:wing_fuel_capacity - aircraft:fuel:fuselage_fuel_capacity [0.] input lbm aircraft:fuel:fuselage_fuel_capacity - aircraft:fuel:auxiliary_fuel_capacity [0.] input lbm aircraft:fuel:auxiliary_fuel_capacity - aircraft:fuel:total_capacity [1718.292967] output lbm pre_mission.AUTO_OVERRIDE:aircraft:fuel:total_capacity - engine_mass - aircraft:engine:scaled_sls_thrust [28928.1] input lbf aircraft:engine:scaled_sls_thrust - aircraft:engine:mass_scaler [1.15] input unitless aircraft:engine:mass_scaler - aircraft:engine:mass [7400.] output lbm pre_mission.AUTO_OVERRIDE:aircraft:engine:mass - aircraft:engine:additional_mass [0.] output lbm aircraft:engine:additional_mass - aircraft:propulsion:total_engine_mass [14800.] output lbm aircraft:propulsion:total_engine_mass - fuel_system - aircraft:fuel:fuel_system_mass_scaler [1.] input unitless aircraft:fuel:fuel_system_mass_scaler - aircraft:fuel:total_capacity [45694.] input lbm aircraft:fuel:total_capacity - aircraft:fuel:fuel_system_mass [669.57723863] output lbm aircraft:fuel:fuel_system_mass - AC - aircraft:air_conditioning:mass_scaler [1.] input unitless aircraft:air_conditioning:mass_scaler - aircraft:avionics:mass [1652.64869221] input lbm aircraft:avionics:mass - aircraft:fuselage:max_height [13.17] input ft aircraft:fuselage:max_height - aircraft:fuselage:planform_area [1578.24] input ft**2 aircraft:fuselage:planform_area - aircraft:air_conditioning:mass [1601.88685398] output lbm aircraft:air_conditioning:mass - engine_oil - aircraft:propulsion:engine_oil_mass_scaler [1.] input unitless aircraft:propulsion:engine_oil_mass_scaler - aircraft:propulsion:total_scaled_sls_thrust [57856.2] input lbf aircraft:propulsion:total_scaled_sls_thrust - aircraft:propulsion:total_engine_oil_mass [130.22722599] output lbm aircraft:propulsion:total_engine_oil_mass - furnishings - aircraft:furnishings:mass_scaler [1.1] input unitless aircraft:furnishings:mass_scaler - aircraft:fuselage:passenger_compartment_length [85.5] input ft aircraft:fuselage:passenger_compartment_length - aircraft:fuselage:max_width [12.33] input ft aircraft:fuselage:max_width - aircraft:fuselage:max_height [13.17] input ft aircraft:fuselage:max_height - aircraft:furnishings:mass [15517.315] output lbm aircraft:furnishings:mass - hydraulics - aircraft:fuselage:planform_area [1578.24] input ft**2 aircraft:fuselage:planform_area - aircraft:hydraulics:system_pressure [3000.] input psi aircraft:hydraulics:system_pressure - aircraft:hydraulics:mass_scaler [1.] input unitless aircraft:hydraulics:mass_scaler - aircraft:wing:area [1370.] input ft**2 aircraft:wing:area - aircraft:wing:var_sweep_mass_penalty [0.] input unitless aircraft:wing:var_sweep_mass_penalty - aircraft:hydraulics:mass [1086.69550641] output lbm aircraft:hydraulics:mass - pass_service - aircraft:crew_and_payload:passenger_service_mass_scaler [1.] input unitless aircraft:crew_and_payload:passenger_service_mass_scaler - mission:design:range [3500.] input nmi mission:design:range - aircraft:crew_and_payload:passenger_service_mass [3022.74805809] output lbm aircraft:crew_and_payload:passenger_service_mass - unusable_fuel - aircraft:fuel:unusable_fuel_mass_scaler [1.] input unitless aircraft:fuel:unusable_fuel_mass_scaler - aircraft:fuel:density_ratio [1.] input unitless aircraft:fuel:density_ratio - aircraft:fuel:total_capacity [45694.] input lbm aircraft:fuel:total_capacity - aircraft:propulsion:total_scaled_sls_thrust [57856.2] input lbf aircraft:propulsion:total_scaled_sls_thrust - aircraft:wing:area [1370.] input ft**2 aircraft:wing:area - aircraft:fuel:total_volume [0.] output galUS aircraft:fuel:total_volume - aircraft:fuel:unusable_fuel_mass [501.30242136] output lbm aircraft:fuel:unusable_fuel_mass - electrical - aircraft:fuselage:length [128.] input ft aircraft:fuselage:length - aircraft:fuselage:max_width [12.33] input ft aircraft:fuselage:max_width - aircraft:electrical:mass_scaler [1.25] input unitless aircraft:electrical:mass_scaler - aircraft:electrical:mass [2463.87138047] output lbm aircraft:electrical:mass - starter - aircraft:nacelle:avg_diameter [7.94] input ft aircraft:nacelle:avg_diameter - aircraft:propulsion:total_starter_mass [560.39438467] output lbm aircraft:propulsion:total_starter_mass - anti_icing - aircraft:anti_icing:mass_scaler [1.] input unitless aircraft:anti_icing:mass_scaler - aircraft:fuselage:max_width [12.33] input ft aircraft:fuselage:max_width - aircraft:nacelle:avg_diameter [7.94] input ft aircraft:nacelle:avg_diameter - aircraft:wing:span [117.83] input ft aircraft:wing:span - aircraft:wing:sweep [25.] input deg aircraft:wing:sweep - aircraft:anti_icing:mass [208.85002019] output lbm aircraft:anti_icing:mass - apu - aircraft:apu:mass_scaler [1.1] input unitless aircraft:apu:mass_scaler - aircraft:fuselage:planform_area [1578.24] input ft**2 aircraft:fuselage:planform_area - aircraft:apu:mass [1142.06504141] output lbm aircraft:apu:mass - nonflight_crew - aircraft:crew_and_payload:non_flight_crew_mass_scaler [1.] input unitless aircraft:crew_and_payload:non_flight_crew_mass_scaler - aircraft:crew_and_payload:non_flight_crew_mass [465.] output lbm aircraft:crew_and_payload:non_flight_crew_mass - flight_crew - aircraft:crew_and_payload:flight_crew_mass_scaler [1.] input unitless aircraft:crew_and_payload:flight_crew_mass_scaler - aircraft:crew_and_payload:flight_crew_mass [450.] output lbm aircraft:crew_and_payload:flight_crew_mass - instruments - aircraft:fuselage:planform_area [1578.24] input ft**2 aircraft:fuselage:planform_area - aircraft:instruments:mass_scaler [1.25] input unitless aircraft:instruments:mass_scaler - aircraft:instruments:mass [601.16492884] output lbm aircraft:instruments:mass - misc_engine - aircraft:engine:additional_mass [0.] input lbm aircraft:engine:additional_mass - aircraft:propulsion:misc_mass_scaler [1.] input unitless aircraft:propulsion:misc_mass_scaler - aircraft:propulsion:total_engine_controls_mass [88.44296603] input lbm aircraft:propulsion:total_engine_controls_mass - aircraft:propulsion:total_starter_mass [560.39438467] input lbm aircraft:propulsion:total_starter_mass - aircraft:propulsion:total_misc_mass [648.8373507] output lbm aircraft:propulsion:total_misc_mass - nacelle - aircraft:nacelle:avg_diameter [7.94] input ft aircraft:nacelle:avg_diameter - aircraft:nacelle:avg_length [12.3] input ft aircraft:nacelle:avg_length - aircraft:nacelle:mass_scaler [1.] input unitless aircraft:nacelle:mass_scaler - aircraft:engine:scaled_sls_thrust [28928.1] input lbf aircraft:engine:scaled_sls_thrust - aircraft:nacelle:mass [1971.38199541] output lbm aircraft:nacelle:mass - paint - aircraft:design:total_wetted_area [8275.8672] input ft**2 aircraft:design:total_wetted_area - aircraft:paint:mass_per_unit_area [0.037] input lbm/ft**2 aircraft:paint:mass_per_unit_area - aircraft:paint:mass [306.2070864] output lbm aircraft:paint:mass - thrust_rev - aircraft:engine:thrust_reversers_mass_scaler [0.] input unitless aircraft:engine:thrust_reversers_mass_scaler - aircraft:engine:scaled_sls_thrust [28928.1] input lbf aircraft:engine:scaled_sls_thrust - aircraft:engine:thrust_reversers_mass [0.] output lbm aircraft:engine:thrust_reversers_mass - aircraft:propulsion:total_thrust_reversers_mass [0.] output lbm aircraft:propulsion:total_thrust_reversers_mass - landing_group - landing_to_takeoff_mass_ratio - mission:summary:cruise_mach [0.785] input unitless mission:summary:cruise_mach - mission:design:range [3500.] input nmi mission:design:range - aircraft:design:landing_to_takeoff_mass_ratio [0.86] output unitless aircraft:design:landing_to_takeoff_mass_ratio - main_landing_gear_length - aircraft:fuselage:length [128.] input ft aircraft:fuselage:length - aircraft:fuselage:max_width [12.33] input ft aircraft:fuselage:max_width - aircraft:nacelle:avg_diameter [7.94] input ft aircraft:nacelle:avg_diameter - aircraft:engine:wing_locations [0.26869218] input unitless aircraft:engine:wing_locations - aircraft:wing:dihedral [0.] input deg aircraft:wing:dihedral - aircraft:wing:span [117.83] input ft aircraft:wing:span - aircraft:landing_gear:main_gear_oleo_length [125.43479933] output inch pre_mission.AUTO_OVERRIDE:aircraft:landing_gear:main_gear_oleo_length - nose_landing_gear_length - aircraft:landing_gear:main_gear_oleo_length [102.] input inch aircraft:landing_gear:main_gear_oleo_length - aircraft:landing_gear:nose_gear_oleo_length [71.4] output inch pre_mission.AUTO_OVERRIDE:aircraft:landing_gear:nose_gear_oleo_length - landing_mass - mission:design:gross_mass [130904.19882744] input lbm mission:design:gross_mass - aircraft:design:landing_to_takeoff_mass_ratio [0.86] input unitless aircraft:design:landing_to_takeoff_mass_ratio - aircraft:design:touchdown_mass [112577.61099159] output lbm pre_mission.AUTO_OVERRIDE:aircraft:design:touchdown_mass - landing_gear - aircraft:landing_gear:main_gear_oleo_length [102.] input inch aircraft:landing_gear:main_gear_oleo_length - aircraft:landing_gear:main_gear_mass_scaler [1.1] input unitless aircraft:landing_gear:main_gear_mass_scaler - aircraft:landing_gear:nose_gear_oleo_length [67.] input inch aircraft:landing_gear:nose_gear_oleo_length - aircraft:landing_gear:nose_gear_mass_scaler [1.] input unitless aircraft:landing_gear:nose_gear_mass_scaler - aircraft:design:touchdown_mass [152800.] input lbm aircraft:design:touchdown_mass - aircraft:landing_gear:main_gear_mass [7910.31553228] output lbm aircraft:landing_gear:main_gear_mass - aircraft:landing_gear:nose_gear_mass [870.59476203] output lbm aircraft:landing_gear:nose_gear_mass - surf_ctrl - aircraft:wing:surface_ctrl_mass_scaler [1.] input unitless aircraft:wing:surface_ctrl_mass_scaler - mission:design:gross_mass [130904.19882744] input lbm mission:design:gross_mass - aircraft:wing:control_surface_area_ratio [0.1] input unitless aircraft:wing:control_surface_area_ratio - aircraft:wing:area [1370.] input ft**2 aircraft:wing:area - aircraft:wing:surface_ctrl_mass [805.71674878] output lbm aircraft:wing:surface_ctrl_mass - aircraft:wing:control_surface_area [137.] output ft**2 pre_mission.AUTO_OVERRIDE:aircraft:wing:control_surface_area - fuselage - aircraft:fuselage:length [128.] input ft aircraft:fuselage:length - aircraft:fuselage:mass_scaler [1.05] input unitless aircraft:fuselage:mass_scaler - aircraft:fuselage:avg_diameter [12.75] input ft aircraft:fuselage:avg_diameter - aircraft:fuselage:mass [18357.13345514] output lbm pre_mission.EXTERNAL_OVERRIDE:aircraft:fuselage:mass - htail - aircraft:horizontal_tail:area [355.] input ft**2 aircraft:horizontal_tail:area - aircraft:horizontal_tail:taper_ratio [0.22] input unitless aircraft:horizontal_tail:taper_ratio - mission:design:gross_mass [130904.19882744] input lbm mission:design:gross_mass - aircraft:horizontal_tail:mass_scaler [1.2] input unitless aircraft:horizontal_tail:mass_scaler - aircraft:horizontal_tail:mass [1715.57093767] output lbm pre_mission.EXTERNAL_OVERRIDE:aircraft:horizontal_tail:mass - vert_tail - aircraft:vertical_tail:area [284.] input ft**2 aircraft:vertical_tail:area - aircraft:vertical_tail:taper_ratio [0.33] input unitless aircraft:vertical_tail:taper_ratio - aircraft:vertical_tail:mass_scaler [1.] input unitless aircraft:vertical_tail:mass_scaler - mission:design:gross_mass [130904.19882744] input lbm mission:design:gross_mass - aircraft:vertical_tail:mass [1108.24232631] output lbm pre_mission.EXTERNAL_OVERRIDE:aircraft:vertical_tail:mass - canard - mission:design:gross_mass [130904.19882744] input lbm mission:design:gross_mass - aircraft:canard:area [0.] input ft**2 aircraft:canard:area - aircraft:canard:taper_ratio [0.] input unitless aircraft:canard:taper_ratio - aircraft:canard:mass_scaler [1.] input unitless aircraft:canard:mass_scaler - aircraft:canard:mass [0.] output lbm aircraft:canard:mass - fin - mission:design:gross_mass [130904.19882744] input lbm mission:design:gross_mass - aircraft:fins:area [0.] input ft**2 aircraft:fins:area - aircraft:fins:taper_ratio [10.] input unitless aircraft:fins:taper_ratio - aircraft:fins:mass_scaler [1.] input unitless aircraft:fins:mass_scaler - aircraft:fins:mass [0.] output lbm pre_mission.AUTO_OVERRIDE:aircraft:fins:mass - wing_group - engine_pod_mass - aircraft:electrical:mass [2463.87138047] input lbm aircraft:electrical:mass - aircraft:fuel:fuel_system_mass [669.57723863] input lbm aircraft:fuel:fuel_system_mass - aircraft:hydraulics:mass [1086.69550641] input lbm aircraft:hydraulics:mass - aircraft:instruments:mass [601.16492884] input lbm aircraft:instruments:mass - aircraft:nacelle:mass [1971.38199541] input lbm aircraft:nacelle:mass - aircraft:propulsion:total_engine_controls_mass [88.44296603] input lbm aircraft:propulsion:total_engine_controls_mass - aircraft:engine:mass [7400.] input lbm aircraft:engine:mass - aircraft:propulsion:total_starter_mass [560.39438467] input lbm aircraft:propulsion:total_starter_mass - aircraft:engine:thrust_reversers_mass [0.] input lbm aircraft:engine:thrust_reversers_mass - aircraft:engine:scaled_sls_thrust [28928.1] input lbf aircraft:engine:scaled_sls_thrust - aircraft:propulsion:total_scaled_sls_thrust [57856.2] input lbf aircraft:propulsion:total_scaled_sls_thrust - aircraft:engine:pod_mass [9024.49163435] output lbm aircraft:engine:pod_mass - wing_bending_material_factor - aircraft:wing:load_path_sweep_dist |22.0| input deg aircraft:wing:load_path_sweep_dist - val: - array([ 0., 22.]) - aircraft:wing:thickness_to_chord_dist |0.21228754| input unitless aircraft:wing:thickness_to_chord_dist - val: - array([0.145, 0.115, 0.104]) - aircraft:wing:chord_per_semispan |0.39503924| input unitless aircraft:wing:chord_per_semispan - val: - array([0.31 , 0.23 , 0.084]) - mission:design:gross_mass [130904.19882744] input lbm mission:design:gross_mass - aircraft:engine:pod_mass [9024.49163435] input lbm aircraft:engine:pod_mass - aircraft:wing:aspect_ratio [11.22091] input unitless aircraft:wing:aspect_ratio - aircraft:wing:aspect_ratio_reference [0.] input unitless aircraft:wing:aspect_ratio_reference - aircraft:wing:strut_bracing_factor [0.] input unitless aircraft:wing:strut_bracing_factor - aircraft:wing:aeroelastic_tailoring_factor [0.] input unitless aircraft:wing:aeroelastic_tailoring_factor - aircraft:engine:wing_locations [0.26869218] input unitless aircraft:engine:wing_locations - aircraft:wing:thickness_to_chord [0.13] input unitless aircraft:wing:thickness_to_chord - aircraft:wing:thickness_to_chord_reference [0.] input unitless aircraft:wing:thickness_to_chord_reference - aircraft:wing:bending_material_factor [11.5916567] output unitless aircraft:wing:bending_material_factor - aircraft:wing:eng_pod_inertia_factor [0.95478088] output unitless aircraft:wing:eng_pod_inertia_factor - wing_misc - aircraft:wing:composite_fraction [0.2] input unitless aircraft:wing:composite_fraction - aircraft:wing:area [1370.] input ft**2 aircraft:wing:area - aircraft:wing:misc_mass_scaler [1.] input unitless aircraft:wing:misc_mass_scaler - aircraft:wing:misc_mass [1668.30998341] output lbm aircraft:wing:misc_mass - wing_shear_control - aircraft:wing:composite_fraction [0.2] input unitless aircraft:wing:composite_fraction - aircraft:wing:control_surface_area [137.] input ft**2 aircraft:wing:control_surface_area - mission:design:gross_mass [130904.19882744] input lbm mission:design:gross_mass - aircraft:wing:shear_control_mass_scaler [1.] input unitless aircraft:wing:shear_control_mass_scaler - aircraft:wing:shear_control_mass [4112.85291254] output lbm aircraft:wing:shear_control_mass - wing_bending - mission:design:gross_mass [130904.19882744] input lbm mission:design:gross_mass - aircraft:wing:aeroelastic_tailoring_factor [0.] input unitless aircraft:wing:aeroelastic_tailoring_factor - aircraft:wing:bending_material_factor [11.5916567] input unitless aircraft:wing:bending_material_factor - aircraft:wing:bending_material_mass_scaler [1.] input unitless aircraft:wing:bending_material_mass_scaler - aircraft:wing:composite_fraction [0.2] input unitless aircraft:wing:composite_fraction - aircraft:wing:eng_pod_inertia_factor [0.95478088] input unitless aircraft:wing:eng_pod_inertia_factor - aircraft:wing:load_fraction [1.] input unitless aircraft:wing:load_fraction - aircraft:wing:misc_mass [1668.30998341] input lbm aircraft:wing:misc_mass - aircraft:wing:misc_mass_scaler [1.] input unitless aircraft:wing:misc_mass_scaler - aircraft:wing:shear_control_mass [4112.85291254] input lbm aircraft:wing:shear_control_mass - aircraft:wing:shear_control_mass_scaler [1.] input unitless aircraft:wing:shear_control_mass_scaler - aircraft:wing:span [117.83] input ft aircraft:wing:span - aircraft:wing:sweep [25.] input deg aircraft:wing:sweep - aircraft:wing:ultimate_load_factor [3.75] input unitless aircraft:wing:ultimate_load_factor - aircraft:wing:var_sweep_mass_penalty [0.] input unitless aircraft:wing:var_sweep_mass_penalty - aircraft:wing:bending_material_mass [5786.25146563] output lbm aircraft:wing:bending_material_mass - wing_total - aircraft:wing:bending_material_mass [5786.25146563] input lbm aircraft:wing:bending_material_mass - aircraft:wing:shear_control_mass [4112.85291254] input lbm aircraft:wing:shear_control_mass - aircraft:wing:misc_mass [1668.30998341] input lbm aircraft:wing:misc_mass - aircraft:wing:bwb_aft_body_mass [0.] input lbm aircraft:wing:bwb_aft_body_mass - aircraft:wing:mass_scaler [1.23] input unitless aircraft:wing:mass_scaler - aircraft:wing:mass [14227.91966474] output lbm pre_mission.EXTERNAL_OVERRIDE:aircraft:wing:mass - total_mass - structure_mass - aircraft:canard:mass [0.] input lbm aircraft:canard:mass - aircraft:fins:mass [0.] input lbm aircraft:fins:mass - aircraft:fuselage:mass [11484.15203519] input lbm aircraft:fuselage:mass - aircraft:horizontal_tail:mass [0.] input lbm aircraft:horizontal_tail:mass - aircraft:landing_gear:main_gear_mass [7910.31553228] input lbm aircraft:landing_gear:main_gear_mass - aircraft:landing_gear:nose_gear_mass [870.59476203] input lbm aircraft:landing_gear:nose_gear_mass - aircraft:nacelle:mass [1971.38199541] input lbm aircraft:nacelle:mass - aircraft:paint:mass [306.2070864] input lbm aircraft:paint:mass - aircraft:vertical_tail:mass [0.] input lbm aircraft:vertical_tail:mass - aircraft:wing:mass [4.95303746] input lbm aircraft:wing:mass - aircraft:design:structure_mass [22547.60444877] output lbm aircraft:design:structure_mass - propulsion_mass - aircraft:fuel:fuel_system_mass [669.57723863] input lbm aircraft:fuel:fuel_system_mass - aircraft:propulsion:total_misc_mass [648.8373507] input lbm aircraft:propulsion:total_misc_mass - aircraft:propulsion:total_thrust_reversers_mass [0.] input lbm aircraft:propulsion:total_thrust_reversers_mass - aircraft:propulsion:total_engine_mass [14800.] input lbm aircraft:propulsion:total_engine_mass - aircraft:propulsion:mass [16118.41458932] output lbm aircraft:propulsion:mass - system_equip_mass - aircraft:air_conditioning:mass [1601.88685398] input lbm aircraft:air_conditioning:mass - aircraft:anti_icing:mass [208.85002019] input lbm aircraft:anti_icing:mass - aircraft:apu:mass [1142.06504141] input lbm aircraft:apu:mass - aircraft:avionics:mass [1652.64869221] input lbm aircraft:avionics:mass - aircraft:electrical:mass [2463.87138047] input lbm aircraft:electrical:mass - aircraft:furnishings:mass [15517.315] input lbm aircraft:furnishings:mass - aircraft:hydraulics:mass [1086.69550641] input lbm aircraft:hydraulics:mass - aircraft:instruments:mass [601.16492884] input lbm aircraft:instruments:mass - aircraft:wing:surface_ctrl_mass [805.71674878] input lbm aircraft:wing:surface_ctrl_mass - aircraft:design:external_subsystems_mass [0.] input lbm aircraft:design:external_subsystems_mass - aircraft:design:systems_equip_mass [25080.21417229] output lbm aircraft:design:systems_equip_mass - empty_mass_margin - aircraft:propulsion:mass [16118.41458932] input lbm aircraft:propulsion:mass - aircraft:design:structure_mass [22547.60444877] input lbm aircraft:design:structure_mass - aircraft:design:systems_equip_mass [25080.21417229] input lbm aircraft:design:systems_equip_mass - aircraft:design:empty_mass_margin_scaler [0.] input unitless aircraft:design:empty_mass_margin_scaler - aircraft:design:empty_mass_margin [0.] output lbm aircraft:design:empty_mass_margin - empty_mass - aircraft:design:empty_mass_margin [0.] input lbm aircraft:design:empty_mass_margin - aircraft:design:structure_mass [22547.60444877] input lbm aircraft:design:structure_mass - aircraft:propulsion:mass [16118.41458932] input lbm aircraft:propulsion:mass - aircraft:design:systems_equip_mass [25080.21417229] input lbm aircraft:design:systems_equip_mass - aircraft:design:empty_mass [63746.23321038] output lbm aircraft:design:empty_mass - operating_mass - aircraft:crew_and_payload:cargo_container_mass [1474.31956451] input lbm aircraft:crew_and_payload:cargo_container_mass - aircraft:crew_and_payload:non_flight_crew_mass [465.] input lbm aircraft:crew_and_payload:non_flight_crew_mass - aircraft:crew_and_payload:flight_crew_mass [450.] input lbm aircraft:crew_and_payload:flight_crew_mass - aircraft:crew_and_payload:passenger_service_mass [3022.74805809] input lbm aircraft:crew_and_payload:passenger_service_mass - aircraft:design:empty_mass [63746.23321038] input lbm aircraft:design:empty_mass - aircraft:fuel:unusable_fuel_mass [501.30242136] input lbm aircraft:fuel:unusable_fuel_mass - aircraft:propulsion:total_engine_oil_mass [130.22722599] input lbm aircraft:propulsion:total_engine_oil_mass - aircraft:design:operating_mass [69789.83048032] output lbm aircraft:design:operating_mass - zero_fuel_mass - aircraft:crew_and_payload:passenger_mass [30420.] input lbm aircraft:crew_and_payload:passenger_mass - aircraft:crew_and_payload:baggage_mass [7605.] input lbm aircraft:crew_and_payload:baggage_mass - aircraft:crew_and_payload:cargo_mass [0.] input lbm aircraft:crew_and_payload:cargo_mass - aircraft:design:operating_mass [69789.83048032] input lbm aircraft:design:operating_mass - aircraft:design:zero_fuel_mass [107814.83048032] output lbm aircraft:design:zero_fuel_mass - fuel_mass - mission:design:gross_mass [130904.19882744] input lbm mission:design:gross_mass - aircraft:design:zero_fuel_mass [107814.83048032] input lbm aircraft:design:zero_fuel_mass - mission:design:fuel_mass [23089.36834711] output lbm mission:design:fuel_mass -traj - param_comp - parameters:aircraft:design:base_area [0.] input ft**2 aircraft:design:base_area - parameters:aircraft:design:lift_dependent_drag_coeff_factor [0.90983938] input unitless aircraft:design:lift_dependent_drag_coeff_factor - parameters:aircraft:design:subsonic_drag_coeff_factor [1.] input unitless aircraft:design:subsonic_drag_coeff_factor - parameters:aircraft:design:supersonic_drag_coeff_factor [1.] input unitless aircraft:design:supersonic_drag_coeff_factor - parameters:aircraft:design:zero_lift_drag_coeff_factor [0.93089003] input unitless aircraft:design:zero_lift_drag_coeff_factor - parameters:aircraft:fuselage:characteristic_length [128.] input ft aircraft:fuselage:characteristic_length - parameters:aircraft:fuselage:cross_section [127.67628894] input ft**2 aircraft:fuselage:cross_section - parameters:aircraft:fuselage:diameter_to_wing_span [0.10826471] input unitless aircraft:fuselage:diameter_to_wing_span - parameters:aircraft:fuselage:fineness [10.03921569] input unitless aircraft:fuselage:fineness - parameters:aircraft:fuselage:laminar_flow_lower [0.] input unitless aircraft:fuselage:laminar_flow_lower - parameters:aircraft:fuselage:laminar_flow_upper [0.] input unitless aircraft:fuselage:laminar_flow_upper - parameters:aircraft:fuselage:length_to_diameter [10.03921569] input unitless aircraft:fuselage:length_to_diameter - parameters:aircraft:fuselage:wetted_area [4158.62] input ft**2 aircraft:fuselage:wetted_area - parameters:aircraft:horizontal_tail:characteristic_length [7.69198717] input ft aircraft:horizontal_tail:characteristic_length - parameters:aircraft:horizontal_tail:fineness [0.125] input unitless aircraft:horizontal_tail:fineness - parameters:aircraft:horizontal_tail:laminar_flow_lower [0.] input unitless aircraft:horizontal_tail:laminar_flow_lower - parameters:aircraft:horizontal_tail:laminar_flow_upper [0.] input unitless aircraft:horizontal_tail:laminar_flow_upper - parameters:aircraft:horizontal_tail:wetted_area [592.65] input ft**2 aircraft:horizontal_tail:wetted_area - parameters:aircraft:vertical_tail:characteristic_length [12.73914103] input ft aircraft:vertical_tail:characteristic_length - parameters:aircraft:vertical_tail:fineness [0.1195] input unitless aircraft:vertical_tail:fineness - parameters:aircraft:vertical_tail:laminar_flow_lower [0.] input unitless aircraft:vertical_tail:laminar_flow_lower - parameters:aircraft:vertical_tail:laminar_flow_upper [0.] input unitless aircraft:vertical_tail:laminar_flow_upper - parameters:aircraft:vertical_tail:wetted_area [581.13] input ft**2 aircraft:vertical_tail:wetted_area - parameters:aircraft:wing:area [1370.] input ft**2 aircraft:wing:area - parameters:aircraft:wing:aspect_ratio [11.22091] input unitless aircraft:wing:aspect_ratio - parameters:aircraft:wing:characteristic_length [10.49530819] input ft aircraft:wing:characteristic_length - parameters:aircraft:wing:fineness [0.13] input unitless aircraft:wing:fineness - parameters:aircraft:wing:laminar_flow_lower [0.] input unitless aircraft:wing:laminar_flow_lower - parameters:aircraft:wing:laminar_flow_upper [0.] input unitless aircraft:wing:laminar_flow_upper - parameters:aircraft:wing:max_camber_at_70_semispan [0.] input unitless aircraft:wing:max_camber_at_70_semispan - parameters:aircraft:wing:span_efficiency_factor [1.] input unitless aircraft:wing:span_efficiency_factor - parameters:aircraft:wing:sweep [25.] input deg aircraft:wing:sweep - parameters:aircraft:wing:taper_ratio [0.278] input unitless aircraft:wing:taper_ratio - parameters:aircraft:wing:thickness_to_chord [0.13] input unitless aircraft:wing:thickness_to_chord - parameters:aircraft:wing:wetted_area [2396.56] input ft**2 aircraft:wing:wetted_area - parameters:mission:design:lift_coefficient [0.56736557] input unitless mission:design:lift_coefficient - parameters:mission:design:mach [0.80017085] input unitless mission:design:mach - parameters:aircraft:nacelle:characteristic_length [12.3] input ft aircraft:nacelle:characteristic_length - parameters:aircraft:nacelle:fineness [1.54911839] input unitless aircraft:nacelle:fineness - parameters:aircraft:nacelle:laminar_flow_lower [0.] input unitless aircraft:nacelle:laminar_flow_lower - parameters:aircraft:nacelle:laminar_flow_upper [0.] input unitless aircraft:nacelle:laminar_flow_upper - parameters:aircraft:nacelle:wetted_area [273.4536] input ft**2 aircraft:nacelle:wetted_area - parameters:aircraft:engine:scale_factor [1.] input unitless aircraft:engine:scale_factor - parameter_vals:aircraft:design:base_area [[0.]] output ft**2 traj.parameter_vals:aircraft:design:base_area - parameter_vals:aircraft:design:lift_dependent_drag_coeff_factor [[0.90983938]] output unitless traj.parameter_vals:aircraft:design:lift_dependent_drag_coeff_factor - parameter_vals:aircraft:design:subsonic_drag_coeff_factor [[1.]] output unitless traj.parameter_vals:aircraft:design:subsonic_drag_coeff_factor - parameter_vals:aircraft:design:supersonic_drag_coeff_factor [[1.]] output unitless traj.parameter_vals:aircraft:design:supersonic_drag_coeff_factor - parameter_vals:aircraft:design:zero_lift_drag_coeff_factor [[0.93089003]] output unitless traj.parameter_vals:aircraft:design:zero_lift_drag_coeff_factor - parameter_vals:aircraft:fuselage:characteristic_length [[128.]] output ft traj.parameter_vals:aircraft:fuselage:characteristic_length - parameter_vals:aircraft:fuselage:cross_section [[127.67628894]] output ft**2 traj.parameter_vals:aircraft:fuselage:cross_section - parameter_vals:aircraft:fuselage:diameter_to_wing_span [[0.10826471]] output unitless traj.parameter_vals:aircraft:fuselage:diameter_to_wing_span - parameter_vals:aircraft:fuselage:fineness [[10.03921569]] output unitless traj.parameter_vals:aircraft:fuselage:fineness - parameter_vals:aircraft:fuselage:laminar_flow_lower [[0.]] output unitless traj.parameter_vals:aircraft:fuselage:laminar_flow_lower - parameter_vals:aircraft:fuselage:laminar_flow_upper [[0.]] output unitless traj.parameter_vals:aircraft:fuselage:laminar_flow_upper - parameter_vals:aircraft:fuselage:length_to_diameter [[10.03921569]] output unitless traj.parameter_vals:aircraft:fuselage:length_to_diameter - parameter_vals:aircraft:fuselage:wetted_area [[4158.62]] output ft**2 traj.parameter_vals:aircraft:fuselage:wetted_area - parameter_vals:aircraft:horizontal_tail:characteristic_length [[7.69198717]] output ft traj.parameter_vals:aircraft:horizontal_tail:characteristic_length - parameter_vals:aircraft:horizontal_tail:fineness [[0.125]] output unitless traj.parameter_vals:aircraft:horizontal_tail:fineness - parameter_vals:aircraft:horizontal_tail:laminar_flow_lower [[0.]] output unitless traj.parameter_vals:aircraft:horizontal_tail:laminar_flow_lower - parameter_vals:aircraft:horizontal_tail:laminar_flow_upper [[0.]] output unitless traj.parameter_vals:aircraft:horizontal_tail:laminar_flow_upper - parameter_vals:aircraft:horizontal_tail:wetted_area [[592.65]] output ft**2 traj.parameter_vals:aircraft:horizontal_tail:wetted_area - parameter_vals:aircraft:vertical_tail:characteristic_length [[12.73914103]] output ft traj.parameter_vals:aircraft:vertical_tail:characteristic_length - parameter_vals:aircraft:vertical_tail:fineness [[0.1195]] output unitless traj.parameter_vals:aircraft:vertical_tail:fineness - parameter_vals:aircraft:vertical_tail:laminar_flow_lower [[0.]] output unitless traj.parameter_vals:aircraft:vertical_tail:laminar_flow_lower - parameter_vals:aircraft:vertical_tail:laminar_flow_upper [[0.]] output unitless traj.parameter_vals:aircraft:vertical_tail:laminar_flow_upper - parameter_vals:aircraft:vertical_tail:wetted_area [[581.13]] output ft**2 traj.parameter_vals:aircraft:vertical_tail:wetted_area - parameter_vals:aircraft:wing:area [[1370.]] output ft**2 traj.parameter_vals:aircraft:wing:area - parameter_vals:aircraft:wing:aspect_ratio [[11.22091]] output unitless traj.parameter_vals:aircraft:wing:aspect_ratio - parameter_vals:aircraft:wing:characteristic_length [[10.49530819]] output ft traj.parameter_vals:aircraft:wing:characteristic_length - parameter_vals:aircraft:wing:fineness [[0.13]] output unitless traj.parameter_vals:aircraft:wing:fineness - parameter_vals:aircraft:wing:laminar_flow_lower [[0.]] output unitless traj.parameter_vals:aircraft:wing:laminar_flow_lower - parameter_vals:aircraft:wing:laminar_flow_upper [[0.]] output unitless traj.parameter_vals:aircraft:wing:laminar_flow_upper - parameter_vals:aircraft:wing:max_camber_at_70_semispan [[0.]] output unitless traj.parameter_vals:aircraft:wing:max_camber_at_70_semispan - parameter_vals:aircraft:wing:span_efficiency_factor [[1.]] output unitless traj.parameter_vals:aircraft:wing:span_efficiency_factor - parameter_vals:aircraft:wing:sweep [[25.]] output deg traj.parameter_vals:aircraft:wing:sweep - parameter_vals:aircraft:wing:taper_ratio [[0.278]] output unitless traj.parameter_vals:aircraft:wing:taper_ratio - parameter_vals:aircraft:wing:thickness_to_chord [[0.13]] output unitless traj.parameter_vals:aircraft:wing:thickness_to_chord - parameter_vals:aircraft:wing:wetted_area [[2396.56]] output ft**2 traj.parameter_vals:aircraft:wing:wetted_area - parameter_vals:mission:design:lift_coefficient [[0.56736557]] output unitless traj.parameter_vals:mission:design:lift_coefficient - parameter_vals:mission:design:mach [[0.80017085]] output unitless traj.parameter_vals:mission:design:mach - parameter_vals:aircraft:nacelle:characteristic_length [[12.3]] output ft traj.parameter_vals:aircraft:nacelle:characteristic_length - parameter_vals:aircraft:nacelle:fineness [[1.54911839]] output unitless traj.parameter_vals:aircraft:nacelle:fineness - parameter_vals:aircraft:nacelle:laminar_flow_lower [[0.]] output unitless traj.parameter_vals:aircraft:nacelle:laminar_flow_lower - parameter_vals:aircraft:nacelle:laminar_flow_upper [[0.]] output unitless traj.parameter_vals:aircraft:nacelle:laminar_flow_upper - parameter_vals:aircraft:nacelle:wetted_area [[273.4536]] output ft**2 traj.parameter_vals:aircraft:nacelle:wetted_area - parameter_vals:aircraft:engine:scale_factor [[1.]] output unitless traj.parameter_vals:aircraft:engine:scale_factor - phases - climb - param_comp - t_initial [0.] input s traj.climb.t_initial - t_duration [3840.] input s traj.climb.t_duration - parameters:aircraft:design:base_area [0.] input ft**2 traj.climb.parameters:aircraft:design:base_area - parameters:aircraft:design:lift_dependent_drag_coeff_factor [0.90983938] input unitless traj.climb.parameters:aircraft:design:lift_dependent_drag_coeff_factor - parameters:aircraft:design:subsonic_drag_coeff_factor [1.] input unitless traj.climb.parameters:aircraft:design:subsonic_drag_coeff_factor - parameters:aircraft:design:supersonic_drag_coeff_factor [1.] input unitless traj.climb.parameters:aircraft:design:supersonic_drag_coeff_factor - parameters:aircraft:design:zero_lift_drag_coeff_factor [0.93089003] input unitless traj.climb.parameters:aircraft:design:zero_lift_drag_coeff_factor - parameters:aircraft:fuselage:characteristic_length [128.] input ft traj.climb.parameters:aircraft:fuselage:characteristic_length - parameters:aircraft:fuselage:cross_section [127.67628894] input ft**2 traj.climb.parameters:aircraft:fuselage:cross_section - parameters:aircraft:fuselage:diameter_to_wing_span [0.10826471] input unitless traj.climb.parameters:aircraft:fuselage:diameter_to_wing_span - parameters:aircraft:fuselage:fineness [10.03921569] input unitless traj.climb.parameters:aircraft:fuselage:fineness - parameters:aircraft:fuselage:laminar_flow_lower [0.] input unitless traj.climb.parameters:aircraft:fuselage:laminar_flow_lower - parameters:aircraft:fuselage:laminar_flow_upper [0.] input unitless traj.climb.parameters:aircraft:fuselage:laminar_flow_upper - parameters:aircraft:fuselage:length_to_diameter [10.03921569] input unitless traj.climb.parameters:aircraft:fuselage:length_to_diameter - parameters:aircraft:fuselage:wetted_area [4158.62] input ft**2 traj.climb.parameters:aircraft:fuselage:wetted_area - parameters:aircraft:horizontal_tail:characteristic_length [7.69198717] input ft traj.climb.parameters:aircraft:horizontal_tail:characteristic_length - parameters:aircraft:horizontal_tail:fineness [0.125] input unitless traj.climb.parameters:aircraft:horizontal_tail:fineness - parameters:aircraft:horizontal_tail:laminar_flow_lower [0.] input unitless traj.climb.parameters:aircraft:horizontal_tail:laminar_flow_lower - parameters:aircraft:horizontal_tail:laminar_flow_upper [0.] input unitless traj.climb.parameters:aircraft:horizontal_tail:laminar_flow_upper - parameters:aircraft:horizontal_tail:wetted_area [592.65] input ft**2 traj.climb.parameters:aircraft:horizontal_tail:wetted_area - parameters:aircraft:vertical_tail:characteristic_length [12.73914103] input ft traj.climb.parameters:aircraft:vertical_tail:characteristic_length - parameters:aircraft:vertical_tail:fineness [0.1195] input unitless traj.climb.parameters:aircraft:vertical_tail:fineness - parameters:aircraft:vertical_tail:laminar_flow_lower [0.] input unitless traj.climb.parameters:aircraft:vertical_tail:laminar_flow_lower - parameters:aircraft:vertical_tail:laminar_flow_upper [0.] input unitless traj.climb.parameters:aircraft:vertical_tail:laminar_flow_upper - parameters:aircraft:vertical_tail:wetted_area [581.13] input ft**2 traj.climb.parameters:aircraft:vertical_tail:wetted_area - parameters:aircraft:wing:area [1370.] input ft**2 traj.climb.parameters:aircraft:wing:area - parameters:aircraft:wing:aspect_ratio [11.22091] input unitless traj.climb.parameters:aircraft:wing:aspect_ratio - parameters:aircraft:wing:characteristic_length [10.49530819] input ft traj.climb.parameters:aircraft:wing:characteristic_length - parameters:aircraft:wing:fineness [0.13] input unitless traj.climb.parameters:aircraft:wing:fineness - parameters:aircraft:wing:laminar_flow_lower [0.] input unitless traj.climb.parameters:aircraft:wing:laminar_flow_lower - parameters:aircraft:wing:laminar_flow_upper [0.] input unitless traj.climb.parameters:aircraft:wing:laminar_flow_upper - parameters:aircraft:wing:max_camber_at_70_semispan [0.] input unitless traj.climb.parameters:aircraft:wing:max_camber_at_70_semispan - parameters:aircraft:wing:span_efficiency_factor [1.] input unitless traj.climb.parameters:aircraft:wing:span_efficiency_factor - parameters:aircraft:wing:sweep [25.] input deg traj.climb.parameters:aircraft:wing:sweep - parameters:aircraft:wing:taper_ratio [0.278] input unitless traj.climb.parameters:aircraft:wing:taper_ratio - parameters:aircraft:wing:thickness_to_chord [0.13] input unitless traj.climb.parameters:aircraft:wing:thickness_to_chord - parameters:aircraft:wing:wetted_area [2396.56] input ft**2 traj.climb.parameters:aircraft:wing:wetted_area - parameters:mission:design:lift_coefficient [0.56736557] input unitless traj.climb.parameters:mission:design:lift_coefficient - parameters:mission:design:mach [0.80017085] input unitless traj.climb.parameters:mission:design:mach - parameters:aircraft:nacelle:characteristic_length [12.3] input ft traj.climb.parameters:aircraft:nacelle:characteristic_length - parameters:aircraft:nacelle:fineness [1.54911839] input unitless traj.climb.parameters:aircraft:nacelle:fineness - parameters:aircraft:nacelle:laminar_flow_lower [0.] input unitless traj.climb.parameters:aircraft:nacelle:laminar_flow_lower - parameters:aircraft:nacelle:laminar_flow_upper [0.] input unitless traj.climb.parameters:aircraft:nacelle:laminar_flow_upper - parameters:aircraft:nacelle:wetted_area [273.4536] input ft**2 traj.climb.parameters:aircraft:nacelle:wetted_area - parameters:aircraft:engine:scale_factor [1.] input unitless traj.climb.parameters:aircraft:engine:scale_factor - t_initial_val [0.] output s traj.climb.t_initial_val - t_duration_val [3840.] output s traj.climb.t_duration_val - parameter_vals:aircraft:design:base_area [[0.]] output ft**2 traj.climb.parameter_vals:aircraft:design:base_area - parameter_vals:aircraft:design:lift_dependent_drag_coeff_factor [[0.90983938]] output unitless traj.climb.parameter_vals:aircraft:design:lift_dependent_drag_coeff_factor - parameter_vals:aircraft:design:subsonic_drag_coeff_factor [[1.]] output unitless traj.climb.parameter_vals:aircraft:design:subsonic_drag_coeff_factor - parameter_vals:aircraft:design:supersonic_drag_coeff_factor [[1.]] output unitless traj.climb.parameter_vals:aircraft:design:supersonic_drag_coeff_factor - parameter_vals:aircraft:design:zero_lift_drag_coeff_factor [[0.93089003]] output unitless traj.climb.parameter_vals:aircraft:design:zero_lift_drag_coeff_factor - parameter_vals:aircraft:fuselage:characteristic_length [[128.]] output ft traj.climb.parameter_vals:aircraft:fuselage:characteristic_length - parameter_vals:aircraft:fuselage:cross_section [[127.67628894]] output ft**2 traj.climb.parameter_vals:aircraft:fuselage:cross_section - parameter_vals:aircraft:fuselage:diameter_to_wing_span [[0.10826471]] output unitless traj.climb.parameter_vals:aircraft:fuselage:diameter_to_wing_span - parameter_vals:aircraft:fuselage:fineness [[10.03921569]] output unitless traj.climb.parameter_vals:aircraft:fuselage:fineness - parameter_vals:aircraft:fuselage:laminar_flow_lower [[0.]] output unitless traj.climb.parameter_vals:aircraft:fuselage:laminar_flow_lower - parameter_vals:aircraft:fuselage:laminar_flow_upper [[0.]] output unitless traj.climb.parameter_vals:aircraft:fuselage:laminar_flow_upper - parameter_vals:aircraft:fuselage:length_to_diameter [[10.03921569]] output unitless traj.climb.parameter_vals:aircraft:fuselage:length_to_diameter - parameter_vals:aircraft:fuselage:wetted_area [[4158.62]] output ft**2 traj.climb.parameter_vals:aircraft:fuselage:wetted_area - parameter_vals:aircraft:horizontal_tail:characteristic_length [[7.69198717]] output ft traj.climb.parameter_vals:aircraft:horizontal_tail:characteristic_length - parameter_vals:aircraft:horizontal_tail:fineness [[0.125]] output unitless traj.climb.parameter_vals:aircraft:horizontal_tail:fineness - parameter_vals:aircraft:horizontal_tail:laminar_flow_lower [[0.]] output unitless traj.climb.parameter_vals:aircraft:horizontal_tail:laminar_flow_lower - parameter_vals:aircraft:horizontal_tail:laminar_flow_upper [[0.]] output unitless traj.climb.parameter_vals:aircraft:horizontal_tail:laminar_flow_upper - parameter_vals:aircraft:horizontal_tail:wetted_area [[592.65]] output ft**2 traj.climb.parameter_vals:aircraft:horizontal_tail:wetted_area - parameter_vals:aircraft:vertical_tail:characteristic_length [[12.73914103]] output ft traj.climb.parameter_vals:aircraft:vertical_tail:characteristic_length - parameter_vals:aircraft:vertical_tail:fineness [[0.1195]] output unitless traj.climb.parameter_vals:aircraft:vertical_tail:fineness - parameter_vals:aircraft:vertical_tail:laminar_flow_lower [[0.]] output unitless traj.climb.parameter_vals:aircraft:vertical_tail:laminar_flow_lower - parameter_vals:aircraft:vertical_tail:laminar_flow_upper [[0.]] output unitless traj.climb.parameter_vals:aircraft:vertical_tail:laminar_flow_upper - parameter_vals:aircraft:vertical_tail:wetted_area [[581.13]] output ft**2 traj.climb.parameter_vals:aircraft:vertical_tail:wetted_area - parameter_vals:aircraft:wing:area [[1370.]] output ft**2 traj.climb.parameter_vals:aircraft:wing:area - parameter_vals:aircraft:wing:aspect_ratio [[11.22091]] output unitless traj.climb.parameter_vals:aircraft:wing:aspect_ratio - parameter_vals:aircraft:wing:characteristic_length [[10.49530819]] output ft traj.climb.parameter_vals:aircraft:wing:characteristic_length - parameter_vals:aircraft:wing:fineness [[0.13]] output unitless traj.climb.parameter_vals:aircraft:wing:fineness - parameter_vals:aircraft:wing:laminar_flow_lower [[0.]] output unitless traj.climb.parameter_vals:aircraft:wing:laminar_flow_lower - parameter_vals:aircraft:wing:laminar_flow_upper [[0.]] output unitless traj.climb.parameter_vals:aircraft:wing:laminar_flow_upper - parameter_vals:aircraft:wing:max_camber_at_70_semispan [[0.]] output unitless traj.climb.parameter_vals:aircraft:wing:max_camber_at_70_semispan - parameter_vals:aircraft:wing:span_efficiency_factor [[1.]] output unitless traj.climb.parameter_vals:aircraft:wing:span_efficiency_factor - parameter_vals:aircraft:wing:sweep [[25.]] output deg traj.climb.parameter_vals:aircraft:wing:sweep - parameter_vals:aircraft:wing:taper_ratio [[0.278]] output unitless traj.climb.parameter_vals:aircraft:wing:taper_ratio - parameter_vals:aircraft:wing:thickness_to_chord [[0.13]] output unitless traj.climb.parameter_vals:aircraft:wing:thickness_to_chord - parameter_vals:aircraft:wing:wetted_area [[2396.56]] output ft**2 traj.climb.parameter_vals:aircraft:wing:wetted_area - parameter_vals:mission:design:lift_coefficient [[0.56736557]] output unitless traj.climb.parameter_vals:mission:design:lift_coefficient - parameter_vals:mission:design:mach [[0.80017085]] output unitless traj.climb.parameter_vals:mission:design:mach - parameter_vals:aircraft:nacelle:characteristic_length [[12.3]] output ft traj.climb.parameter_vals:aircraft:nacelle:characteristic_length - parameter_vals:aircraft:nacelle:fineness [[1.54911839]] output unitless traj.climb.parameter_vals:aircraft:nacelle:fineness - parameter_vals:aircraft:nacelle:laminar_flow_lower [[0.]] output unitless traj.climb.parameter_vals:aircraft:nacelle:laminar_flow_lower - parameter_vals:aircraft:nacelle:laminar_flow_upper [[0.]] output unitless traj.climb.parameter_vals:aircraft:nacelle:laminar_flow_upper - parameter_vals:aircraft:nacelle:wetted_area [[273.4536]] output ft**2 traj.climb.parameter_vals:aircraft:nacelle:wetted_area - parameter_vals:aircraft:engine:scale_factor [[1.]] output unitless traj.climb.parameter_vals:aircraft:engine:scale_factor - time - t_initial [0.] input s traj.climb.t_initial - t_duration [3840.] input s traj.climb.t_duration - t |10483.03643104| output s traj.climb.t - val: - array([ 0. , 160.1613086 , 381.15122507, 451.09377806, - 451.09377806, 778.18869326, 1229.51291522, 1372.35548836, - 1372.35548836, 1761.23897954, 2297.81882512, 2467.64451164, - 2467.64451164, 2794.73942684, 3246.0636488 , 3388.90622194, - 3388.90622194, 3549.06753054, 3770.05744702, 3840. ]) - t_phase |10483.03643104| output s traj.climb.t_phase - val: - array([ 0. , 160.1613086 , 381.15122507, 451.09377806, - 451.09377806, 778.18869326, 1229.51291522, 1372.35548836, - 1372.35548836, 1761.23897954, 2297.81882512, 2467.64451164, - 2467.64451164, 2794.73942684, 3246.0636488 , 3388.90622194, - 3388.90622194, 3549.06753054, 3770.05744702, 3840. ]) - dt_dstau |1817.71161504| output s traj.climb.dt_dstau - val: - array([225.54688903, 225.54688903, 225.54688903, 225.54688903, - 460.63085515, 460.63085515, 460.63085515, 460.63085515, - 547.64451164, 547.64451164, 547.64451164, 547.64451164, - 460.63085515, 460.63085515, 460.63085515, 460.63085515, - 225.54688903, 225.54688903, 225.54688903, 225.54688903]) - control_comp - dt_dstau |1817.71161504| input s traj.climb.control_comp.dt_dstau - val: - array([225.54688903, 225.54688903, 225.54688903, 225.54688903, - 460.63085515, 460.63085515, 460.63085515, 460.63085515, - 547.64451164, 547.64451164, 547.64451164, 547.64451164, - 460.63085515, 460.63085515, 460.63085515, 460.63085515, - 225.54688903, 225.54688903, 225.54688903, 225.54688903]) - t_duration [3840.] input s traj.climb.control_comp.t_duration - controls:mach |1.00431071| input unitless traj.climb.controls:mach - val: - array([[0.2 ], - [0.34372447], - [0.57627553], - [0.72 ]]) - controls:altitude |40477.15405016| input ft traj.climb.controls:altitude - val: - array([[ 0. ], - [ 8844.582472], - [23155.417528], - [32000. ]]) - control_values:mach |2.22189137| output unitless traj.climb.control_values:mach - val: - array([[0.2 ], - [0.22168851], - [0.25161423], - [0.26108562], - [0.26108562], - [0.30537972], - [0.36649654], - [0.38583981], - [0.38583981], - [0.43850111], - [0.51116297], - [0.53416019], - [0.53416019], - [0.5784543 ], - [0.63957112], - [0.65891438], - [0.65891438], - [0.68060289], - [0.71052861], - [0.72 ]]) - control_rates:mach_rate |0.0006056| output unitless/s traj.climb.control_rates:mach_rate - val: - array([[0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542]]) - control_rates:mach_rate2 |0.0| output unitless/s**2 traj.climb.control_rates:mach_rate2 - val: - array([[-2.40933816e-22], - [ 0.00000000e+00], - [-2.40933816e-22], - [-1.20466908e-22], - [-1.20466908e-22], - [-1.20466908e-22], - [-1.20466908e-22], - [-6.02334540e-23], - [-6.02334540e-23], - [-6.02334540e-23], - [ 0.00000000e+00], - [-1.20466908e-22], - [-1.20466908e-22], - [ 1.20466908e-22], - [ 2.40933816e-22], - [ 0.00000000e+00], - [ 0.00000000e+00], - [ 2.40933816e-22], - [ 2.40933816e-22], - [ 2.40933816e-22]]) - control_boundary_values:mach |0.74726167| output unitless traj.climb.control_comp.control_boundary_values:mach - val: - array([[0.2 ], - [0.72]]) - control_boundary_rates:mach_rate |0.00019151| output unitless/s traj.climb.control_comp.control_boundary_rates:mach_rate - val: - array([[0.00013542], - [0.00013542]]) - control_boundary_rates:mach_rate2 |0.0| output unitless/s**2 traj.climb.control_comp.control_boundary_rates:mach_rate2 - val: - array([[-2.40933816e-22], - [ 2.40933816e-22]]) - control_values:altitude |87358.6369253| output ft traj.climb.control_values:altitude - val: - array([[ 0. ], - [ 1334.67757163], - [ 3176.26020893], - [ 3759.11481713], - [ 3759.11481713], - [ 6484.90577713], - [10245.94096014], - [11436.29573631], - [11436.29573631], - [14676.99149614], - [19148.49020934], - [20563.70426369], - [20563.70426369], - [23289.4952237 ], - [27050.5304067 ], - [28240.88518287], - [28240.88518287], - [29575.5627545 ], - [31417.1453918 ], - [32000. ]]) - control_rates:altitude_rate |37.26779962| output ft/s traj.climb.control_rates:altitude_rate - val: - array([[8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333]]) - control_rates:altitude_rate2 |0.0| output ft/s**2 traj.climb.control_rates:altitude_rate2 - val: - array([[-7.89491929e-18], - [ 0.00000000e+00], - [-3.94745964e-18], - [-7.89491929e-18], - [-7.89491929e-18], - [-3.94745964e-18], - [-5.92118946e-18], - [-3.94745964e-18], - [-3.94745964e-18], - [-1.97372982e-18], - [ 0.00000000e+00], - [ 0.00000000e+00], - [ 0.00000000e+00], - [ 3.94745964e-18], - [ 1.57898386e-17], - [ 1.57898386e-17], - [ 1.57898386e-17], - [ 1.57898386e-17], - [ 1.57898386e-17], - [ 7.89491929e-18]]) - control_boundary_values:altitude |32000.0| output ft traj.climb.control_comp.control_boundary_values:altitude - val: - array([[ 0.], - [32000.]]) - control_boundary_rates:altitude_rate |11.78511302| output ft/s traj.climb.control_comp.control_boundary_rates:altitude_rate - val: - array([[8.33333333], - [8.33333333]]) - control_boundary_rates:altitude_rate2 |0.0| output ft/s**2 traj.climb.control_comp.control_boundary_rates:altitude_rate2 - val: - array([[-7.89491929e-18], - [ 7.89491929e-18]]) - indep_states - states:mass |232631.68332249| output kg traj.climb.states:mass - val: - array([[59377.14578909], - [59253.2001355 ], - [59099.30211114], - [59053.23865024], - [58849.04195155], - [58583.91501949], - [58501.0166128 ], - [58275.75043339], - [57961.72209353], - [57860.85002365], - [57664.1758047 ], - [57387.22609857], - [57298.3740442 ], - [57198.30721763], - [57059.51640479], - [57015.39290411]]) - states:distance |1273831.39141224| output m traj.climb.states:distance - val: - array([[1.00000000e+00], - [1.14581007e+04], - [2.91056018e+04], - [3.51310537e+04], - [6.60814858e+04], - [1.16145544e+05], - [1.33731831e+05], - [1.85754660e+05], - [2.67231556e+05], - [2.95296884e+05], - [3.52354108e+05], - [4.37399478e+05], - [4.65802163e+05], - [4.98478689e+05], - [5.44983286e+05], - [5.60039406e+05]]) - state_interp - dt_dstau |1574.18443538| input s traj.climb.state_interp.dt_dstau - val: - array([225.54688903, 225.54688903, 225.54688903, 460.63085515, - 460.63085515, 460.63085515, 547.64451164, 547.64451164, - 547.64451164, 460.63085515, 460.63085515, 460.63085515, - 225.54688903, 225.54688903, 225.54688903]) - state_disc:mass |260111.77531753| input kg traj.climb.state_interp.state_disc:mass - val: - array([[59377.14578909], - [59253.2001355 ], - [59099.30211114], - [59053.23865024], - [59053.23865024], - [58849.04195155], - [58583.91501949], - [58501.0166128 ], - [58501.0166128 ], - [58275.75043339], - [57961.72209353], - [57860.85002365], - [57860.85002365], - [57664.1758047 ], - [57387.22609857], - [57298.3740442 ], - [57298.3740442 ], - [57198.30721763], - [57059.51640479], - [57015.39290411]]) - state_disc:distance |1394968.35548323| input m traj.climb.state_interp.state_disc:distance - val: - array([[1.00000000e+00], - [1.14581007e+04], - [2.91056018e+04], - [3.51310537e+04], - [3.51310537e+04], - [6.60814858e+04], - [1.16145544e+05], - [1.33731831e+05], - [1.33731831e+05], - [1.85754660e+05], - [2.67231556e+05], - [2.95296884e+05], - [2.95296884e+05], - [3.52354108e+05], - [4.37399478e+05], - [4.65802163e+05], - [4.65802163e+05], - [4.98478689e+05], - [5.44983286e+05], - [5.60039406e+05]]) - staterate_col:mass |2.46548436| output kg/s traj.climb.state_interp.staterate_col:mass - val: - array([[-0.81635589], - [-0.73557259], - [-0.66516889], - [-0.64952724], - [-0.60312819], - [-0.57957803], - [-0.57869286], - [-0.58065035], - [-0.59138326], - [-0.59559425], - [-0.60675259], - [-0.62013408], - [-0.62357343], - [-0.62606633], - [-0.63013871]]) - staterate_col:distance |583.61135954| output m/s traj.climb.state_interp.staterate_col:distance - val: - array([[ 68.00995794], - [ 75.04782293], - [ 84.6430095 ], - [ 87.65174596], - [101.54257372], - [120.21625082], - [126.00588218], - [141.46990952], - [162.07913243], - [168.42295523], - [180.39460351], - [196.37105177], - [201.29434073], - [206.73713847], - [214.11204164]]) - rhs_all - atmosphere - standard_atmosphere - h |87358.6369253| input ft traj.climb.rhs_all.altitude - val: - array([ 0. , 1334.67757163, 3176.26020893, 3759.11481713, - 3759.11481713, 6484.90577713, 10245.94096014, 11436.29573631, - 11436.29573631, 14676.99149614, 19148.49020934, 20563.70426369, - 20563.70426369, 23289.4952237 , 27050.5304067 , 28240.88518287, - 28240.88518287, 29575.5627545 , 31417.1453918 , 32000. ]) - temp |2066.65858384| output degR traj.climb.rhs_all.temperature - val: - array([518.67 , 513.91084435, 507.34509901, 505.26655918, - 505.26655918, 495.5510144 , 482.14891569, 477.90852019, - 477.90852019, 466.36665517, 450.44612086, 445.40906345, - 445.40906345, 435.70829939, 422.32876215, 418.09508175, - 418.09508175, 413.34789509, 406.79997501, 404.72782123]) - pres |41.12989507| output psi traj.climb.rhs_all.static_pressure - val: - array([14.6959 , 14.0009012 , 13.08590864, 12.80663963, 12.80663963, - 11.56420805, 10.01237775, 9.55809623, 9.55809623, 8.40553073, - 7.0030012 , 6.60106653, 6.60106653, 5.8796902 , 4.99066923, - 4.73327683, 4.73327683, 4.45757854, 4.09872669, 3.99016779]) - rho |0.00710413| output slug/ft**3 traj.climb.rhs_all.density - val: - array([0.00237717, 0.00228572, 0.00216399, 0.00212652, 0.00212652, - 0.00195786, 0.00174224, 0.00167795, 0.00167795, 0.00151214, - 0.00130436, 0.0012434 , 0.0012434 , 0.00113217, 0.00099143, - 0.00094982, 0.00094982, 0.00090477, 0.00084532, 0.00082715]) - viscosity |1.54e-06| output lbf*s/ft**2 traj.climb.rhs_all.viscosity - val: - array([3.78456000e-07, 3.75691988e-07, 3.71861243e-07, 3.70643612e-07, - 3.70643612e-07, 3.64920138e-07, 3.56939502e-07, 3.54394280e-07, - 3.54394280e-07, 3.47411497e-07, 3.37652624e-07, 3.34533376e-07, - 3.34533376e-07, 3.28482402e-07, 3.20038906e-07, 3.17342868e-07, - 3.17342868e-07, 3.14307095e-07, 3.10094120e-07, 3.08755112e-07]) - drhos_dh |2.2e-07| output slug/ft**4 traj.climb.rhs_all.drhos_dh - val: - array([-6.95548710e-08, -6.75005931e-08, -6.47287414e-08, -6.38683907e-08, - -6.38683907e-08, -5.99679763e-08, -5.48403871e-08, -5.32949389e-08, - -5.32949389e-08, -4.92050502e-08, -4.39443505e-08, -4.23756474e-08, - -4.23756474e-08, -3.94403259e-08, -3.56212794e-08, -3.44788975e-08, - -3.44788975e-08, -3.32238160e-08, -3.15408200e-08, -3.10133821e-08]) - sos |4704.69211471| output ft/s traj.climb.rhs_all.speed_of_sound - val: - array([1116.42671753, 1111.29292057, 1104.17113919, 1101.90698094, - 1101.90698094, 1091.26151998, 1076.4038783 , 1071.66005531, - 1071.66005531, 1058.64025047, 1040.41374789, 1034.58024563, - 1034.58024563, 1023.25193102, 1007.41864968, 1002.3564424 , - 1002.3564424 , 996.64965751, 988.72408929, 986.20269773]) - flight_conditions - density |0.00710413| input slug/ft**3 traj.climb.rhs_all.density - val: - array([0.00237717, 0.00228572, 0.00216399, 0.00212652, 0.00212652, - 0.00195786, 0.00174224, 0.00167795, 0.00167795, 0.00151214, - 0.00130436, 0.0012434 , 0.0012434 , 0.00113217, 0.00099143, - 0.00094982, 0.00094982, 0.00090477, 0.00084532, 0.00082715]) - speed_of_sound |4704.69211471| input ft/s traj.climb.rhs_all.speed_of_sound - val: - array([1116.42671753, 1111.29292057, 1104.17113919, 1101.90698094, - 1101.90698094, 1091.26151998, 1076.4038783 , 1071.66005531, - 1071.66005531, 1058.64025047, 1040.41374789, 1034.58024563, - 1034.58024563, 1023.25193102, 1007.41864968, 1002.3564424 , - 1002.3564424 , 996.64965751, 988.72408929, 986.20269773]) - mach |2.22189137| input unitless traj.climb.rhs_all.mach - val: - array([0.2 , 0.22168851, 0.25161423, 0.26108562, 0.26108562, - 0.30537972, 0.36649654, 0.38583981, 0.38583981, 0.43850111, - 0.51116297, 0.53416019, 0.53416019, 0.5784543 , 0.63957112, - 0.65891438, 0.65891438, 0.68060289, 0.71052861, 0.72 ]) - dynamic_pressure |729.82648439| output lbf/ft**2 traj.climb.rhs_all.dynamic_pressure - val: - array([ 59.25850338, 69.36442415, 83.51573809, 88.00275154, - 88.00275154, 108.7150004 , 135.57151342, 143.44259835, - 143.44259835, 162.92998731, 184.45796777, 189.86816523, - 189.86816523, 198.32854638, 205.79302246, 207.1635135 , - 207.1635135 , 208.1516967 , 208.59603076, 208.52120555]) - EAS |1612.50052137| output ft/s traj.climb.rhs_all.EAS - val: - array([223.29802501, 241.58943331, 265.09021925, 272.11824924, - 272.11824924, 302.45048022, 337.74876107, 347.41503892, - 347.41503892, 370.26277725, 393.96555484, 399.7013539 , - 399.7013539 , 408.5094965 , 416.12601294, 417.50932185, - 417.50932185, 418.50391026, 418.95035488, 418.87520758]) - velocity |2273.06081681| output ft/s traj.climb.rhs_all.velocity - val: - array([223.28534351, 246.36087233, 277.8251692 , 287.69206265, - 287.69206265, 333.2491362 , 394.49829769, 413.48910753, - 413.48910753, 464.21492684, 531.82097714, 552.63158501, - 552.63158501, 591.90447681, 644.31587319, 660.46707802, - 660.46707802, 678.32264196, 702.51675542, 710.06594237]) - velocity_rate_comp - mach_rate |0.0006056| input unitless/s traj.climb.rhs_all.mach_rate - val: - array([0.00013542, 0.00013542, 0.00013542, 0.00013542, 0.00013542, - 0.00013542, 0.00013542, 0.00013542, 0.00013542, 0.00013542, - 0.00013542, 0.00013542, 0.00013542, 0.00013542, 0.00013542, - 0.00013542, 0.00013542, 0.00013542, 0.00013542, 0.00013542]) - sos |1433.99015656| input m/s traj.climb.rhs_all.speed_of_sound - val: - array([340.2868635 , 338.72208219, 336.55136322, 335.86124779, - 335.86124779, 332.61651129, 328.08790211, 326.64198486, - 326.64198486, 322.67354834, 317.11811036, 315.34005887, - 315.34005887, 311.88718858, 307.06120442, 305.51824364, - 305.51824364, 303.77881561, 301.36310241, 300.59458227]) - velocity_rate |0.19418617| output m/s**2 traj.climb.rhs_all.velocity_rate - val: - array([0.04608051, 0.04586862, 0.04557466, 0.04548121, 0.04548121, - 0.04504182, 0.04442857, 0.04423277, 0.04423277, 0.04369538, - 0.04294308, 0.0427023 , 0.0427023 , 0.04223472, 0.0415812 , - 0.04137226, 0.04137226, 0.04113671, 0.04080959, 0.04070552]) - solver_sub - core_aerodynamics - Mux - aircraft:wing:wetted_area [2396.56] input ft**2 traj.climb.rhs_all.aircraft:wing:wetted_area - aircraft:wing:fineness [0.13] input unitless traj.climb.rhs_all.aircraft:wing:fineness - aircraft:wing:characteristic_length [10.49530819] input ft traj.climb.rhs_all.aircraft:wing:characteristic_length - aircraft:wing:laminar_flow_upper [0.] input unitless traj.climb.rhs_all.aircraft:wing:laminar_flow_upper - aircraft:wing:laminar_flow_lower [0.] input unitless traj.climb.rhs_all.aircraft:wing:laminar_flow_lower - aircraft:horizontal_tail:wetted_area [592.65] input ft**2 traj.climb.rhs_all.aircraft:horizontal_tail:wetted_area - aircraft:horizontal_tail:fineness [0.125] input unitless traj.climb.rhs_all.aircraft:horizontal_tail:fineness - aircraft:horizontal_tail:characteristic_length [7.69198717] input ft traj.climb.rhs_all.aircraft:horizontal_tail:characteristic_length - aircraft:horizontal_tail:laminar_flow_upper [0.] input unitless traj.climb.rhs_all.aircraft:horizontal_tail:laminar_flow_upper - aircraft:horizontal_tail:laminar_flow_lower [0.] input unitless traj.climb.rhs_all.aircraft:horizontal_tail:laminar_flow_lower - aircraft:vertical_tail:wetted_area [581.13] input ft**2 traj.climb.rhs_all.aircraft:vertical_tail:wetted_area - aircraft:vertical_tail:fineness [0.1195] input unitless traj.climb.rhs_all.aircraft:vertical_tail:fineness - aircraft:vertical_tail:characteristic_length [12.73914103] input ft traj.climb.rhs_all.aircraft:vertical_tail:characteristic_length - aircraft:vertical_tail:laminar_flow_upper [0.] input unitless traj.climb.rhs_all.aircraft:vertical_tail:laminar_flow_upper - aircraft:vertical_tail:laminar_flow_lower [0.] input unitless traj.climb.rhs_all.aircraft:vertical_tail:laminar_flow_lower - aircraft:fuselage:wetted_area [4158.62] input ft**2 traj.climb.rhs_all.aircraft:fuselage:wetted_area - aircraft:fuselage:fineness [10.03921569] input unitless traj.climb.rhs_all.aircraft:fuselage:fineness - aircraft:fuselage:characteristic_length [128.] input ft traj.climb.rhs_all.aircraft:fuselage:characteristic_length - aircraft:fuselage:laminar_flow_upper [0.] input unitless traj.climb.rhs_all.aircraft:fuselage:laminar_flow_upper - aircraft:fuselage:laminar_flow_lower [0.] input unitless traj.climb.rhs_all.aircraft:fuselage:laminar_flow_lower - aircraft:nacelle:wetted_area [273.4536] input ft**2 traj.climb.rhs_all.aircraft:nacelle:wetted_area - aircraft:nacelle:fineness [1.54911839] input unitless traj.climb.rhs_all.aircraft:nacelle:fineness - aircraft:nacelle:characteristic_length [12.3] input ft traj.climb.rhs_all.aircraft:nacelle:characteristic_length - aircraft:nacelle:laminar_flow_upper [0.] input unitless traj.climb.rhs_all.aircraft:nacelle:laminar_flow_upper - aircraft:nacelle:laminar_flow_lower [0.] input unitless traj.climb.rhs_all.aircraft:nacelle:laminar_flow_lower - wetted_areas |4886.31967641| output ft**2 traj.climb.rhs_all.core_aerodynamics.wetted_areas - val: - array([2396.56 , 592.65 , 581.13 , 4158.62 , 273.4536, 273.4536]) - fineness_ratios |10.2777523| output unitless traj.climb.rhs_all.core_aerodynamics.fineness_ratios - val: - array([ 0.13 , 0.125 , 0.1195 , 10.03921569, 1.54911839, - 1.54911839]) - characteristic_lengths |130.45376144| output ft traj.climb.rhs_all.core_aerodynamics.characteristic_lengths - val: - array([ 10.49530819, 7.69198717, 12.73914103, 128. , - 12.3 , 12.3 ]) - laminar_fractions_upper |0.0| output unitless traj.climb.rhs_all.core_aerodynamics.laminar_fractions_upper - val: - array([0., 0., 0., 0., 0., 0.]) - laminar_fractions_lower |0.0| output unitless traj.climb.rhs_all.core_aerodynamics.laminar_fractions_lower - val: - array([0., 0., 0., 0., 0., 0.]) - DynamicPressure - static_pressure |5922.70488396| input lbf/ft**2 traj.climb.rhs_all.static_pressure - val: - array([2116.20959775, 2016.12977059, 1884.3708425 , 1844.15610466, - 1844.15610466, 1665.24595683, 1441.7823939 , 1376.36585521, - 1376.36585521, 1210.39642326, 1008.43217102, 950.5535796 , - 950.5535796 , 846.67538744, 718.65636826, 681.59186207, - 681.59186207, 641.89130933, 590.21664278, 574.58416126]) - mach |2.22189137| input unitless traj.climb.rhs_all.mach - val: - array([0.2 , 0.22168851, 0.25161423, 0.26108562, 0.26108562, - 0.30537972, 0.36649654, 0.38583981, 0.38583981, 0.43850111, - 0.51116297, 0.53416019, 0.53416019, 0.5784543 , 0.63957112, - 0.65891438, 0.65891438, 0.68060289, 0.71052861, 0.72 ]) - dynamic_pressure |729.77059557| output lbf/ft**2 traj.climb.rhs_all.core_aerodynamics.dynamic_pressure - val: - array([ 59.25386874, 69.35901127, 83.5092932 , 87.99573266, - 87.99573266, 108.70682458, 135.56185944, 143.43197899, - 143.43197899, 162.91724951, 184.44355948, 189.85309614, - 189.85309614, 198.31386506, 205.77708313, 207.14784198, - 207.14784198, 208.13595957, 208.57998617, 208.50510044]) - lift - aircraft:wing:area [127.2771648] input m**2 traj.climb.rhs_all.aircraft:wing:area - mass |260111.77531753| input kg traj.climb.rhs_all.mass - val: - array([59377.14578909, 59253.2001355 , 59099.30211114, 59053.23865024, - 59053.23865024, 58849.04195155, 58583.91501949, 58501.0166128 , - 58501.0166128 , 58275.75043339, 57961.72209353, 57860.85002365, - 57860.85002365, 57664.1758047 , 57387.22609857, 57298.3740442 , - 57298.3740442 , 57198.30721763, 57059.51640479, 57015.39290411]) - dynamic_pressure |34941.60514958| input N/m**2 traj.climb.rhs_all.core_aerodynamics.dynamic_pressure - val: - array([2837.09058373, 3320.92742596, 3998.4465899 , 4213.25847322, - 4213.25847322, 5204.91091948, 6490.73694453, 6867.56030763, - 6867.56030763, 7800.52010707, 8831.20540436, 9090.215421 , - 9090.215421 , 9495.31922842, 9852.66004282, 9918.29233157, - 9918.29233157, 9965.60365807, 9986.86376675, 9983.27821833]) - cl |3.56252196| output unitless traj.climb.rhs_all.core_aerodynamics.cl - val: - array([1.61256154, 1.37474646, 1.13883613, 1.07993048, 1.07993048, - 0.8711567 , 0.69543183, 0.65634339, 0.65634339, 0.57561817, - 0.50569828, 0.49043428, 0.49043428, 0.46791471, 0.44877837, - 0.44511843, 0.44511843, 0.44223158, 0.44021937, 0.44003693]) - lift |2550825.14141767| output N traj.climb.rhs_all.lift - val: - array([582290.88675256, 581075.39510879, 579566.17104819, 579114.44280941, - 579114.44280941, 577111.9572542 , 574511.95022592, 573698.99456589, - 573698.99456589, 571489.88798758, 568410.32196854, 567421.10488442, - 567421.10488442, 565492.38965516, 562776.44081958, 561905.09982059, - 561905.09982059, 560923.77947573, 559562.70655104, 559130.00282312]) - PressureDrag - mach |2.22189137| input unitless traj.climb.rhs_all.mach - val: - array([0.2 , 0.22168851, 0.25161423, 0.26108562, 0.26108562, - 0.30537972, 0.36649654, 0.38583981, 0.38583981, 0.43850111, - 0.51116297, 0.53416019, 0.53416019, 0.5784543 , 0.63957112, - 0.65891438, 0.65891438, 0.68060289, 0.71052861, 0.72 ]) - lift |573448.30346328| input lbf traj.climb.rhs_all.core_aerodynamics.lift - val: - array([130904.19868796, 130630.94529647, 130291.65823087, 130190.10568305, - 130190.10568305, 129739.92902229, 129155.42419083, 128972.66448831, - 128972.66448831, 128476.03757377, 127783.72359256, 127561.33874562, - 127561.33874562, 127127.74631385, 126517.17672727, 126321.29147841, - 126321.29147841, 126100.68188908, 125794.70052372, 125697.42485608]) - static_pressure |5922.70488396| input lbf/ft**2 traj.climb.rhs_all.static_pressure - val: - array([2116.20959775, 2016.12977059, 1884.3708425 , 1844.15610466, - 1844.15610466, 1665.24595683, 1441.7823939 , 1376.36585521, - 1376.36585521, 1210.39642326, 1008.43217102, 950.5535796 , - 950.5535796 , 846.67538744, 718.65636826, 681.59186207, - 681.59186207, 641.89130933, 590.21664278, 574.58416126]) - mission:design:lift_coefficient [0.56736557] input unitless traj.climb.rhs_all.mission:design:lift_coefficient - mission:design:mach [0.80017085] input unitless traj.climb.rhs_all.mission:design:mach - aircraft:wing:area [1370.] input ft**2 traj.climb.rhs_all.aircraft:wing:area - aircraft:wing:aspect_ratio [11.22091] input unitless traj.climb.rhs_all.aircraft:wing:aspect_ratio - aircraft:wing:max_camber_at_70_semispan [0.] input unitless traj.climb.rhs_all.aircraft:wing:max_camber_at_70_semispan - aircraft:wing:sweep [25.] input deg traj.climb.rhs_all.aircraft:wing:sweep - aircraft:wing:thickness_to_chord [0.13] input unitless traj.climb.rhs_all.aircraft:wing:thickness_to_chord - CD |0.08027558| output unitless traj.climb.rhs_all.core_aerodynamics.PressureDrag.CD - val: - array([0.06048713, 0.03849179, 0.02182262, 0.01846069, 0.01846069, - 0.00912059, 0.00437262, 0.00368886, 0.00368886, 0.00232912, - 0.00128049, 0.00117909, 0.00117909, 0.00110638, 0.00098379, - 0.0009615 , 0.0009615 , 0.00094423, 0.0009321 , 0.00093247]) - InducedDrag - mach |2.22189137| input unitless traj.climb.rhs_all.mach - val: - array([0.2 , 0.22168851, 0.25161423, 0.26108562, 0.26108562, - 0.30537972, 0.36649654, 0.38583981, 0.38583981, 0.43850111, - 0.51116297, 0.53416019, 0.53416019, 0.5784543 , 0.63957112, - 0.65891438, 0.65891438, 0.68060289, 0.71052861, 0.72 ]) - lift |573448.30346328| input lbf traj.climb.rhs_all.core_aerodynamics.lift - val: - array([130904.19868796, 130630.94529647, 130291.65823087, 130190.10568305, - 130190.10568305, 129739.92902229, 129155.42419083, 128972.66448831, - 128972.66448831, 128476.03757377, 127783.72359256, 127561.33874562, - 127561.33874562, 127127.74631385, 126517.17672727, 126321.29147841, - 126321.29147841, 126100.68188908, 125794.70052372, 125697.42485608]) - static_pressure |5922.70488396| input lbf/ft**2 traj.climb.rhs_all.static_pressure - val: - array([2116.20959775, 2016.12977059, 1884.3708425 , 1844.15610466, - 1844.15610466, 1665.24595683, 1441.7823939 , 1376.36585521, - 1376.36585521, 1210.39642326, 1008.43217102, 950.5535796 , - 950.5535796 , 846.67538744, 718.65636826, 681.59186207, - 681.59186207, 641.89130933, 590.21664278, 574.58416126]) - aircraft:wing:area [1370.] input ft**2 traj.climb.rhs_all.aircraft:wing:area - aircraft:wing:aspect_ratio [11.22091] input unitless traj.climb.rhs_all.aircraft:wing:aspect_ratio - aircraft:wing:span_efficiency_factor [1.] input unitless traj.climb.rhs_all.aircraft:wing:span_efficiency_factor - aircraft:wing:sweep [25.] input deg traj.climb.rhs_all.aircraft:wing:sweep - aircraft:wing:taper_ratio [0.278] input unitless traj.climb.rhs_all.aircraft:wing:taper_ratio - induced_drag_coeff |0.11518843| output unitless traj.climb.rhs_all.core_aerodynamics.InducedDrag.induced_drag_coeff - val: - array([0.07376573, 0.05361265, 0.03679125, 0.03308367, 0.03308367, - 0.02152854, 0.01371928, 0.01222037, 0.01222037, 0.0093992 , - 0.00725446, 0.00682313, 0.00682313, 0.00621091, 0.00571328, - 0.00562048, 0.00562048, 0.00554781, 0.00549744, 0.00549288]) - CompressibilityDrag - mach |2.22189137| input unitless traj.climb.rhs_all.mach - val: - array([0.2 , 0.22168851, 0.25161423, 0.26108562, 0.26108562, - 0.30537972, 0.36649654, 0.38583981, 0.38583981, 0.43850111, - 0.51116297, 0.53416019, 0.53416019, 0.5784543 , 0.63957112, - 0.65891438, 0.65891438, 0.68060289, 0.71052861, 0.72 ]) - mission:design:mach [0.80017085] input unitless traj.climb.rhs_all.mission:design:mach - aircraft:design:base_area [0.] input ft**2 traj.climb.rhs_all.aircraft:design:base_area - aircraft:wing:area [1370.] input ft**2 traj.climb.rhs_all.aircraft:wing:area - aircraft:wing:aspect_ratio [11.22091] input unitless traj.climb.rhs_all.aircraft:wing:aspect_ratio - aircraft:wing:max_camber_at_70_semispan [0.] input unitless traj.climb.rhs_all.aircraft:wing:max_camber_at_70_semispan - aircraft:wing:sweep [25.] input deg traj.climb.rhs_all.aircraft:wing:sweep - aircraft:wing:taper_ratio [0.278] input unitless traj.climb.rhs_all.aircraft:wing:taper_ratio - aircraft:wing:thickness_to_chord [0.13] input unitless traj.climb.rhs_all.aircraft:wing:thickness_to_chord - aircraft:fuselage:cross_section [127.67628894] input ft**2 traj.climb.rhs_all.aircraft:fuselage:cross_section - aircraft:fuselage:diameter_to_wing_span [0.10826471] input unitless traj.climb.rhs_all.aircraft:fuselage:diameter_to_wing_span - aircraft:fuselage:length_to_diameter [10.03921569] input unitless traj.climb.rhs_all.aircraft:fuselage:length_to_diameter - compress_drag_coeff |0.00168953| output unitless traj.climb.rhs_all.core_aerodynamics.CompressibilityDrag.compress_drag_coeff - val: - array([0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 6.84397531e-05, 4.21572944e-04, 5.38360174e-04, - 5.38360174e-04, 6.74912191e-04, 8.66966315e-04, 9.40914533e-04]) - SkinFrictionCoef - temperature |2066.65858384| input degR traj.climb.rhs_all.temperature - val: - array([518.67 , 513.91084435, 507.34509901, 505.26655918, - 505.26655918, 495.5510144 , 482.14891569, 477.90852019, - 477.90852019, 466.36665517, 450.44612086, 445.40906345, - 445.40906345, 435.70829939, 422.32876215, 418.09508175, - 418.09508175, 413.34789509, 406.79997501, 404.72782123]) - static_pressure |5922.70488396| input lbf/ft**2 traj.climb.rhs_all.static_pressure - val: - array([2116.20959775, 2016.12977059, 1884.3708425 , 1844.15610466, - 1844.15610466, 1665.24595683, 1441.7823939 , 1376.36585521, - 1376.36585521, 1210.39642326, 1008.43217102, 950.5535796 , - 950.5535796 , 846.67538744, 718.65636826, 681.59186207, - 681.59186207, 641.89130933, 590.21664278, 574.58416126]) - mach |2.22189137| input unitless traj.climb.rhs_all.mach - val: - array([0.2 , 0.22168851, 0.25161423, 0.26108562, 0.26108562, - 0.30537972, 0.36649654, 0.38583981, 0.38583981, 0.43850111, - 0.51116297, 0.53416019, 0.53416019, 0.5784543 , 0.63957112, - 0.65891438, 0.65891438, 0.68060289, 0.71052861, 0.72 ]) - characteristic_lengths |130.45376144| input ft traj.climb.rhs_all.core_aerodynamics.characteristic_lengths - val: - array([ 10.49530819, 7.69198717, 12.73914103, 128. , - 12.3 , 12.3 ]) - cf_iter |0.02765794| output unitless traj.climb.rhs_all.core_aerodynamics.SkinFrictionCoef.cf_iter - val: - array([[0.00275238, 0.00289295, 0.00266959, 0.00190747, 0.00268432, - 0.00268432], - [0.00272469, 0.00286322, 0.00264309, 0.00189109, 0.0026576 , - 0.0026576 ], - [0.00269395, 0.00283024, 0.00261365, 0.00187287, 0.00262794, - 0.00262794], - [0.00268571, 0.0028214 , 0.00260576, 0.00186798, 0.00261999, - 0.00261999], - [0.00268571, 0.0028214 , 0.00260576, 0.00186798, 0.00261999, - 0.00261999], - [0.00265482, 0.00278826, 0.00257618, 0.00184962, 0.00259017, - 0.00259017], - [0.00262816, 0.00275967, 0.00255063, 0.00183373, 0.00256443, - 0.00256443], - [0.00262272, 0.00275383, 0.00254542, 0.00183049, 0.00255917, - 0.00255917], - [0.00262272, 0.00275383, 0.00254542, 0.00183049, 0.00255917, - 0.00255917], - [0.00261376, 0.00274423, 0.00253683, 0.00182515, 0.00255052, - 0.00255052], - [0.00261303, 0.00274344, 0.00253614, 0.00182474, 0.00254982, - 0.00254982], - [0.00261518, 0.00274575, 0.0025382 , 0.00182603, 0.0025519 , - 0.0025519 ], - [0.00261518, 0.00274575, 0.0025382 , 0.00182603, 0.0025519 , - 0.0025519 ], - [0.00262218, 0.00275325, 0.00254491, 0.00183022, 0.00255866, - 0.00255866], - [0.0026375 , 0.00276967, 0.00255959, 0.00183939, 0.00257345, - 0.00257345], - [0.00264363, 0.00277624, 0.00256546, 0.00184305, 0.00257937, - 0.00257937], - [0.00264363, 0.00277624, 0.00256546, 0.00184305, 0.00257937, - 0.00257937], - [0.0026512 , 0.00278435, 0.00257272, 0.00184757, 0.00258668, - 0.00258668], - [0.00266284, 0.00279683, 0.00258387, 0.00185451, 0.00259792, - 0.00259792], - [0.00266681, 0.00280109, 0.00258767, 0.00185688, 0.00260175, - 0.00260175]]) - skin_friction_coeff |0.02700108| output unitless traj.climb.rhs_all.core_aerodynamics.skin_friction_coeff - val: - array([[0.00275142, 0.00289141, 0.00266898, 0.0019099 , 0.00268364, - 0.00268364], - [0.00272014, 0.00285796, 0.00263896, 0.00189079, 0.0026534 , - 0.0026534 ], - [0.0026843 , 0.00281966, 0.00260455, 0.00186876, 0.00261874, - 0.00261874], - [0.0026744 , 0.00280909, 0.00259504, 0.00186264, 0.00260916, - 0.00260916], - [0.0026744 , 0.00280909, 0.00259504, 0.00186264, 0.00260916, - 0.00260916], - [0.00263531, 0.00276739, 0.00255747, 0.00183829, 0.00257131, - 0.00257131], - [0.00259601, 0.00272557, 0.00251963, 0.00181333, 0.00253322, - 0.00253322], - [0.00258622, 0.00271518, 0.00251019, 0.00180698, 0.00252372, - 0.00252372], - [0.00258622, 0.00271518, 0.00251019, 0.00180698, 0.00252372, - 0.00252372], - [0.00256449, 0.00269219, 0.0024892 , 0.0017926 , 0.0025026 , - 0.0025026 ], - [0.00254382, 0.00267048, 0.00246914, 0.00177815, 0.00248243, - 0.00248243], - [0.00253908, 0.00266555, 0.00246451, 0.00177461, 0.00247778, - 0.00247778], - [0.00253908, 0.00266555, 0.00246451, 0.00177461, 0.00247778, - 0.00247778], - [0.00253198, 0.00265825, 0.00245753, 0.00176896, 0.00247078, - 0.00247078], - [0.00252603, 0.00265233, 0.00245158, 0.00176333, 0.00246483, - 0.00246483], - [0.00252498, 0.00265136, 0.00245049, 0.00176201, 0.00246374, - 0.00246374], - [0.00252498, 0.00265136, 0.00245049, 0.00176201, 0.00246374, - 0.00246374], - [0.00252424, 0.00265074, 0.00244969, 0.00176078, 0.00246295, - 0.00246295], - [0.00252395, 0.00265068, 0.00244927, 0.00175948, 0.00246256, - 0.00246256], - [0.00252403, 0.00265084, 0.0024493 , 0.00175916, 0.0024626 , - 0.0024626 ]]) - Re |1107669904.6272902| output unitless traj.climb.rhs_all.core_aerodynamics.Re - val: - array([[1.49048396e+07, 1.09237226e+07, 1.80914034e+07, 1.81778318e+08, - 1.74677603e+07, 1.74677603e+07], - [1.59263513e+07, 1.16723862e+07, 1.93313080e+07, 1.94236599e+08, - 1.86649232e+07, 1.86649232e+07], - [1.71753244e+07, 1.25877557e+07, 2.08473040e+07, 2.09468982e+08, - 2.01286600e+07, 2.01286600e+07], - [1.75335338e+07, 1.28502865e+07, 2.12820963e+07, 2.13837677e+08, - 2.05484643e+07, 2.05484643e+07], - [1.75335338e+07, 1.28502865e+07, 2.12820963e+07, 2.13837677e+08, - 2.05484643e+07, 2.05484643e+07], - [1.89861298e+07, 1.39148908e+07, 2.30452485e+07, 2.31553430e+08, - 2.22508374e+07, 2.22508374e+07], - [2.04379008e+07, 1.49788904e+07, 2.48073993e+07, 2.49259122e+08, - 2.39522438e+07, 2.39522438e+07], - [2.07762539e+07, 1.52268686e+07, 2.52180903e+07, 2.53385652e+08, - 2.43487775e+07, 2.43487775e+07], - [2.07762539e+07, 1.52268686e+07, 2.52180903e+07, 2.53385652e+08, - 2.43487775e+07, 2.43487775e+07], - [2.14332068e+07, 1.57083478e+07, 2.60154956e+07, 2.61397800e+08, - 2.51186948e+07, 2.51186948e+07], - [2.17791933e+07, 1.59619205e+07, 2.64354519e+07, 2.65617425e+08, - 2.55241745e+07, 2.55241745e+07], - [2.17705043e+07, 1.59555524e+07, 2.64249053e+07, 2.65511455e+08, - 2.55139914e+07, 2.55139914e+07], - [2.17705043e+07, 1.59555524e+07, 2.64249053e+07, 2.65511455e+08, - 2.55139914e+07, 2.55139914e+07], - [2.16143630e+07, 1.58411168e+07, 2.62353819e+07, 2.63607167e+08, - 2.53310012e+07, 2.53310012e+07], - [2.11348941e+07, 1.54897151e+07, 2.56534055e+07, 2.57759600e+08, - 2.47690866e+07, 2.47690866e+07], - [2.09278119e+07, 1.53379451e+07, 2.54020504e+07, 2.55234041e+08, - 2.45263961e+07, 2.45263961e+07], - [2.09278119e+07, 1.53379451e+07, 2.54020504e+07, 2.55234041e+08, - 2.45263961e+07, 2.45263961e+07], - [2.06675501e+07, 1.51471998e+07, 2.50861462e+07, 2.52059907e+08, - 2.42213817e+07, 2.42213817e+07], - [2.02640027e+07, 1.48514408e+07, 2.45963228e+07, 2.47138273e+08, - 2.37484434e+07, 2.37484434e+07], - [2.01263640e+07, 1.47505658e+07, 2.44292579e+07, 2.45459643e+08, - 2.35871375e+07, 2.35871375e+07]]) - wall_temp |5223.80281063| output degR traj.climb.rhs_all.core_aerodynamics.SkinFrictionCoef.wall_temp - val: - array([[517.45689455, 517.66707174, 517.32335332, 515.58822228, - 517.3476737 , 517.3476737 ], - [513.854417 , 514.0486032 , 513.73102617, 512.12694876, - 513.75349856, 513.75349856], - [508.89835549, 509.07488197, 508.78617651, 507.32703495, - 508.80660754, 508.80660754], - [507.33691225, 507.50868154, 507.22775391, 505.80769049, - 507.24763494, 507.24763494], - [507.33691225, 507.50868154, 507.22775391, 505.80769049, - 507.24763494, 507.24763494], - [500.11106052, 500.26454358, 500.01351449, 498.74379226, - 500.03128108, 500.03128108], - [490.37943577, 490.51525847, 490.2931062 , 489.16874675, - 490.30883032, 490.30883032], - [487.36237489, 487.49388997, 487.27878132, 486.18989638, - 487.29400722, 487.29400722], - [487.36237489, 487.49388997, 487.27878132, 486.18989638, - 487.29400722, 487.29400722], - [479.30136684, 479.4234047 , 479.22379274, 478.2129665 , - 479.23792251, 479.23792251], - [468.52528202, 468.6382647 , 468.45345876, 467.51719419, - 468.46654134, 468.46654134], - [465.19176552, 465.30261739, 465.12129528, 464.20256275, - 465.1341315 , 465.1341315 ], - [465.19176552, 465.30261739, 465.12129528, 464.20256275, - 465.1341315 , 465.1341315 ], - [458.86276147, 458.97030016, 458.79439463, 457.90289629, - 458.80684787, 458.80684787], - [450.30606285, 450.41046911, 450.2396836 , 449.37386472, - 450.25177501, 450.25177501], - [447.63366089, 447.73737307, 447.56772169, 446.70757004, - 447.57973301, 447.57973301], - [447.63366089, 447.73737307, 447.56772169, 446.70757004, - 447.57973301, 447.57973301], - [444.65385165, 444.75693768, 444.58830918, 443.73325265, - 444.60024831, 444.60024831], - [440.57008048, 440.67255101, 440.50492745, 439.65484333, - 440.51679574, 440.51679574], - [439.28316759, 439.38550012, 439.2181017 , 438.36912071, - 439.22995416, 439.22995416]]) - SkinFrictionDrag - skin_friction_coeff |0.02700108| input unitless traj.climb.rhs_all.core_aerodynamics.skin_friction_coeff - val: - array([[0.00275142, 0.00289141, 0.00266898, 0.0019099 , 0.00268364, - 0.00268364], - [0.00272014, 0.00285796, 0.00263896, 0.00189079, 0.0026534 , - 0.0026534 ], - [0.0026843 , 0.00281966, 0.00260455, 0.00186876, 0.00261874, - 0.00261874], - [0.0026744 , 0.00280909, 0.00259504, 0.00186264, 0.00260916, - 0.00260916], - [0.0026744 , 0.00280909, 0.00259504, 0.00186264, 0.00260916, - 0.00260916], - [0.00263531, 0.00276739, 0.00255747, 0.00183829, 0.00257131, - 0.00257131], - [0.00259601, 0.00272557, 0.00251963, 0.00181333, 0.00253322, - 0.00253322], - [0.00258622, 0.00271518, 0.00251019, 0.00180698, 0.00252372, - 0.00252372], - [0.00258622, 0.00271518, 0.00251019, 0.00180698, 0.00252372, - 0.00252372], - [0.00256449, 0.00269219, 0.0024892 , 0.0017926 , 0.0025026 , - 0.0025026 ], - [0.00254382, 0.00267048, 0.00246914, 0.00177815, 0.00248243, - 0.00248243], - [0.00253908, 0.00266555, 0.00246451, 0.00177461, 0.00247778, - 0.00247778], - [0.00253908, 0.00266555, 0.00246451, 0.00177461, 0.00247778, - 0.00247778], - [0.00253198, 0.00265825, 0.00245753, 0.00176896, 0.00247078, - 0.00247078], - [0.00252603, 0.00265233, 0.00245158, 0.00176333, 0.00246483, - 0.00246483], - [0.00252498, 0.00265136, 0.00245049, 0.00176201, 0.00246374, - 0.00246374], - [0.00252498, 0.00265136, 0.00245049, 0.00176201, 0.00246374, - 0.00246374], - [0.00252424, 0.00265074, 0.00244969, 0.00176078, 0.00246295, - 0.00246295], - [0.00252395, 0.00265068, 0.00244927, 0.00175948, 0.00246256, - 0.00246256], - [0.00252403, 0.00265084, 0.0024493 , 0.00175916, 0.0024626 , - 0.0024626 ]]) - Re |1107669904.6272902| input unitless traj.climb.rhs_all.core_aerodynamics.Re - val: - array([[1.49048396e+07, 1.09237226e+07, 1.80914034e+07, 1.81778318e+08, - 1.74677603e+07, 1.74677603e+07], - [1.59263513e+07, 1.16723862e+07, 1.93313080e+07, 1.94236599e+08, - 1.86649232e+07, 1.86649232e+07], - [1.71753244e+07, 1.25877557e+07, 2.08473040e+07, 2.09468982e+08, - 2.01286600e+07, 2.01286600e+07], - [1.75335338e+07, 1.28502865e+07, 2.12820963e+07, 2.13837677e+08, - 2.05484643e+07, 2.05484643e+07], - [1.75335338e+07, 1.28502865e+07, 2.12820963e+07, 2.13837677e+08, - 2.05484643e+07, 2.05484643e+07], - [1.89861298e+07, 1.39148908e+07, 2.30452485e+07, 2.31553430e+08, - 2.22508374e+07, 2.22508374e+07], - [2.04379008e+07, 1.49788904e+07, 2.48073993e+07, 2.49259122e+08, - 2.39522438e+07, 2.39522438e+07], - [2.07762539e+07, 1.52268686e+07, 2.52180903e+07, 2.53385652e+08, - 2.43487775e+07, 2.43487775e+07], - [2.07762539e+07, 1.52268686e+07, 2.52180903e+07, 2.53385652e+08, - 2.43487775e+07, 2.43487775e+07], - [2.14332068e+07, 1.57083478e+07, 2.60154956e+07, 2.61397800e+08, - 2.51186948e+07, 2.51186948e+07], - [2.17791933e+07, 1.59619205e+07, 2.64354519e+07, 2.65617425e+08, - 2.55241745e+07, 2.55241745e+07], - [2.17705043e+07, 1.59555524e+07, 2.64249053e+07, 2.65511455e+08, - 2.55139914e+07, 2.55139914e+07], - [2.17705043e+07, 1.59555524e+07, 2.64249053e+07, 2.65511455e+08, - 2.55139914e+07, 2.55139914e+07], - [2.16143630e+07, 1.58411168e+07, 2.62353819e+07, 2.63607167e+08, - 2.53310012e+07, 2.53310012e+07], - [2.11348941e+07, 1.54897151e+07, 2.56534055e+07, 2.57759600e+08, - 2.47690866e+07, 2.47690866e+07], - [2.09278119e+07, 1.53379451e+07, 2.54020504e+07, 2.55234041e+08, - 2.45263961e+07, 2.45263961e+07], - [2.09278119e+07, 1.53379451e+07, 2.54020504e+07, 2.55234041e+08, - 2.45263961e+07, 2.45263961e+07], - [2.06675501e+07, 1.51471998e+07, 2.50861462e+07, 2.52059907e+08, - 2.42213817e+07, 2.42213817e+07], - [2.02640027e+07, 1.48514408e+07, 2.45963228e+07, 2.47138273e+08, - 2.37484434e+07, 2.37484434e+07], - [2.01263640e+07, 1.47505658e+07, 2.44292579e+07, 2.45459643e+08, - 2.35871375e+07, 2.35871375e+07]]) - fineness_ratios |10.2777523| input unitless traj.climb.rhs_all.core_aerodynamics.fineness_ratios - val: - array([ 0.13 , 0.125 , 0.1195 , 10.03921569, 1.54911839, - 1.54911839]) - wetted_areas |4886.31967641| input ft**2 traj.climb.rhs_all.core_aerodynamics.wetted_areas - val: - array([2396.56 , 592.65 , 581.13 , 4158.62 , 273.4536, 273.4536]) - laminar_fractions_upper |0.0| input unitless traj.climb.rhs_all.core_aerodynamics.laminar_fractions_upper - val: - array([0., 0., 0., 0., 0., 0.]) - laminar_fractions_lower |0.0| input unitless traj.climb.rhs_all.core_aerodynamics.laminar_fractions_lower - val: - array([0., 0., 0., 0., 0., 0.]) - aircraft:wing:area [1370.] input ft**2 traj.climb.rhs_all.aircraft:wing:area - skin_friction_drag_coeff |0.09198219| output unitless traj.climb.rhs_all.core_aerodynamics.SkinFrictionDrag.skin_friction_drag_coeff - val: - array([0.02181828, 0.02157963, 0.02130564, 0.02122983, 0.02122983, - 0.02092983, 0.02062655, 0.02055053, 0.02055053, 0.02038073, - 0.02021645, 0.02017796, 0.02017796, 0.02011904, 0.02006652, - 0.02005606, 0.02005606, 0.02004762, 0.02004138, 0.02004067]) - Drag - CDI - induced_drag_coeff |0.11518843| input unitless traj.climb.rhs_all.core_aerodynamics.Drag.induced_drag_coeff - val: - array([0.07376573, 0.05361265, 0.03679125, 0.03308367, 0.03308367, - 0.02152854, 0.01371928, 0.01222037, 0.01222037, 0.0093992 , - 0.00725446, 0.00682313, 0.00682313, 0.00621091, 0.00571328, - 0.00562048, 0.00562048, 0.00554781, 0.00549744, 0.00549288]) - pressure_drag_coeff |0.08027558| input unitless traj.climb.rhs_all.core_aerodynamics.Drag.pressure_drag_coeff - val: - array([0.06048713, 0.03849179, 0.02182262, 0.01846069, 0.01846069, - 0.00912059, 0.00437262, 0.00368886, 0.00368886, 0.00232912, - 0.00128049, 0.00117909, 0.00117909, 0.00110638, 0.00098379, - 0.0009615 , 0.0009615 , 0.00094423, 0.0009321 , 0.00093247]) - CDI |0.19410682| output unitless traj.climb.rhs_all.core_aerodynamics.CDI - val: - array([0.13425286, 0.09210444, 0.05861387, 0.05154436, 0.05154436, - 0.03064913, 0.01809189, 0.01590923, 0.01590923, 0.01172832, - 0.00853495, 0.00800222, 0.00800222, 0.00731729, 0.00669708, - 0.00658197, 0.00658197, 0.00649204, 0.00642953, 0.00642535]) - CD0 - compress_drag_coeff |0.00168953| input unitless traj.climb.rhs_all.core_aerodynamics.Drag.compress_drag_coeff - val: - array([0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 6.84397531e-05, 4.21572944e-04, 5.38360174e-04, - 5.38360174e-04, 6.74912191e-04, 8.66966315e-04, 9.40914533e-04]) - skin_friction_drag_coeff |0.09198219| input unitless traj.climb.rhs_all.core_aerodynamics.Drag.skin_friction_drag_coeff - val: - array([0.02181828, 0.02157963, 0.02130564, 0.02122983, 0.02122983, - 0.02092983, 0.02062655, 0.02055053, 0.02055053, 0.02038073, - 0.02021645, 0.02017796, 0.02017796, 0.02011904, 0.02006652, - 0.02005606, 0.02005606, 0.02004762, 0.02004138, 0.02004067]) - CD0 |0.09287608| output unitless traj.climb.rhs_all.core_aerodynamics.CD0 - val: - array([0.02181828, 0.02157963, 0.02130564, 0.02122983, 0.02122983, - 0.02092983, 0.02062655, 0.02055053, 0.02055053, 0.02038073, - 0.02021645, 0.02017796, 0.02017796, 0.02018748, 0.02048809, - 0.02059442, 0.02059442, 0.02072253, 0.02090835, 0.02098159]) - drag - total_drag_coeff - CD0 |0.09287608| input unitless traj.climb.rhs_all.core_aerodynamics.Drag.CD0 - val: - array([0.02181828, 0.02157963, 0.02130564, 0.02122983, 0.02122983, - 0.02092983, 0.02062655, 0.02055053, 0.02055053, 0.02038073, - 0.02021645, 0.02017796, 0.02017796, 0.02018748, 0.02048809, - 0.02059442, 0.02059442, 0.02072253, 0.02090835, 0.02098159]) - CDI |0.19410682| input unitless traj.climb.rhs_all.core_aerodynamics.Drag.CDI - val: - array([0.13425286, 0.09210444, 0.05861387, 0.05154436, 0.05154436, - 0.03064913, 0.01809189, 0.01590923, 0.01590923, 0.01172832, - 0.00853495, 0.00800222, 0.00800222, 0.00731729, 0.00669708, - 0.00658197, 0.00658197, 0.00649204, 0.00642953, 0.00642535]) - FCD0 [0.93089003] input unitless traj.climb.rhs_all.aircraft:design:zero_lift_drag_coeff_factor - FCDI [0.90983938] input unitless traj.climb.rhs_all.aircraft:design:lift_dependent_drag_coeff_factor - CD_prescaled |0.24189295| output unitless traj.climb.rhs_all.core_aerodynamics.Drag.drag.CD_prescaled - val: - array([0.14245896, 0.10388851, 0.07316241, 0.06665972, 0.06665972, - 0.04736916, 0.03566177, 0.03360513, 0.03360513, 0.0296431 , - 0.02658473, 0.0260642 , 0.0260642 , 0.02544989, 0.02516542, - 0.02515968, 0.02515968, 0.02519711, 0.02531322, 0.02537759]) - simple_CD - aircraft:design:subsonic_drag_coeff_factor [1.] input unitless traj.climb.rhs_all.aircraft:design:subsonic_drag_coeff_factor - aircraft:design:supersonic_drag_coeff_factor [1.] input unitless traj.climb.rhs_all.aircraft:design:supersonic_drag_coeff_factor - mach |2.22189137| input unitless traj.climb.rhs_all.mach - val: - array([0.2 , 0.22168851, 0.25161423, 0.26108562, 0.26108562, - 0.30537972, 0.36649654, 0.38583981, 0.38583981, 0.43850111, - 0.51116297, 0.53416019, 0.53416019, 0.5784543 , 0.63957112, - 0.65891438, 0.65891438, 0.68060289, 0.71052861, 0.72 ]) - CD_prescaled |0.24189295| input unitless traj.climb.rhs_all.core_aerodynamics.Drag.drag.CD_prescaled - val: - array([0.14245896, 0.10388851, 0.07316241, 0.06665972, 0.06665972, - 0.04736916, 0.03566177, 0.03360513, 0.03360513, 0.0296431 , - 0.02658473, 0.0260642 , 0.0260642 , 0.02544989, 0.02516542, - 0.02515968, 0.02515968, 0.02519711, 0.02531322, 0.02537759]) - CD |0.24189295| output unitless traj.climb.rhs_all.core_aerodynamics.CD - val: - array([0.14245896, 0.10388851, 0.07316241, 0.06665972, 0.06665972, - 0.04736916, 0.03566177, 0.03360513, 0.03360513, 0.0296431 , - 0.02658473, 0.0260642 , 0.0260642 , 0.02544989, 0.02516542, - 0.02515968, 0.02515968, 0.02519711, 0.02531322, 0.02537759]) - simple_drag - aircraft:wing:area [127.2771648] input m**2 traj.climb.rhs_all.aircraft:wing:area - dynamic_pressure |34941.60514958| input N/m**2 traj.climb.rhs_all.core_aerodynamics.dynamic_pressure - val: - array([2837.09058373, 3320.92742596, 3998.4465899 , 4213.25847322, - 4213.25847322, 5204.91091948, 6490.73694453, 6867.56030763, - 6867.56030763, 7800.52010707, 8831.20540436, 9090.215421 , - 9090.215421 , 9495.31922842, 9852.66004282, 9918.29233157, - 9918.29233157, 9965.60365807, 9986.86376675, 9983.27821833]) - CD |0.24189295| input unitless traj.climb.rhs_all.core_aerodynamics.Drag.drag.CD - val: - array([0.14245896, 0.10388851, 0.07316241, 0.06665972, 0.06665972, - 0.04736916, 0.03566177, 0.03360513, 0.03360513, 0.0296431 , - 0.02658473, 0.0260642 , 0.0260642 , 0.02544989, 0.02516542, - 0.02515968, 0.02515968, 0.02519711, 0.02531322, 0.02537759]) - drag |150759.28928049| output N traj.climb.rhs_all.drag - val: - array([51441.48042457, 43911.41111041, 37233.15286355, 35746.38288226, - 35746.38288226, 31380.47324171, 29460.99199568, 29373.69267134, - 29373.69267134, 29430.50374299, 29881.51771429, 30155.67367994, - 30155.67367994, 30757.1359626 , 31557.90749055, 31760.88321635, - 31760.88321635, 31959.85759632, 32175.62183799, 32245.86305683]) - Buffet - mach |2.22189137| input unitless traj.climb.rhs_all.mach - val: - array([0.2 , 0.22168851, 0.25161423, 0.26108562, 0.26108562, - 0.30537972, 0.36649654, 0.38583981, 0.38583981, 0.43850111, - 0.51116297, 0.53416019, 0.53416019, 0.5784543 , 0.63957112, - 0.65891438, 0.65891438, 0.68060289, 0.71052861, 0.72 ]) - mission:design:mach [0.80017085] input unitless traj.climb.rhs_all.mission:design:mach - aircraft:wing:aspect_ratio [11.22091] input unitless traj.climb.rhs_all.aircraft:wing:aspect_ratio - aircraft:wing:max_camber_at_70_semispan [0.] input unitless traj.climb.rhs_all.aircraft:wing:max_camber_at_70_semispan - aircraft:wing:sweep [25.] input deg traj.climb.rhs_all.aircraft:wing:sweep - aircraft:wing:thickness_to_chord [0.13] input unitless traj.climb.rhs_all.aircraft:wing:thickness_to_chord - DELCLB |2.82576417| output unitless traj.climb.rhs_all.core_aerodynamics.Buffet.DELCLB - val: - array([0.86560792, 0.85224899, 0.83173953, 0.82475258, 0.82475258, - 0.78891304, 0.73090207, 0.71047393, 0.71047393, 0.64533429, - 0.55812083, 0.53350129, 0.53350129, 0.4823821 , 0.41244945, - 0.38579137, 0.38579137, 0.35159113, 0.29970276, 0.28257367]) - core_propulsion - turbofan_28k - interpolation - mach |2.22189137| input unitless traj.climb.rhs_all.mach - val: - array([0.2 , 0.22168851, 0.25161423, 0.26108562, 0.26108562, - 0.30537972, 0.36649654, 0.38583981, 0.38583981, 0.43850111, - 0.51116297, 0.53416019, 0.53416019, 0.5784543 , 0.63957112, - 0.65891438, 0.65891438, 0.68060289, 0.71052861, 0.72 ]) - altitude |87358.6369253| input ft traj.climb.rhs_all.altitude - val: - array([ 0. , 1334.67757163, 3176.26020893, 3759.11481713, - 3759.11481713, 6484.90577713, 10245.94096014, 11436.29573631, - 11436.29573631, 14676.99149614, 19148.49020934, 20563.70426369, - 20563.70426369, 23289.4952237 , 27050.5304067 , 28240.88518287, - 28240.88518287, 29575.5627545 , 31417.1453918 , 32000. ]) - throttle |2.27639903| input unitless traj.climb.rhs_all.throttle - val: - array([0.36272519, 0.34217892, 0.32721108, 0.32475961, 0.32475961, - 0.32505412, 0.34982841, 0.36112935, 0.36112935, 0.40082952, - 0.46816406, 0.49426945, 0.49426945, 0.54853485, 0.63668329, - 0.6672203 , 0.6672203 , 0.70468433, 0.75486115, 0.77136189]) - fuel_flow_rate_unscaled |11208.88451868| output lbm/h traj.climb.rhs_all.turbofan_28k.interpolation.fuel_flow_rate_unscaled - val: - array([3239.56199085, 2918.98793851, 2639.60346984, 2577.53239335, - 2577.53239335, 2393.40610099, 2299.95148918, 2296.43887466, - 2296.43887466, 2304.20682221, 2346.79843317, 2363.50900188, - 2363.50900188, 2407.78889133, 2460.8909312 , 2474.53935068, - 2474.53935068, 2484.43200533, 2500.59248016, 2507.76511382]) - nox_rate_unscaled |58.65166043| output lbm/h traj.climb.rhs_all.turbofan_28k.interpolation.nox_rate_unscaled - val: - array([13.84282768, 13.22353665, 12.59493128, 12.44304625, 12.44304625, - 12.0221227 , 12.15639189, 12.24459752, 12.24459752, 12.56052319, - 12.86332862, 13.12504521, 13.12504521, 13.37192625, 13.76383712, - 13.84749833, 13.84749833, 13.96635966, 14.09873028, 14.13201018]) - thrust_net_unscaled |24207.42074097| output lbf traj.climb.rhs_all.turbofan_28k.interpolation.thrust_net_unscaled - val: - array([8532.57300146, 7450.68156717, 6441.96803141, 6205.50413313, - 6205.50413313, 5447.41128948, 4968.24516058, 4892.23703914, - 4892.23703914, 4747.51070881, 4639.74635182, 4629.13254482, - 4629.13254482, 4625.89901783, 4633.63504935, 4633.44613673, - 4633.44613673, 4631.49947216, 4624.52153368, 4623.04453842]) - interp_max_throttles - mach |2.22189137| input unitless traj.climb.rhs_all.mach - val: - array([0.2 , 0.22168851, 0.25161423, 0.26108562, 0.26108562, - 0.30537972, 0.36649654, 0.38583981, 0.38583981, 0.43850111, - 0.51116297, 0.53416019, 0.53416019, 0.5784543 , 0.63957112, - 0.65891438, 0.65891438, 0.68060289, 0.71052861, 0.72 ]) - altitude |87358.6369253| input ft traj.climb.rhs_all.altitude - val: - array([ 0. , 1334.67757163, 3176.26020893, 3759.11481713, - 3759.11481713, 6484.90577713, 10245.94096014, 11436.29573631, - 11436.29573631, 14676.99149614, 19148.49020934, 20563.70426369, - 20563.70426369, 23289.4952237 , 27050.5304067 , 28240.88518287, - 28240.88518287, 29575.5627545 , 31417.1453918 , 32000. ]) - throttle_max |4.47213595| output unitless traj.climb.rhs_all.turbofan_28k.throttle_max - val: - array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - 1., 1., 1.]) - max_interpolation - mach |2.22189137| input unitless traj.climb.rhs_all.mach - val: - array([0.2 , 0.22168851, 0.25161423, 0.26108562, 0.26108562, - 0.30537972, 0.36649654, 0.38583981, 0.38583981, 0.43850111, - 0.51116297, 0.53416019, 0.53416019, 0.5784543 , 0.63957112, - 0.65891438, 0.65891438, 0.68060289, 0.71052861, 0.72 ]) - altitude |87358.6369253| input ft traj.climb.rhs_all.altitude - val: - array([ 0. , 1334.67757163, 3176.26020893, 3759.11481713, - 3759.11481713, 6484.90577713, 10245.94096014, 11436.29573631, - 11436.29573631, 14676.99149614, 19148.49020934, 20563.70426369, - 20563.70426369, 23289.4952237 , 27050.5304067 , 28240.88518287, - 28240.88518287, 29575.5627545 , 31417.1453918 , 32000. ]) - throttle_max |4.47213595| input unitless traj.climb.rhs_all.throttle_max - val: - array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - 1., 1., 1.]) - thrust_net_max_unscaled |68847.2855466| output lbf traj.climb.rhs_all.turbofan_28k.max_interpolation.thrust_net_max_unscaled - val: - array([26469. , 24792.97627383, 22635.23967936, 22005.94254328, - 22005.94254328, 19296.17450843, 16096.80803552, 15256.52557923, - 15256.52557923, 13082.84267052, 10678.74368018, 10014.48915139, - 10014.48915139, 8896.88333758, 7550.59501168, 7170.84981635, - 7170.84981635, 6751.56561794, 6254.90218295, 6107.972 ]) - engine_scaling - aircraft:engine:scale_factor [1.] input unitless traj.climb.rhs_all.aircraft:engine:scale_factor - mach |2.22189137| input unitless traj.climb.rhs_all.mach - val: - array([0.2 , 0.22168851, 0.25161423, 0.26108562, 0.26108562, - 0.30537972, 0.36649654, 0.38583981, 0.38583981, 0.43850111, - 0.51116297, 0.53416019, 0.53416019, 0.5784543 , 0.63957112, - 0.65891438, 0.65891438, 0.68060289, 0.71052861, 0.72 ]) - fuel_flow_rate_unscaled |11208.88451868| input lbm/h traj.climb.rhs_all.engine_scaling.fuel_flow_rate_unscaled - val: - array([3239.56199085, 2918.98793851, 2639.60346984, 2577.53239335, - 2577.53239335, 2393.40610099, 2299.95148918, 2296.43887466, - 2296.43887466, 2304.20682221, 2346.79843317, 2363.50900188, - 2363.50900188, 2407.78889133, 2460.8909312 , 2474.53935068, - 2474.53935068, 2484.43200533, 2500.59248016, 2507.76511382]) - nox_rate_unscaled |58.65166043| input lbm/h traj.climb.rhs_all.engine_scaling.nox_rate_unscaled - val: - array([13.84282768, 13.22353665, 12.59493128, 12.44304625, 12.44304625, - 12.0221227 , 12.15639189, 12.24459752, 12.24459752, 12.56052319, - 12.86332862, 13.12504521, 13.12504521, 13.37192625, 13.76383712, - 13.84749833, 13.84749833, 13.96635966, 14.09873028, 14.13201018]) - thrust_net_unscaled |24207.42074097| input lbf traj.climb.rhs_all.engine_scaling.thrust_net_unscaled - val: - array([8532.57300146, 7450.68156717, 6441.96803141, 6205.50413313, - 6205.50413313, 5447.41128948, 4968.24516058, 4892.23703914, - 4892.23703914, 4747.51070881, 4639.74635182, 4629.13254482, - 4629.13254482, 4625.89901783, 4633.63504935, 4633.44613673, - 4633.44613673, 4631.49947216, 4624.52153368, 4623.04453842]) - thrust_net_max_unscaled |68847.2855466| input lbf traj.climb.rhs_all.engine_scaling.thrust_net_max_unscaled - val: - array([26469. , 24792.97627383, 22635.23967936, 22005.94254328, - 22005.94254328, 19296.17450843, 16096.80803552, 15256.52557923, - 15256.52557923, 13082.84267052, 10678.74368018, 10014.48915139, - 10014.48915139, 8896.88333758, 7550.59501168, 7170.84981635, - 7170.84981635, 6751.56561794, 6254.90218295, 6107.972 ]) - fuel_flow_rate_negative |11208.88451868| output lbm/h traj.climb.rhs_all.turbofan_28k.fuel_flow_rate_negative - val: - array([-3239.56199085, -2918.98793851, -2639.60346984, -2577.53239335, - -2577.53239335, -2393.40610099, -2299.95148918, -2296.43887466, - -2296.43887466, -2304.20682221, -2346.79843317, -2363.50900188, - -2363.50900188, -2407.78889133, -2460.8909312 , -2474.53935068, - -2474.53935068, -2484.43200533, -2500.59248016, -2507.76511382]) - nox_rate |58.65166043| output lbm/h traj.climb.rhs_all.turbofan_28k.nox_rate - val: - array([13.84282768, 13.22353665, 12.59493128, 12.44304625, 12.44304625, - 12.0221227 , 12.15639189, 12.24459752, 12.24459752, 12.56052319, - 12.86332862, 13.12504521, 13.12504521, 13.37192625, 13.76383712, - 13.84749833, 13.84749833, 13.96635966, 14.09873028, 14.13201018]) - thrust_net |24207.42074097| output lbf traj.climb.rhs_all.turbofan_28k.thrust_net - val: - array([8532.57300146, 7450.68156717, 6441.96803141, 6205.50413313, - 6205.50413313, 5447.41128948, 4968.24516058, 4892.23703914, - 4892.23703914, 4747.51070881, 4639.74635182, 4629.13254482, - 4629.13254482, 4625.89901783, 4633.63504935, 4633.44613673, - 4633.44613673, 4631.49947216, 4624.52153368, 4623.04453842]) - thrust_net_max |68847.2855466| output lbf traj.climb.rhs_all.turbofan_28k.thrust_net_max - val: - array([26469. , 24792.97627383, 22635.23967936, 22005.94254328, - 22005.94254328, 19296.17450843, 16096.80803552, 15256.52557923, - 15256.52557923, 13082.84267052, 10678.74368018, 10014.48915139, - 10014.48915139, 8896.88333758, 7550.59501168, 7170.84981635, - 7170.84981635, 6751.56561794, 6254.90218295, 6107.972 ]) - vectorize_performance - thrust_net_0 |24207.42074097| input lbf traj.climb.rhs_all.vectorize_performance.thrust_net_0 - val: - array([8532.57300146, 7450.68156717, 6441.96803141, 6205.50413313, - 6205.50413313, 5447.41128948, 4968.24516058, 4892.23703914, - 4892.23703914, 4747.51070881, 4639.74635182, 4629.13254482, - 4629.13254482, 4625.89901783, 4633.63504935, 4633.44613673, - 4633.44613673, 4631.49947216, 4624.52153368, 4623.04453842]) - thrust_net_max_0 |68847.2855466| input lbf traj.climb.rhs_all.vectorize_performance.thrust_net_max_0 - val: - array([26469. , 24792.97627383, 22635.23967936, 22005.94254328, - 22005.94254328, 19296.17450843, 16096.80803552, 15256.52557923, - 15256.52557923, 13082.84267052, 10678.74368018, 10014.48915139, - 10014.48915139, 8896.88333758, 7550.59501168, 7170.84981635, - 7170.84981635, 6751.56561794, 6254.90218295, 6107.972 ]) - fuel_flow_rate_negative_0 |11208.88451868| input lbm/h traj.climb.rhs_all.vectorize_performance.fuel_flow_rate_negative_0 - val: - array([-3239.56199085, -2918.98793851, -2639.60346984, -2577.53239335, - -2577.53239335, -2393.40610099, -2299.95148918, -2296.43887466, - -2296.43887466, -2304.20682221, -2346.79843317, -2363.50900188, - -2363.50900188, -2407.78889133, -2460.8909312 , -2474.53935068, - -2474.53935068, -2484.43200533, -2500.59248016, -2507.76511382]) - electric_power_in_0 |0.0| input kW traj.climb.rhs_all.vectorize_performance.electric_power_in_0 - val: - array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., - 0., 0., 0.]) - nox_rate_0 |58.65166043| input lbm/h traj.climb.rhs_all.vectorize_performance.nox_rate_0 - val: - array([13.84282768, 13.22353665, 12.59493128, 12.44304625, 12.44304625, - 12.0221227 , 12.15639189, 12.24459752, 12.24459752, 12.56052319, - 12.86332862, 13.12504521, 13.12504521, 13.37192625, 13.76383712, - 13.84749833, 13.84749833, 13.96635966, 14.09873028, 14.13201018]) - t4_0 |0.0| input degR traj.climb.rhs_all.vectorize_performance.t4_0 - val: - array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., - 0., 0., 0.]) - shaft_power_0 |0.0| input hp traj.climb.rhs_all.vectorize_performance.shaft_power_0 - val: - array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., - 0., 0., 0.]) - shaft_power_max_0 |0.0| input hp traj.climb.rhs_all.vectorize_performance.shaft_power_max_0 - val: - array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., - 0., 0., 0.]) - thrust_net |24207.42074097| output lbf traj.climb.rhs_all.thrust_net - val: - array([[8532.57300146], - [7450.68156717], - [6441.96803141], - [6205.50413313], - [6205.50413313], - [5447.41128948], - [4968.24516058], - [4892.23703914], - [4892.23703914], - [4747.51070881], - [4639.74635182], - [4629.13254482], - [4629.13254482], - [4625.89901783], - [4633.63504935], - [4633.44613673], - [4633.44613673], - [4631.49947216], - [4624.52153368], - [4623.04453842]]) - thrust_net_max |68847.2855466| output lbf traj.climb.rhs_all.thrust_net_max - val: - array([[26469. ], - [24792.97627383], - [22635.23967936], - [22005.94254328], - [22005.94254328], - [19296.17450843], - [16096.80803552], - [15256.52557923], - [15256.52557923], - [13082.84267052], - [10678.74368018], - [10014.48915139], - [10014.48915139], - [ 8896.88333758], - [ 7550.59501168], - [ 7170.84981635], - [ 7170.84981635], - [ 6751.56561794], - [ 6254.90218295], - [ 6107.972 ]]) - fuel_flow_rate_negative |11208.88451868| output lbm/h traj.climb.rhs_all.fuel_flow_rate_negative - val: - array([[-3239.56199085], - [-2918.98793851], - [-2639.60346984], - [-2577.53239335], - [-2577.53239335], - [-2393.40610099], - [-2299.95148918], - [-2296.43887466], - [-2296.43887466], - [-2304.20682221], - [-2346.79843317], - [-2363.50900188], - [-2363.50900188], - [-2407.78889133], - [-2460.8909312 ], - [-2474.53935068], - [-2474.53935068], - [-2484.43200533], - [-2500.59248016], - [-2507.76511382]]) - electric_power_in |0.0| output kW traj.climb.rhs_all.electric_power_in - val: - array([[0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.]]) - nox_rate |58.65166043| output lbm/h traj.climb.rhs_all.nox_rate - val: - array([[13.84282768], - [13.22353665], - [12.59493128], - [12.44304625], - [12.44304625], - [12.0221227 ], - [12.15639189], - [12.24459752], - [12.24459752], - [12.56052319], - [12.86332862], - [13.12504521], - [13.12504521], - [13.37192625], - [13.76383712], - [13.84749833], - [13.84749833], - [13.96635966], - [14.09873028], - [14.13201018]]) - t4 |0.0| output degR traj.climb.rhs_all.t4 - val: - array([[0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.]]) - shaft_power |0.0| output hp traj.climb.rhs_all.shaft_power - val: - array([[0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.]]) - shaft_power_max |0.0| output hp traj.climb.rhs_all.shaft_power_max - val: - array([[0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.]]) - propulsion_sum - thrust_net |24207.42074097| input lbf traj.climb.rhs_all.thrust_net - val: - array([[8532.57300146], - [7450.68156717], - [6441.96803141], - [6205.50413313], - [6205.50413313], - [5447.41128948], - [4968.24516058], - [4892.23703914], - [4892.23703914], - [4747.51070881], - [4639.74635182], - [4629.13254482], - [4629.13254482], - [4625.89901783], - [4633.63504935], - [4633.44613673], - [4633.44613673], - [4631.49947216], - [4624.52153368], - [4623.04453842]]) - thrust_net_max |68847.2855466| input lbf traj.climb.rhs_all.thrust_net_max - val: - array([[26469. ], - [24792.97627383], - [22635.23967936], - [22005.94254328], - [22005.94254328], - [19296.17450843], - [16096.80803552], - [15256.52557923], - [15256.52557923], - [13082.84267052], - [10678.74368018], - [10014.48915139], - [10014.48915139], - [ 8896.88333758], - [ 7550.59501168], - [ 7170.84981635], - [ 7170.84981635], - [ 6751.56561794], - [ 6254.90218295], - [ 6107.972 ]]) - fuel_flow_rate_negative |11208.88451868| input lbm/h traj.climb.rhs_all.fuel_flow_rate_negative - val: - array([[-3239.56199085], - [-2918.98793851], - [-2639.60346984], - [-2577.53239335], - [-2577.53239335], - [-2393.40610099], - [-2299.95148918], - [-2296.43887466], - [-2296.43887466], - [-2304.20682221], - [-2346.79843317], - [-2363.50900188], - [-2363.50900188], - [-2407.78889133], - [-2460.8909312 ], - [-2474.53935068], - [-2474.53935068], - [-2484.43200533], - [-2500.59248016], - [-2507.76511382]]) - electric_power_in |0.0| input kW traj.climb.rhs_all.electric_power_in - val: - array([[0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.]]) - nox_rate |58.65166043| input lbm/h traj.climb.rhs_all.nox_rate - val: - array([[13.84282768], - [13.22353665], - [12.59493128], - [12.44304625], - [12.44304625], - [12.0221227 ], - [12.15639189], - [12.24459752], - [12.24459752], - [12.56052319], - [12.86332862], - [13.12504521], - [13.12504521], - [13.37192625], - [13.76383712], - [13.84749833], - [13.84749833], - [13.96635966], - [14.09873028], - [14.13201018]]) - thrust_net_total |48414.84148193| output lbf traj.climb.rhs_all.thrust_net_total - val: - array([17065.14600291, 14901.36313434, 12883.93606283, 12411.00826626, - 12411.00826626, 10894.82257897, 9936.49032117, 9784.47407829, - 9784.47407829, 9495.02141762, 9279.49270363, 9258.26508964, - 9258.26508964, 9251.79803565, 9267.2700987 , 9266.89227346, - 9266.89227346, 9262.99894433, 9249.04306736, 9246.08907684]) - thrust_net_max_total |137694.5710932| output lbf traj.climb.rhs_all.thrust_net_max_total - val: - array([52938. , 49585.95254766, 45270.47935872, 44011.88508656, - 44011.88508656, 38592.34901686, 32193.61607105, 30513.05115847, - 30513.05115847, 26165.68534103, 21357.48736037, 20028.97830279, - 20028.97830279, 17793.76667517, 15101.19002336, 14341.69963271, - 14341.69963271, 13503.13123587, 12509.8043659 , 12215.944 ]) - fuel_flow_rate_negative_total |22417.76903736| output lbm/h traj.climb.rhs_all.fuel_flow_rate_negative_total - val: - array([-6479.1239817 , -5837.97587703, -5279.20693967, -5155.06478669, - -5155.06478669, -4786.81220198, -4599.90297835, -4592.87774932, - -4592.87774932, -4608.41364442, -4693.59686634, -4727.01800377, - -4727.01800377, -4815.57778266, -4921.78186239, -4949.07870135, - -4949.07870135, -4968.86401067, -5001.18496031, -5015.53022764]) - electric_power_in_total |0.0| output kW traj.climb.rhs_all.electric_power_in_total - val: - array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., - 0., 0., 0.]) - nox_rate_total |117.30332085| output lbm/h traj.climb.rhs_all.nox_rate_total - val: - array([27.68565536, 26.4470733 , 25.18986255, 24.8860925 , 24.8860925 , - 24.0442454 , 24.31278379, 24.48919503, 24.48919503, 25.12104637, - 25.72665723, 26.25009041, 26.25009041, 26.74385251, 27.52767425, - 27.69499666, 27.69499666, 27.93271932, 28.19746055, 28.26402037]) - mission_EOM - required_thrust - drag |150759.28928049| input N traj.climb.rhs_all.drag - val: - array([51441.48042457, 43911.41111041, 37233.15286355, 35746.38288226, - 35746.38288226, 31380.47324171, 29460.99199568, 29373.69267134, - 29373.69267134, 29430.50374299, 29881.51771429, 30155.67367994, - 30155.67367994, 30757.1359626 , 31557.90749055, 31760.88321635, - 31760.88321635, 31959.85759632, 32175.62183799, 32245.86305683]) - altitude_rate |11.35922533| input m/s traj.climb.rhs_all.altitude_rate - val: - array([2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, - 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54]) - velocity |692.82893696| input m/s traj.climb.rhs_all.velocity - val: - array([ 68.0573727 , 75.09079389, 84.68111157, 87.6885407 , - 87.6885407 , 101.57433671, 120.24308114, 126.03147998, - 126.03147998, 141.4927097 , 162.09903383, 168.44210711, - 168.44210711, 180.41248453, 196.38747815, 201.31036538, - 201.31036538, 206.75274127, 214.12710705, 216.42809923]) - velocity_rate |0.19418617| input m/s**2 traj.climb.rhs_all.velocity_rate - val: - array([0.04608051, 0.04586862, 0.04557466, 0.04548121, 0.04548121, - 0.04504182, 0.04442857, 0.04423277, 0.04423277, 0.04369538, - 0.04294308, 0.0427023 , 0.0427023 , 0.04223472, 0.0415812 , - 0.04137226, 0.04137226, 0.04113671, 0.04080959, 0.04070552]) - mass |260111.77531753| input kg traj.climb.rhs_all.mass - val: - array([59377.14578909, 59253.2001355 , 59099.30211114, 59053.23865024, - 59053.23865024, 58849.04195155, 58583.91501949, 58501.0166128 , - 58501.0166128 , 58275.75043339, 57961.72209353, 57860.85002365, - 57860.85002365, 57664.1758047 , 57387.22609857, 57298.3740442 , - 57298.3740442 , 57198.30721763, 57059.51640479, 57015.39290411]) - thrust_required |215359.94460881| output N traj.climb.rhs_all.thrust_required - val: - array([75909.55139862, 66284.56566165, 57310.60294538, 55206.91529598, - 55206.91529598, 48462.58534184, 44199.71107353, 43523.50913536, - 43523.50913536, 42235.95955221, 41277.24006694, 41182.81493542, - 41182.81493542, 41154.04804606, 41222.87121142, 41221.19056101, - 41221.19056101, 41203.8721702 , 41141.79333655, 41128.65333204]) - groundspeed - altitude_rate |11.35922533| input m/s traj.climb.rhs_all.altitude_rate - val: - array([2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, - 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54, 2.54]) - velocity |692.82893696| input m/s traj.climb.rhs_all.velocity - val: - array([ 68.0573727 , 75.09079389, 84.68111157, 87.6885407 , - 87.6885407 , 101.57433671, 120.24308114, 126.03147998, - 126.03147998, 141.4927097 , 162.09903383, 168.44210711, - 168.44210711, 180.41248453, 196.38747815, 201.31036538, - 201.31036538, 206.75274127, 214.12710705, 216.42809923]) - distance_rate |692.73581104| output m/s traj.climb.rhs_all.distance_rate - val: - array([ 68.00995794, 75.04782293, 84.6430095 , 87.65174596, - 87.65174596, 101.54257372, 120.21625082, 126.00588218, - 126.00588218, 141.46990952, 162.07913243, 168.42295523, - 168.42295523, 180.39460351, 196.37105177, 201.29434073, - 201.29434073, 206.73713847, 214.11204164, 216.413194 ]) - excess_specific_power - velocity |692.82893696| input m/s traj.climb.rhs_all.velocity - val: - array([ 68.0573727 , 75.09079389, 84.68111157, 87.6885407 , - 87.6885407 , 101.57433671, 120.24308114, 126.03147998, - 126.03147998, 141.4927097 , 162.09903383, 168.44210711, - 168.44210711, 180.41248453, 196.38747815, 201.31036538, - 201.31036538, 206.75274127, 214.12710705, 216.42809923]) - mass |260111.77531753| input kg traj.climb.rhs_all.mass - val: - array([59377.14578909, 59253.2001355 , 59099.30211114, 59053.23865024, - 59053.23865024, 58849.04195155, 58583.91501949, 58501.0166128 , - 58501.0166128 , 58275.75043339, 57961.72209353, 57860.85002365, - 57860.85002365, 57664.1758047 , 57387.22609857, 57298.3740442 , - 57298.3740442 , 57198.30721763, 57059.51640479, 57015.39290411]) - thrust_net_total |612495.9680934| input N traj.climb.rhs_all.thrust_net_max_total - val: - array([235479.95611956, 220569.3061708 , 201373.12503122, 195774.61877901, - 195774.61877901, 171667.32126336, 143204.33903321, 135728.81385526, - 135728.81385526, 116390.76723609, 95002.83702527, 89093.33431297, - 89093.33431297, 79150.61762572, 67173.43994963, 63795.05837376, - 63795.05837376, 60064.9203011 , 55646.38224237, 54339.22620951]) - drag |150759.28928049| input N traj.climb.rhs_all.drag - val: - array([51441.48042457, 43911.41111041, 37233.15286355, 35746.38288226, - 35746.38288226, 31380.47324171, 29460.99199568, 29373.69267134, - 29373.69267134, 29430.50374299, 29881.51771429, 30155.67367994, - 30155.67367994, 30757.1359626 , 31557.90749055, 31760.88321635, - 31760.88321635, 31959.85759632, 32175.62183799, 32245.86305683]) - specific_energy_rate |85.6710443| output m/s traj.climb.rhs_all.specific_energy_rate_excess - val: - array([21.51016857, 22.8290196 , 23.98268911, 24.23120792, 24.23120792, - 24.69112511, 23.80603311, 23.36433121, 23.36433121, 21.53011554, - 18.57127243, 17.49597197, 17.49597197, 15.43926748, 12.42846021, - 11.47669154, 11.47669154, 10.35933753, 8.98152426, 8.55190129]) - altitude_rate_max - specific_energy_rate |85.6710443| input m/s traj.climb.rhs_all.mission_EOM.specific_energy_rate_excess - val: - array([21.51016857, 22.8290196 , 23.98268911, 24.23120792, 24.23120792, - 24.69112511, 23.80603311, 23.36433121, 23.36433121, 21.53011554, - 18.57127243, 17.49597197, 17.49597197, 15.43926748, 12.42846021, - 11.47669154, 11.47669154, 10.35933753, 8.98152426, 8.55190129]) - velocity_rate |0.19418617| input m/s**2 traj.climb.rhs_all.velocity_rate - val: - array([0.04608051, 0.04586862, 0.04557466, 0.04548121, 0.04548121, - 0.04504182, 0.04442857, 0.04423277, 0.04423277, 0.04369538, - 0.04294308, 0.0427023 , 0.0427023 , 0.04223472, 0.0415812 , - 0.04137226, 0.04137226, 0.04113671, 0.04080959, 0.04070552]) - velocity |692.82893696| input m/s traj.climb.rhs_all.velocity - val: - array([ 68.0573727 , 75.09079389, 84.68111157, 87.6885407 , - 87.6885407 , 101.57433671, 120.24308114, 126.03147998, - 126.03147998, 141.4927097 , 162.09903383, 168.44210711, - 168.44210711, 180.41248453, 196.38747815, 201.31036538, - 201.31036538, 206.75274127, 214.12710705, 216.42809923]) - altitude_rate |83.18904841| output m/s traj.climb.rhs_all.altitude_rate_max - val: - array([21.19037347, 22.47779765, 23.58914868, 23.82452664, 23.82452664, - 24.22459546, 23.26127744, 22.79586784, 22.79586784, 20.89966812, - 17.86144478, 16.76250383, 16.76250383, 14.66227723, 11.5957571 , - 10.62740405, 10.62740405, 9.49205578, 8.0904515 , 7.65354991]) - throttle_balance - thrust_required |48414.84148193| input lbf traj.climb.rhs_all.thrust_required - val: - array([17065.14600291, 14901.36313434, 12883.93606283, 12411.00826626, - 12411.00826626, 10894.82257897, 9936.49032117, 9784.47407829, - 9784.47407829, 9495.02141762, 9279.49270363, 9258.26508964, - 9258.26508964, 9251.79803565, 9267.2700987 , 9266.89227346, - 9266.89227346, 9262.99894433, 9249.04306736, 9246.08907684]) - thrust_net_total |48414.84148193| input lbf traj.climb.rhs_all.thrust_net_total - val: - array([17065.14600291, 14901.36313434, 12883.93606283, 12411.00826626, - 12411.00826626, 10894.82257897, 9936.49032117, 9784.47407829, - 9784.47407829, 9495.02141762, 9279.49270363, 9258.26508964, - 9258.26508964, 9251.79803565, 9267.2700987 , 9266.89227346, - 9266.89227346, 9262.99894433, 9249.04306736, 9246.08907684]) - throttle |2.27639903| output unitless traj.climb.rhs_all.throttle - val: - array([0.36272519, 0.34217892, 0.32721108, 0.32475961, 0.32475961, - 0.32505412, 0.34982841, 0.36112935, 0.36112935, 0.40082952, - 0.46816406, 0.49426945, 0.49426945, 0.54853485, 0.63668329, - 0.6672203 , 0.6672203 , 0.70468433, 0.75486115, 0.77136189]) - initial_mass_residual_constraint - initial_mass [1.] input kg traj.climb.rhs_all.mission:summary:gross_mass - mass |260111.77531753| input kg traj.climb.rhs_all.mass - val: - array([59377.14578909, 59253.2001355 , 59099.30211114, 59053.23865024, - 59053.23865024, 58849.04195155, 58583.91501949, 58501.0166128 , - 58501.0166128 , 58275.75043339, 57961.72209353, 57860.85002365, - 57860.85002365, 57664.1758047 , 57387.22609857, 57298.3740442 , - 57298.3740442 , 57198.30721763, 57059.51640479, 57015.39290411]) - initial_mass_residual [-59476.14578909] output kg traj.climb.rhs_all.initial_mass_residual - timeseries - dt_dstau |1817.71161504| input s traj.climb.timeseries.dt_dstau - val: - array([225.54688903, 225.54688903, 225.54688903, 225.54688903, - 460.63085515, 460.63085515, 460.63085515, 460.63085515, - 547.64451164, 547.64451164, 547.64451164, 547.64451164, - 460.63085515, 460.63085515, 460.63085515, 460.63085515, - 225.54688903, 225.54688903, 225.54688903, 225.54688903]) - input_values:mach |2.22189137| input unitless traj.climb.timeseries.input_values:mach - val: - array([[0.2 ], - [0.22168851], - [0.25161423], - [0.26108562], - [0.26108562], - [0.30537972], - [0.36649654], - [0.38583981], - [0.38583981], - [0.43850111], - [0.51116297], - [0.53416019], - [0.53416019], - [0.5784543 ], - [0.63957112], - [0.65891438], - [0.65891438], - [0.68060289], - [0.71052861], - [0.72 ]]) - input_values:thrust_net_total |48414.84148193| input lbf traj.climb.timeseries.input_values:thrust_net_total - val: - array([[17065.14600291], - [14901.36313434], - [12883.93606283], - [12411.00826626], - [12411.00826626], - [10894.82257897], - [ 9936.49032117], - [ 9784.47407829], - [ 9784.47407829], - [ 9495.02141762], - [ 9279.49270363], - [ 9258.26508964], - [ 9258.26508964], - [ 9251.79803565], - [ 9267.2700987 ], - [ 9266.89227346], - [ 9266.89227346], - [ 9262.99894433], - [ 9249.04306736], - [ 9246.08907684]]) - input_values:drag |33892.0364495| input lbf traj.climb.timeseries.input_values:drag - val: - array([[11564.50483341], - [ 9871.67791123], - [ 8370.34573461], - [ 8036.10654684], - [ 8036.10654684], - [ 7054.61101592], - [ 6623.09446616], - [ 6603.46879734], - [ 6603.46879734], - [ 6616.2404343 ], - [ 6717.63240841], - [ 6779.26512122], - [ 6779.26512122], - [ 6914.47922116], - [ 7094.49982183], - [ 7140.13058017], - [ 7140.13058017], - [ 7184.86180019], - [ 7233.36753127], - [ 7249.15838542]]) - input_values:specific_energy_rate_excess |85.6710443| input m/s traj.climb.timeseries.input_values:specific_energy_rate_excess - val: - array([[21.51016857], - [22.8290196 ], - [23.98268911], - [24.23120792], - [24.23120792], - [24.69112511], - [23.80603311], - [23.36433121], - [23.36433121], - [21.53011554], - [18.57127243], - [17.49597197], - [17.49597197], - [15.43926748], - [12.42846021], - [11.47669154], - [11.47669154], - [10.35933753], - [ 8.98152426], - [ 8.55190129]]) - input_values:fuel_flow_rate_negative_total |22417.76903736| input lbm/h traj.climb.timeseries.input_values:fuel_flow_rate_negative_total - val: - array([[-6479.1239817 ], - [-5837.97587703], - [-5279.20693967], - [-5155.06478669], - [-5155.06478669], - [-4786.81220198], - [-4599.90297835], - [-4592.87774932], - [-4592.87774932], - [-4608.41364442], - [-4693.59686634], - [-4727.01800377], - [-4727.01800377], - [-4815.57778266], - [-4921.78186239], - [-4949.07870135], - [-4949.07870135], - [-4968.86401067], - [-5001.18496031], - [-5015.53022764]]) - input_values:electric_power_in_total |0.0| input kW traj.climb.timeseries.input_values:electric_power_in_total - val: - array([[0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.]]) - input_values:altitude_rate |37.26779962| input ft/s traj.climb.timeseries.input_values:altitude_rate - val: - array([[8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333]]) - input_values:throttle |2.27639903| input unitless traj.climb.timeseries.input_values:throttle - val: - array([[0.36272519], - [0.34217892], - [0.32721108], - [0.32475961], - [0.32475961], - [0.32505412], - [0.34982841], - [0.36112935], - [0.36112935], - [0.40082952], - [0.46816406], - [0.49426945], - [0.49426945], - [0.54853485], - [0.63668329], - [0.6672203 ], - [0.6672203 ], - [0.70468433], - [0.75486115], - [0.77136189]]) - input_values:velocity |692.82893696| input m/s traj.climb.timeseries.input_values:velocity - val: - array([[ 68.0573727 ], - [ 75.09079389], - [ 84.68111157], - [ 87.6885407 ], - [ 87.6885407 ], - [101.57433671], - [120.24308114], - [126.03147998], - [126.03147998], - [141.4927097 ], - [162.09903383], - [168.44210711], - [168.44210711], - [180.41248453], - [196.38747815], - [201.31036538], - [201.31036538], - [206.75274127], - [214.12710705], - [216.42809923]]) - input_values:altitude |87358.6369253| input ft traj.climb.timeseries.input_values:altitude - val: - array([[ 0. ], - [ 1334.67757163], - [ 3176.26020893], - [ 3759.11481713], - [ 3759.11481713], - [ 6484.90577713], - [10245.94096014], - [11436.29573631], - [11436.29573631], - [14676.99149614], - [19148.49020934], - [20563.70426369], - [20563.70426369], - [23289.4952237 ], - [27050.5304067 ], - [28240.88518287], - [28240.88518287], - [29575.5627545 ], - [31417.1453918 ], - [32000. ]]) - input_values:time |10483.03643104| input s traj.climb.timeseries.input_values:time - val: - array([[ 0. ], - [ 160.1613086 ], - [ 381.15122507], - [ 451.09377806], - [ 451.09377806], - [ 778.18869326], - [1229.51291522], - [1372.35548836], - [1372.35548836], - [1761.23897954], - [2297.81882512], - [2467.64451164], - [2467.64451164], - [2794.73942684], - [3246.0636488 ], - [3388.90622194], - [3388.90622194], - [3549.06753054], - [3770.05744702], - [3840. ]]) - input_values:time_phase |10483.03643104| input s traj.climb.timeseries.input_values:time_phase - val: - array([[ 0. ], - [ 160.1613086 ], - [ 381.15122507], - [ 451.09377806], - [ 451.09377806], - [ 778.18869326], - [1229.51291522], - [1372.35548836], - [1372.35548836], - [1761.23897954], - [2297.81882512], - [2467.64451164], - [2467.64451164], - [2794.73942684], - [3246.0636488 ], - [3388.90622194], - [3388.90622194], - [3549.06753054], - [3770.05744702], - [3840. ]]) - input_values:mach_rate |0.0006056| input unitless/s traj.climb.timeseries.input_values:mach_rate - val: - array([[0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542]]) - input_values:mass |260111.77531753| input kg traj.climb.timeseries.input_values:mass - val: - array([[59377.14578909], - [59253.2001355 ], - [59099.30211114], - [59053.23865024], - [59053.23865024], - [58849.04195155], - [58583.91501949], - [58501.0166128 ], - [58501.0166128 ], - [58275.75043339], - [57961.72209353], - [57860.85002365], - [57860.85002365], - [57664.1758047 ], - [57387.22609857], - [57298.3740442 ], - [57298.3740442 ], - [57198.30721763], - [57059.51640479], - [57015.39290411]]) - input_values:distance |1394968.35548323| input m traj.climb.timeseries.input_values:distance - val: - array([[1.00000000e+00], - [1.14581007e+04], - [2.91056018e+04], - [3.51310537e+04], - [3.51310537e+04], - [6.60814858e+04], - [1.16145544e+05], - [1.33731831e+05], - [1.33731831e+05], - [1.85754660e+05], - [2.67231556e+05], - [2.95296884e+05], - [2.95296884e+05], - [3.52354108e+05], - [4.37399478e+05], - [4.65802163e+05], - [4.65802163e+05], - [4.98478689e+05], - [5.44983286e+05], - [5.60039406e+05]]) - mach |2.22189137| output unitless traj.climb.timeseries.mach - val: - array([[0.2 ], - [0.22168851], - [0.25161423], - [0.26108562], - [0.26108562], - [0.30537972], - [0.36649654], - [0.38583981], - [0.38583981], - [0.43850111], - [0.51116297], - [0.53416019], - [0.53416019], - [0.5784543 ], - [0.63957112], - [0.65891438], - [0.65891438], - [0.68060289], - [0.71052861], - [0.72 ]]) - thrust_net_total |48414.84148193| output lbf traj.climb.timeseries.thrust_net_total - val: - array([[17065.14600291], - [14901.36313434], - [12883.93606283], - [12411.00826626], - [12411.00826626], - [10894.82257897], - [ 9936.49032117], - [ 9784.47407829], - [ 9784.47407829], - [ 9495.02141762], - [ 9279.49270363], - [ 9258.26508964], - [ 9258.26508964], - [ 9251.79803565], - [ 9267.2700987 ], - [ 9266.89227346], - [ 9266.89227346], - [ 9262.99894433], - [ 9249.04306736], - [ 9246.08907684]]) - drag |33892.0364495| output lbf traj.climb.timeseries.drag - val: - array([[11564.50483341], - [ 9871.67791123], - [ 8370.34573461], - [ 8036.10654684], - [ 8036.10654684], - [ 7054.61101592], - [ 6623.09446616], - [ 6603.46879734], - [ 6603.46879734], - [ 6616.2404343 ], - [ 6717.63240841], - [ 6779.26512122], - [ 6779.26512122], - [ 6914.47922116], - [ 7094.49982183], - [ 7140.13058017], - [ 7140.13058017], - [ 7184.86180019], - [ 7233.36753127], - [ 7249.15838542]]) - specific_energy_rate_excess |85.6710443| output m/s traj.climb.timeseries.specific_energy_rate_excess - val: - array([[21.51016857], - [22.8290196 ], - [23.98268911], - [24.23120792], - [24.23120792], - [24.69112511], - [23.80603311], - [23.36433121], - [23.36433121], - [21.53011554], - [18.57127243], - [17.49597197], - [17.49597197], - [15.43926748], - [12.42846021], - [11.47669154], - [11.47669154], - [10.35933753], - [ 8.98152426], - [ 8.55190129]]) - fuel_flow_rate_negative_total |22417.76903736| output lbm/h traj.climb.timeseries.fuel_flow_rate_negative_total - val: - array([[-6479.1239817 ], - [-5837.97587703], - [-5279.20693967], - [-5155.06478669], - [-5155.06478669], - [-4786.81220198], - [-4599.90297835], - [-4592.87774932], - [-4592.87774932], - [-4608.41364442], - [-4693.59686634], - [-4727.01800377], - [-4727.01800377], - [-4815.57778266], - [-4921.78186239], - [-4949.07870135], - [-4949.07870135], - [-4968.86401067], - [-5001.18496031], - [-5015.53022764]]) - electric_power_in_total |0.0| output kW traj.climb.timeseries.electric_power_in_total - val: - array([[0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.]]) - altitude_rate |37.26779962| output ft/s traj.climb.timeseries.altitude_rate - val: - array([[8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333]]) - throttle |2.27639903| output unitless traj.climb.timeseries.throttle - val: - array([[0.36272519], - [0.34217892], - [0.32721108], - [0.32475961], - [0.32475961], - [0.32505412], - [0.34982841], - [0.36112935], - [0.36112935], - [0.40082952], - [0.46816406], - [0.49426945], - [0.49426945], - [0.54853485], - [0.63668329], - [0.6672203 ], - [0.6672203 ], - [0.70468433], - [0.75486115], - [0.77136189]]) - velocity |692.82893696| output m/s traj.climb.timeseries.velocity - val: - array([[ 68.0573727 ], - [ 75.09079389], - [ 84.68111157], - [ 87.6885407 ], - [ 87.6885407 ], - [101.57433671], - [120.24308114], - [126.03147998], - [126.03147998], - [141.4927097 ], - [162.09903383], - [168.44210711], - [168.44210711], - [180.41248453], - [196.38747815], - [201.31036538], - [201.31036538], - [206.75274127], - [214.12710705], - [216.42809923]]) - altitude |87358.6369253| output ft traj.climb.timeseries.altitude - val: - array([[ 0. ], - [ 1334.67757163], - [ 3176.26020893], - [ 3759.11481713], - [ 3759.11481713], - [ 6484.90577713], - [10245.94096014], - [11436.29573631], - [11436.29573631], - [14676.99149614], - [19148.49020934], - [20563.70426369], - [20563.70426369], - [23289.4952237 ], - [27050.5304067 ], - [28240.88518287], - [28240.88518287], - [29575.5627545 ], - [31417.1453918 ], - [32000. ]]) - time |10483.03643104| output s traj.climb.timeseries.time - val: - array([[ 0. ], - [ 160.1613086 ], - [ 381.15122507], - [ 451.09377806], - [ 451.09377806], - [ 778.18869326], - [1229.51291522], - [1372.35548836], - [1372.35548836], - [1761.23897954], - [2297.81882512], - [2467.64451164], - [2467.64451164], - [2794.73942684], - [3246.0636488 ], - [3388.90622194], - [3388.90622194], - [3549.06753054], - [3770.05744702], - [3840. ]]) - time_phase |10483.03643104| output s traj.climb.timeseries.time_phase - val: - array([[ 0. ], - [ 160.1613086 ], - [ 381.15122507], - [ 451.09377806], - [ 451.09377806], - [ 778.18869326], - [1229.51291522], - [1372.35548836], - [1372.35548836], - [1761.23897954], - [2297.81882512], - [2467.64451164], - [2467.64451164], - [2794.73942684], - [3246.0636488 ], - [3388.90622194], - [3388.90622194], - [3549.06753054], - [3770.05744702], - [3840. ]]) - mach_rate |0.0006056| output unitless/s traj.climb.timeseries.mach_rate - val: - array([[0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542]]) - mass |260111.77531753| output kg traj.climb.timeseries.mass - val: - array([[59377.14578909], - [59253.2001355 ], - [59099.30211114], - [59053.23865024], - [59053.23865024], - [58849.04195155], - [58583.91501949], - [58501.0166128 ], - [58501.0166128 ], - [58275.75043339], - [57961.72209353], - [57860.85002365], - [57860.85002365], - [57664.1758047 ], - [57387.22609857], - [57298.3740442 ], - [57298.3740442 ], - [57198.30721763], - [57059.51640479], - [57015.39290411]]) - distance |1394968.35548323| output m traj.climb.timeseries.distance - val: - array([[1.00000000e+00], - [1.14581007e+04], - [2.91056018e+04], - [3.51310537e+04], - [3.51310537e+04], - [6.60814858e+04], - [1.16145544e+05], - [1.33731831e+05], - [1.33731831e+05], - [1.85754660e+05], - [2.67231556e+05], - [2.95296884e+05], - [2.95296884e+05], - [3.52354108e+05], - [4.37399478e+05], - [4.65802163e+05], - [4.65802163e+05], - [4.98478689e+05], - [5.44983286e+05], - [5.60039406e+05]]) - mission_bus_variables - dt_dstau |1817.71161504| input s traj.climb.mission_bus_variables.dt_dstau - val: - array([225.54688903, 225.54688903, 225.54688903, 225.54688903, - 460.63085515, 460.63085515, 460.63085515, 460.63085515, - 547.64451164, 547.64451164, 547.64451164, 547.64451164, - 460.63085515, 460.63085515, 460.63085515, 460.63085515, - 225.54688903, 225.54688903, 225.54688903, 225.54688903]) - input_values:mach |2.22189137| input unitless traj.climb.mission_bus_variables.input_values:mach - val: - array([[0.2 ], - [0.22168851], - [0.25161423], - [0.26108562], - [0.26108562], - [0.30537972], - [0.36649654], - [0.38583981], - [0.38583981], - [0.43850111], - [0.51116297], - [0.53416019], - [0.53416019], - [0.5784543 ], - [0.63957112], - [0.65891438], - [0.65891438], - [0.68060289], - [0.71052861], - [0.72 ]]) - input_values:thrust_net_total |48414.84148193| input lbf traj.climb.mission_bus_variables.input_values:thrust_net_total - val: - array([[17065.14600291], - [14901.36313434], - [12883.93606283], - [12411.00826626], - [12411.00826626], - [10894.82257897], - [ 9936.49032117], - [ 9784.47407829], - [ 9784.47407829], - [ 9495.02141762], - [ 9279.49270363], - [ 9258.26508964], - [ 9258.26508964], - [ 9251.79803565], - [ 9267.2700987 ], - [ 9266.89227346], - [ 9266.89227346], - [ 9262.99894433], - [ 9249.04306736], - [ 9246.08907684]]) - input_values:drag |33892.0364495| input lbf traj.climb.mission_bus_variables.input_values:drag - val: - array([[11564.50483341], - [ 9871.67791123], - [ 8370.34573461], - [ 8036.10654684], - [ 8036.10654684], - [ 7054.61101592], - [ 6623.09446616], - [ 6603.46879734], - [ 6603.46879734], - [ 6616.2404343 ], - [ 6717.63240841], - [ 6779.26512122], - [ 6779.26512122], - [ 6914.47922116], - [ 7094.49982183], - [ 7140.13058017], - [ 7140.13058017], - [ 7184.86180019], - [ 7233.36753127], - [ 7249.15838542]]) - input_values:specific_energy_rate_excess |85.6710443| input m/s traj.climb.mission_bus_variables.input_values:specific_energy_rate_excess - val: - array([[21.51016857], - [22.8290196 ], - [23.98268911], - [24.23120792], - [24.23120792], - [24.69112511], - [23.80603311], - [23.36433121], - [23.36433121], - [21.53011554], - [18.57127243], - [17.49597197], - [17.49597197], - [15.43926748], - [12.42846021], - [11.47669154], - [11.47669154], - [10.35933753], - [ 8.98152426], - [ 8.55190129]]) - input_values:fuel_flow_rate_negative_total |22417.76903736| input lbm/h traj.climb.mission_bus_variables.input_values:fuel_flow_rate_negative_total - val: - array([[-6479.1239817 ], - [-5837.97587703], - [-5279.20693967], - [-5155.06478669], - [-5155.06478669], - [-4786.81220198], - [-4599.90297835], - [-4592.87774932], - [-4592.87774932], - [-4608.41364442], - [-4693.59686634], - [-4727.01800377], - [-4727.01800377], - [-4815.57778266], - [-4921.78186239], - [-4949.07870135], - [-4949.07870135], - [-4968.86401067], - [-5001.18496031], - [-5015.53022764]]) - input_values:electric_power_in_total |0.0| input kW traj.climb.mission_bus_variables.input_values:electric_power_in_total - val: - array([[0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.]]) - input_values:altitude_rate |37.26779962| input ft/s traj.climb.mission_bus_variables.input_values:altitude_rate - val: - array([[8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333]]) - input_values:throttle |2.27639903| input unitless traj.climb.mission_bus_variables.input_values:throttle - val: - array([[0.36272519], - [0.34217892], - [0.32721108], - [0.32475961], - [0.32475961], - [0.32505412], - [0.34982841], - [0.36112935], - [0.36112935], - [0.40082952], - [0.46816406], - [0.49426945], - [0.49426945], - [0.54853485], - [0.63668329], - [0.6672203 ], - [0.6672203 ], - [0.70468433], - [0.75486115], - [0.77136189]]) - input_values:velocity |692.82893696| input m/s traj.climb.mission_bus_variables.input_values:velocity - val: - array([[ 68.0573727 ], - [ 75.09079389], - [ 84.68111157], - [ 87.6885407 ], - [ 87.6885407 ], - [101.57433671], - [120.24308114], - [126.03147998], - [126.03147998], - [141.4927097 ], - [162.09903383], - [168.44210711], - [168.44210711], - [180.41248453], - [196.38747815], - [201.31036538], - [201.31036538], - [206.75274127], - [214.12710705], - [216.42809923]]) - input_values:altitude |87358.6369253| input ft traj.climb.mission_bus_variables.input_values:altitude - val: - array([[ 0. ], - [ 1334.67757163], - [ 3176.26020893], - [ 3759.11481713], - [ 3759.11481713], - [ 6484.90577713], - [10245.94096014], - [11436.29573631], - [11436.29573631], - [14676.99149614], - [19148.49020934], - [20563.70426369], - [20563.70426369], - [23289.4952237 ], - [27050.5304067 ], - [28240.88518287], - [28240.88518287], - [29575.5627545 ], - [31417.1453918 ], - [32000. ]]) - input_values:time |10483.03643104| input s traj.climb.mission_bus_variables.input_values:time - val: - array([[ 0. ], - [ 160.1613086 ], - [ 381.15122507], - [ 451.09377806], - [ 451.09377806], - [ 778.18869326], - [1229.51291522], - [1372.35548836], - [1372.35548836], - [1761.23897954], - [2297.81882512], - [2467.64451164], - [2467.64451164], - [2794.73942684], - [3246.0636488 ], - [3388.90622194], - [3388.90622194], - [3549.06753054], - [3770.05744702], - [3840. ]]) - input_values:time_phase |10483.03643104| input s traj.climb.mission_bus_variables.input_values:time_phase - val: - array([[ 0. ], - [ 160.1613086 ], - [ 381.15122507], - [ 451.09377806], - [ 451.09377806], - [ 778.18869326], - [1229.51291522], - [1372.35548836], - [1372.35548836], - [1761.23897954], - [2297.81882512], - [2467.64451164], - [2467.64451164], - [2794.73942684], - [3246.0636488 ], - [3388.90622194], - [3388.90622194], - [3549.06753054], - [3770.05744702], - [3840. ]]) - input_values:mach_rate |0.0006056| input unitless/s traj.climb.mission_bus_variables.input_values:mach_rate - val: - array([[0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542]]) - input_values:mass |260111.77531753| input kg traj.climb.mission_bus_variables.input_values:mass - val: - array([[59377.14578909], - [59253.2001355 ], - [59099.30211114], - [59053.23865024], - [59053.23865024], - [58849.04195155], - [58583.91501949], - [58501.0166128 ], - [58501.0166128 ], - [58275.75043339], - [57961.72209353], - [57860.85002365], - [57860.85002365], - [57664.1758047 ], - [57387.22609857], - [57298.3740442 ], - [57298.3740442 ], - [57198.30721763], - [57059.51640479], - [57015.39290411]]) - input_values:distance |1394968.35548323| input m traj.climb.mission_bus_variables.input_values:distance - val: - array([[1.00000000e+00], - [1.14581007e+04], - [2.91056018e+04], - [3.51310537e+04], - [3.51310537e+04], - [6.60814858e+04], - [1.16145544e+05], - [1.33731831e+05], - [1.33731831e+05], - [1.85754660e+05], - [2.67231556e+05], - [2.95296884e+05], - [2.95296884e+05], - [3.52354108e+05], - [4.37399478e+05], - [4.65802163e+05], - [4.65802163e+05], - [4.98478689e+05], - [5.44983286e+05], - [5.60039406e+05]]) - mach |1.87763681| output unitless traj.climb.mission_bus_variables.mach - val: - array([[0.2 ], - [0.252], - [0.304], - [0.304], - [0.356], - [0.408], - [0.408], - [0.46 ], - [0.512], - [0.512], - [0.564], - [0.616], - [0.616], - [0.668], - [0.72 ]]) - thrust_net_total |40887.66800453| output lbf traj.climb.mission_bus_variables.thrust_net_total - val: - array([[17065.14600291], - [12863.43667775], - [10929.29459826], - [10929.29459826], - [10039.41837459], - [ 9649.57306885], - [ 9649.57306885], - [ 9408.40094249], - [ 9278.31316437], - [ 9278.31316437], - [ 9250.40031304], - [ 9262.11775109], - [ 9262.11775109], - [ 9266.65324415], - [ 9246.08907684]]) - drag |28622.67791387| output lbf traj.climb.mission_bus_variables.drag - val: - array([[11564.50483341], - [ 8355.69107042], - [ 7074.68337595], - [ 7074.68337595], - [ 6648.6263692 ], - [ 6604.61391842], - [ 6604.61391842], - [ 6633.79494003], - [ 6719.58769169], - [ 6719.58769169], - [ 6869.15471209], - [ 7029.61212988], - [ 7029.61212988], - [ 7160.62450818], - [ 7249.15838542]]) - specific_energy_rate_excess |76.1474751| output m/s traj.climb.mission_bus_variables.specific_energy_rate_excess - val: - array([[21.51016857], - [23.99370022], - [24.69468355], - [24.69468355], - [24.02998969], - [22.61667701], - [22.61667701], - [20.71522371], - [18.53345324], - [18.53345324], - [16.12920993], - [13.59739582], - [13.59739582], - [10.98938407], - [ 8.55190129]]) - fuel_flow_rate_negative_total |19107.36560966| output lbm/h traj.climb.mission_bus_variables.fuel_flow_rate_negative_total - val: - array([[-6479.1239817 ], - [-5273.77681527], - [-4794.84549506], - [-4794.84549506], - [-4612.12691124], - [-4592.77340524], - [-4592.77340524], - [-4628.15205094], - [-4694.79617454], - [-4694.79617454], - [-4787.33714298], - [-4883.93359025], - [-4883.93359025], - [-4957.61495291], - [-5015.53022764]]) - electric_power_in_total |0.0| output kW traj.climb.mission_bus_variables.electric_power_in_total - val: - array([[0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.]]) - altitude_rate |32.27486122| output ft/s traj.climb.mission_bus_variables.altitude_rate - val: - array([[8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333], - [8.33333333]]) - throttle |1.87968944| output unitless traj.climb.mission_bus_variables.throttle - val: - array([[0.36272519], - [0.32709417], - [0.32477473], - [0.32477473], - [0.34419414], - [0.37727971], - [0.37727971], - [0.41879527], - [0.46906644], - [0.46906644], - [0.52984264], - [0.60107542], - [0.60107542], - [0.68323756], - [0.77136189]]) - velocity |589.5380269| output m/s traj.climb.mission_bus_variables.velocity - val: - array([[ 68.0573727 ], - [ 84.80386775], - [101.14628752], - [101.14628752], - [117.07770966], - [132.59095385], - [132.59095385], - [147.67822143], - [162.33142405], - [162.33142405], - [176.54212679], - [190.30161455], - [190.30161455], - [203.60018377], - [216.42809923]]) - altitude |71911.05617358| output ft traj.climb.mission_bus_variables.altitude - val: - array([[ 0.], - [ 3200.], - [ 6400.], - [ 6400.], - [ 9600.], - [12800.], - [12800.], - [16000.], - [19200.], - [19200.], - [22400.], - [25600.], - [25600.], - [28800.], - [32000.]]) - time |8629.32674083| output s traj.climb.mission_bus_variables.time - val: - array([[ 0.], - [ 384.], - [ 768.], - [ 768.], - [1152.], - [1536.], - [1536.], - [1920.], - [2304.], - [2304.], - [2688.], - [3072.], - [3072.], - [3456.], - [3840.]]) - time_phase |8629.32674083| output s traj.climb.mission_bus_variables.time_phase - val: - array([[ 0.], - [ 384.], - [ 768.], - [ 768.], - [1152.], - [1536.], - [1536.], - [1920.], - [2304.], - [2304.], - [2688.], - [3072.], - [3072.], - [3456.], - [3840.]]) - mach_rate |0.00052447| output unitless/s traj.climb.mission_bus_variables.mach_rate - val: - array([[0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542], - [0.00013542]]) - mass |225349.72849892| output kg traj.climb.mission_bus_variables.mass - val: - array([[59377.14578909], - [59097.40804654], - [58855.1924873 ], - [58855.1924873 ], - [58628.85825225], - [58406.30989701], - [58406.30989701], - [58183.40151086], - [57958.06610101], - [57958.06610101], - [57728.75425743], - [57494.74886721], - [57494.74886721], - [57256.50306513], - [57015.39290411]]) - distance |1112101.93489637| output m traj.climb.mission_bus_variables.distance - val: - array([[1.00000000e+00], - [2.93469056e+04], - [6.50490806e+04], - [6.50490806e+04], - [1.06949844e+05], - [1.54889941e+05], - [1.54889941e+05], - [2.08706570e+05], - [2.68234114e+05], - [2.68234114e+05], - [3.33305139e+05], - [4.03746843e+05], - [4.03746843e+05], - [4.79384667e+05], - [5.60039406e+05]]) - collocation_constraint - dt_dstau |1574.18443538| input s traj.climb.collocation_constraint.dt_dstau - val: - array([225.54688903, 225.54688903, 225.54688903, 460.63085515, - 460.63085515, 460.63085515, 547.64451164, 547.64451164, - 547.64451164, 460.63085515, 460.63085515, 460.63085515, - 225.54688903, 225.54688903, 225.54688903]) - f_approx:mass |2.46548436| input kg/s traj.climb.collocation_constraint.f_approx:mass - val: - array([[-0.81635589], - [-0.73557259], - [-0.66516889], - [-0.64952724], - [-0.60312819], - [-0.57957803], - [-0.57869286], - [-0.58065035], - [-0.59138326], - [-0.59559425], - [-0.60675259], - [-0.62013408], - [-0.62357343], - [-0.62606633], - [-0.63013871]]) - f_computed:mass |2.46548436| input kg/s traj.climb.collocation_constraint.f_computed:mass - val: - array([[-0.81635589], - [-0.73557259], - [-0.66516889], - [-0.64952724], - [-0.60312819], - [-0.57957803], - [-0.57869286], - [-0.58065035], - [-0.59138326], - [-0.59559425], - [-0.60675259], - [-0.62013408], - [-0.62357343], - [-0.62606633], - [-0.63013871]]) - f_approx:distance |583.61135954| input m/s traj.climb.collocation_constraint.f_approx:distance - val: - array([[ 68.00995794], - [ 75.04782293], - [ 84.6430095 ], - [ 87.65174596], - [101.54257372], - [120.21625082], - [126.00588218], - [141.46990952], - [162.07913243], - [168.42295523], - [180.39460351], - [196.37105177], - [201.29434073], - [206.73713847], - [214.11204164]]) - f_computed:distance |583.61135954| input m/s traj.climb.collocation_constraint.f_computed:distance - val: - array([[ 68.00995794], - [ 75.04782293], - [ 84.6430095 ], - [ 87.65174596], - [101.54257372], - [120.21625082], - [126.00588218], - [141.46990952], - [162.07913243], - [168.42295523], - [180.39460351], - [196.37105177], - [201.29434073], - [206.73713847], - [214.11204164]]) - defects:mass |0.0| output kg traj.climb.collocation_constraint.defects:mass - val: - array([[ 5.27357878e-11], - [ 5.75936903e-13], - [-7.51222048e-12], - [ 2.42405013e-11], - [-5.42087160e-12], - [ 1.22736715e-12], - [-1.33761660e-12], - [-7.96489885e-12], - [ 1.25249555e-11], - [-1.68251581e-11], - [ 2.10698028e-11], - [-9.30753426e-12], - [-4.59747893e-11], - [ 1.18693084e-11], - [-7.61238342e-12]]) - defects:distance |0.0| output m traj.climb.collocation_constraint.defects:distance - val: - array([[-6.41042814e-12], - [ 0.00000000e+00], - [-6.41042814e-12], - [ 0.00000000e+00], - [ 6.54595816e-12], - [ 0.00000000e+00], - [ 2.33474898e-11], - [-1.55649932e-11], - [-1.86779918e-10], - [ 5.23676653e-11], - [ 1.70194912e-10], - [-1.57102996e-10], - [-2.69237982e-10], - [-1.02566850e-10], - [ 6.41042814e-12]]) - cruise - param_comp - t_initial [3840.] input s traj.cruise.t_initial - t_duration [10170.] input s traj.cruise.t_duration - parameters:aircraft:design:base_area [0.] input ft**2 traj.cruise.parameters:aircraft:design:base_area - parameters:aircraft:design:lift_dependent_drag_coeff_factor [0.90983938] input unitless traj.cruise.parameters:aircraft:design:lift_dependent_drag_coeff_factor - parameters:aircraft:design:subsonic_drag_coeff_factor [1.] input unitless traj.cruise.parameters:aircraft:design:subsonic_drag_coeff_factor - parameters:aircraft:design:supersonic_drag_coeff_factor [1.] input unitless traj.cruise.parameters:aircraft:design:supersonic_drag_coeff_factor - parameters:aircraft:design:zero_lift_drag_coeff_factor [0.93089003] input unitless traj.cruise.parameters:aircraft:design:zero_lift_drag_coeff_factor - parameters:aircraft:fuselage:characteristic_length [128.] input ft traj.cruise.parameters:aircraft:fuselage:characteristic_length - parameters:aircraft:fuselage:cross_section [127.67628894] input ft**2 traj.cruise.parameters:aircraft:fuselage:cross_section - parameters:aircraft:fuselage:diameter_to_wing_span [0.10826471] input unitless traj.cruise.parameters:aircraft:fuselage:diameter_to_wing_span - parameters:aircraft:fuselage:fineness [10.03921569] input unitless traj.cruise.parameters:aircraft:fuselage:fineness - parameters:aircraft:fuselage:laminar_flow_lower [0.] input unitless traj.cruise.parameters:aircraft:fuselage:laminar_flow_lower - parameters:aircraft:fuselage:laminar_flow_upper [0.] input unitless traj.cruise.parameters:aircraft:fuselage:laminar_flow_upper - parameters:aircraft:fuselage:length_to_diameter [10.03921569] input unitless traj.cruise.parameters:aircraft:fuselage:length_to_diameter - parameters:aircraft:fuselage:wetted_area [4158.62] input ft**2 traj.cruise.parameters:aircraft:fuselage:wetted_area - parameters:aircraft:horizontal_tail:characteristic_length [7.69198717] input ft traj.cruise.parameters:aircraft:horizontal_tail:characteristic_length - parameters:aircraft:horizontal_tail:fineness [0.125] input unitless traj.cruise.parameters:aircraft:horizontal_tail:fineness - parameters:aircraft:horizontal_tail:laminar_flow_lower [0.] input unitless traj.cruise.parameters:aircraft:horizontal_tail:laminar_flow_lower - parameters:aircraft:horizontal_tail:laminar_flow_upper [0.] input unitless traj.cruise.parameters:aircraft:horizontal_tail:laminar_flow_upper - parameters:aircraft:horizontal_tail:wetted_area [592.65] input ft**2 traj.cruise.parameters:aircraft:horizontal_tail:wetted_area - parameters:aircraft:vertical_tail:characteristic_length [12.73914103] input ft traj.cruise.parameters:aircraft:vertical_tail:characteristic_length - parameters:aircraft:vertical_tail:fineness [0.1195] input unitless traj.cruise.parameters:aircraft:vertical_tail:fineness - parameters:aircraft:vertical_tail:laminar_flow_lower [0.] input unitless traj.cruise.parameters:aircraft:vertical_tail:laminar_flow_lower - parameters:aircraft:vertical_tail:laminar_flow_upper [0.] input unitless traj.cruise.parameters:aircraft:vertical_tail:laminar_flow_upper - parameters:aircraft:vertical_tail:wetted_area [581.13] input ft**2 traj.cruise.parameters:aircraft:vertical_tail:wetted_area - parameters:aircraft:wing:area [1370.] input ft**2 traj.cruise.parameters:aircraft:wing:area - parameters:aircraft:wing:aspect_ratio [11.22091] input unitless traj.cruise.parameters:aircraft:wing:aspect_ratio - parameters:aircraft:wing:characteristic_length [10.49530819] input ft traj.cruise.parameters:aircraft:wing:characteristic_length - parameters:aircraft:wing:fineness [0.13] input unitless traj.cruise.parameters:aircraft:wing:fineness - parameters:aircraft:wing:laminar_flow_lower [0.] input unitless traj.cruise.parameters:aircraft:wing:laminar_flow_lower - parameters:aircraft:wing:laminar_flow_upper [0.] input unitless traj.cruise.parameters:aircraft:wing:laminar_flow_upper - parameters:aircraft:wing:max_camber_at_70_semispan [0.] input unitless traj.cruise.parameters:aircraft:wing:max_camber_at_70_semispan - parameters:aircraft:wing:span_efficiency_factor [1.] input unitless traj.cruise.parameters:aircraft:wing:span_efficiency_factor - parameters:aircraft:wing:sweep [25.] input deg traj.cruise.parameters:aircraft:wing:sweep - parameters:aircraft:wing:taper_ratio [0.278] input unitless traj.cruise.parameters:aircraft:wing:taper_ratio - parameters:aircraft:wing:thickness_to_chord [0.13] input unitless traj.cruise.parameters:aircraft:wing:thickness_to_chord - parameters:aircraft:wing:wetted_area [2396.56] input ft**2 traj.cruise.parameters:aircraft:wing:wetted_area - parameters:mission:design:lift_coefficient [0.56736557] input unitless traj.cruise.parameters:mission:design:lift_coefficient - parameters:mission:design:mach [0.80017085] input unitless traj.cruise.parameters:mission:design:mach - parameters:aircraft:nacelle:characteristic_length [12.3] input ft traj.cruise.parameters:aircraft:nacelle:characteristic_length - parameters:aircraft:nacelle:fineness [1.54911839] input unitless traj.cruise.parameters:aircraft:nacelle:fineness - parameters:aircraft:nacelle:laminar_flow_lower [0.] input unitless traj.cruise.parameters:aircraft:nacelle:laminar_flow_lower - parameters:aircraft:nacelle:laminar_flow_upper [0.] input unitless traj.cruise.parameters:aircraft:nacelle:laminar_flow_upper - parameters:aircraft:nacelle:wetted_area [273.4536] input ft**2 traj.cruise.parameters:aircraft:nacelle:wetted_area - parameters:aircraft:engine:scale_factor [1.] input unitless traj.cruise.parameters:aircraft:engine:scale_factor - t_initial_val [3840.] output s traj.cruise.t_initial_val - t_duration_val [10170.] output s traj.cruise.t_duration_val - parameter_vals:aircraft:design:base_area [[0.]] output ft**2 traj.cruise.parameter_vals:aircraft:design:base_area - parameter_vals:aircraft:design:lift_dependent_drag_coeff_factor [[0.90983938]] output unitless traj.cruise.parameter_vals:aircraft:design:lift_dependent_drag_coeff_factor - parameter_vals:aircraft:design:subsonic_drag_coeff_factor [[1.]] output unitless traj.cruise.parameter_vals:aircraft:design:subsonic_drag_coeff_factor - parameter_vals:aircraft:design:supersonic_drag_coeff_factor [[1.]] output unitless traj.cruise.parameter_vals:aircraft:design:supersonic_drag_coeff_factor - parameter_vals:aircraft:design:zero_lift_drag_coeff_factor [[0.93089003]] output unitless traj.cruise.parameter_vals:aircraft:design:zero_lift_drag_coeff_factor - parameter_vals:aircraft:fuselage:characteristic_length [[128.]] output ft traj.cruise.parameter_vals:aircraft:fuselage:characteristic_length - parameter_vals:aircraft:fuselage:cross_section [[127.67628894]] output ft**2 traj.cruise.parameter_vals:aircraft:fuselage:cross_section - parameter_vals:aircraft:fuselage:diameter_to_wing_span [[0.10826471]] output unitless traj.cruise.parameter_vals:aircraft:fuselage:diameter_to_wing_span - parameter_vals:aircraft:fuselage:fineness [[10.03921569]] output unitless traj.cruise.parameter_vals:aircraft:fuselage:fineness - parameter_vals:aircraft:fuselage:laminar_flow_lower [[0.]] output unitless traj.cruise.parameter_vals:aircraft:fuselage:laminar_flow_lower - parameter_vals:aircraft:fuselage:laminar_flow_upper [[0.]] output unitless traj.cruise.parameter_vals:aircraft:fuselage:laminar_flow_upper - parameter_vals:aircraft:fuselage:length_to_diameter [[10.03921569]] output unitless traj.cruise.parameter_vals:aircraft:fuselage:length_to_diameter - parameter_vals:aircraft:fuselage:wetted_area [[4158.62]] output ft**2 traj.cruise.parameter_vals:aircraft:fuselage:wetted_area - parameter_vals:aircraft:horizontal_tail:characteristic_length [[7.69198717]] output ft traj.cruise.parameter_vals:aircraft:horizontal_tail:characteristic_length - parameter_vals:aircraft:horizontal_tail:fineness [[0.125]] output unitless traj.cruise.parameter_vals:aircraft:horizontal_tail:fineness - parameter_vals:aircraft:horizontal_tail:laminar_flow_lower [[0.]] output unitless traj.cruise.parameter_vals:aircraft:horizontal_tail:laminar_flow_lower - parameter_vals:aircraft:horizontal_tail:laminar_flow_upper [[0.]] output unitless traj.cruise.parameter_vals:aircraft:horizontal_tail:laminar_flow_upper - parameter_vals:aircraft:horizontal_tail:wetted_area [[592.65]] output ft**2 traj.cruise.parameter_vals:aircraft:horizontal_tail:wetted_area - parameter_vals:aircraft:vertical_tail:characteristic_length [[12.73914103]] output ft traj.cruise.parameter_vals:aircraft:vertical_tail:characteristic_length - parameter_vals:aircraft:vertical_tail:fineness [[0.1195]] output unitless traj.cruise.parameter_vals:aircraft:vertical_tail:fineness - parameter_vals:aircraft:vertical_tail:laminar_flow_lower [[0.]] output unitless traj.cruise.parameter_vals:aircraft:vertical_tail:laminar_flow_lower - parameter_vals:aircraft:vertical_tail:laminar_flow_upper [[0.]] output unitless traj.cruise.parameter_vals:aircraft:vertical_tail:laminar_flow_upper - parameter_vals:aircraft:vertical_tail:wetted_area [[581.13]] output ft**2 traj.cruise.parameter_vals:aircraft:vertical_tail:wetted_area - parameter_vals:aircraft:wing:area [[1370.]] output ft**2 traj.cruise.parameter_vals:aircraft:wing:area - parameter_vals:aircraft:wing:aspect_ratio [[11.22091]] output unitless traj.cruise.parameter_vals:aircraft:wing:aspect_ratio - parameter_vals:aircraft:wing:characteristic_length [[10.49530819]] output ft traj.cruise.parameter_vals:aircraft:wing:characteristic_length - parameter_vals:aircraft:wing:fineness [[0.13]] output unitless traj.cruise.parameter_vals:aircraft:wing:fineness - parameter_vals:aircraft:wing:laminar_flow_lower [[0.]] output unitless traj.cruise.parameter_vals:aircraft:wing:laminar_flow_lower - parameter_vals:aircraft:wing:laminar_flow_upper [[0.]] output unitless traj.cruise.parameter_vals:aircraft:wing:laminar_flow_upper - parameter_vals:aircraft:wing:max_camber_at_70_semispan [[0.]] output unitless traj.cruise.parameter_vals:aircraft:wing:max_camber_at_70_semispan - parameter_vals:aircraft:wing:span_efficiency_factor [[1.]] output unitless traj.cruise.parameter_vals:aircraft:wing:span_efficiency_factor - parameter_vals:aircraft:wing:sweep [[25.]] output deg traj.cruise.parameter_vals:aircraft:wing:sweep - parameter_vals:aircraft:wing:taper_ratio [[0.278]] output unitless traj.cruise.parameter_vals:aircraft:wing:taper_ratio - parameter_vals:aircraft:wing:thickness_to_chord [[0.13]] output unitless traj.cruise.parameter_vals:aircraft:wing:thickness_to_chord - parameter_vals:aircraft:wing:wetted_area [[2396.56]] output ft**2 traj.cruise.parameter_vals:aircraft:wing:wetted_area - parameter_vals:mission:design:lift_coefficient [[0.56736557]] output unitless traj.cruise.parameter_vals:mission:design:lift_coefficient - parameter_vals:mission:design:mach [[0.80017085]] output unitless traj.cruise.parameter_vals:mission:design:mach - parameter_vals:aircraft:nacelle:characteristic_length [[12.3]] output ft traj.cruise.parameter_vals:aircraft:nacelle:characteristic_length - parameter_vals:aircraft:nacelle:fineness [[1.54911839]] output unitless traj.cruise.parameter_vals:aircraft:nacelle:fineness - parameter_vals:aircraft:nacelle:laminar_flow_lower [[0.]] output unitless traj.cruise.parameter_vals:aircraft:nacelle:laminar_flow_lower - parameter_vals:aircraft:nacelle:laminar_flow_upper [[0.]] output unitless traj.cruise.parameter_vals:aircraft:nacelle:laminar_flow_upper - parameter_vals:aircraft:nacelle:wetted_area [[273.4536]] output ft**2 traj.cruise.parameter_vals:aircraft:nacelle:wetted_area - parameter_vals:aircraft:engine:scale_factor [[1.]] output unitless traj.cruise.parameter_vals:aircraft:engine:scale_factor - time - t_initial [3840.] input s traj.cruise.t_initial - t_duration [10170.] input s traj.cruise.t_duration - t |43155.65216817| output s traj.cruise.t - val: - array([ 3840. , 4264.17721573, 4849.45519765, 5034.69367782, - 5034.69367782, 5900.9841173 , 7096.28811139, 7474.5977387 , - 7474.5977387 , 8504.53135987, 9925.62954466, 10375.4022613 , - 10375.4022613 , 11241.69270078, 12436.99669488, 12815.30632218, - 12815.30632218, 13239.48353791, 13824.76151983, 14010. ]) - t_phase |27763.66679782| output s traj.cruise.t_phase - val: - array([ 0. , 424.17721573, 1009.45519765, 1194.69367782, - 1194.69367782, 2060.9841173 , 3256.28811139, 3634.5977387 , - 3634.5977387 , 4664.53135987, 6085.62954466, 6535.4022613 , - 6535.4022613 , 7401.69270078, 8596.99669488, 8975.30632218, - 8975.30632218, 9399.48353791, 9984.76151983, 10170. ]) - dt_dstau |4814.09560547| output s traj.cruise.dt_dstau - val: - array([ 597.34683891, 597.34683891, 597.34683891, 597.34683891, - 1219.95203044, 1219.95203044, 1219.95203044, 1219.95203044, - 1450.4022613 , 1450.4022613 , 1450.4022613 , 1450.4022613 , - 1219.95203044, 1219.95203044, 1219.95203044, 1219.95203044, - 597.34683891, 597.34683891, 597.34683891, 597.34683891]) - control_comp - dt_dstau |4814.09560547| input s traj.cruise.control_comp.dt_dstau - val: - array([ 597.34683891, 597.34683891, 597.34683891, 597.34683891, - 1219.95203044, 1219.95203044, 1219.95203044, 1219.95203044, - 1450.4022613 , 1450.4022613 , 1450.4022613 , 1450.4022613 , - 1219.95203044, 1219.95203044, 1219.95203044, 1219.95203044, - 597.34683891, 597.34683891, 597.34683891, 597.34683891]) - t_duration [10170.] input s traj.cruise.control_comp.t_duration - controls:mach |1.44| input unitless traj.cruise.controls:mach - val: - array([[0.72], - [0.72], - [0.72], - [0.72]]) - controls:altitude |66018.17931449| input ft traj.cruise.controls:altitude - val: - array([[32000. ], - [32552.7864045], - [33447.2135955], - [34000. ]]) - control_values:mach |3.21993789| output unitless traj.cruise.control_values:mach - val: - array([[0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72]]) - control_rates:mach_rate |0.0| output unitless/s traj.cruise.control_rates:mach_rate - val: - array([[ 0.00000000e+00], - [ 8.73331779e-20], - [ 4.36665890e-20], - [ 0.00000000e+00], - [ 0.00000000e+00], - [ 3.27499417e-20], - [ 2.18332945e-20], - [ 0.00000000e+00], - [ 0.00000000e+00], - [-4.36665890e-20], - [-6.54998835e-20], - [-4.36665890e-20], - [-4.36665890e-20], - [-4.91249126e-20], - [-2.18332945e-20], - [ 8.73331779e-20], - [ 8.73331779e-20], - [-8.73331779e-20], - [ 0.00000000e+00], - [ 1.74666356e-19]]) - control_rates:mach_rate2 |0.0| output unitless/s**2 traj.cruise.control_rates:mach_rate2 - val: - array([[ 0.00000000e+00], - [-6.86986651e-23], - [ 0.00000000e+00], - [ 0.00000000e+00], - [ 0.00000000e+00], - [-3.43493325e-23], - [-3.43493325e-23], - [ 0.00000000e+00], - [ 0.00000000e+00], - [-8.58733313e-24], - [ 0.00000000e+00], - [ 0.00000000e+00], - [ 0.00000000e+00], - [ 3.43493325e-23], - [ 3.43493325e-23], - [ 3.43493325e-23], - [ 3.43493325e-23], - [ 6.86986651e-23], - [ 1.37397330e-22], - [ 6.86986651e-23]]) - control_boundary_values:mach |1.01823376| output unitless traj.cruise.control_comp.control_boundary_values:mach - val: - array([[0.72], - [0.72]]) - control_boundary_rates:mach_rate |0.0| output unitless/s traj.cruise.control_comp.control_boundary_rates:mach_rate - val: - array([[0.00000000e+00], - [1.74666356e-19]]) - control_boundary_rates:mach_rate2 |0.0| output unitless/s**2 traj.cruise.control_comp.control_boundary_rates:mach_rate2 - val: - array([[0.00000000e+00], - [6.86986651e-23]]) - control_values:altitude |147700.4084954| output ft traj.cruise.control_values:altitude - val: - array([[32000. ], - [32083.41734823], - [32198.51626306], - [32234.94467607], - [32234.94467607], - [32405.30661107], - [32640.37131001], - [32714.76848352], - [32714.76848352], - [32917.31196851], - [33196.78063808], - [33285.23151648], - [33285.23151648], - [33455.59345148], - [33690.65815042], - [33765.05532393], - [33765.05532393], - [33848.47267216], - [33963.57158699], - [34000. ]]) - control_rates:altitude_rate |0.8794761| output ft/s traj.cruise.control_rates:altitude_rate - val: - array([[0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683]]) - control_rates:altitude_rate2 |0.0| output ft/s**2 traj.cruise.control_rates:altitude_rate2 - val: - array([[-4.50223571e-18], - [-4.50223571e-18], - [ 0.00000000e+00], - [ 0.00000000e+00], - [ 0.00000000e+00], - [-2.25111786e-18], - [-2.25111786e-18], - [ 5.62779464e-19], - [ 5.62779464e-19], - [-1.40694866e-19], - [ 5.62779464e-19], - [ 1.12555893e-18], - [ 1.12555893e-18], - [ 1.12555893e-18], - [ 2.25111786e-18], - [ 4.50223571e-18], - [ 4.50223571e-18], - [ 2.25111786e-18], - [ 4.50223571e-18], - [ 4.50223571e-18]]) - control_boundary_values:altitude |46690.47011972| output ft traj.cruise.control_comp.control_boundary_values:altitude - val: - array([[32000.], - [34000.]]) - control_boundary_rates:altitude_rate |0.27811476| output ft/s traj.cruise.control_comp.control_boundary_rates:altitude_rate - val: - array([[0.19665683], - [0.19665683]]) - control_boundary_rates:altitude_rate2 |0.0| output ft/s**2 traj.cruise.control_comp.control_boundary_rates:altitude_rate2 - val: - array([[-4.50223571e-18], - [ 4.50223571e-18]]) - indep_states - initial_states:mass [[57015.39290411]] input kg traj.cruise.initial_states:mass - initial_states:distance [[560039.40638961]] input m traj.cruise.initial_states:distance - states:mass |217826.10552332| output kg traj.cruise.states:mass - val: - array([[57015.39290411], - [56797.93787223], - [56499.27092781], - [56405.0756841 ], - [55966.67143281], - [55367.45066061], - [55179.16707729], - [54669.88811206], - [53975.10803913], - [53757.11559708], - [53339.81352995], - [52769.53817769], - [52590.37433179], - [52390.24374586], - [52115.41253722], - [52028.74471935]]) - states:distance |7389061.26546158| output m traj.cruise.states:distance - val: - array([[ 560039.40638961], - [ 651826.45257603], - [ 778418.59972934], - [ 818471.23138883], - [1005697.02623753], - [1263799.66653641], - [1345432.48793709], - [1567538.74520054], - [1873673.16694925], - [1970484.63129816], - [2156842.41376365], - [2413746.32168934], - [2494999.4935999 ], - [2586072.02583254], - [2711677.86536452], - [2751418.23144865]]) - state_interp - dt_dstau |4169.12909058| input s traj.cruise.state_interp.dt_dstau - val: - array([ 597.34683891, 597.34683891, 597.34683891, 1219.95203044, - 1219.95203044, 1219.95203044, 1450.4022613 , 1450.4022613 , - 1450.4022613 , 1219.95203044, 1219.95203044, 1219.95203044, - 597.34683891, 597.34683891, 597.34683891]) - state_disc:mass |243577.62672176| input kg traj.cruise.state_interp.state_disc:mass - val: - array([[57015.39290411], - [56797.93787223], - [56499.27092781], - [56405.0756841 ], - [56405.0756841 ], - [55966.67143281], - [55367.45066061], - [55179.16707729], - [55179.16707729], - [54669.88811206], - [53975.10803913], - [53757.11559708], - [53757.11559708], - [53339.81352995], - [52769.53817769], - [52590.37433179], - [52590.37433179], - [52390.24374586], - [52115.41253722], - [52028.74471935]]) - state_disc:distance |8196715.33458363| input m traj.cruise.state_interp.state_disc:distance - val: - array([[ 560039.40638961], - [ 651826.45257603], - [ 778418.59972934], - [ 818471.23138883], - [ 818471.23138883], - [1005697.02623753], - [1263799.66653641], - [1345432.48793709], - [1345432.48793709], - [1567538.74520054], - [1873673.16694925], - [1970484.63129816], - [1970484.63129816], - [2156842.41376365], - [2413746.32168934], - [2494999.4935999 ], - [2494999.4935999 ], - [2586072.02583254], - [2711677.86536452], - [2751418.23144865]]) - staterate_col:mass |1.90369215| output kg/s traj.cruise.state_interp.staterate_col:mass - val: - array([[-0.51364159], - [-0.51166194], - [-0.50893815], - [-0.50807793], - [-0.50406681], - [-0.49856426], - [-0.49683045], - [-0.49212903], - [-0.48568691], - [-0.48365848], - [-0.47976777], - [-0.47443141], - [-0.47274987], - [-0.47086868], - [-0.46828035]]) - staterate_col:distance |834.68098413| output m/s traj.cruise.state_interp.staterate_col:distance - val: - array([[216.42809093], - [216.34878522], - [216.23931282], - [216.20465388], - [216.04249491], - [215.81855294], - [215.7476287 ], - [215.55442444], - [215.28756351], - [215.20303548], - [215.04013759], - [214.81517331], - [214.74392485], - [214.66401045], - [214.55369706]]) - rhs_all - atmosphere - standard_atmosphere - h |147700.4084954| input ft traj.cruise.rhs_all.altitude - val: - array([32000. , 32083.41734823, 32198.51626306, 32234.94467607, - 32234.94467607, 32405.30661107, 32640.37131001, 32714.76848352, - 32714.76848352, 32917.31196851, 33196.78063808, 33285.23151648, - 33285.23151648, 33455.59345148, 33690.65815042, 33765.05532393, - 33765.05532393, 33848.47267216, 33963.57158699, 34000. ]) - temp |1793.81389837| output degR traj.cruise.rhs_all.temperature - val: - array([404.72782123, 404.4312669 , 404.02208634, 403.89258303, - 403.89258303, 403.28695094, 402.45131848, 402.18684758, - 402.18684758, 401.46684514, 400.47341164, 400.15899887, - 400.15899887, 399.55342768, 398.71787925, 398.45343495, - 398.45343495, 398.15693073, 397.74781931, 397.61833789]) - pres |17.03521656| output psi traj.cruise.rhs_all.static_pressure - val: - array([3.99016779, 3.97482967, 3.95374201, 3.94708596, 3.94708596, - 3.91607491, 3.87360603, 3.86024318, 3.86024318, 3.8240572 , - 3.77459278, 3.75904314, 3.75904314, 3.72923595, 3.68842027, - 3.67557869, 3.67557869, 3.66122435, 3.64149559, 3.6352703 ]) - rho |0.00356213| output slug/ft**3 traj.cruise.rhs_all.density - val: - array([0.00082715, 0.00082457, 0.00082103, 0.00081991, 0.00081991, - 0.00081469, 0.00080753, 0.00080527, 0.00080527, 0.00079915, - 0.00079077, 0.00078813, 0.00078813, 0.00078307, 0.00077612, - 0.00077393, 0.00077393, 0.00077148, 0.00076812, 0.00076705]) - viscosity |1.37e-06| output lbf*s/ft**2 traj.cruise.rhs_all.viscosity - val: - array([3.08755112e-07, 3.08563223e-07, 3.08298345e-07, 3.08214487e-07, - 3.08214487e-07, 3.07822153e-07, 3.07280402e-07, 3.07108846e-07, - 3.07108846e-07, 3.06641579e-07, 3.05996367e-07, 3.05792045e-07, - 3.05792045e-07, 3.05398344e-07, 3.04854735e-07, 3.04682587e-07, - 3.04682587e-07, 3.04489508e-07, 3.04222996e-07, 3.04138620e-07]) - drhos_dh |1.3e-07| output slug/ft**4 traj.cruise.rhs_all.drhos_dh - val: - array([-3.10133821e-08, -3.09387152e-08, -3.08399518e-08, -3.08085662e-08, - -3.08085662e-08, -3.06609758e-08, -3.04551345e-08, -3.03894557e-08, - -3.03894557e-08, -3.02093550e-08, -2.99676306e-08, -2.98931906e-08, - -2.98931906e-08, -2.97485691e-08, -2.95463292e-08, -2.94816707e-08, - -2.94816707e-08, -2.94088010e-08, -2.93076103e-08, -2.92754279e-08]) - sos |4390.63170709| output ft/s traj.cruise.rhs_all.speed_of_sound - val: - array([986.20269773, 985.84132367, 985.34248836, 985.18455722, - 985.18455722, 984.44564389, 983.42520261, 983.10202055, - 983.10202055, 982.22164251, 981.00563142, 980.62046071, - 980.62046071, 979.87818034, 978.85308069, 978.52842124, - 978.52842124, 978.16427355, 977.66160614, 977.50246093]) - flight_conditions - density |0.00356213| input slug/ft**3 traj.cruise.rhs_all.density - val: - array([0.00082715, 0.00082457, 0.00082103, 0.00081991, 0.00081991, - 0.00081469, 0.00080753, 0.00080527, 0.00080527, 0.00079915, - 0.00079077, 0.00078813, 0.00078813, 0.00078307, 0.00077612, - 0.00077393, 0.00077393, 0.00077148, 0.00076812, 0.00076705]) - speed_of_sound |4390.63170709| input ft/s traj.cruise.rhs_all.speed_of_sound - val: - array([986.20269773, 985.84132367, 985.34248836, 985.18455722, - 985.18455722, 984.44564389, 983.42520261, 983.10202055, - 983.10202055, 982.22164251, 981.00563142, 980.62046071, - 980.62046071, 979.87818034, 978.85308069, 978.52842124, - 978.52842124, 978.16427355, 977.66160614, 977.50246093]) - mach |3.21993789| input unitless traj.cruise.rhs_all.mach - val: - array([0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, - 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72]) - dynamic_pressure |890.23908728| output lbf/ft**2 traj.cruise.rhs_all.dynamic_pressure - val: - array([208.52120555, 207.71950091, 206.61736786, 206.2695204 , - 206.2695204 , 204.64899564, 202.42988607, 201.73163473, - 201.73163473, 199.84066159, 197.25538564, 196.44275765, - 196.44275765, 194.88514212, 192.75234949, 192.08130474, - 192.08130474, 191.33118115, 190.30013108, 189.97476746]) - EAS |1829.84522618| output ft/s traj.cruise.rhs_all.EAS - val: - array([418.87520758, 418.06920419, 416.95861826, 416.60748832, - 416.60748832, 414.96775506, 412.71177312, 411.99936477, - 411.99936477, 410.06383776, 407.40276977, 406.56272029, - 406.56272029, 404.94767291, 402.72573493, 402.02410248, - 402.02410248, 401.23833427, 400.15577248, 399.8135451 ]) - velocity |3161.2548291| output ft/s traj.cruise.rhs_all.velocity - val: - array([710.06594237, 709.80575304, 709.44659162, 709.3328812 , - 709.3328812 , 708.8008636 , 708.06614588, 707.8334548 , - 707.8334548 , 707.19958261, 706.32405462, 706.04673171, - 706.04673171, 705.51228985, 704.7742181 , 704.54046329, - 704.54046329, 704.27827695, 703.91635642, 703.80177187]) - velocity_rate_comp - mach_rate |0.0| input unitless/s traj.cruise.rhs_all.mach_rate - val: - array([ 0.00000000e+00, 8.73331779e-20, 4.36665890e-20, 0.00000000e+00, - 0.00000000e+00, 3.27499417e-20, 2.18332945e-20, 0.00000000e+00, - 0.00000000e+00, -4.36665890e-20, -6.54998835e-20, -4.36665890e-20, - -4.36665890e-20, -4.91249126e-20, -2.18332945e-20, 8.73331779e-20, - 8.73331779e-20, -8.73331779e-20, 0.00000000e+00, 1.74666356e-19]) - sos |1338.26454432| input m/s traj.cruise.rhs_all.speed_of_sound - val: - array([300.59458227, 300.48443545, 300.33239045, 300.28425304, - 300.28425304, 300.05903226, 299.74800175, 299.64949586, - 299.64949586, 299.38115664, 299.01051646, 298.89311642, - 298.89311642, 298.66686937, 298.354419 , 298.25546279, - 298.25546279, 298.14447058, 297.99125755, 297.94275009]) - velocity_rate |0.0| output m/s**2 traj.cruise.rhs_all.velocity_rate - val: - array([ 0.00000000e+00, 2.62422607e-17, 1.31144910e-17, 0.00000000e+00, - 0.00000000e+00, 9.82691582e-18, 6.54448639e-18, 0.00000000e+00, - 0.00000000e+00, -1.30729539e-17, -1.95851540e-17, -1.30516429e-17, - -1.30516429e-17, -1.46719839e-17, -6.51405989e-18, 2.60475974e-17, - 2.60475974e-17, -2.60379041e-17, 0.00000000e+00, 5.20405744e-17]) - solver_sub - core_aerodynamics - Mux - aircraft:wing:wetted_area [2396.56] input ft**2 traj.cruise.rhs_all.aircraft:wing:wetted_area - aircraft:wing:fineness [0.13] input unitless traj.cruise.rhs_all.aircraft:wing:fineness - aircraft:wing:characteristic_length [10.49530819] input ft traj.cruise.rhs_all.aircraft:wing:characteristic_length - aircraft:wing:laminar_flow_upper [0.] input unitless traj.cruise.rhs_all.aircraft:wing:laminar_flow_upper - aircraft:wing:laminar_flow_lower [0.] input unitless traj.cruise.rhs_all.aircraft:wing:laminar_flow_lower - aircraft:horizontal_tail:wetted_area [592.65] input ft**2 traj.cruise.rhs_all.aircraft:horizontal_tail:wetted_area - aircraft:horizontal_tail:fineness [0.125] input unitless traj.cruise.rhs_all.aircraft:horizontal_tail:fineness - aircraft:horizontal_tail:characteristic_length [7.69198717] input ft traj.cruise.rhs_all.aircraft:horizontal_tail:characteristic_length - aircraft:horizontal_tail:laminar_flow_upper [0.] input unitless traj.cruise.rhs_all.aircraft:horizontal_tail:laminar_flow_upper - aircraft:horizontal_tail:laminar_flow_lower [0.] input unitless traj.cruise.rhs_all.aircraft:horizontal_tail:laminar_flow_lower - aircraft:vertical_tail:wetted_area [581.13] input ft**2 traj.cruise.rhs_all.aircraft:vertical_tail:wetted_area - aircraft:vertical_tail:fineness [0.1195] input unitless traj.cruise.rhs_all.aircraft:vertical_tail:fineness - aircraft:vertical_tail:characteristic_length [12.73914103] input ft traj.cruise.rhs_all.aircraft:vertical_tail:characteristic_length - aircraft:vertical_tail:laminar_flow_upper [0.] input unitless traj.cruise.rhs_all.aircraft:vertical_tail:laminar_flow_upper - aircraft:vertical_tail:laminar_flow_lower [0.] input unitless traj.cruise.rhs_all.aircraft:vertical_tail:laminar_flow_lower - aircraft:fuselage:wetted_area [4158.62] input ft**2 traj.cruise.rhs_all.aircraft:fuselage:wetted_area - aircraft:fuselage:fineness [10.03921569] input unitless traj.cruise.rhs_all.aircraft:fuselage:fineness - aircraft:fuselage:characteristic_length [128.] input ft traj.cruise.rhs_all.aircraft:fuselage:characteristic_length - aircraft:fuselage:laminar_flow_upper [0.] input unitless traj.cruise.rhs_all.aircraft:fuselage:laminar_flow_upper - aircraft:fuselage:laminar_flow_lower [0.] input unitless traj.cruise.rhs_all.aircraft:fuselage:laminar_flow_lower - aircraft:nacelle:wetted_area [273.4536] input ft**2 traj.cruise.rhs_all.aircraft:nacelle:wetted_area - aircraft:nacelle:fineness [1.54911839] input unitless traj.cruise.rhs_all.aircraft:nacelle:fineness - aircraft:nacelle:characteristic_length [12.3] input ft traj.cruise.rhs_all.aircraft:nacelle:characteristic_length - aircraft:nacelle:laminar_flow_upper [0.] input unitless traj.cruise.rhs_all.aircraft:nacelle:laminar_flow_upper - aircraft:nacelle:laminar_flow_lower [0.] input unitless traj.cruise.rhs_all.aircraft:nacelle:laminar_flow_lower - wetted_areas |4886.31967641| output ft**2 traj.cruise.rhs_all.core_aerodynamics.wetted_areas - val: - array([2396.56 , 592.65 , 581.13 , 4158.62 , 273.4536, 273.4536]) - fineness_ratios |10.2777523| output unitless traj.cruise.rhs_all.core_aerodynamics.fineness_ratios - val: - array([ 0.13 , 0.125 , 0.1195 , 10.03921569, 1.54911839, - 1.54911839]) - characteristic_lengths |130.45376144| output ft traj.cruise.rhs_all.core_aerodynamics.characteristic_lengths - val: - array([ 10.49530819, 7.69198717, 12.73914103, 128. , - 12.3 , 12.3 ]) - laminar_fractions_upper |0.0| output unitless traj.cruise.rhs_all.core_aerodynamics.laminar_fractions_upper - val: - array([0., 0., 0., 0., 0., 0.]) - laminar_fractions_lower |0.0| output unitless traj.cruise.rhs_all.core_aerodynamics.laminar_fractions_lower - val: - array([0., 0., 0., 0., 0., 0.]) - DynamicPressure - static_pressure |2453.07118165| input lbf/ft**2 traj.cruise.rhs_all.static_pressure - val: - array([574.58416126, 572.37547248, 569.33884949, 568.38037824, - 568.38037824, 563.91478575, 557.79926709, 555.8750171 , - 555.8750171 , 550.66423551, 543.5413597 , 541.30221159, - 541.30221159, 537.00997557, 531.13251762, 529.28333072, - 529.28333072, 527.21630621, 524.37536456, 523.4789226 ]) - mach |3.21993789| input unitless traj.cruise.rhs_all.mach - val: - array([0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, - 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72]) - dynamic_pressure |890.1704704| output lbf/ft**2 traj.cruise.rhs_all.core_aerodynamics.dynamic_pressure - val: - array([208.50510044, 207.70361145, 206.6016817 , 206.25387165, - 206.25387165, 204.63339745, 202.41419804, 201.7159262 , - 201.7159262 , 199.82503778, 197.24028861, 196.42774654, - 196.42774654, 194.87017994, 192.73736799, 192.06633505, - 192.06633505, 191.3162532 , 190.28533229, 189.96003143]) - lift - aircraft:wing:area [127.2771648] input m**2 traj.cruise.rhs_all.aircraft:wing:area - mass |243577.62672176| input kg traj.cruise.rhs_all.mass - val: - array([57015.39290411, 56797.93787223, 56499.27092781, 56405.0756841 , - 56405.0756841 , 55966.67143281, 55367.45066061, 55179.16707729, - 55179.16707729, 54669.88811206, 53975.10803913, 53757.11559708, - 53757.11559708, 53339.81352995, 52769.53817769, 52590.37433179, - 52590.37433179, 52390.24374586, 52115.41253722, 52028.74471935]) - dynamic_pressure |42621.59270473| input N/m**2 traj.cruise.rhs_all.core_aerodynamics.dynamic_pressure - val: - array([9983.27821833, 9944.90271819, 9892.14203622, 9875.48880103, - 9875.48880103, 9797.90007646, 9691.64423382, 9658.21079739, - 9658.21079739, 9567.67456994, 9443.91610993, 9405.01138535, - 9405.01138535, 9330.43469278, 9228.31510457, 9196.18587354, - 9196.18587354, 9160.27175995, 9110.91099999, 9095.33551064]) - cl |1.96928114| output unitless traj.cruise.rhs_all.core_aerodynamics.cl - val: - array([0.44003693, 0.44005019, 0.44007093, 0.44007811, 0.44007811, - 0.44011549, 0.4401769 , 0.44019859, 0.44019859, 0.44026278, - 0.44036377, 0.4403995 , 0.4403995 , 0.44047351, 0.44058637, - 0.44062456, 0.44062456, 0.44066874, 0.44073197, 0.44075252]) - lift |2388680.53309095| output N traj.cruise.rhs_all.lift - val: - array([559130.00282312, 556997.49743474, 554068.57524424, 553144.83545746, - 553144.83545746, 548845.55840659, 542969.21002082, 541122.77881849, - 541122.77881849, 536128.45825413, 529314.99325197, 527177.21767011, - 527177.21767011, 523084.88235346, 517492.39157025, 515735.39444086, - 515735.39444086, 513772.78383032, 511077.61035812, 510227.68940198]) - PressureDrag - mach |3.21993789| input unitless traj.cruise.rhs_all.mach - val: - array([0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, - 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72]) - lift |536996.74547487| input lbf traj.cruise.rhs_all.core_aerodynamics.lift - val: - array([125697.42485608, 125218.01857407, 124559.5706727 , 124351.90570776, - 124351.90570776, 123385.38977889, 122064.33411041, 121649.23986375, - 121649.23986375, 120526.47193737, 118994.74407302, 118514.15300439, - 118514.15300439, 117594.15942802, 116336.91748709, 115941.92881983, - 115941.92881983, 115500.71640323, 114894.81730412, 114703.74747245]) - static_pressure |2453.07118165| input lbf/ft**2 traj.cruise.rhs_all.static_pressure - val: - array([574.58416126, 572.37547248, 569.33884949, 568.38037824, - 568.38037824, 563.91478575, 557.79926709, 555.8750171 , - 555.8750171 , 550.66423551, 543.5413597 , 541.30221159, - 541.30221159, 537.00997557, 531.13251762, 529.28333072, - 529.28333072, 527.21630621, 524.37536456, 523.4789226 ]) - mission:design:lift_coefficient [0.56736557] input unitless traj.cruise.rhs_all.mission:design:lift_coefficient - mission:design:mach [0.80017085] input unitless traj.cruise.rhs_all.mission:design:mach - aircraft:wing:area [1370.] input ft**2 traj.cruise.rhs_all.aircraft:wing:area - aircraft:wing:aspect_ratio [11.22091] input unitless traj.cruise.rhs_all.aircraft:wing:aspect_ratio - aircraft:wing:max_camber_at_70_semispan [0.] input unitless traj.cruise.rhs_all.aircraft:wing:max_camber_at_70_semispan - aircraft:wing:sweep [25.] input deg traj.cruise.rhs_all.aircraft:wing:sweep - aircraft:wing:thickness_to_chord [0.13] input unitless traj.cruise.rhs_all.aircraft:wing:thickness_to_chord - CD |0.00417813| output unitless traj.cruise.rhs_all.core_aerodynamics.PressureDrag.CD - val: - array([0.00093247, 0.00093254, 0.00093267, 0.00093271, 0.00093271, - 0.00093292, 0.00093328, 0.00093341, 0.00093341, 0.00093378, - 0.00093437, 0.00093458, 0.00093458, 0.00093501, 0.00093566, - 0.00093589, 0.00093589, 0.00093614, 0.00093651, 0.00093663]) - InducedDrag - mach |3.21993789| input unitless traj.cruise.rhs_all.mach - val: - array([0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, - 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72]) - lift |536996.74547487| input lbf traj.cruise.rhs_all.core_aerodynamics.lift - val: - array([125697.42485608, 125218.01857407, 124559.5706727 , 124351.90570776, - 124351.90570776, 123385.38977889, 122064.33411041, 121649.23986375, - 121649.23986375, 120526.47193737, 118994.74407302, 118514.15300439, - 118514.15300439, 117594.15942802, 116336.91748709, 115941.92881983, - 115941.92881983, 115500.71640323, 114894.81730412, 114703.74747245]) - static_pressure |2453.07118165| input lbf/ft**2 traj.cruise.rhs_all.static_pressure - val: - array([574.58416126, 572.37547248, 569.33884949, 568.38037824, - 568.38037824, 563.91478575, 557.79926709, 555.8750171 , - 555.8750171 , 550.66423551, 543.5413597 , 541.30221159, - 541.30221159, 537.00997557, 531.13251762, 529.28333072, - 529.28333072, 527.21630621, 524.37536456, 523.4789226 ]) - aircraft:wing:area [1370.] input ft**2 traj.cruise.rhs_all.aircraft:wing:area - aircraft:wing:aspect_ratio [11.22091] input unitless traj.cruise.rhs_all.aircraft:wing:aspect_ratio - aircraft:wing:span_efficiency_factor [1.] input unitless traj.cruise.rhs_all.aircraft:wing:span_efficiency_factor - aircraft:wing:sweep [25.] input deg traj.cruise.rhs_all.aircraft:wing:sweep - aircraft:wing:taper_ratio [0.278] input unitless traj.cruise.rhs_all.aircraft:wing:taper_ratio - induced_drag_coeff |0.0245993| output unitless traj.cruise.rhs_all.core_aerodynamics.InducedDrag.induced_drag_coeff - val: - array([0.00549288, 0.00549321, 0.00549373, 0.00549391, 0.00549391, - 0.00549484, 0.00549638, 0.00549692, 0.00549692, 0.00549852, - 0.00550105, 0.00550194, 0.00550194, 0.00550379, 0.00550661, - 0.00550756, 0.00550756, 0.00550867, 0.00551025, 0.00551076]) - CompressibilityDrag - mach |3.21993789| input unitless traj.cruise.rhs_all.mach - val: - array([0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, - 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72]) - mission:design:mach [0.80017085] input unitless traj.cruise.rhs_all.mission:design:mach - aircraft:design:base_area [0.] input ft**2 traj.cruise.rhs_all.aircraft:design:base_area - aircraft:wing:area [1370.] input ft**2 traj.cruise.rhs_all.aircraft:wing:area - aircraft:wing:aspect_ratio [11.22091] input unitless traj.cruise.rhs_all.aircraft:wing:aspect_ratio - aircraft:wing:max_camber_at_70_semispan [0.] input unitless traj.cruise.rhs_all.aircraft:wing:max_camber_at_70_semispan - aircraft:wing:sweep [25.] input deg traj.cruise.rhs_all.aircraft:wing:sweep - aircraft:wing:taper_ratio [0.278] input unitless traj.cruise.rhs_all.aircraft:wing:taper_ratio - aircraft:wing:thickness_to_chord [0.13] input unitless traj.cruise.rhs_all.aircraft:wing:thickness_to_chord - aircraft:fuselage:cross_section [127.67628894] input ft**2 traj.cruise.rhs_all.aircraft:fuselage:cross_section - aircraft:fuselage:diameter_to_wing_span [0.10826471] input unitless traj.cruise.rhs_all.aircraft:fuselage:diameter_to_wing_span - aircraft:fuselage:length_to_diameter [10.03921569] input unitless traj.cruise.rhs_all.aircraft:fuselage:length_to_diameter - compress_drag_coeff |0.0042079| output unitless traj.cruise.rhs_all.core_aerodynamics.CompressibilityDrag.compress_drag_coeff - val: - array([0.00094091, 0.00094091, 0.00094091, 0.00094091, 0.00094091, - 0.00094091, 0.00094091, 0.00094091, 0.00094091, 0.00094091, - 0.00094091, 0.00094091, 0.00094091, 0.00094091, 0.00094091, - 0.00094091, 0.00094091, 0.00094091, 0.00094091, 0.00094091]) - SkinFrictionCoef - temperature |1793.81389837| input degR traj.cruise.rhs_all.temperature - val: - array([404.72782123, 404.4312669 , 404.02208634, 403.89258303, - 403.89258303, 403.28695094, 402.45131848, 402.18684758, - 402.18684758, 401.46684514, 400.47341164, 400.15899887, - 400.15899887, 399.55342768, 398.71787925, 398.45343495, - 398.45343495, 398.15693073, 397.74781931, 397.61833789]) - static_pressure |2453.07118165| input lbf/ft**2 traj.cruise.rhs_all.static_pressure - val: - array([574.58416126, 572.37547248, 569.33884949, 568.38037824, - 568.38037824, 563.91478575, 557.79926709, 555.8750171 , - 555.8750171 , 550.66423551, 543.5413597 , 541.30221159, - 541.30221159, 537.00997557, 531.13251762, 529.28333072, - 529.28333072, 527.21630621, 524.37536456, 523.4789226 ]) - mach |3.21993789| input unitless traj.cruise.rhs_all.mach - val: - array([0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, - 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72]) - characteristic_lengths |130.45376144| input ft traj.cruise.rhs_all.core_aerodynamics.characteristic_lengths - val: - array([ 10.49530819, 7.69198717, 12.73914103, 128. , - 12.3 , 12.3 ]) - cf_iter |0.02795227| output unitless traj.cruise.rhs_all.core_aerodynamics.SkinFrictionCoef.cf_iter - val: - array([[0.00266681, 0.00280109, 0.00258767, 0.00185688, 0.00260175, - 0.00260175], - [0.00266801, 0.00280238, 0.00258882, 0.0018576 , 0.00260291, - 0.00260291], - [0.00266967, 0.00280416, 0.00259041, 0.00185859, 0.00260451, - 0.00260451], - [0.0026702 , 0.00280472, 0.00259092, 0.0018589 , 0.00260502, - 0.00260502], - [0.0026702 , 0.00280472, 0.00259092, 0.0018589 , 0.00260502, - 0.00260502], - [0.00267266, 0.00280737, 0.00259328, 0.00186037, 0.0026074 , - 0.0026074 ], - [0.00267608, 0.00281103, 0.00259655, 0.0018624 , 0.0026107 , - 0.0026107 ], - [0.00267716, 0.0028122 , 0.00259759, 0.00186305, 0.00261175, - 0.00261175], - [0.00267716, 0.0028122 , 0.00259759, 0.00186305, 0.00261175, - 0.00261175], - [0.00268012, 0.00281537, 0.00260042, 0.00186481, 0.0026146 , - 0.0026146 ], - [0.00268421, 0.00281976, 0.00260435, 0.00186725, 0.00261855, - 0.00261855], - [0.00268551, 0.00282115, 0.00260559, 0.00186802, 0.00261981, - 0.00261981], - [0.00268551, 0.00282115, 0.00260559, 0.00186802, 0.00261981, - 0.00261981], - [0.00268802, 0.00282384, 0.00260799, 0.00186952, 0.00262223, - 0.00262223], - [0.0026915 , 0.00282757, 0.00261132, 0.00187158, 0.00262558, - 0.00262558], - [0.0026926 , 0.00282875, 0.00261238, 0.00187224, 0.00262665, - 0.00262665], - [0.0026926 , 0.00282875, 0.00261238, 0.00187224, 0.00262665, - 0.00262665], - [0.00269384, 0.00283008, 0.00261356, 0.00187297, 0.00262784, - 0.00262784], - [0.00269555, 0.00283191, 0.0026152 , 0.00187399, 0.00262949, - 0.00262949], - [0.00269609, 0.00283249, 0.00261572, 0.00187431, 0.00263002, - 0.00263002]]) - skin_friction_coeff |0.02645907| output unitless traj.cruise.rhs_all.core_aerodynamics.skin_friction_coeff - val: - array([[0.00252403, 0.00265084, 0.0024493 , 0.00175916, 0.0024626 , - 0.0024626 ], - [0.00252518, 0.00265207, 0.0024504 , 0.00175984, 0.0024637 , - 0.0024637 ], - [0.00252676, 0.00265376, 0.00245191, 0.00176079, 0.00246523, - 0.00246523], - [0.00252726, 0.0026543 , 0.00245239, 0.00176109, 0.00246571, - 0.00246571], - [0.00252726, 0.0026543 , 0.00245239, 0.00176109, 0.00246571, - 0.00246571], - [0.0025296 , 0.00265681, 0.00245464, 0.00176249, 0.00246798, - 0.00246798], - [0.00253285, 0.0026603 , 0.00245775, 0.00176444, 0.00247111, - 0.00247111], - [0.00253388, 0.0026614 , 0.00245874, 0.00176505, 0.00247211, - 0.00247211], - [0.00253388, 0.0026614 , 0.00245874, 0.00176505, 0.00247211, - 0.00247211], - [0.0025367 , 0.00266442, 0.00246144, 0.00176674, 0.00247482, - 0.00247482], - [0.00254059, 0.00266859, 0.00246517, 0.00176906, 0.00247858, - 0.00247858], - [0.00254182, 0.00266991, 0.00246635, 0.0017698 , 0.00247978, - 0.00247978], - [0.00254182, 0.00266991, 0.00246635, 0.0017698 , 0.00247978, - 0.00247978], - [0.00254421, 0.00267247, 0.00246864, 0.00177123, 0.00248208, - 0.00248208], - [0.00254752, 0.00267602, 0.0024718 , 0.0017732 , 0.00248527, - 0.00248527], - [0.00254856, 0.00267714, 0.00247281, 0.00177383, 0.00248628, - 0.00248628], - [0.00254856, 0.00267714, 0.00247281, 0.00177383, 0.00248628, - 0.00248628], - [0.00254974, 0.0026784 , 0.00247393, 0.00177453, 0.00248742, - 0.00248742], - [0.00255137, 0.00268014, 0.00247549, 0.00177551, 0.00248899, - 0.00248899], - [0.00255188, 0.0026807 , 0.00247599, 0.00177581, 0.00248949, - 0.00248949]]) - Re |1080455359.9739447| output unitless traj.cruise.rhs_all.core_aerodynamics.Re - val: - array([[2.01263640e+07, 1.47505658e+07, 2.44292579e+07, 2.45459643e+08, - 2.35871375e+07, 2.35871375e+07], - [2.00685447e+07, 1.47081901e+07, 2.43590771e+07, 2.44754482e+08, - 2.35193760e+07, 2.35193760e+07], - [1.99889596e+07, 1.46498624e+07, 2.42624772e+07, 2.43783868e+08, - 2.34261061e+07, 2.34261061e+07], - [1.99638172e+07, 1.46314356e+07, 2.42319595e+07, 2.43477233e+08, - 2.33966404e+07, 2.33966404e+07], - [1.99638172e+07, 1.46314356e+07, 2.42319595e+07, 2.43477233e+08, - 2.33966404e+07, 2.33966404e+07], - [1.98465360e+07, 1.45454805e+07, 2.40896043e+07, 2.42046880e+08, - 2.32591924e+07, 2.32591924e+07], - [1.96855499e+07, 1.44274941e+07, 2.38942003e+07, 2.40083506e+08, - 2.30705244e+07, 2.30705244e+07], - [1.96348075e+07, 1.43903052e+07, 2.38326096e+07, 2.39464656e+08, - 2.30110568e+07, 2.30110568e+07], - [1.96348075e+07, 1.43903052e+07, 2.38326096e+07, 2.39464656e+08, - 2.30110568e+07, 2.30110568e+07], - [1.94971908e+07, 1.42894462e+07, 2.36655712e+07, 2.37786292e+08, - 2.28497765e+07, 2.28497765e+07], - [1.93085792e+07, 1.41512132e+07, 2.34366357e+07, 2.35486000e+08, - 2.26287328e+07, 2.26287328e+07], - [1.92491598e+07, 1.41076648e+07, 2.33645127e+07, 2.34761325e+08, - 2.25590960e+07, 2.25590960e+07], - [1.92491598e+07, 1.41076648e+07, 2.33645127e+07, 2.34761325e+08, - 2.25590960e+07, 2.25590960e+07], - [1.91350858e+07, 1.40240603e+07, 2.32260504e+07, 2.33370087e+08, - 2.24254068e+07, 2.24254068e+07], - [1.89785178e+07, 1.39093120e+07, 2.30360091e+07, 2.31460596e+08, - 2.22419166e+07, 2.22419166e+07], - [1.89291719e+07, 1.38731464e+07, 2.29761133e+07, 2.30858776e+08, - 2.21840855e+07, 2.21840855e+07], - [1.89291719e+07, 1.38731464e+07, 2.29761133e+07, 2.30858776e+08, - 2.21840855e+07, 2.21840855e+07], - [1.88739646e+07, 1.38326851e+07, 2.29091031e+07, 2.30185472e+08, - 2.21193852e+07, 2.21193852e+07], - [1.87980046e+07, 1.37770142e+07, 2.28169033e+07, 2.29259069e+08, - 2.20303637e+07, 2.20303637e+07], - [1.87740162e+07, 1.37594332e+07, 2.27877863e+07, 2.28966508e+08, - 2.20022504e+07, 2.20022504e+07]]) - wall_temp |4767.00873853| output degR traj.cruise.rhs_all.core_aerodynamics.SkinFrictionCoef.wall_temp - val: - array([[439.28316759, 439.38550012, 439.2181017 , 438.36912071, - 439.22995416, 439.22995416], - [438.95927068, 439.06163127, 438.89418676, 438.04496127, - 438.90604251, 438.90604251], - [438.51236175, 438.61476117, 438.4472529 , 437.59768921, - 438.45911321, 438.45911321], - [438.37091718, 438.47332892, 438.30580042, 437.45612946, - 438.31766217, 438.31766217], - [438.37091718, 438.47332892, 438.30580042, 437.45612946, - 438.31766217, 438.31766217], - [437.7094387 , 437.81190818, 437.64428486, 436.79411101, - 437.65615339, 437.65615339], - [436.79674802, 436.89929743, 436.73154285, 435.88067283, - 436.74342075, 436.74342075], - [436.5078888 , 436.61046354, 436.44266736, 435.59157674, - 436.45454824, 436.45454824], - [436.5078888 , 436.61046354, 436.44266736, 435.59157674, - 436.45454824, 436.45454824], - [435.72149288, 435.82413657, 435.65622717, 434.80453602, - 435.66811613, 435.66811613], - [434.63645774, 434.73919648, 434.57113099, 433.71861181, - 434.58303111, 434.58303111], - [434.29305211, 434.39582105, 434.22770597, 433.37492366, - 434.23960963, 434.23960963], - [434.29305211, 434.39582105, 434.22770597, 433.37492366, - 434.23960963, 434.23960963], - [433.63163707, 433.73446435, 433.56625346, 432.71296292, - 433.57816397, 433.57816397], - [432.71903478, 432.82194279, 432.65359932, 431.79960555, - 432.6655193 , 432.6655193 ], - [432.43020376, 432.53313734, 432.36475188, 431.51053533, - 432.37667486, 432.37667486], - [432.43020376, 432.53313734, 432.36475188, 431.51053533, - 432.37667486, 432.37667486], - [432.10635676, 432.20931901, 432.04088647, 431.18642017, - 432.05281281, 432.05281281], - [431.65951951, 431.76252129, 431.59402384, 430.73921313, - 431.60595482, 431.60595482], - [431.51809847, 431.62111275, 431.45259477, 430.59767514, - 431.46452722, 431.46452722]]) - SkinFrictionDrag - skin_friction_coeff |0.02645907| input unitless traj.cruise.rhs_all.core_aerodynamics.skin_friction_coeff - val: - array([[0.00252403, 0.00265084, 0.0024493 , 0.00175916, 0.0024626 , - 0.0024626 ], - [0.00252518, 0.00265207, 0.0024504 , 0.00175984, 0.0024637 , - 0.0024637 ], - [0.00252676, 0.00265376, 0.00245191, 0.00176079, 0.00246523, - 0.00246523], - [0.00252726, 0.0026543 , 0.00245239, 0.00176109, 0.00246571, - 0.00246571], - [0.00252726, 0.0026543 , 0.00245239, 0.00176109, 0.00246571, - 0.00246571], - [0.0025296 , 0.00265681, 0.00245464, 0.00176249, 0.00246798, - 0.00246798], - [0.00253285, 0.0026603 , 0.00245775, 0.00176444, 0.00247111, - 0.00247111], - [0.00253388, 0.0026614 , 0.00245874, 0.00176505, 0.00247211, - 0.00247211], - [0.00253388, 0.0026614 , 0.00245874, 0.00176505, 0.00247211, - 0.00247211], - [0.0025367 , 0.00266442, 0.00246144, 0.00176674, 0.00247482, - 0.00247482], - [0.00254059, 0.00266859, 0.00246517, 0.00176906, 0.00247858, - 0.00247858], - [0.00254182, 0.00266991, 0.00246635, 0.0017698 , 0.00247978, - 0.00247978], - [0.00254182, 0.00266991, 0.00246635, 0.0017698 , 0.00247978, - 0.00247978], - [0.00254421, 0.00267247, 0.00246864, 0.00177123, 0.00248208, - 0.00248208], - [0.00254752, 0.00267602, 0.0024718 , 0.0017732 , 0.00248527, - 0.00248527], - [0.00254856, 0.00267714, 0.00247281, 0.00177383, 0.00248628, - 0.00248628], - [0.00254856, 0.00267714, 0.00247281, 0.00177383, 0.00248628, - 0.00248628], - [0.00254974, 0.0026784 , 0.00247393, 0.00177453, 0.00248742, - 0.00248742], - [0.00255137, 0.00268014, 0.00247549, 0.00177551, 0.00248899, - 0.00248899], - [0.00255188, 0.0026807 , 0.00247599, 0.00177581, 0.00248949, - 0.00248949]]) - Re |1080455359.9739447| input unitless traj.cruise.rhs_all.core_aerodynamics.Re - val: - array([[2.01263640e+07, 1.47505658e+07, 2.44292579e+07, 2.45459643e+08, - 2.35871375e+07, 2.35871375e+07], - [2.00685447e+07, 1.47081901e+07, 2.43590771e+07, 2.44754482e+08, - 2.35193760e+07, 2.35193760e+07], - [1.99889596e+07, 1.46498624e+07, 2.42624772e+07, 2.43783868e+08, - 2.34261061e+07, 2.34261061e+07], - [1.99638172e+07, 1.46314356e+07, 2.42319595e+07, 2.43477233e+08, - 2.33966404e+07, 2.33966404e+07], - [1.99638172e+07, 1.46314356e+07, 2.42319595e+07, 2.43477233e+08, - 2.33966404e+07, 2.33966404e+07], - [1.98465360e+07, 1.45454805e+07, 2.40896043e+07, 2.42046880e+08, - 2.32591924e+07, 2.32591924e+07], - [1.96855499e+07, 1.44274941e+07, 2.38942003e+07, 2.40083506e+08, - 2.30705244e+07, 2.30705244e+07], - [1.96348075e+07, 1.43903052e+07, 2.38326096e+07, 2.39464656e+08, - 2.30110568e+07, 2.30110568e+07], - [1.96348075e+07, 1.43903052e+07, 2.38326096e+07, 2.39464656e+08, - 2.30110568e+07, 2.30110568e+07], - [1.94971908e+07, 1.42894462e+07, 2.36655712e+07, 2.37786292e+08, - 2.28497765e+07, 2.28497765e+07], - [1.93085792e+07, 1.41512132e+07, 2.34366357e+07, 2.35486000e+08, - 2.26287328e+07, 2.26287328e+07], - [1.92491598e+07, 1.41076648e+07, 2.33645127e+07, 2.34761325e+08, - 2.25590960e+07, 2.25590960e+07], - [1.92491598e+07, 1.41076648e+07, 2.33645127e+07, 2.34761325e+08, - 2.25590960e+07, 2.25590960e+07], - [1.91350858e+07, 1.40240603e+07, 2.32260504e+07, 2.33370087e+08, - 2.24254068e+07, 2.24254068e+07], - [1.89785178e+07, 1.39093120e+07, 2.30360091e+07, 2.31460596e+08, - 2.22419166e+07, 2.22419166e+07], - [1.89291719e+07, 1.38731464e+07, 2.29761133e+07, 2.30858776e+08, - 2.21840855e+07, 2.21840855e+07], - [1.89291719e+07, 1.38731464e+07, 2.29761133e+07, 2.30858776e+08, - 2.21840855e+07, 2.21840855e+07], - [1.88739646e+07, 1.38326851e+07, 2.29091031e+07, 2.30185472e+08, - 2.21193852e+07, 2.21193852e+07], - [1.87980046e+07, 1.37770142e+07, 2.28169033e+07, 2.29259069e+08, - 2.20303637e+07, 2.20303637e+07], - [1.87740162e+07, 1.37594332e+07, 2.27877863e+07, 2.28966508e+08, - 2.20022504e+07, 2.20022504e+07]]) - fineness_ratios |10.2777523| input unitless traj.cruise.rhs_all.core_aerodynamics.fineness_ratios - val: - array([ 0.13 , 0.125 , 0.1195 , 10.03921569, 1.54911839, - 1.54911839]) - wetted_areas |4886.31967641| input ft**2 traj.cruise.rhs_all.core_aerodynamics.wetted_areas - val: - array([2396.56 , 592.65 , 581.13 , 4158.62 , 273.4536, 273.4536]) - laminar_fractions_upper |0.0| input unitless traj.cruise.rhs_all.core_aerodynamics.laminar_fractions_upper - val: - array([0., 0., 0., 0., 0., 0.]) - laminar_fractions_lower |0.0| input unitless traj.cruise.rhs_all.core_aerodynamics.laminar_fractions_lower - val: - array([0., 0., 0., 0., 0., 0.]) - aircraft:wing:area [1370.] input ft**2 traj.cruise.rhs_all.aircraft:wing:area - skin_friction_drag_coeff |0.09010481| output unitless traj.cruise.rhs_all.core_aerodynamics.SkinFrictionDrag.skin_friction_drag_coeff - val: - array([0.02004067, 0.02004935, 0.02006133, 0.02006513, 0.02006513, - 0.02008293, 0.02010757, 0.02011539, 0.02011539, 0.02013671, - 0.02016624, 0.02017562, 0.02017562, 0.02019371, 0.02021877, - 0.02022672, 0.02022672, 0.02023564, 0.02024797, 0.02025187]) - Drag - CDI - induced_drag_coeff |0.0245993| input unitless traj.cruise.rhs_all.core_aerodynamics.Drag.induced_drag_coeff - val: - array([0.00549288, 0.00549321, 0.00549373, 0.00549391, 0.00549391, - 0.00549484, 0.00549638, 0.00549692, 0.00549692, 0.00549852, - 0.00550105, 0.00550194, 0.00550194, 0.00550379, 0.00550661, - 0.00550756, 0.00550756, 0.00550867, 0.00551025, 0.00551076]) - pressure_drag_coeff |0.00417813| input unitless traj.cruise.rhs_all.core_aerodynamics.Drag.pressure_drag_coeff - val: - array([0.00093247, 0.00093254, 0.00093267, 0.00093271, 0.00093271, - 0.00093292, 0.00093328, 0.00093341, 0.00093341, 0.00093378, - 0.00093437, 0.00093458, 0.00093458, 0.00093501, 0.00093566, - 0.00093589, 0.00093589, 0.00093614, 0.00093651, 0.00093663]) - CDI |0.02877743| output unitless traj.cruise.rhs_all.core_aerodynamics.CDI - val: - array([0.00642535, 0.00642576, 0.0064264 , 0.00642662, 0.00642662, - 0.00642777, 0.00642966, 0.00643033, 0.00643033, 0.0064323 , - 0.00643541, 0.00643651, 0.00643651, 0.00643879, 0.00644227, - 0.00644345, 0.00644345, 0.00644481, 0.00644676, 0.00644739]) - CD0 - compress_drag_coeff |0.0042079| input unitless traj.cruise.rhs_all.core_aerodynamics.Drag.compress_drag_coeff - val: - array([0.00094091, 0.00094091, 0.00094091, 0.00094091, 0.00094091, - 0.00094091, 0.00094091, 0.00094091, 0.00094091, 0.00094091, - 0.00094091, 0.00094091, 0.00094091, 0.00094091, 0.00094091, - 0.00094091, 0.00094091, 0.00094091, 0.00094091, 0.00094091]) - skin_friction_drag_coeff |0.09010481| input unitless traj.cruise.rhs_all.core_aerodynamics.Drag.skin_friction_drag_coeff - val: - array([0.02004067, 0.02004935, 0.02006133, 0.02006513, 0.02006513, - 0.02008293, 0.02010757, 0.02011539, 0.02011539, 0.02013671, - 0.02016624, 0.02017562, 0.02017562, 0.02019371, 0.02021877, - 0.02022672, 0.02022672, 0.02023564, 0.02024797, 0.02025187]) - CD0 |0.09431269| output unitless traj.cruise.rhs_all.core_aerodynamics.CD0 - val: - array([0.02098159, 0.02099026, 0.02100225, 0.02100605, 0.02100605, - 0.02102385, 0.02104849, 0.0210563 , 0.0210563 , 0.02107763, - 0.02110716, 0.02111653, 0.02111653, 0.02113463, 0.02115968, - 0.02116763, 0.02116763, 0.02117655, 0.02118888, 0.02119279]) - drag - total_drag_coeff - CD0 |0.09431269| input unitless traj.cruise.rhs_all.core_aerodynamics.Drag.CD0 - val: - array([0.02098159, 0.02099026, 0.02100225, 0.02100605, 0.02100605, - 0.02102385, 0.02104849, 0.0210563 , 0.0210563 , 0.02107763, - 0.02110716, 0.02111653, 0.02111653, 0.02113463, 0.02115968, - 0.02116763, 0.02116763, 0.02117655, 0.02118888, 0.02119279]) - CDI |0.02877743| input unitless traj.cruise.rhs_all.core_aerodynamics.Drag.CDI - val: - array([0.00642535, 0.00642576, 0.0064264 , 0.00642662, 0.00642662, - 0.00642777, 0.00642966, 0.00643033, 0.00643033, 0.0064323 , - 0.00643541, 0.00643651, 0.00643651, 0.00643879, 0.00644227, - 0.00644345, 0.00644345, 0.00644481, 0.00644676, 0.00644739]) - FCD0 [0.93089003] input unitless traj.cruise.rhs_all.aircraft:design:zero_lift_drag_coeff_factor - FCDI [0.90983938] input unitless traj.cruise.rhs_all.aircraft:design:lift_dependent_drag_coeff_factor - CD_prescaled |0.11397753| output unitless traj.cruise.rhs_all.core_aerodynamics.Drag.drag.CD_prescaled - val: - array([0.02537759, 0.02538603, 0.02539777, 0.02540151, 0.02540151, - 0.02541912, 0.02544378, 0.02545167, 0.02545167, 0.02547332, - 0.02550363, 0.02551336, 0.02551336, 0.02553228, 0.02555877, - 0.02556724, 0.02556724, 0.02557679, 0.02559004, 0.02559425]) - simple_CD - aircraft:design:subsonic_drag_coeff_factor [1.] input unitless traj.cruise.rhs_all.aircraft:design:subsonic_drag_coeff_factor - aircraft:design:supersonic_drag_coeff_factor [1.] input unitless traj.cruise.rhs_all.aircraft:design:supersonic_drag_coeff_factor - mach |3.21993789| input unitless traj.cruise.rhs_all.mach - val: - array([0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, - 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72]) - CD_prescaled |0.11397753| input unitless traj.cruise.rhs_all.core_aerodynamics.Drag.drag.CD_prescaled - val: - array([0.02537759, 0.02538603, 0.02539777, 0.02540151, 0.02540151, - 0.02541912, 0.02544378, 0.02545167, 0.02545167, 0.02547332, - 0.02550363, 0.02551336, 0.02551336, 0.02553228, 0.02555877, - 0.02556724, 0.02556724, 0.02557679, 0.02559004, 0.02559425]) - CD |0.11397753| output unitless traj.cruise.rhs_all.core_aerodynamics.CD - val: - array([0.02537759, 0.02538603, 0.02539777, 0.02540151, 0.02540151, - 0.02541912, 0.02544378, 0.02545167, 0.02545167, 0.02547332, - 0.02550363, 0.02551336, 0.02551336, 0.02553228, 0.02555877, - 0.02556724, 0.02556724, 0.02557679, 0.02559004, 0.02559425]) - simple_drag - aircraft:wing:area [127.2771648] input m**2 traj.cruise.rhs_all.aircraft:wing:area - dynamic_pressure |42621.59270473| input N/m**2 traj.cruise.rhs_all.core_aerodynamics.dynamic_pressure - val: - array([9983.27821833, 9944.90271819, 9892.14203622, 9875.48880103, - 9875.48880103, 9797.90007646, 9691.64423382, 9658.21079739, - 9658.21079739, 9567.67456994, 9443.91610993, 9405.01138535, - 9405.01138535, 9330.43469278, 9228.31510457, 9196.18587354, - 9196.18587354, 9160.27175995, 9110.91099999, 9095.33551064]) - CD |0.11397753| input unitless traj.cruise.rhs_all.core_aerodynamics.Drag.drag.CD - val: - array([0.02537759, 0.02538603, 0.02539777, 0.02540151, 0.02540151, - 0.02541912, 0.02544378, 0.02545167, 0.02545167, 0.02547332, - 0.02550363, 0.02551336, 0.02551336, 0.02553228, 0.02555877, - 0.02556724, 0.02556724, 0.02557679, 0.02559004, 0.02559425]) - drag |138231.49046391| output N traj.cruise.rhs_all.drag - val: - array([32245.86305683, 32132.59930567, 31976.90699449, 31927.77231031, - 31927.77231031, 31698.89271539, 31385.54185499, 31286.96306422, - 31286.96306422, 31020.04336447, 30655.23779807, 30540.59717096, - 30540.59717096, 30320.89657307, 30020.15057154, 29925.54646903, - 29925.54646903, 29819.80551962, 29674.48430755, 29628.63095587]) - Buffet - mach |3.21993789| input unitless traj.cruise.rhs_all.mach - val: - array([0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, - 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72]) - mission:design:mach [0.80017085] input unitless traj.cruise.rhs_all.mission:design:mach - aircraft:wing:aspect_ratio [11.22091] input unitless traj.cruise.rhs_all.aircraft:wing:aspect_ratio - aircraft:wing:max_camber_at_70_semispan [0.] input unitless traj.cruise.rhs_all.aircraft:wing:max_camber_at_70_semispan - aircraft:wing:sweep [25.] input deg traj.cruise.rhs_all.aircraft:wing:sweep - aircraft:wing:thickness_to_chord [0.13] input unitless traj.cruise.rhs_all.aircraft:wing:thickness_to_chord - DELCLB |1.26370788| output unitless traj.cruise.rhs_all.core_aerodynamics.Buffet.DELCLB - val: - array([0.28257367, 0.28257367, 0.28257367, 0.28257367, 0.28257367, - 0.28257367, 0.28257367, 0.28257367, 0.28257367, 0.28257367, - 0.28257367, 0.28257367, 0.28257367, 0.28257367, 0.28257367, - 0.28257367, 0.28257367, 0.28257367, 0.28257367, 0.28257367]) - core_propulsion - turbofan_28k - interpolation - mach |3.21993789| input unitless traj.cruise.rhs_all.mach - val: - array([0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, - 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72]) - altitude |147700.4084954| input ft traj.cruise.rhs_all.altitude - val: - array([32000. , 32083.41734823, 32198.51626306, 32234.94467607, - 32234.94467607, 32405.30661107, 32640.37131001, 32714.76848352, - 32714.76848352, 32917.31196851, 33196.78063808, 33285.23151648, - 33285.23151648, 33455.59345148, 33690.65815042, 33765.05532393, - 33765.05532393, 33848.47267216, 33963.57158699, 34000. ]) - throttle |2.78644451| input unitless traj.cruise.rhs_all.throttle - val: - array([0.62030938, 0.62046836, 0.62070005, 0.62077638, 0.62077638, - 0.62115279, 0.62172604, 0.62192082, 0.62192082, 0.62248454, - 0.62334458, 0.62363676, 0.62363676, 0.6242272 , 0.62510335, - 0.62539589, 0.62539589, 0.62573279, 0.62621334, 0.62636927]) - fuel_flow_rate_unscaled |8698.65228821| output lbm/h traj.cruise.rhs_all.turbofan_28k.interpolation.fuel_flow_rate_unscaled - val: - array([2038.29455175, 2030.43868351, 2019.62980286, 2016.21617134, - 2016.21617134, 2000.29878137, 1978.46288981, 1971.58256237, - 1971.58256237, 1952.92584537, 1927.36144242, 1919.31195184, - 1919.31195184, 1903.87239807, 1882.69600876, 1876.02310243, - 1876.02310243, 1868.55792623, 1858.28661428, 1855.04280882]) - nox_rate_unscaled |53.10083024| output lbm/h traj.cruise.rhs_all.turbofan_28k.interpolation.nox_rate_unscaled - val: - array([12.26163399, 12.22868063, 12.18343233, 12.16916537, 12.16916537, - 12.10279735, 12.01221129, 11.98378873, 11.98378873, 11.90703657, - 11.80269729, 11.77005993, 11.77005993, 11.70594487, 11.61704483, - 11.5890778 , 11.5890778 , 11.55781859, 11.51486054, 11.50130677]) - thrust_net_unscaled |15612.52281263| output lbf traj.cruise.rhs_all.turbofan_28k.interpolation.thrust_net_unscaled - val: - array([3641.98550395, 3629.19412091, 3611.61113056, 3606.06215312, - 3606.06215312, 3580.21392177, 3544.8261912 , 3533.69340408, - 3533.69340408, 3503.5494743 , 3462.35123567, 3449.40469312, - 3449.40469312, 3424.59364544, 3390.63020633, 3379.94654122, - 3379.94654122, 3368.00520937, 3351.59410981, 3346.41590658]) - interp_max_throttles - mach |3.21993789| input unitless traj.cruise.rhs_all.mach - val: - array([0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, - 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72]) - altitude |147700.4084954| input ft traj.cruise.rhs_all.altitude - val: - array([32000. , 32083.41734823, 32198.51626306, 32234.94467607, - 32234.94467607, 32405.30661107, 32640.37131001, 32714.76848352, - 32714.76848352, 32917.31196851, 33196.78063808, 33285.23151648, - 33285.23151648, 33455.59345148, 33690.65815042, 33765.05532393, - 33765.05532393, 33848.47267216, 33963.57158699, 34000. ]) - throttle_max |4.47213595| output unitless traj.cruise.rhs_all.turbofan_28k.throttle_max - val: - array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - 1., 1., 1.]) - max_interpolation - mach |3.21993789| input unitless traj.cruise.rhs_all.mach - val: - array([0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, - 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72]) - altitude |147700.4084954| input ft traj.cruise.rhs_all.altitude - val: - array([32000. , 32083.41734823, 32198.51626306, 32234.94467607, - 32234.94467607, 32405.30661107, 32640.37131001, 32714.76848352, - 32714.76848352, 32917.31196851, 33196.78063808, 33285.23151648, - 33285.23151648, 33455.59345148, 33690.65815042, 33765.05532393, - 33765.05532393, 33848.47267216, 33963.57158699, 34000. ]) - throttle_max |4.47213595| input unitless traj.cruise.rhs_all.throttle_max - val: - array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - 1., 1., 1.]) - thrust_net_max_unscaled |26061.52151244| output lbf traj.cruise.rhs_all.turbofan_28k.max_interpolation.thrust_net_max_unscaled - val: - array([6107.972 , 6084.79332195, 6052.81147708, 6042.68933253, - 6042.68933253, 5995.35188382, 5930.03586632, 5909.3635701 , - 5909.3635701 , 5853.08402718, 5775.42974478, 5750.8524299 , - 5750.8524299 , 5703.5149812 , 5638.19896369, 5617.52666747, - 5617.52666747, 5594.34798942, 5562.36614455, 5552.244 ]) - engine_scaling - aircraft:engine:scale_factor [1.] input unitless traj.cruise.rhs_all.aircraft:engine:scale_factor - mach |3.21993789| input unitless traj.cruise.rhs_all.mach - val: - array([0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, - 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72, 0.72]) - fuel_flow_rate_unscaled |8698.65228821| input lbm/h traj.cruise.rhs_all.engine_scaling.fuel_flow_rate_unscaled - val: - array([2038.29455175, 2030.43868351, 2019.62980286, 2016.21617134, - 2016.21617134, 2000.29878137, 1978.46288981, 1971.58256237, - 1971.58256237, 1952.92584537, 1927.36144242, 1919.31195184, - 1919.31195184, 1903.87239807, 1882.69600876, 1876.02310243, - 1876.02310243, 1868.55792623, 1858.28661428, 1855.04280882]) - nox_rate_unscaled |53.10083024| input lbm/h traj.cruise.rhs_all.engine_scaling.nox_rate_unscaled - val: - array([12.26163399, 12.22868063, 12.18343233, 12.16916537, 12.16916537, - 12.10279735, 12.01221129, 11.98378873, 11.98378873, 11.90703657, - 11.80269729, 11.77005993, 11.77005993, 11.70594487, 11.61704483, - 11.5890778 , 11.5890778 , 11.55781859, 11.51486054, 11.50130677]) - thrust_net_unscaled |15612.52281263| input lbf traj.cruise.rhs_all.engine_scaling.thrust_net_unscaled - val: - array([3641.98550395, 3629.19412091, 3611.61113056, 3606.06215312, - 3606.06215312, 3580.21392177, 3544.8261912 , 3533.69340408, - 3533.69340408, 3503.5494743 , 3462.35123567, 3449.40469312, - 3449.40469312, 3424.59364544, 3390.63020633, 3379.94654122, - 3379.94654122, 3368.00520937, 3351.59410981, 3346.41590658]) - thrust_net_max_unscaled |26061.52151244| input lbf traj.cruise.rhs_all.engine_scaling.thrust_net_max_unscaled - val: - array([6107.972 , 6084.79332195, 6052.81147708, 6042.68933253, - 6042.68933253, 5995.35188382, 5930.03586632, 5909.3635701 , - 5909.3635701 , 5853.08402718, 5775.42974478, 5750.8524299 , - 5750.8524299 , 5703.5149812 , 5638.19896369, 5617.52666747, - 5617.52666747, 5594.34798942, 5562.36614455, 5552.244 ]) - fuel_flow_rate_negative |8698.65228821| output lbm/h traj.cruise.rhs_all.turbofan_28k.fuel_flow_rate_negative - val: - array([-2038.29455175, -2030.43868351, -2019.62980286, -2016.21617134, - -2016.21617134, -2000.29878137, -1978.46288981, -1971.58256237, - -1971.58256237, -1952.92584537, -1927.36144242, -1919.31195184, - -1919.31195184, -1903.87239807, -1882.69600876, -1876.02310243, - -1876.02310243, -1868.55792623, -1858.28661428, -1855.04280882]) - nox_rate |53.10083024| output lbm/h traj.cruise.rhs_all.turbofan_28k.nox_rate - val: - array([12.26163399, 12.22868063, 12.18343233, 12.16916537, 12.16916537, - 12.10279735, 12.01221129, 11.98378873, 11.98378873, 11.90703657, - 11.80269729, 11.77005993, 11.77005993, 11.70594487, 11.61704483, - 11.5890778 , 11.5890778 , 11.55781859, 11.51486054, 11.50130677]) - thrust_net |15612.52281263| output lbf traj.cruise.rhs_all.turbofan_28k.thrust_net - val: - array([3641.98550395, 3629.19412091, 3611.61113056, 3606.06215312, - 3606.06215312, 3580.21392177, 3544.8261912 , 3533.69340408, - 3533.69340408, 3503.5494743 , 3462.35123567, 3449.40469312, - 3449.40469312, 3424.59364544, 3390.63020633, 3379.94654122, - 3379.94654122, 3368.00520937, 3351.59410981, 3346.41590658]) - thrust_net_max |26061.52151244| output lbf traj.cruise.rhs_all.turbofan_28k.thrust_net_max - val: - array([6107.972 , 6084.79332195, 6052.81147708, 6042.68933253, - 6042.68933253, 5995.35188382, 5930.03586632, 5909.3635701 , - 5909.3635701 , 5853.08402718, 5775.42974478, 5750.8524299 , - 5750.8524299 , 5703.5149812 , 5638.19896369, 5617.52666747, - 5617.52666747, 5594.34798942, 5562.36614455, 5552.244 ]) - vectorize_performance - thrust_net_0 |15612.52281263| input lbf traj.cruise.rhs_all.vectorize_performance.thrust_net_0 - val: - array([3641.98550395, 3629.19412091, 3611.61113056, 3606.06215312, - 3606.06215312, 3580.21392177, 3544.8261912 , 3533.69340408, - 3533.69340408, 3503.5494743 , 3462.35123567, 3449.40469312, - 3449.40469312, 3424.59364544, 3390.63020633, 3379.94654122, - 3379.94654122, 3368.00520937, 3351.59410981, 3346.41590658]) - thrust_net_max_0 |26061.52151244| input lbf traj.cruise.rhs_all.vectorize_performance.thrust_net_max_0 - val: - array([6107.972 , 6084.79332195, 6052.81147708, 6042.68933253, - 6042.68933253, 5995.35188382, 5930.03586632, 5909.3635701 , - 5909.3635701 , 5853.08402718, 5775.42974478, 5750.8524299 , - 5750.8524299 , 5703.5149812 , 5638.19896369, 5617.52666747, - 5617.52666747, 5594.34798942, 5562.36614455, 5552.244 ]) - fuel_flow_rate_negative_0 |8698.65228821| input lbm/h traj.cruise.rhs_all.vectorize_performance.fuel_flow_rate_negative_0 - val: - array([-2038.29455175, -2030.43868351, -2019.62980286, -2016.21617134, - -2016.21617134, -2000.29878137, -1978.46288981, -1971.58256237, - -1971.58256237, -1952.92584537, -1927.36144242, -1919.31195184, - -1919.31195184, -1903.87239807, -1882.69600876, -1876.02310243, - -1876.02310243, -1868.55792623, -1858.28661428, -1855.04280882]) - electric_power_in_0 |0.0| input kW traj.cruise.rhs_all.vectorize_performance.electric_power_in_0 - val: - array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., - 0., 0., 0.]) - nox_rate_0 |53.10083024| input lbm/h traj.cruise.rhs_all.vectorize_performance.nox_rate_0 - val: - array([12.26163399, 12.22868063, 12.18343233, 12.16916537, 12.16916537, - 12.10279735, 12.01221129, 11.98378873, 11.98378873, 11.90703657, - 11.80269729, 11.77005993, 11.77005993, 11.70594487, 11.61704483, - 11.5890778 , 11.5890778 , 11.55781859, 11.51486054, 11.50130677]) - t4_0 |0.0| input degR traj.cruise.rhs_all.vectorize_performance.t4_0 - val: - array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., - 0., 0., 0.]) - shaft_power_0 |0.0| input hp traj.cruise.rhs_all.vectorize_performance.shaft_power_0 - val: - array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., - 0., 0., 0.]) - shaft_power_max_0 |0.0| input hp traj.cruise.rhs_all.vectorize_performance.shaft_power_max_0 - val: - array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., - 0., 0., 0.]) - thrust_net |15612.52281263| output lbf traj.cruise.rhs_all.thrust_net - val: - array([[3641.98550395], - [3629.19412091], - [3611.61113056], - [3606.06215312], - [3606.06215312], - [3580.21392177], - [3544.8261912 ], - [3533.69340408], - [3533.69340408], - [3503.5494743 ], - [3462.35123567], - [3449.40469312], - [3449.40469312], - [3424.59364544], - [3390.63020633], - [3379.94654122], - [3379.94654122], - [3368.00520937], - [3351.59410981], - [3346.41590658]]) - thrust_net_max |26061.52151244| output lbf traj.cruise.rhs_all.thrust_net_max - val: - array([[6107.972 ], - [6084.79332195], - [6052.81147708], - [6042.68933253], - [6042.68933253], - [5995.35188382], - [5930.03586632], - [5909.3635701 ], - [5909.3635701 ], - [5853.08402718], - [5775.42974478], - [5750.8524299 ], - [5750.8524299 ], - [5703.5149812 ], - [5638.19896369], - [5617.52666747], - [5617.52666747], - [5594.34798942], - [5562.36614455], - [5552.244 ]]) - fuel_flow_rate_negative |8698.65228821| output lbm/h traj.cruise.rhs_all.fuel_flow_rate_negative - val: - array([[-2038.29455175], - [-2030.43868351], - [-2019.62980286], - [-2016.21617134], - [-2016.21617134], - [-2000.29878137], - [-1978.46288981], - [-1971.58256237], - [-1971.58256237], - [-1952.92584537], - [-1927.36144242], - [-1919.31195184], - [-1919.31195184], - [-1903.87239807], - [-1882.69600876], - [-1876.02310243], - [-1876.02310243], - [-1868.55792623], - [-1858.28661428], - [-1855.04280882]]) - electric_power_in |0.0| output kW traj.cruise.rhs_all.electric_power_in - val: - array([[0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.]]) - nox_rate |53.10083024| output lbm/h traj.cruise.rhs_all.nox_rate - val: - array([[12.26163399], - [12.22868063], - [12.18343233], - [12.16916537], - [12.16916537], - [12.10279735], - [12.01221129], - [11.98378873], - [11.98378873], - [11.90703657], - [11.80269729], - [11.77005993], - [11.77005993], - [11.70594487], - [11.61704483], - [11.5890778 ], - [11.5890778 ], - [11.55781859], - [11.51486054], - [11.50130677]]) - t4 |0.0| output degR traj.cruise.rhs_all.t4 - val: - array([[0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.]]) - shaft_power |0.0| output hp traj.cruise.rhs_all.shaft_power - val: - array([[0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.]]) - shaft_power_max |0.0| output hp traj.cruise.rhs_all.shaft_power_max - val: - array([[0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.]]) - propulsion_sum - thrust_net |15612.52281263| input lbf traj.cruise.rhs_all.thrust_net - val: - array([[3641.98550395], - [3629.19412091], - [3611.61113056], - [3606.06215312], - [3606.06215312], - [3580.21392177], - [3544.8261912 ], - [3533.69340408], - [3533.69340408], - [3503.5494743 ], - [3462.35123567], - [3449.40469312], - [3449.40469312], - [3424.59364544], - [3390.63020633], - [3379.94654122], - [3379.94654122], - [3368.00520937], - [3351.59410981], - [3346.41590658]]) - thrust_net_max |26061.52151244| input lbf traj.cruise.rhs_all.thrust_net_max - val: - array([[6107.972 ], - [6084.79332195], - [6052.81147708], - [6042.68933253], - [6042.68933253], - [5995.35188382], - [5930.03586632], - [5909.3635701 ], - [5909.3635701 ], - [5853.08402718], - [5775.42974478], - [5750.8524299 ], - [5750.8524299 ], - [5703.5149812 ], - [5638.19896369], - [5617.52666747], - [5617.52666747], - [5594.34798942], - [5562.36614455], - [5552.244 ]]) - fuel_flow_rate_negative |8698.65228821| input lbm/h traj.cruise.rhs_all.fuel_flow_rate_negative - val: - array([[-2038.29455175], - [-2030.43868351], - [-2019.62980286], - [-2016.21617134], - [-2016.21617134], - [-2000.29878137], - [-1978.46288981], - [-1971.58256237], - [-1971.58256237], - [-1952.92584537], - [-1927.36144242], - [-1919.31195184], - [-1919.31195184], - [-1903.87239807], - [-1882.69600876], - [-1876.02310243], - [-1876.02310243], - [-1868.55792623], - [-1858.28661428], - [-1855.04280882]]) - electric_power_in |0.0| input kW traj.cruise.rhs_all.electric_power_in - val: - array([[0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.]]) - nox_rate |53.10083024| input lbm/h traj.cruise.rhs_all.nox_rate - val: - array([[12.26163399], - [12.22868063], - [12.18343233], - [12.16916537], - [12.16916537], - [12.10279735], - [12.01221129], - [11.98378873], - [11.98378873], - [11.90703657], - [11.80269729], - [11.77005993], - [11.77005993], - [11.70594487], - [11.61704483], - [11.5890778 ], - [11.5890778 ], - [11.55781859], - [11.51486054], - [11.50130677]]) - thrust_net_total |31225.04562526| output lbf traj.cruise.rhs_all.thrust_net_total - val: - array([7283.97100791, 7258.38824181, 7223.22226111, 7212.12430625, - 7212.12430625, 7160.42784354, 7089.6523824 , 7067.38680815, - 7067.38680815, 7007.0989486 , 6924.70247135, 6898.80938625, - 6898.80938625, 6849.18729088, 6781.26041265, 6759.89308244, - 6759.89308244, 6736.01041873, 6703.18821962, 6692.83181316]) - thrust_net_max_total |52123.04302488| output lbf traj.cruise.rhs_all.thrust_net_max_total - val: - array([12215.944 , 12169.5866439 , 12105.62295416, 12085.37866506, - 12085.37866506, 11990.70376764, 11860.07173263, 11818.72714019, - 11818.72714019, 11706.16805436, 11550.85948956, 11501.70485981, - 11501.70485981, 11407.0299624 , 11276.39792738, 11235.05333494, - 11235.05333494, 11188.69597885, 11124.73228911, 11104.488 ]) - fuel_flow_rate_negative_total |17397.30457641| output lbm/h traj.cruise.rhs_all.fuel_flow_rate_negative_total - val: - array([-4076.58910351, -4060.87736702, -4039.25960572, -4032.43234269, - -4032.43234269, -4000.59756274, -3956.92577962, -3943.16512475, - -3943.16512475, -3905.85169075, -3854.72288485, -3838.62390368, - -3838.62390368, -3807.74479615, -3765.39201751, -3752.04620486, - -3752.04620486, -3737.11585247, -3716.57322856, -3710.08561764]) - electric_power_in_total |0.0| output kW traj.cruise.rhs_all.electric_power_in_total - val: - array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., - 0., 0., 0.]) - nox_rate_total |106.20166048| output lbm/h traj.cruise.rhs_all.nox_rate_total - val: - array([24.52326798, 24.45736125, 24.36686465, 24.33833074, 24.33833074, - 24.2055947 , 24.02442257, 23.96757746, 23.96757746, 23.81407315, - 23.60539459, 23.54011987, 23.54011987, 23.41188974, 23.23408966, - 23.17815561, 23.17815561, 23.11563718, 23.02972108, 23.00261354]) - mission_EOM - required_thrust - drag |138231.49046391| input N traj.cruise.rhs_all.drag - val: - array([32245.86305683, 32132.59930567, 31976.90699449, 31927.77231031, - 31927.77231031, 31698.89271539, 31385.54185499, 31286.96306422, - 31286.96306422, 31020.04336447, 30655.23779807, 30540.59717096, - 30540.59717096, 30320.89657307, 30020.15057154, 29925.54646903, - 29925.54646903, 29819.80551962, 29674.48430755, 29628.63095587]) - altitude_rate |0.26806431| input m/s traj.cruise.rhs_all.altitude_rate - val: - array([0.059941, 0.059941, 0.059941, 0.059941, 0.059941, 0.059941, - 0.059941, 0.059941, 0.059941, 0.059941, 0.059941, 0.059941, - 0.059941, 0.059941, 0.059941, 0.059941, 0.059941, 0.059941, - 0.059941, 0.059941]) - velocity |963.55047191| input m/s traj.cruise.rhs_all.velocity - val: - array([216.42809923, 216.34879353, 216.23932113, 216.20466219, - 216.20466219, 216.04250323, 215.81856126, 215.74763702, - 215.74763702, 215.55443278, 215.28757185, 215.20304383, - 215.20304383, 215.04014595, 214.81518168, 214.74393321, - 214.74393321, 214.66401882, 214.55370544, 214.51878007]) - velocity_rate |0.0| input m/s**2 traj.cruise.rhs_all.velocity_rate - val: - array([ 0.00000000e+00, 2.62422607e-17, 1.31144910e-17, 0.00000000e+00, - 0.00000000e+00, 9.82691582e-18, 6.54448639e-18, 0.00000000e+00, - 0.00000000e+00, -1.30729539e-17, -1.95851540e-17, -1.30516429e-17, - -1.30516429e-17, -1.46719839e-17, -6.51405989e-18, 2.60475974e-17, - 2.60475974e-17, -2.60379041e-17, 0.00000000e+00, 5.20405744e-17]) - mass |243577.62672176| input kg traj.cruise.rhs_all.mass - val: - array([57015.39290411, 56797.93787223, 56499.27092781, 56405.0756841 , - 56405.0756841 , 55966.67143281, 55367.45066061, 55179.16707729, - 55179.16707729, 54669.88811206, 53975.10803913, 53757.11559708, - 53757.11559708, 53339.81352995, 52769.53817769, 52590.37433179, - 52590.37433179, 52390.24374586, 52115.41253722, 52028.74471935]) - thrust_required |138895.92303576| output N traj.cruise.rhs_all.thrust_required - val: - array([32400.71731682, 32286.91950359, 32130.49342794, 32081.12726519, - 32081.12726519, 31851.16994206, 31536.34500569, 31437.30279692, - 31437.30279692, 31169.12903663, 30802.61124513, 30687.43306416, - 30687.43306416, 30466.70298674, 30164.54917842, 30069.50255821, - 30069.50255821, 29963.26717715, 29817.26676143, 29771.1991703 ]) - groundspeed - altitude_rate |0.26806431| input m/s traj.cruise.rhs_all.altitude_rate - val: - array([0.059941, 0.059941, 0.059941, 0.059941, 0.059941, 0.059941, - 0.059941, 0.059941, 0.059941, 0.059941, 0.059941, 0.059941, - 0.059941, 0.059941, 0.059941, 0.059941, 0.059941, 0.059941, - 0.059941, 0.059941]) - velocity |963.55047191| input m/s traj.cruise.rhs_all.velocity - val: - array([216.42809923, 216.34879353, 216.23932113, 216.20466219, - 216.20466219, 216.04250323, 215.81856126, 215.74763702, - 215.74763702, 215.55443278, 215.28757185, 215.20304383, - 215.20304383, 215.04014595, 214.81518168, 214.74393321, - 214.74393321, 214.66401882, 214.55370544, 214.51878007]) - distance_rate |963.55043462| output m/s traj.cruise.rhs_all.distance_rate - val: - array([216.42809093, 216.34878522, 216.23931282, 216.20465388, - 216.20465388, 216.04249491, 215.81855294, 215.7476287 , - 215.7476287 , 215.55442444, 215.28756351, 215.20303548, - 215.20303548, 215.04013759, 214.81517331, 214.74392485, - 214.74392485, 214.66401045, 214.55369706, 214.51877169]) - excess_specific_power - velocity |963.55047191| input m/s traj.cruise.rhs_all.velocity - val: - array([216.42809923, 216.34879353, 216.23932113, 216.20466219, - 216.20466219, 216.04250323, 215.81856126, 215.74763702, - 215.74763702, 215.55443278, 215.28757185, 215.20304383, - 215.20304383, 215.04014595, 214.81518168, 214.74393321, - 214.74393321, 214.66401882, 214.55370544, 214.51878007]) - mass |243577.62672176| input kg traj.cruise.rhs_all.mass - val: - array([57015.39290411, 56797.93787223, 56499.27092781, 56405.0756841 , - 56405.0756841 , 55966.67143281, 55367.45066061, 55179.16707729, - 55179.16707729, 54669.88811206, 53975.10803913, 53757.11559708, - 53757.11559708, 53339.81352995, 52769.53817769, 52590.37433179, - 52590.37433179, 52390.24374586, 52115.41253722, 52028.74471935]) - thrust_net_total |231854.84688348| input N traj.cruise.rhs_all.thrust_net_max_total - val: - array([54339.22620951, 54133.01841588, 53848.49374828, 53758.44266379, - 53758.44266379, 53337.30773824, 52756.22749584, 52572.31758588, - 52572.31758588, 52071.62982678, 51380.78291104, 51162.13222426, - 51162.13222426, 50740.99729871, 50159.91705631, 49976.00714635, - 49976.00714635, 49769.79935272, 49485.27468512, 49395.22360063]) - drag |138231.49046391| input N traj.cruise.rhs_all.drag - val: - array([32245.86305683, 32132.59930567, 31976.90699449, 31927.77231031, - 31927.77231031, 31698.89271539, 31385.54185499, 31286.96306422, - 31286.96306422, 31020.04336447, 30655.23779807, 30540.59717096, - 30540.59717096, 30320.89657307, 30020.15057154, 29925.54646903, - 29925.54646903, 29819.80551962, 29674.48430755, 29628.63095587]) - specific_energy_rate |37.75301942| output m/s traj.cruise.rhs_all.specific_energy_rate_excess - val: - array([8.55190129, 8.5453959 , 8.53594173, 8.53283337, 8.53283337, - 8.5175461 , 8.49438705, 8.48654893, 8.48654893, 8.46394686, - 8.42967295, 8.41807454, 8.41807454, 8.39470149, 8.36017624, - 8.34868973, 8.34868973, 8.33548601, 8.31669867, 8.31061392]) - altitude_rate_max - specific_energy_rate |37.75301942| input m/s traj.cruise.rhs_all.mission_EOM.specific_energy_rate_excess - val: - array([8.55190129, 8.5453959 , 8.53594173, 8.53283337, 8.53283337, - 8.5175461 , 8.49438705, 8.48654893, 8.48654893, 8.46394686, - 8.42967295, 8.41807454, 8.41807454, 8.39470149, 8.36017624, - 8.34868973, 8.34868973, 8.33548601, 8.31669867, 8.31061392]) - velocity_rate |0.0| input m/s**2 traj.cruise.rhs_all.velocity_rate - val: - array([ 0.00000000e+00, 2.62422607e-17, 1.31144910e-17, 0.00000000e+00, - 0.00000000e+00, 9.82691582e-18, 6.54448639e-18, 0.00000000e+00, - 0.00000000e+00, -1.30729539e-17, -1.95851540e-17, -1.30516429e-17, - -1.30516429e-17, -1.46719839e-17, -6.51405989e-18, 2.60475974e-17, - 2.60475974e-17, -2.60379041e-17, 0.00000000e+00, 5.20405744e-17]) - velocity |963.55047191| input m/s traj.cruise.rhs_all.velocity - val: - array([216.42809923, 216.34879353, 216.23932113, 216.20466219, - 216.20466219, 216.04250323, 215.81856126, 215.74763702, - 215.74763702, 215.55443278, 215.28757185, 215.20304383, - 215.20304383, 215.04014595, 214.81518168, 214.74393321, - 214.74393321, 214.66401882, 214.55370544, 214.51878007]) - altitude_rate |37.75301942| output m/s traj.cruise.rhs_all.altitude_rate_max - val: - array([8.55190129, 8.5453959 , 8.53594173, 8.53283337, 8.53283337, - 8.5175461 , 8.49438705, 8.48654893, 8.48654893, 8.46394686, - 8.42967295, 8.41807454, 8.41807454, 8.39470149, 8.36017624, - 8.34868973, 8.34868973, 8.33548601, 8.31669867, 8.31061392]) - throttle_balance - thrust_required |31225.04562526| input lbf traj.cruise.rhs_all.thrust_required - val: - array([7283.97100791, 7258.38824181, 7223.22226111, 7212.12430625, - 7212.12430625, 7160.42784354, 7089.6523824 , 7067.38680815, - 7067.38680815, 7007.0989486 , 6924.70247135, 6898.80938625, - 6898.80938625, 6849.18729088, 6781.26041265, 6759.89308244, - 6759.89308244, 6736.01041873, 6703.18821962, 6692.83181316]) - thrust_net_total |31225.04562526| input lbf traj.cruise.rhs_all.thrust_net_total - val: - array([7283.97100791, 7258.38824181, 7223.22226111, 7212.12430625, - 7212.12430625, 7160.42784354, 7089.6523824 , 7067.38680815, - 7067.38680815, 7007.0989486 , 6924.70247135, 6898.80938625, - 6898.80938625, 6849.18729088, 6781.26041265, 6759.89308244, - 6759.89308244, 6736.01041873, 6703.18821962, 6692.83181316]) - throttle |2.78644451| output unitless traj.cruise.rhs_all.throttle - val: - array([0.62030938, 0.62046836, 0.62070005, 0.62077638, 0.62077638, - 0.62115279, 0.62172604, 0.62192082, 0.62192082, 0.62248454, - 0.62334458, 0.62363676, 0.62363676, 0.6242272 , 0.62510335, - 0.62539589, 0.62539589, 0.62573279, 0.62621334, 0.62636927]) - initial_mass_residual_constraint - initial_mass [1.] input kg traj.cruise.rhs_all.mission:summary:gross_mass - mass |243577.62672176| input kg traj.cruise.rhs_all.mass - val: - array([57015.39290411, 56797.93787223, 56499.27092781, 56405.0756841 , - 56405.0756841 , 55966.67143281, 55367.45066061, 55179.16707729, - 55179.16707729, 54669.88811206, 53975.10803913, 53757.11559708, - 53757.11559708, 53339.81352995, 52769.53817769, 52590.37433179, - 52590.37433179, 52390.24374586, 52115.41253722, 52028.74471935]) - initial_mass_residual [-57114.39290411] output kg traj.cruise.rhs_all.initial_mass_residual - timeseries - dt_dstau |4814.09560547| input s traj.cruise.timeseries.dt_dstau - val: - array([ 597.34683891, 597.34683891, 597.34683891, 597.34683891, - 1219.95203044, 1219.95203044, 1219.95203044, 1219.95203044, - 1450.4022613 , 1450.4022613 , 1450.4022613 , 1450.4022613 , - 1219.95203044, 1219.95203044, 1219.95203044, 1219.95203044, - 597.34683891, 597.34683891, 597.34683891, 597.34683891]) - input_values:mach |3.21993789| input unitless traj.cruise.timeseries.input_values:mach - val: - array([[0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72]]) - input_values:thrust_net_total |31225.04562526| input lbf traj.cruise.timeseries.input_values:thrust_net_total - val: - array([[7283.97100791], - [7258.38824181], - [7223.22226111], - [7212.12430625], - [7212.12430625], - [7160.42784354], - [7089.6523824 ], - [7067.38680815], - [7067.38680815], - [7007.0989486 ], - [6924.70247135], - [6898.80938625], - [6898.80938625], - [6849.18729088], - [6781.26041265], - [6759.89308244], - [6759.89308244], - [6736.01041873], - [6703.18821962], - [6692.83181316]]) - input_values:drag |31075.67524118| input lbf traj.cruise.timeseries.input_values:drag - val: - array([[7249.15838542], - [7223.69568126], - [7188.69465737], - [7177.64874096], - [7177.64874096], - [7126.19456118], - [7055.75048551], - [7033.58909177], - [7033.58909177], - [6973.58315624], - [6891.57160251], - [6865.79936432], - [6865.79936432], - [6816.40870516], - [6748.79831449], - [6727.53046622], - [6727.53046622], - [6703.75895516], - [6671.0894471 ], - [6660.78120358]]) - input_values:specific_energy_rate_excess |37.75301942| input m/s traj.cruise.timeseries.input_values:specific_energy_rate_excess - val: - array([[8.55190129], - [8.5453959 ], - [8.53594173], - [8.53283337], - [8.53283337], - [8.5175461 ], - [8.49438705], - [8.48654893], - [8.48654893], - [8.46394686], - [8.42967295], - [8.41807454], - [8.41807454], - [8.39470149], - [8.36017624], - [8.34868973], - [8.34868973], - [8.33548601], - [8.31669867], - [8.31061392]]) - input_values:fuel_flow_rate_negative_total |17397.30457641| input lbm/h traj.cruise.timeseries.input_values:fuel_flow_rate_negative_total - val: - array([[-4076.58910351], - [-4060.87736702], - [-4039.25960572], - [-4032.43234269], - [-4032.43234269], - [-4000.59756274], - [-3956.92577962], - [-3943.16512475], - [-3943.16512475], - [-3905.85169075], - [-3854.72288485], - [-3838.62390368], - [-3838.62390368], - [-3807.74479615], - [-3765.39201751], - [-3752.04620486], - [-3752.04620486], - [-3737.11585247], - [-3716.57322856], - [-3710.08561764]]) - input_values:electric_power_in_total |0.0| input kW traj.cruise.timeseries.input_values:electric_power_in_total - val: - array([[0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.]]) - input_values:altitude_rate |0.8794761| input ft/s traj.cruise.timeseries.input_values:altitude_rate - val: - array([[0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683]]) - input_values:throttle |2.78644451| input unitless traj.cruise.timeseries.input_values:throttle - val: - array([[0.62030938], - [0.62046836], - [0.62070005], - [0.62077638], - [0.62077638], - [0.62115279], - [0.62172604], - [0.62192082], - [0.62192082], - [0.62248454], - [0.62334458], - [0.62363676], - [0.62363676], - [0.6242272 ], - [0.62510335], - [0.62539589], - [0.62539589], - [0.62573279], - [0.62621334], - [0.62636927]]) - input_values:velocity |963.55047191| input m/s traj.cruise.timeseries.input_values:velocity - val: - array([[216.42809923], - [216.34879353], - [216.23932113], - [216.20466219], - [216.20466219], - [216.04250323], - [215.81856126], - [215.74763702], - [215.74763702], - [215.55443278], - [215.28757185], - [215.20304383], - [215.20304383], - [215.04014595], - [214.81518168], - [214.74393321], - [214.74393321], - [214.66401882], - [214.55370544], - [214.51878007]]) - input_values:altitude |147700.4084954| input ft traj.cruise.timeseries.input_values:altitude - val: - array([[32000. ], - [32083.41734823], - [32198.51626306], - [32234.94467607], - [32234.94467607], - [32405.30661107], - [32640.37131001], - [32714.76848352], - [32714.76848352], - [32917.31196851], - [33196.78063808], - [33285.23151648], - [33285.23151648], - [33455.59345148], - [33690.65815042], - [33765.05532393], - [33765.05532393], - [33848.47267216], - [33963.57158699], - [34000. ]]) - input_values:time |43155.65216817| input s traj.cruise.timeseries.input_values:time - val: - array([[ 3840. ], - [ 4264.17721573], - [ 4849.45519765], - [ 5034.69367782], - [ 5034.69367782], - [ 5900.9841173 ], - [ 7096.28811139], - [ 7474.5977387 ], - [ 7474.5977387 ], - [ 8504.53135987], - [ 9925.62954466], - [10375.4022613 ], - [10375.4022613 ], - [11241.69270078], - [12436.99669488], - [12815.30632218], - [12815.30632218], - [13239.48353791], - [13824.76151983], - [14010. ]]) - input_values:time_phase |27763.66679782| input s traj.cruise.timeseries.input_values:time_phase - val: - array([[ 0. ], - [ 424.17721573], - [ 1009.45519765], - [ 1194.69367782], - [ 1194.69367782], - [ 2060.9841173 ], - [ 3256.28811139], - [ 3634.5977387 ], - [ 3634.5977387 ], - [ 4664.53135987], - [ 6085.62954466], - [ 6535.4022613 ], - [ 6535.4022613 ], - [ 7401.69270078], - [ 8596.99669488], - [ 8975.30632218], - [ 8975.30632218], - [ 9399.48353791], - [ 9984.76151983], - [10170. ]]) - input_values:mach_rate |0.0| input unitless/s traj.cruise.timeseries.input_values:mach_rate - val: - array([[ 0.00000000e+00], - [ 8.73331779e-20], - [ 4.36665890e-20], - [ 0.00000000e+00], - [ 0.00000000e+00], - [ 3.27499417e-20], - [ 2.18332945e-20], - [ 0.00000000e+00], - [ 0.00000000e+00], - [-4.36665890e-20], - [-6.54998835e-20], - [-4.36665890e-20], - [-4.36665890e-20], - [-4.91249126e-20], - [-2.18332945e-20], - [ 8.73331779e-20], - [ 8.73331779e-20], - [-8.73331779e-20], - [ 0.00000000e+00], - [ 1.74666356e-19]]) - input_values:mass |243577.62672176| input kg traj.cruise.timeseries.input_values:mass - val: - array([[57015.39290411], - [56797.93787223], - [56499.27092781], - [56405.0756841 ], - [56405.0756841 ], - [55966.67143281], - [55367.45066061], - [55179.16707729], - [55179.16707729], - [54669.88811206], - [53975.10803913], - [53757.11559708], - [53757.11559708], - [53339.81352995], - [52769.53817769], - [52590.37433179], - [52590.37433179], - [52390.24374586], - [52115.41253722], - [52028.74471935]]) - input_values:distance |8196715.33458363| input m traj.cruise.timeseries.input_values:distance - val: - array([[ 560039.40638961], - [ 651826.45257603], - [ 778418.59972934], - [ 818471.23138883], - [ 818471.23138883], - [1005697.02623753], - [1263799.66653641], - [1345432.48793709], - [1345432.48793709], - [1567538.74520054], - [1873673.16694925], - [1970484.63129816], - [1970484.63129816], - [2156842.41376365], - [2413746.32168934], - [2494999.4935999 ], - [2494999.4935999 ], - [2586072.02583254], - [2711677.86536452], - [2751418.23144865]]) - mach |3.21993789| output unitless traj.cruise.timeseries.mach - val: - array([[0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72]]) - thrust_net_total |31225.04562526| output lbf traj.cruise.timeseries.thrust_net_total - val: - array([[7283.97100791], - [7258.38824181], - [7223.22226111], - [7212.12430625], - [7212.12430625], - [7160.42784354], - [7089.6523824 ], - [7067.38680815], - [7067.38680815], - [7007.0989486 ], - [6924.70247135], - [6898.80938625], - [6898.80938625], - [6849.18729088], - [6781.26041265], - [6759.89308244], - [6759.89308244], - [6736.01041873], - [6703.18821962], - [6692.83181316]]) - drag |31075.67524118| output lbf traj.cruise.timeseries.drag - val: - array([[7249.15838542], - [7223.69568126], - [7188.69465737], - [7177.64874096], - [7177.64874096], - [7126.19456118], - [7055.75048551], - [7033.58909177], - [7033.58909177], - [6973.58315624], - [6891.57160251], - [6865.79936432], - [6865.79936432], - [6816.40870516], - [6748.79831449], - [6727.53046622], - [6727.53046622], - [6703.75895516], - [6671.0894471 ], - [6660.78120358]]) - specific_energy_rate_excess |37.75301942| output m/s traj.cruise.timeseries.specific_energy_rate_excess - val: - array([[8.55190129], - [8.5453959 ], - [8.53594173], - [8.53283337], - [8.53283337], - [8.5175461 ], - [8.49438705], - [8.48654893], - [8.48654893], - [8.46394686], - [8.42967295], - [8.41807454], - [8.41807454], - [8.39470149], - [8.36017624], - [8.34868973], - [8.34868973], - [8.33548601], - [8.31669867], - [8.31061392]]) - fuel_flow_rate_negative_total |17397.30457641| output lbm/h traj.cruise.timeseries.fuel_flow_rate_negative_total - val: - array([[-4076.58910351], - [-4060.87736702], - [-4039.25960572], - [-4032.43234269], - [-4032.43234269], - [-4000.59756274], - [-3956.92577962], - [-3943.16512475], - [-3943.16512475], - [-3905.85169075], - [-3854.72288485], - [-3838.62390368], - [-3838.62390368], - [-3807.74479615], - [-3765.39201751], - [-3752.04620486], - [-3752.04620486], - [-3737.11585247], - [-3716.57322856], - [-3710.08561764]]) - electric_power_in_total |0.0| output kW traj.cruise.timeseries.electric_power_in_total - val: - array([[0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.]]) - altitude_rate |0.8794761| output ft/s traj.cruise.timeseries.altitude_rate - val: - array([[0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683]]) - throttle |2.78644451| output unitless traj.cruise.timeseries.throttle - val: - array([[0.62030938], - [0.62046836], - [0.62070005], - [0.62077638], - [0.62077638], - [0.62115279], - [0.62172604], - [0.62192082], - [0.62192082], - [0.62248454], - [0.62334458], - [0.62363676], - [0.62363676], - [0.6242272 ], - [0.62510335], - [0.62539589], - [0.62539589], - [0.62573279], - [0.62621334], - [0.62636927]]) - velocity |963.55047191| output m/s traj.cruise.timeseries.velocity - val: - array([[216.42809923], - [216.34879353], - [216.23932113], - [216.20466219], - [216.20466219], - [216.04250323], - [215.81856126], - [215.74763702], - [215.74763702], - [215.55443278], - [215.28757185], - [215.20304383], - [215.20304383], - [215.04014595], - [214.81518168], - [214.74393321], - [214.74393321], - [214.66401882], - [214.55370544], - [214.51878007]]) - altitude |147700.4084954| output ft traj.cruise.timeseries.altitude - val: - array([[32000. ], - [32083.41734823], - [32198.51626306], - [32234.94467607], - [32234.94467607], - [32405.30661107], - [32640.37131001], - [32714.76848352], - [32714.76848352], - [32917.31196851], - [33196.78063808], - [33285.23151648], - [33285.23151648], - [33455.59345148], - [33690.65815042], - [33765.05532393], - [33765.05532393], - [33848.47267216], - [33963.57158699], - [34000. ]]) - time |43155.65216817| output s traj.cruise.timeseries.time - val: - array([[ 3840. ], - [ 4264.17721573], - [ 4849.45519765], - [ 5034.69367782], - [ 5034.69367782], - [ 5900.9841173 ], - [ 7096.28811139], - [ 7474.5977387 ], - [ 7474.5977387 ], - [ 8504.53135987], - [ 9925.62954466], - [10375.4022613 ], - [10375.4022613 ], - [11241.69270078], - [12436.99669488], - [12815.30632218], - [12815.30632218], - [13239.48353791], - [13824.76151983], - [14010. ]]) - time_phase |27763.66679782| output s traj.cruise.timeseries.time_phase - val: - array([[ 0. ], - [ 424.17721573], - [ 1009.45519765], - [ 1194.69367782], - [ 1194.69367782], - [ 2060.9841173 ], - [ 3256.28811139], - [ 3634.5977387 ], - [ 3634.5977387 ], - [ 4664.53135987], - [ 6085.62954466], - [ 6535.4022613 ], - [ 6535.4022613 ], - [ 7401.69270078], - [ 8596.99669488], - [ 8975.30632218], - [ 8975.30632218], - [ 9399.48353791], - [ 9984.76151983], - [10170. ]]) - mach_rate |0.0| output unitless/s traj.cruise.timeseries.mach_rate - val: - array([[ 0.00000000e+00], - [ 8.73331779e-20], - [ 4.36665890e-20], - [ 0.00000000e+00], - [ 0.00000000e+00], - [ 3.27499417e-20], - [ 2.18332945e-20], - [ 0.00000000e+00], - [ 0.00000000e+00], - [-4.36665890e-20], - [-6.54998835e-20], - [-4.36665890e-20], - [-4.36665890e-20], - [-4.91249126e-20], - [-2.18332945e-20], - [ 8.73331779e-20], - [ 8.73331779e-20], - [-8.73331779e-20], - [ 0.00000000e+00], - [ 1.74666356e-19]]) - mass |243577.62672176| output kg traj.cruise.timeseries.mass - val: - array([[57015.39290411], - [56797.93787223], - [56499.27092781], - [56405.0756841 ], - [56405.0756841 ], - [55966.67143281], - [55367.45066061], - [55179.16707729], - [55179.16707729], - [54669.88811206], - [53975.10803913], - [53757.11559708], - [53757.11559708], - [53339.81352995], - [52769.53817769], - [52590.37433179], - [52590.37433179], - [52390.24374586], - [52115.41253722], - [52028.74471935]]) - distance |8196715.33458363| output m traj.cruise.timeseries.distance - val: - array([[ 560039.40638961], - [ 651826.45257603], - [ 778418.59972934], - [ 818471.23138883], - [ 818471.23138883], - [1005697.02623753], - [1263799.66653641], - [1345432.48793709], - [1345432.48793709], - [1567538.74520054], - [1873673.16694925], - [1970484.63129816], - [1970484.63129816], - [2156842.41376365], - [2413746.32168934], - [2494999.4935999 ], - [2494999.4935999 ], - [2586072.02583254], - [2711677.86536452], - [2751418.23144865]]) - mission_bus_variables - dt_dstau |4814.09560547| input s traj.cruise.mission_bus_variables.dt_dstau - val: - array([ 597.34683891, 597.34683891, 597.34683891, 597.34683891, - 1219.95203044, 1219.95203044, 1219.95203044, 1219.95203044, - 1450.4022613 , 1450.4022613 , 1450.4022613 , 1450.4022613 , - 1219.95203044, 1219.95203044, 1219.95203044, 1219.95203044, - 597.34683891, 597.34683891, 597.34683891, 597.34683891]) - input_values:mach |3.21993789| input unitless traj.cruise.mission_bus_variables.input_values:mach - val: - array([[0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72]]) - input_values:thrust_net_total |31225.04562526| input lbf traj.cruise.mission_bus_variables.input_values:thrust_net_total - val: - array([[7283.97100791], - [7258.38824181], - [7223.22226111], - [7212.12430625], - [7212.12430625], - [7160.42784354], - [7089.6523824 ], - [7067.38680815], - [7067.38680815], - [7007.0989486 ], - [6924.70247135], - [6898.80938625], - [6898.80938625], - [6849.18729088], - [6781.26041265], - [6759.89308244], - [6759.89308244], - [6736.01041873], - [6703.18821962], - [6692.83181316]]) - input_values:drag |31075.67524118| input lbf traj.cruise.mission_bus_variables.input_values:drag - val: - array([[7249.15838542], - [7223.69568126], - [7188.69465737], - [7177.64874096], - [7177.64874096], - [7126.19456118], - [7055.75048551], - [7033.58909177], - [7033.58909177], - [6973.58315624], - [6891.57160251], - [6865.79936432], - [6865.79936432], - [6816.40870516], - [6748.79831449], - [6727.53046622], - [6727.53046622], - [6703.75895516], - [6671.0894471 ], - [6660.78120358]]) - input_values:specific_energy_rate_excess |37.75301942| input m/s traj.cruise.mission_bus_variables.input_values:specific_energy_rate_excess - val: - array([[8.55190129], - [8.5453959 ], - [8.53594173], - [8.53283337], - [8.53283337], - [8.5175461 ], - [8.49438705], - [8.48654893], - [8.48654893], - [8.46394686], - [8.42967295], - [8.41807454], - [8.41807454], - [8.39470149], - [8.36017624], - [8.34868973], - [8.34868973], - [8.33548601], - [8.31669867], - [8.31061392]]) - input_values:fuel_flow_rate_negative_total |17397.30457641| input lbm/h traj.cruise.mission_bus_variables.input_values:fuel_flow_rate_negative_total - val: - array([[-4076.58910351], - [-4060.87736702], - [-4039.25960572], - [-4032.43234269], - [-4032.43234269], - [-4000.59756274], - [-3956.92577962], - [-3943.16512475], - [-3943.16512475], - [-3905.85169075], - [-3854.72288485], - [-3838.62390368], - [-3838.62390368], - [-3807.74479615], - [-3765.39201751], - [-3752.04620486], - [-3752.04620486], - [-3737.11585247], - [-3716.57322856], - [-3710.08561764]]) - input_values:electric_power_in_total |0.0| input kW traj.cruise.mission_bus_variables.input_values:electric_power_in_total - val: - array([[0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.]]) - input_values:altitude_rate |0.8794761| input ft/s traj.cruise.mission_bus_variables.input_values:altitude_rate - val: - array([[0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683]]) - input_values:throttle |2.78644451| input unitless traj.cruise.mission_bus_variables.input_values:throttle - val: - array([[0.62030938], - [0.62046836], - [0.62070005], - [0.62077638], - [0.62077638], - [0.62115279], - [0.62172604], - [0.62192082], - [0.62192082], - [0.62248454], - [0.62334458], - [0.62363676], - [0.62363676], - [0.6242272 ], - [0.62510335], - [0.62539589], - [0.62539589], - [0.62573279], - [0.62621334], - [0.62636927]]) - input_values:velocity |963.55047191| input m/s traj.cruise.mission_bus_variables.input_values:velocity - val: - array([[216.42809923], - [216.34879353], - [216.23932113], - [216.20466219], - [216.20466219], - [216.04250323], - [215.81856126], - [215.74763702], - [215.74763702], - [215.55443278], - [215.28757185], - [215.20304383], - [215.20304383], - [215.04014595], - [214.81518168], - [214.74393321], - [214.74393321], - [214.66401882], - [214.55370544], - [214.51878007]]) - input_values:altitude |147700.4084954| input ft traj.cruise.mission_bus_variables.input_values:altitude - val: - array([[32000. ], - [32083.41734823], - [32198.51626306], - [32234.94467607], - [32234.94467607], - [32405.30661107], - [32640.37131001], - [32714.76848352], - [32714.76848352], - [32917.31196851], - [33196.78063808], - [33285.23151648], - [33285.23151648], - [33455.59345148], - [33690.65815042], - [33765.05532393], - [33765.05532393], - [33848.47267216], - [33963.57158699], - [34000. ]]) - input_values:time |43155.65216817| input s traj.cruise.mission_bus_variables.input_values:time - val: - array([[ 3840. ], - [ 4264.17721573], - [ 4849.45519765], - [ 5034.69367782], - [ 5034.69367782], - [ 5900.9841173 ], - [ 7096.28811139], - [ 7474.5977387 ], - [ 7474.5977387 ], - [ 8504.53135987], - [ 9925.62954466], - [10375.4022613 ], - [10375.4022613 ], - [11241.69270078], - [12436.99669488], - [12815.30632218], - [12815.30632218], - [13239.48353791], - [13824.76151983], - [14010. ]]) - input_values:time_phase |27763.66679782| input s traj.cruise.mission_bus_variables.input_values:time_phase - val: - array([[ 0. ], - [ 424.17721573], - [ 1009.45519765], - [ 1194.69367782], - [ 1194.69367782], - [ 2060.9841173 ], - [ 3256.28811139], - [ 3634.5977387 ], - [ 3634.5977387 ], - [ 4664.53135987], - [ 6085.62954466], - [ 6535.4022613 ], - [ 6535.4022613 ], - [ 7401.69270078], - [ 8596.99669488], - [ 8975.30632218], - [ 8975.30632218], - [ 9399.48353791], - [ 9984.76151983], - [10170. ]]) - input_values:mach_rate |0.0| input unitless/s traj.cruise.mission_bus_variables.input_values:mach_rate - val: - array([[ 0.00000000e+00], - [ 8.73331779e-20], - [ 4.36665890e-20], - [ 0.00000000e+00], - [ 0.00000000e+00], - [ 3.27499417e-20], - [ 2.18332945e-20], - [ 0.00000000e+00], - [ 0.00000000e+00], - [-4.36665890e-20], - [-6.54998835e-20], - [-4.36665890e-20], - [-4.36665890e-20], - [-4.91249126e-20], - [-2.18332945e-20], - [ 8.73331779e-20], - [ 8.73331779e-20], - [-8.73331779e-20], - [ 0.00000000e+00], - [ 1.74666356e-19]]) - input_values:mass |243577.62672176| input kg traj.cruise.mission_bus_variables.input_values:mass - val: - array([[57015.39290411], - [56797.93787223], - [56499.27092781], - [56405.0756841 ], - [56405.0756841 ], - [55966.67143281], - [55367.45066061], - [55179.16707729], - [55179.16707729], - [54669.88811206], - [53975.10803913], - [53757.11559708], - [53757.11559708], - [53339.81352995], - [52769.53817769], - [52590.37433179], - [52590.37433179], - [52390.24374586], - [52115.41253722], - [52028.74471935]]) - input_values:distance |8196715.33458363| input m traj.cruise.mission_bus_variables.input_values:distance - val: - array([[ 560039.40638961], - [ 651826.45257603], - [ 778418.59972934], - [ 818471.23138883], - [ 818471.23138883], - [1005697.02623753], - [1263799.66653641], - [1345432.48793709], - [1345432.48793709], - [1567538.74520054], - [1873673.16694925], - [1970484.63129816], - [1970484.63129816], - [2156842.41376365], - [2413746.32168934], - [2494999.4935999 ], - [2494999.4935999 ], - [2586072.02583254], - [2711677.86536452], - [2751418.23144865]]) - mach |2.78854801| output unitless traj.cruise.mission_bus_variables.mach - val: - array([[0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72], - [0.72]]) - thrust_net_total |27059.7506392| output lbf traj.cruise.mission_bus_variables.thrust_net_total - val: - array([[7283.97100791], - [7222.76993971], - [7162.03304682], - [7162.03304682], - [7101.76183506], - [7041.95764492], - [7041.95764492], - [6982.6259213 ], - [6923.75849779], - [6923.75849779], - [6865.34407699], - [6807.38342407], - [6807.38342407], - [6749.87860684], - [6692.83181316]]) - drag |26930.30868092| output lbf traj.cruise.mission_bus_variables.drag - val: - array([[7249.15838542], - [7188.2444571 ], - [7127.79224443], - [7127.79224443], - [7067.80326401], - [7008.27886715], - [7008.27886715], - [6949.22450959], - [6890.63203568], - [6890.63203568], - [6832.49015876], - [6774.79965532], - [6774.79965532], - [6717.56260424], - [6660.78120358]]) - specific_energy_rate_excess |32.71327904| output m/s traj.cruise.mission_bus_variables.specific_energy_rate_excess - val: - array([[8.55190129], - [8.53581622], - [8.5180411 ], - [8.5180411 ], - [8.49853731], - [8.47726597], - [8.47726597], - [8.45418023], - [8.42925716], - [8.42925716], - [8.4024794 ], - [8.37380788], - [8.37380788], - [8.34320043], - [8.31061392]]) - fuel_flow_rate_negative_total |15077.90378893| output lbm/h traj.cruise.mission_bus_variables.fuel_flow_rate_negative_total - val: - array([[-4076.58910351], - [-4038.98139242], - [-4001.58685424], - [-4001.58685424], - [-3964.40528187], - [-3927.43635038], - [-3927.43635038], - [-3890.68162598], - [-3854.13623888], - [-3854.13623888], - [-3817.80397591], - [-3781.69244616], - [-3781.69244616], - [-3745.78735803], - [-3710.08561764]]) - electric_power_in_total |0.0| output kW traj.cruise.mission_bus_variables.electric_power_in_total - val: - array([[0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.]]) - altitude_rate |0.76164864| output ft/s traj.cruise.mission_bus_variables.altitude_rate - val: - array([[0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683], - [0.19665683]]) - throttle |2.41264855| output unitless traj.cruise.mission_bus_variables.throttle - val: - array([[0.62030938], - [0.62070313], - [0.62114057], - [0.62114057], - [0.62162306], - [0.62215196], - [0.62215196], - [0.62272905], - [0.62335505], - [0.62335505], - [0.62403048], - [0.62475686], - [0.62475686], - [0.62553587], - [0.62636927]]) - velocity |834.53311829| output m/s traj.cruise.mission_bus_variables.velocity - val: - array([[216.42809923], - [216.23790957], - [216.04755612], - [216.04755612], - [215.85703846], - [215.66635615], - [215.66635615], - [215.47550876], - [215.28449584], - [215.28449584], - [215.09331695], - [214.90197166], - [214.90197166], - [214.71045951], - [214.51878007]]) - altitude |127828.79174896| output ft traj.cruise.mission_bus_variables.altitude - val: - array([[32000.], - [32200.], - [32400.], - [32400.], - [32600.], - [32800.], - [32800.], - [33000.], - [33200.], - [33200.], - [33400.], - [33600.], - [33600.], - [33800.], - [34000.]]) - time |36459.4561808| output s traj.cruise.mission_bus_variables.time - val: - array([[ 3840.], - [ 4857.], - [ 5874.], - [ 5874.], - [ 6891.], - [ 7908.], - [ 7908.], - [ 8925.], - [ 9942.], - [ 9942.], - [10959.], - [11976.], - [11976.], - [12993.], - [14010.]]) - time_phase |22854.23254017| output s traj.cruise.mission_bus_variables.time_phase - val: - array([[ 0.], - [ 1017.], - [ 2034.], - [ 2034.], - [ 3051.], - [ 4068.], - [ 4068.], - [ 5085.], - [ 6102.], - [ 6102.], - [ 7119.], - [ 8136.], - [ 8136.], - [ 9153.], - [10170.]]) - mach_rate |0.0| output unitless/s traj.cruise.mission_bus_variables.mach_rate - val: - array([[ 0.00000000e+00], - [ 4.21226452e-20], - [ 3.21535108e-20], - [ 3.21535108e-20], - [ 2.95885122e-20], - [-1.70675411e-20], - [-1.70675411e-20], - [-5.96326498e-20], - [-6.50288885e-20], - [-6.50288885e-20], - [-3.42111904e-20], - [-7.15043654e-20], - [-7.15043654e-20], - [ 4.28728963e-21], - [ 1.74666356e-19]]) - mass |211091.10966044| output kg traj.cruise.mission_bus_variables.mass - val: - array([[57015.39290411], - [56495.43122231], - [55980.27491257], - [55980.27491257], - [55469.89668958], - [54964.26925183], - [54964.26925183], - [54463.36530601], - [53967.15772816], - [53967.15772816], - [53475.6194842 ], - [52988.7226521 ], - [52988.7226521 ], - [52506.43974513], - [52028.74471935]]) - distance |6887901.12410551| output m traj.cruise.mission_bus_variables.distance - val: - array([[ 560039.40638961], - [ 780050.07727996], - [ 999867.2420398 ], - [ 999867.2420398 ], - [1219490.73383222], - [1438920.38552 ], - [1438920.38552 ], - [1658156.02936447], - [1877197.49721605], - [1877197.49721605], - [2096044.62065779], - [2314697.23052702], - [2314697.23052702], - [2533155.15743856], - [2751418.23144865]]) - collocation_constraint - dt_dstau |4169.12909058| input s traj.cruise.collocation_constraint.dt_dstau - val: - array([ 597.34683891, 597.34683891, 597.34683891, 1219.95203044, - 1219.95203044, 1219.95203044, 1450.4022613 , 1450.4022613 , - 1450.4022613 , 1219.95203044, 1219.95203044, 1219.95203044, - 597.34683891, 597.34683891, 597.34683891]) - f_approx:mass |1.90369215| input kg/s traj.cruise.collocation_constraint.f_approx:mass - val: - array([[-0.51364159], - [-0.51166194], - [-0.50893815], - [-0.50807793], - [-0.50406681], - [-0.49856426], - [-0.49683045], - [-0.49212903], - [-0.48568691], - [-0.48365848], - [-0.47976777], - [-0.47443141], - [-0.47274987], - [-0.47086868], - [-0.46828035]]) - f_computed:mass |1.90369215| input kg/s traj.cruise.collocation_constraint.f_computed:mass - val: - array([[-0.51364159], - [-0.51166194], - [-0.50893815], - [-0.50807793], - [-0.50406681], - [-0.49856426], - [-0.49683045], - [-0.49212903], - [-0.48568691], - [-0.48365848], - [-0.47976777], - [-0.47443141], - [-0.47274987], - [-0.47086868], - [-0.46828035]]) - f_approx:distance |834.68098413| input m/s traj.cruise.collocation_constraint.f_approx:distance - val: - array([[216.42809093], - [216.34878522], - [216.23931282], - [216.20465388], - [216.04249491], - [215.81855294], - [215.7476287 ], - [215.55442444], - [215.28756351], - [215.20303548], - [215.04013759], - [214.81517331], - [214.74392485], - [214.66401045], - [214.55369706]]) - f_computed:distance |834.68098413| input m/s traj.cruise.collocation_constraint.f_computed:distance - val: - array([[216.42809093], - [216.34878522], - [216.23931282], - [216.20465388], - [216.04249491], - [215.81855294], - [215.7476287 ], - [215.55442444], - [215.28756351], - [215.20303548], - [215.04013759], - [214.81517331], - [214.74392485], - [214.66401045], - [214.55369706]]) - defects:mass |0.0| output kg traj.cruise.collocation_constraint.defects:mass - val: - array([[ 2.58643404e-12], - [-6.63188214e-12], - [-1.45901407e-12], - [-2.50567484e-11], - [ 2.87136793e-11], - [-8.87144336e-12], - [ 9.56500371e-11], - [-9.17853892e-12], - [ 9.74213341e-12], - [ 3.56889363e-11], - [-6.43348946e-12], - [ 3.31832614e-12], - [ 7.45423553e-11], - [-2.18520517e-11], - [ 3.71385400e-12]]) - defects:distance |0.0| output m traj.cruise.collocation_constraint.defects:distance - val: - array([[-6.28171877e-10], - [ 2.88619511e-10], - [ 5.09328549e-11], - [-5.54769954e-10], - [-1.38692489e-10], - [-2.42711855e-10], - [ 2.18481432e-09], - [-4.12229116e-11], - [ 5.35897851e-10], - [-2.46179167e-09], - [ 5.89443076e-10], - [-4.85423710e-10], - [ 2.56362036e-09], - [ 5.94216640e-10], - [-1.44309755e-09]]) - descent - param_comp - t_initial [14010.] input s traj.descent.t_initial - t_duration [4548.94581634] input s traj.descent.t_duration - parameters:aircraft:design:base_area [0.] input ft**2 traj.descent.parameters:aircraft:design:base_area - parameters:aircraft:design:lift_dependent_drag_coeff_factor [0.90983938] input unitless traj.descent.parameters:aircraft:design:lift_dependent_drag_coeff_factor - parameters:aircraft:design:subsonic_drag_coeff_factor [1.] input unitless traj.descent.parameters:aircraft:design:subsonic_drag_coeff_factor - parameters:aircraft:design:supersonic_drag_coeff_factor [1.] input unitless traj.descent.parameters:aircraft:design:supersonic_drag_coeff_factor - parameters:aircraft:design:zero_lift_drag_coeff_factor [0.93089003] input unitless traj.descent.parameters:aircraft:design:zero_lift_drag_coeff_factor - parameters:aircraft:fuselage:characteristic_length [128.] input ft traj.descent.parameters:aircraft:fuselage:characteristic_length - parameters:aircraft:fuselage:cross_section [127.67628894] input ft**2 traj.descent.parameters:aircraft:fuselage:cross_section - parameters:aircraft:fuselage:diameter_to_wing_span [0.10826471] input unitless traj.descent.parameters:aircraft:fuselage:diameter_to_wing_span - parameters:aircraft:fuselage:fineness [10.03921569] input unitless traj.descent.parameters:aircraft:fuselage:fineness - parameters:aircraft:fuselage:laminar_flow_lower [0.] input unitless traj.descent.parameters:aircraft:fuselage:laminar_flow_lower - parameters:aircraft:fuselage:laminar_flow_upper [0.] input unitless traj.descent.parameters:aircraft:fuselage:laminar_flow_upper - parameters:aircraft:fuselage:length_to_diameter [10.03921569] input unitless traj.descent.parameters:aircraft:fuselage:length_to_diameter - parameters:aircraft:fuselage:wetted_area [4158.62] input ft**2 traj.descent.parameters:aircraft:fuselage:wetted_area - parameters:aircraft:horizontal_tail:characteristic_length [7.69198717] input ft traj.descent.parameters:aircraft:horizontal_tail:characteristic_length - parameters:aircraft:horizontal_tail:fineness [0.125] input unitless traj.descent.parameters:aircraft:horizontal_tail:fineness - parameters:aircraft:horizontal_tail:laminar_flow_lower [0.] input unitless traj.descent.parameters:aircraft:horizontal_tail:laminar_flow_lower - parameters:aircraft:horizontal_tail:laminar_flow_upper [0.] input unitless traj.descent.parameters:aircraft:horizontal_tail:laminar_flow_upper - parameters:aircraft:horizontal_tail:wetted_area [592.65] input ft**2 traj.descent.parameters:aircraft:horizontal_tail:wetted_area - parameters:aircraft:vertical_tail:characteristic_length [12.73914103] input ft traj.descent.parameters:aircraft:vertical_tail:characteristic_length - parameters:aircraft:vertical_tail:fineness [0.1195] input unitless traj.descent.parameters:aircraft:vertical_tail:fineness - parameters:aircraft:vertical_tail:laminar_flow_lower [0.] input unitless traj.descent.parameters:aircraft:vertical_tail:laminar_flow_lower - parameters:aircraft:vertical_tail:laminar_flow_upper [0.] input unitless traj.descent.parameters:aircraft:vertical_tail:laminar_flow_upper - parameters:aircraft:vertical_tail:wetted_area [581.13] input ft**2 traj.descent.parameters:aircraft:vertical_tail:wetted_area - parameters:aircraft:wing:area [1370.] input ft**2 traj.descent.parameters:aircraft:wing:area - parameters:aircraft:wing:aspect_ratio [11.22091] input unitless traj.descent.parameters:aircraft:wing:aspect_ratio - parameters:aircraft:wing:characteristic_length [10.49530819] input ft traj.descent.parameters:aircraft:wing:characteristic_length - parameters:aircraft:wing:fineness [0.13] input unitless traj.descent.parameters:aircraft:wing:fineness - parameters:aircraft:wing:laminar_flow_lower [0.] input unitless traj.descent.parameters:aircraft:wing:laminar_flow_lower - parameters:aircraft:wing:laminar_flow_upper [0.] input unitless traj.descent.parameters:aircraft:wing:laminar_flow_upper - parameters:aircraft:wing:max_camber_at_70_semispan [0.] input unitless traj.descent.parameters:aircraft:wing:max_camber_at_70_semispan - parameters:aircraft:wing:span_efficiency_factor [1.] input unitless traj.descent.parameters:aircraft:wing:span_efficiency_factor - parameters:aircraft:wing:sweep [25.] input deg traj.descent.parameters:aircraft:wing:sweep - parameters:aircraft:wing:taper_ratio [0.278] input unitless traj.descent.parameters:aircraft:wing:taper_ratio - parameters:aircraft:wing:thickness_to_chord [0.13] input unitless traj.descent.parameters:aircraft:wing:thickness_to_chord - parameters:aircraft:wing:wetted_area [2396.56] input ft**2 traj.descent.parameters:aircraft:wing:wetted_area - parameters:mission:design:lift_coefficient [0.56736557] input unitless traj.descent.parameters:mission:design:lift_coefficient - parameters:mission:design:mach [0.80017085] input unitless traj.descent.parameters:mission:design:mach - parameters:aircraft:nacelle:characteristic_length [12.3] input ft traj.descent.parameters:aircraft:nacelle:characteristic_length - parameters:aircraft:nacelle:fineness [1.54911839] input unitless traj.descent.parameters:aircraft:nacelle:fineness - parameters:aircraft:nacelle:laminar_flow_lower [0.] input unitless traj.descent.parameters:aircraft:nacelle:laminar_flow_lower - parameters:aircraft:nacelle:laminar_flow_upper [0.] input unitless traj.descent.parameters:aircraft:nacelle:laminar_flow_upper - parameters:aircraft:nacelle:wetted_area [273.4536] input ft**2 traj.descent.parameters:aircraft:nacelle:wetted_area - parameters:aircraft:engine:scale_factor [1.] input unitless traj.descent.parameters:aircraft:engine:scale_factor - t_initial_val [14010.] output s traj.descent.t_initial_val - t_duration_val [4548.94581634] output s traj.descent.t_duration_val - parameter_vals:aircraft:design:base_area [[0.]] output ft**2 traj.descent.parameter_vals:aircraft:design:base_area - parameter_vals:aircraft:design:lift_dependent_drag_coeff_factor [[0.90983938]] output unitless traj.descent.parameter_vals:aircraft:design:lift_dependent_drag_coeff_factor - parameter_vals:aircraft:design:subsonic_drag_coeff_factor [[1.]] output unitless traj.descent.parameter_vals:aircraft:design:subsonic_drag_coeff_factor - parameter_vals:aircraft:design:supersonic_drag_coeff_factor [[1.]] output unitless traj.descent.parameter_vals:aircraft:design:supersonic_drag_coeff_factor - parameter_vals:aircraft:design:zero_lift_drag_coeff_factor [[0.93089003]] output unitless traj.descent.parameter_vals:aircraft:design:zero_lift_drag_coeff_factor - parameter_vals:aircraft:fuselage:characteristic_length [[128.]] output ft traj.descent.parameter_vals:aircraft:fuselage:characteristic_length - parameter_vals:aircraft:fuselage:cross_section [[127.67628894]] output ft**2 traj.descent.parameter_vals:aircraft:fuselage:cross_section - parameter_vals:aircraft:fuselage:diameter_to_wing_span [[0.10826471]] output unitless traj.descent.parameter_vals:aircraft:fuselage:diameter_to_wing_span - parameter_vals:aircraft:fuselage:fineness [[10.03921569]] output unitless traj.descent.parameter_vals:aircraft:fuselage:fineness - parameter_vals:aircraft:fuselage:laminar_flow_lower [[0.]] output unitless traj.descent.parameter_vals:aircraft:fuselage:laminar_flow_lower - parameter_vals:aircraft:fuselage:laminar_flow_upper [[0.]] output unitless traj.descent.parameter_vals:aircraft:fuselage:laminar_flow_upper - parameter_vals:aircraft:fuselage:length_to_diameter [[10.03921569]] output unitless traj.descent.parameter_vals:aircraft:fuselage:length_to_diameter - parameter_vals:aircraft:fuselage:wetted_area [[4158.62]] output ft**2 traj.descent.parameter_vals:aircraft:fuselage:wetted_area - parameter_vals:aircraft:horizontal_tail:characteristic_length [[7.69198717]] output ft traj.descent.parameter_vals:aircraft:horizontal_tail:characteristic_length - parameter_vals:aircraft:horizontal_tail:fineness [[0.125]] output unitless traj.descent.parameter_vals:aircraft:horizontal_tail:fineness - parameter_vals:aircraft:horizontal_tail:laminar_flow_lower [[0.]] output unitless traj.descent.parameter_vals:aircraft:horizontal_tail:laminar_flow_lower - parameter_vals:aircraft:horizontal_tail:laminar_flow_upper [[0.]] output unitless traj.descent.parameter_vals:aircraft:horizontal_tail:laminar_flow_upper - parameter_vals:aircraft:horizontal_tail:wetted_area [[592.65]] output ft**2 traj.descent.parameter_vals:aircraft:horizontal_tail:wetted_area - parameter_vals:aircraft:vertical_tail:characteristic_length [[12.73914103]] output ft traj.descent.parameter_vals:aircraft:vertical_tail:characteristic_length - parameter_vals:aircraft:vertical_tail:fineness [[0.1195]] output unitless traj.descent.parameter_vals:aircraft:vertical_tail:fineness - parameter_vals:aircraft:vertical_tail:laminar_flow_lower [[0.]] output unitless traj.descent.parameter_vals:aircraft:vertical_tail:laminar_flow_lower - parameter_vals:aircraft:vertical_tail:laminar_flow_upper [[0.]] output unitless traj.descent.parameter_vals:aircraft:vertical_tail:laminar_flow_upper - parameter_vals:aircraft:vertical_tail:wetted_area [[581.13]] output ft**2 traj.descent.parameter_vals:aircraft:vertical_tail:wetted_area - parameter_vals:aircraft:wing:area [[1370.]] output ft**2 traj.descent.parameter_vals:aircraft:wing:area - parameter_vals:aircraft:wing:aspect_ratio [[11.22091]] output unitless traj.descent.parameter_vals:aircraft:wing:aspect_ratio - parameter_vals:aircraft:wing:characteristic_length [[10.49530819]] output ft traj.descent.parameter_vals:aircraft:wing:characteristic_length - parameter_vals:aircraft:wing:fineness [[0.13]] output unitless traj.descent.parameter_vals:aircraft:wing:fineness - parameter_vals:aircraft:wing:laminar_flow_lower [[0.]] output unitless traj.descent.parameter_vals:aircraft:wing:laminar_flow_lower - parameter_vals:aircraft:wing:laminar_flow_upper [[0.]] output unitless traj.descent.parameter_vals:aircraft:wing:laminar_flow_upper - parameter_vals:aircraft:wing:max_camber_at_70_semispan [[0.]] output unitless traj.descent.parameter_vals:aircraft:wing:max_camber_at_70_semispan - parameter_vals:aircraft:wing:span_efficiency_factor [[1.]] output unitless traj.descent.parameter_vals:aircraft:wing:span_efficiency_factor - parameter_vals:aircraft:wing:sweep [[25.]] output deg traj.descent.parameter_vals:aircraft:wing:sweep - parameter_vals:aircraft:wing:taper_ratio [[0.278]] output unitless traj.descent.parameter_vals:aircraft:wing:taper_ratio - parameter_vals:aircraft:wing:thickness_to_chord [[0.13]] output unitless traj.descent.parameter_vals:aircraft:wing:thickness_to_chord - parameter_vals:aircraft:wing:wetted_area [[2396.56]] output ft**2 traj.descent.parameter_vals:aircraft:wing:wetted_area - parameter_vals:mission:design:lift_coefficient [[0.56736557]] output unitless traj.descent.parameter_vals:mission:design:lift_coefficient - parameter_vals:mission:design:mach [[0.80017085]] output unitless traj.descent.parameter_vals:mission:design:mach - parameter_vals:aircraft:nacelle:characteristic_length [[12.3]] output ft traj.descent.parameter_vals:aircraft:nacelle:characteristic_length - parameter_vals:aircraft:nacelle:fineness [[1.54911839]] output unitless traj.descent.parameter_vals:aircraft:nacelle:fineness - parameter_vals:aircraft:nacelle:laminar_flow_lower [[0.]] output unitless traj.descent.parameter_vals:aircraft:nacelle:laminar_flow_lower - parameter_vals:aircraft:nacelle:laminar_flow_upper [[0.]] output unitless traj.descent.parameter_vals:aircraft:nacelle:laminar_flow_upper - parameter_vals:aircraft:nacelle:wetted_area [[273.4536]] output ft**2 traj.descent.parameter_vals:aircraft:nacelle:wetted_area - parameter_vals:aircraft:engine:scale_factor [[1.]] output unitless traj.descent.parameter_vals:aircraft:engine:scale_factor - time - t_initial [14010.] input s traj.descent.t_initial - t_duration [4548.94581634] input s traj.descent.t_duration - t |73347.98069351| output s traj.descent.t - val: - array([14010. , 14199.73049861, 14461.51986216, 14544.37530064, - 14544.37530064, 14931.85890638, 15466.50719578, 15635.72155138, - 15635.72155138, 16096.40122071, 16732.04513834, 16933.22426496, - 16933.22426496, 17320.7078707 , 17855.3561601 , 18024.5705157 , - 18024.5705157 , 18214.30101431, 18476.09037785, 18558.94581634]) - t_phase |12418.42831132| output s traj.descent.t_phase - val: - array([ 0. , 189.73049861, 451.51986216, 534.37530064, - 534.37530064, 921.85890638, 1456.50719578, 1625.72155138, - 1625.72155138, 2086.40122071, 2722.04513834, 2923.22426496, - 2923.22426496, 3310.7078707 , 3845.3561601 , 4014.5705157 , - 4014.5705157 , 4204.30101431, 4466.09037785, 4548.94581634]) - dt_dstau |2153.29990796| output s traj.descent.dt_dstau - val: - array([267.18765032, 267.18765032, 267.18765032, 267.18765032, - 545.67312537, 545.67312537, 545.67312537, 545.67312537, - 648.75135679, 648.75135679, 648.75135679, 648.75135679, - 545.67312537, 545.67312537, 545.67312537, 545.67312537, - 267.18765032, 267.18765032, 267.18765032, 267.18765032]) - control_comp - dt_dstau |2153.29990796| input s traj.descent.control_comp.dt_dstau - val: - array([267.18765032, 267.18765032, 267.18765032, 267.18765032, - 545.67312537, 545.67312537, 545.67312537, 545.67312537, - 648.75135679, 648.75135679, 648.75135679, 648.75135679, - 545.67312537, 545.67312537, 545.67312537, 545.67312537, - 267.18765032, 267.18765032, 267.18765032, 267.18765032]) - t_duration [4548.94581634] input s traj.descent.control_comp.t_duration - controls:mach |1.1154192| input unitless traj.descent.controls:mach - val: - array([[0.72 ], - [0.62049845], - [0.45950155], - [0.36 ]]) - controls:altitude |43169.43363075| input ft traj.descent.controls:altitude - val: - array([[34000. ], - [24740.82772462], - [ 9759.17227538], - [ 500. ]]) - control_values:mach |2.45889929| output unitless traj.descent.control_values:mach - val: - array([[0.72 ], - [0.70498488], - [0.68426707], - [0.67770996], - [0.67770996], - [0.64704481], - [0.60473316], - [0.59134167], - [0.59134167], - [0.55488385], - [0.50457949], - [0.48865833], - [0.48865833], - [0.45799318], - [0.41568153], - [0.40229004], - [0.40229004], - [0.38727492], - [0.36655711], - [0.36 ]]) - control_rates:mach_rate |0.00035392| output unitless/s traj.descent.control_rates:mach_rate - val: - array([[-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05]]) - control_rates:mach_rate2 |0.0| output unitless/s**2 traj.descent.control_rates:mach_rate2 - val: - array([[-3.43375003e-22], - [-5.15062504e-22], - [-1.71687501e-22], - [-1.71687501e-22], - [-1.71687501e-22], - [-1.71687501e-22], - [-2.57531252e-22], - [-8.58437507e-23], - [-8.58437507e-23], - [-8.58437507e-23], - [-2.14609377e-23], - [ 4.29218754e-23], - [ 4.29218754e-23], - [ 8.58437507e-23], - [ 0.00000000e+00], - [ 1.71687501e-22], - [ 1.71687501e-22], - [ 1.71687501e-22], - [ 3.43375003e-22], - [ 3.43375003e-22]]) - control_boundary_values:mach |0.80498447| output unitless traj.descent.control_comp.control_boundary_values:mach - val: - array([[0.72], - [0.36]]) - control_boundary_rates:mach_rate |0.00011192| output unitless/s traj.descent.control_comp.control_boundary_rates:mach_rate - val: - array([[-7.91392148e-05], - [-7.91392148e-05]]) - control_boundary_rates:mach_rate2 |0.0| output unitless/s**2 traj.descent.control_comp.control_boundary_rates:mach_rate2 - val: - array([[-3.43375003e-22], - [ 3.43375003e-22]]) - control_values:altitude |90819.35928076| output ft traj.descent.control_values:altitude - val: - array([[34000. ], - [32602.7594172 ], - [30674.85259378], - [30064.67667582], - [30064.67667582], - [27211.11426456], - [23273.78055735], - [22027.62790105], - [22027.62790105], - [18635.02452748], - [13953.9243121 ], - [12472.37209895], - [12472.37209895], - [ 9618.80968769], - [ 5681.47598048], - [ 4435.32332418], - [ 4435.32332418], - [ 3038.08274138], - [ 1110.17591796], - [ 500. ]]) - control_rates:altitude_rate |32.93434579| output ft/s traj.descent.control_rates:altitude_rate - val: - array([[-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436]]) - control_rates:altitude_rate2 |0.0| output ft/s**2 traj.descent.control_rates:altitude_rate2 - val: - array([[-1.12517121e-17], - [-1.68775681e-17], - [-5.62585605e-18], - [-5.62585605e-18], - [-5.62585605e-18], - [-5.62585605e-18], - [-8.43878407e-18], - [ 0.00000000e+00], - [ 0.00000000e+00], - [-1.40646401e-18], - [-3.51616003e-19], - [ 1.40646401e-18], - [ 1.40646401e-18], - [ 2.81292802e-18], - [ 0.00000000e+00], - [ 2.81292802e-18], - [ 2.81292802e-18], - [ 0.00000000e+00], - [ 5.62585605e-18], - [ 5.62585605e-18]]) - control_boundary_values:altitude |34003.67627184| output ft traj.descent.control_comp.control_boundary_values:altitude - val: - array([[34000.], - [ 500.]]) - control_boundary_rates:altitude_rate |10.41475459| output ft/s traj.descent.control_comp.control_boundary_rates:altitude_rate - val: - array([[-7.3643436], - [-7.3643436]]) - control_boundary_rates:altitude_rate2 |0.0| output ft/s**2 traj.descent.control_comp.control_boundary_rates:altitude_rate2 - val: - array([[-1.12517121e-17], - [ 5.62585605e-18]]) - indep_states - initial_states:mass [[52028.74471935]] input kg traj.descent.initial_states:mass - initial_states:distance [[2751418.23144865]] input m traj.descent.initial_states:distance - states:mass |204485.67328288| output kg traj.descent.states:mass - val: - array([[52028.74471935], - [51956.50719188], - [51855.82599664], - [51823.76601249], - [51672.54219645], - [51461.12266693], - [51393.8106793 ], - [51210.06984292], - [50956.67116637], - [50876.7919899 ], - [50724.57452871], - [50519.93012614], - [50456.90390387], - [50387.51580428], - [50293.8882617 ], - [50264.76158872]]) - states:distance |12756536.37582982| output m traj.descent.states:distance - val: - array([[2751418.23144865], - [2791817.41185045], - [2846561.44051968], - [2863642.02155273], - [2941914.82037522], - [3045428.93171548], - [3077070.29224964], - [3160390.83905457], - [3268342.75197541], - [3300756.63996977], - [3360741.81646801], - [3438080.96818847], - [3461214.38233449], - [3486369.12667608], - [3519699.62007001], - [3529912. ]]) - state_interp - dt_dstau |1864.81242226| input s traj.descent.state_interp.dt_dstau - val: - array([267.18765032, 267.18765032, 267.18765032, 545.67312537, - 545.67312537, 545.67312537, 648.75135679, 648.75135679, - 648.75135679, 545.67312537, 545.67312537, 545.67312537, - 267.18765032, 267.18765032, 267.18765032]) - state_disc:mass |228638.93848721| input kg traj.descent.state_interp.state_disc:mass - val: - array([[52028.74471935], - [51956.50719188], - [51855.82599664], - [51823.76601249], - [51823.76601249], - [51672.54219645], - [51461.12266693], - [51393.8106793 ], - [51393.8106793 ], - [51210.06984292], - [50956.67116637], - [50876.7919899 ], - [50876.7919899 ], - [50724.57452871], - [50519.93012614], - [50456.90390387], - [50456.90390387], - [50387.51580428], - [50293.8882617 ], - [50264.76158872]]) - state_disc:distance |14257384.99570313| input m traj.descent.state_interp.state_disc:distance - val: - array([[2751418.23144865], - [2791817.41185045], - [2846561.44051968], - [2863642.02155273], - [2863642.02155273], - [2941914.82037522], - [3045428.93171548], - [3077070.29224964], - [3077070.29224964], - [3160390.83905457], - [3268342.75197541], - [3300756.63996977], - [3300756.63996977], - [3360741.81646801], - [3438080.96818847], - [3461214.38233449], - [3461214.38233449], - [3486369.12667608], - [3519699.62007001], - [3529912. ]]) - staterate_col:mass |1.48954691| output kg/s traj.descent.state_interp.staterate_col:mass - val: - array([[-0.37884527], - [-0.38251468], - [-0.38644318], - [-0.38736247], - [-0.39287019], - [-0.3974122 ], - [-0.39825982], - [-0.39915285], - [-0.39760802], - [-0.39585232], - [-0.38930864], - [-0.37524796], - [-0.36913783], - [-0.36231144], - [-0.35299812]]) - staterate_col:distance |678.62402375| output m/s traj.descent.state_interp.staterate_col:distance - val: - array([[214.5070361 ], - [211.34098824], - [206.86850148], - [205.42809125], - [198.53527609], - [188.60727137], - [185.36616898], - [176.30605727], - [163.24787168], - [158.98300661], - [150.59309082], - [138.64324625], - [134.77225428], - [130.38185021], - [124.23737345]]) - rhs_all - atmosphere - standard_atmosphere - h |90819.35928076| input ft traj.descent.rhs_all.altitude - val: - array([34000. , 32602.7594172 , 30674.85259378, 30064.67667582, - 30064.67667582, 27211.11426456, 23273.78055735, 22027.62790105, - 22027.62790105, 18635.02452748, 13953.9243121 , 12472.37209895, - 12472.37209895, 9618.80968769, 5681.47598048, 4435.32332418, - 4435.32332418, 3038.08274138, 1110.17591796, 500. ]) - temp |2057.90503542| output degR traj.descent.rhs_all.temperature - val: - array([397.61833789, 402.58502389, 409.43912788, 411.60869197, - 411.60869197, 421.75760711, 435.76421298, 440.19835649, - 440.19835649, 452.27382677, 468.94157663, 474.21810376, - 474.21810376, 484.38346865, 498.41437443, 502.85599996, - 502.85599996, 507.83777076, 514.7113234 , 516.88704275]) - pres |40.67816643| output psi traj.descent.rhs_all.static_pressure - val: - array([ 3.6352703 , 3.88037611, 4.24043035, 4.35988134, 4.35988134, - 4.95530237, 5.88365723, 6.20522118, 6.20522118, 7.15363949, - 8.65234929, 9.17647506, 9.17647506, 10.25865618, 11.91976345, - 12.48876061, 12.48876061, 13.15282131, 14.11591336, 14.43234102]) - rho |0.00703051| output slug/ft**3 traj.descent.rhs_all.density - val: - array([0.00076705, 0.00080867, 0.00086891, 0.00088868, 0.00088868, - 0.00098574, 0.00113279, 0.00118267, 0.00118267, 0.00132703, - 0.00154799, 0.0016235 , 0.0016235 , 0.00177686, 0.00200646, - 0.00208368, 0.00208368, 0.00217294, 0.00230091, 0.00234259]) - viscosity |1.53e-06| output lbf*s/ft**2 traj.descent.rhs_all.viscosity - val: - array([3.04138620e-07, 3.07367116e-07, 3.11795581e-07, 3.13190984e-07, - 3.13190984e-07, 3.19675903e-07, 3.28517441e-07, 3.31290236e-07, - 3.31290236e-07, 3.38780681e-07, 3.48975867e-07, 3.52169371e-07, - 3.52169371e-07, 3.58276954e-07, 3.66611763e-07, 3.69227842e-07, - 3.69227842e-07, 3.72149488e-07, 3.76157667e-07, 3.77421833e-07]) - drhos_dh |2.2e-07| output slug/ft**4 traj.descent.rhs_all.drhos_dh - val: - array([-2.92754279e-08, -3.04882416e-08, -3.22109276e-08, -3.27621989e-08, - -3.27621989e-08, -3.54703549e-08, -3.94566362e-08, -4.07705940e-08, - -4.07705940e-08, -4.45375443e-08, -5.00972532e-08, -5.19550694e-08, - -5.19550694e-08, -5.56782862e-08, -6.11034075e-08, -6.28984502e-08, - -6.28984502e-08, -6.49319629e-08, -6.78347342e-08, -6.87819117e-08]) - sos |4693.86791488| output ft/s traj.descent.rhs_all.speed_of_sound - val: - array([ 977.50246093, 983.5885495 , 991.92612429, 994.55069512, - 994.55069512, 1006.73720555, 1023.31758488, 1028.51082041, - 1028.51082041, 1042.52237447, 1061.55873018, 1067.51434936, - 1067.51434936, 1078.89532956, 1094.40970637, 1099.27531289, - 1099.27531289, 1104.70712734, 1112.15807119, 1114.50617585]) - flight_conditions - density |0.00703051| input slug/ft**3 traj.descent.rhs_all.density - val: - array([0.00076705, 0.00080867, 0.00086891, 0.00088868, 0.00088868, - 0.00098574, 0.00113279, 0.00118267, 0.00118267, 0.00132703, - 0.00154799, 0.0016235 , 0.0016235 , 0.00177686, 0.00200646, - 0.00208368, 0.00208368, 0.00217294, 0.00230091, 0.00234259]) - speed_of_sound |4693.86791488| input ft/s traj.descent.rhs_all.speed_of_sound - val: - array([ 977.50246093, 983.5885495 , 991.92612429, 994.55069512, - 994.55069512, 1006.73720555, 1023.31758488, 1028.51082041, - 1028.51082041, 1042.52237447, 1061.55873018, 1067.51434936, - 1067.51434936, 1078.89532956, 1094.40970637, 1099.27531289, - 1099.27531289, 1104.70712734, 1112.15807119, 1114.50617585]) - mach |2.45889929| input unitless traj.descent.rhs_all.mach - val: - array([0.72 , 0.70498488, 0.68426707, 0.67770996, 0.67770996, - 0.64704481, 0.60473316, 0.59134167, 0.59134167, 0.55488385, - 0.50457949, 0.48865833, 0.48865833, 0.45799318, 0.41568153, - 0.40229004, 0.40229004, 0.38727492, 0.36655711, 0.36 ]) - dynamic_pressure |928.96258055| output lbf/ft**2 traj.descent.rhs_all.dynamic_pressure - val: - array([189.97476746, 194.41399439, 200.14980358, 201.86238278, - 201.86238278, 209.1379374 , 216.90403419, 218.74024951, - 218.74024951, 222.03734202, 222.06822194, 220.89198309, - 220.89198309, 216.92011004, 207.6264045 , 203.74806627, - 203.74806627, 198.86198706, 191.19926567, 188.55390789]) - EAS |1868.29888869| output ft/s traj.descent.rhs_all.EAS - val: - array([399.8135451 , 404.45788281, 410.38088776, 412.13285744, - 412.13285744, 419.49419246, 427.21191554, 429.01639983, - 429.01639983, 432.23760925, 432.267665 , 431.12133914, - 431.12133914, 427.22774666, 417.97550788, 414.05333815, - 414.05333815, 409.05850787, 401.09999123, 398.31559595]) - velocity |2531.95454473| output ft/s traj.descent.rhs_all.velocity - val: - array([703.80177187, 693.4150529 , 678.74238535, 674.01691012, - 674.01691012, 651.40408389, 618.83408108, 608.20130921, - 608.20130921, 578.47882434, 535.64075753, 521.64977604, - 521.64977604, 494.12670151, 454.92590439, 442.22751145, - 442.22751145, 427.82536327, 407.66945327, 401.22222331]) - velocity_rate_comp - mach_rate |0.00035392| input unitless/s traj.descent.rhs_all.mach_rate - val: - array([-7.91392148e-05, -7.91392148e-05, -7.91392148e-05, -7.91392148e-05, - -7.91392148e-05, -7.91392148e-05, -7.91392148e-05, -7.91392148e-05, - -7.91392148e-05, -7.91392148e-05, -7.91392148e-05, -7.91392148e-05, - -7.91392148e-05, -7.91392148e-05, -7.91392148e-05, -7.91392148e-05, - -7.91392148e-05, -7.91392148e-05, -7.91392148e-05, -7.91392148e-05]) - sos |1430.69094045| input m/s traj.descent.rhs_all.speed_of_sound - val: - array([297.94275009, 299.79778989, 302.33908268, 303.13905187, - 303.13905187, 306.85350025, 311.90719987, 313.49009806, - 313.49009806, 317.76081974, 323.56310096, 325.37837369, - 325.37837369, 328.84729645, 333.5760785 , 335.05911537, - 335.05911537, 336.71473241, 338.9857801 , 339.7014824 ]) - velocity_rate |0.11322376| output m/s**2 traj.descent.rhs_all.velocity_rate - val: - array([-0.02357896, -0.02372576, -0.02392688, -0.02399019, -0.02399019, - -0.02428415, -0.02468409, -0.02480936, -0.02480936, -0.02514734, - -0.02560653, -0.02575019, -0.02575019, -0.02602472, -0.02639895, - -0.02651632, -0.02651632, -0.02664734, -0.02682707, -0.02688371]) - solver_sub - core_aerodynamics - Mux - aircraft:wing:wetted_area [2396.56] input ft**2 traj.descent.rhs_all.aircraft:wing:wetted_area - aircraft:wing:fineness [0.13] input unitless traj.descent.rhs_all.aircraft:wing:fineness - aircraft:wing:characteristic_length [10.49530819] input ft traj.descent.rhs_all.aircraft:wing:characteristic_length - aircraft:wing:laminar_flow_upper [0.] input unitless traj.descent.rhs_all.aircraft:wing:laminar_flow_upper - aircraft:wing:laminar_flow_lower [0.] input unitless traj.descent.rhs_all.aircraft:wing:laminar_flow_lower - aircraft:horizontal_tail:wetted_area [592.65] input ft**2 traj.descent.rhs_all.aircraft:horizontal_tail:wetted_area - aircraft:horizontal_tail:fineness [0.125] input unitless traj.descent.rhs_all.aircraft:horizontal_tail:fineness - aircraft:horizontal_tail:characteristic_length [7.69198717] input ft traj.descent.rhs_all.aircraft:horizontal_tail:characteristic_length - aircraft:horizontal_tail:laminar_flow_upper [0.] input unitless traj.descent.rhs_all.aircraft:horizontal_tail:laminar_flow_upper - aircraft:horizontal_tail:laminar_flow_lower [0.] input unitless traj.descent.rhs_all.aircraft:horizontal_tail:laminar_flow_lower - aircraft:vertical_tail:wetted_area [581.13] input ft**2 traj.descent.rhs_all.aircraft:vertical_tail:wetted_area - aircraft:vertical_tail:fineness [0.1195] input unitless traj.descent.rhs_all.aircraft:vertical_tail:fineness - aircraft:vertical_tail:characteristic_length [12.73914103] input ft traj.descent.rhs_all.aircraft:vertical_tail:characteristic_length - aircraft:vertical_tail:laminar_flow_upper [0.] input unitless traj.descent.rhs_all.aircraft:vertical_tail:laminar_flow_upper - aircraft:vertical_tail:laminar_flow_lower [0.] input unitless traj.descent.rhs_all.aircraft:vertical_tail:laminar_flow_lower - aircraft:fuselage:wetted_area [4158.62] input ft**2 traj.descent.rhs_all.aircraft:fuselage:wetted_area - aircraft:fuselage:fineness [10.03921569] input unitless traj.descent.rhs_all.aircraft:fuselage:fineness - aircraft:fuselage:characteristic_length [128.] input ft traj.descent.rhs_all.aircraft:fuselage:characteristic_length - aircraft:fuselage:laminar_flow_upper [0.] input unitless traj.descent.rhs_all.aircraft:fuselage:laminar_flow_upper - aircraft:fuselage:laminar_flow_lower [0.] input unitless traj.descent.rhs_all.aircraft:fuselage:laminar_flow_lower - aircraft:nacelle:wetted_area [273.4536] input ft**2 traj.descent.rhs_all.aircraft:nacelle:wetted_area - aircraft:nacelle:fineness [1.54911839] input unitless traj.descent.rhs_all.aircraft:nacelle:fineness - aircraft:nacelle:characteristic_length [12.3] input ft traj.descent.rhs_all.aircraft:nacelle:characteristic_length - aircraft:nacelle:laminar_flow_upper [0.] input unitless traj.descent.rhs_all.aircraft:nacelle:laminar_flow_upper - aircraft:nacelle:laminar_flow_lower [0.] input unitless traj.descent.rhs_all.aircraft:nacelle:laminar_flow_lower - wetted_areas |4886.31967641| output ft**2 traj.descent.rhs_all.core_aerodynamics.wetted_areas - val: - array([2396.56 , 592.65 , 581.13 , 4158.62 , 273.4536, 273.4536]) - fineness_ratios |10.2777523| output unitless traj.descent.rhs_all.core_aerodynamics.fineness_ratios - val: - array([ 0.13 , 0.125 , 0.1195 , 10.03921569, 1.54911839, - 1.54911839]) - characteristic_lengths |130.45376144| output ft traj.descent.rhs_all.core_aerodynamics.characteristic_lengths - val: - array([ 10.49530819, 7.69198717, 12.73914103, 128. , - 12.3 , 12.3 ]) - laminar_fractions_upper |0.0| output unitless traj.descent.rhs_all.core_aerodynamics.laminar_fractions_upper - val: - array([0., 0., 0., 0., 0., 0.]) - laminar_fractions_lower |0.0| output unitless traj.descent.rhs_all.core_aerodynamics.laminar_fractions_lower - val: - array([0., 0., 0., 0., 0., 0.]) - DynamicPressure - static_pressure |5857.65596001| input lbf/ft**2 traj.descent.rhs_all.static_pressure - val: - array([ 523.4789226 , 558.77415991, 610.62196946, 627.82291255, - 627.82291255, 713.56354112, 847.24664051, 893.5518483 , - 893.5518483 , 1030.12408532, 1245.93829696, 1321.41240663, - 1321.41240663, 1477.24648833, 1716.44593554, 1798.38152578, - 1798.38152578, 1894.006267 , 2032.69152116, 2078.25710533]) - mach |2.45889929| input unitless traj.descent.rhs_all.mach - val: - array([0.72 , 0.70498488, 0.68426707, 0.67770996, 0.67770996, - 0.64704481, 0.60473316, 0.59134167, 0.59134167, 0.55488385, - 0.50457949, 0.48865833, 0.48865833, 0.45799318, 0.41568153, - 0.40229004, 0.40229004, 0.38727492, 0.36655711, 0.36 ]) - dynamic_pressure |928.89141001| output lbf/ft**2 traj.descent.rhs_all.core_aerodynamics.dynamic_pressure - val: - array([189.96003143, 194.39896856, 200.13440281, 201.84729598, - 201.84729598, 209.12184804, 216.88797219, 218.72315851, - 218.72315851, 222.01981902, 222.05152171, 220.87523658, - 220.87523658, 216.90473154, 207.61065114, 203.73161921, - 203.73161921, 198.84661178, 191.18456249, 188.5394846 ]) - lift - aircraft:wing:area [127.2771648] input m**2 traj.descent.rhs_all.aircraft:wing:area - mass |228638.93848721| input kg traj.descent.rhs_all.mass - val: - array([52028.74471935, 51956.50719188, 51855.82599664, 51823.76601249, - 51823.76601249, 51672.54219645, 51461.12266693, 51393.8106793 , - 51393.8106793 , 51210.06984292, 50956.67116637, 50876.7919899 , - 50876.7919899 , 50724.57452871, 50519.93012614, 50456.90390387, - 50456.90390387, 50387.51580428, 50293.8882617 , 50264.76158872]) - dynamic_pressure |44475.56132351| input N/m**2 traj.descent.rhs_all.core_aerodynamics.dynamic_pressure - val: - array([ 9095.33551064, 9307.87296998, 9582.48704743, 9664.50081633, - 9664.50081633, 10012.80825307, 10384.65228946, 10472.52148539, - 10472.52148539, 10630.36644494, 10631.88437784, 10575.56354086, - 10575.56354086, 10385.45473119, 9940.45175416, 9754.72270062, - 9754.72270062, 9520.82727965, 9153.9663749 , 9027.31936006]) - cl |1.78197778| output unitless traj.descent.rhs_all.core_aerodynamics.cl - val: - array([0.44075252, 0.43009033, 0.4169553 , 0.41316139, 0.41316139, - 0.39762539, 0.38181895, 0.37812008, 0.37812008, 0.3711738 , - 0.36928442, 0.3706691 , 0.3706691 , 0.37632501, 0.39158568, - 0.39854361, 0.39854361, 0.40777298, 0.42332711, 0.4290175 ]) - lift |2242182.04611564| output N traj.descent.rhs_all.lift - val: - array([510227.68940198, 509519.28125321, 508531.93600992, 508217.53496643, - 508217.53496643, 506734.53593078, 504661.21860166, 504001.11349819, - 504001.11349819, 502199.23142511, 499714.2392937 , 498930.89216773, - 498930.89216773, 497438.14880199, 495431.27277151, 494813.19666888, - 494813.19666888, 494132.73186204, 493214.55932157, 492928.92423401]) - PressureDrag - mach |2.45889929| input unitless traj.descent.rhs_all.mach - val: - array([0.72 , 0.70498488, 0.68426707, 0.67770996, 0.67770996, - 0.64704481, 0.60473316, 0.59134167, 0.59134167, 0.55488385, - 0.50457949, 0.48865833, 0.48865833, 0.45799318, 0.41568153, - 0.40229004, 0.40229004, 0.38727492, 0.36655711, 0.36 ]) - lift |504062.57548733| input lbf traj.descent.rhs_all.core_aerodynamics.lift - val: - array([114703.74747245, 114544.49098541, 114322.52694503, 114251.84677881, - 114251.84677881, 113918.45533334, 113452.35505637, 113303.95752588, - 113303.95752588, 112898.87832187, 112340.22986779, 112164.12642851, - 112164.12642851, 111828.5443705 , 111377.38069164, 111238.4316564 , - 111238.4316564 , 111085.45708252, 110879.04368433, 110814.83036225]) - static_pressure |5857.65596001| input lbf/ft**2 traj.descent.rhs_all.static_pressure - val: - array([ 523.4789226 , 558.77415991, 610.62196946, 627.82291255, - 627.82291255, 713.56354112, 847.24664051, 893.5518483 , - 893.5518483 , 1030.12408532, 1245.93829696, 1321.41240663, - 1321.41240663, 1477.24648833, 1716.44593554, 1798.38152578, - 1798.38152578, 1894.006267 , 2032.69152116, 2078.25710533]) - mission:design:lift_coefficient [0.56736557] input unitless traj.descent.rhs_all.mission:design:lift_coefficient - mission:design:mach [0.80017085] input unitless traj.descent.rhs_all.mission:design:mach - aircraft:wing:area [1370.] input ft**2 traj.descent.rhs_all.aircraft:wing:area - aircraft:wing:aspect_ratio [11.22091] input unitless traj.descent.rhs_all.aircraft:wing:aspect_ratio - aircraft:wing:max_camber_at_70_semispan [0.] input unitless traj.descent.rhs_all.aircraft:wing:max_camber_at_70_semispan - aircraft:wing:sweep [25.] input deg traj.descent.rhs_all.aircraft:wing:sweep - aircraft:wing:thickness_to_chord [0.13] input unitless traj.descent.rhs_all.aircraft:wing:thickness_to_chord - CD |0.0029774| output unitless traj.descent.rhs_all.core_aerodynamics.PressureDrag.CD - val: - array([0.00093663, 0.0008723 , 0.00079139, 0.00076681, 0.00076681, - 0.00065978, 0.0005458 , 0.00051791, 0.00051791, 0.00045833, - 0.00043096, 0.00043829, 0.00043829, 0.00047777, 0.00059396, - 0.00064705, 0.00064705, 0.00071638, 0.00082929, 0.00086917]) - InducedDrag - mach |2.45889929| input unitless traj.descent.rhs_all.mach - val: - array([0.72 , 0.70498488, 0.68426707, 0.67770996, 0.67770996, - 0.64704481, 0.60473316, 0.59134167, 0.59134167, 0.55488385, - 0.50457949, 0.48865833, 0.48865833, 0.45799318, 0.41568153, - 0.40229004, 0.40229004, 0.38727492, 0.36655711, 0.36 ]) - lift |504062.57548733| input lbf traj.descent.rhs_all.core_aerodynamics.lift - val: - array([114703.74747245, 114544.49098541, 114322.52694503, 114251.84677881, - 114251.84677881, 113918.45533334, 113452.35505637, 113303.95752588, - 113303.95752588, 112898.87832187, 112340.22986779, 112164.12642851, - 112164.12642851, 111828.5443705 , 111377.38069164, 111238.4316564 , - 111238.4316564 , 111085.45708252, 110879.04368433, 110814.83036225]) - static_pressure |5857.65596001| input lbf/ft**2 traj.descent.rhs_all.static_pressure - val: - array([ 523.4789226 , 558.77415991, 610.62196946, 627.82291255, - 627.82291255, 713.56354112, 847.24664051, 893.5518483 , - 893.5518483 , 1030.12408532, 1245.93829696, 1321.41240663, - 1321.41240663, 1477.24648833, 1716.44593554, 1798.38152578, - 1798.38152578, 1894.006267 , 2032.69152116, 2078.25710533]) - aircraft:wing:area [1370.] input ft**2 traj.descent.rhs_all.aircraft:wing:area - aircraft:wing:aspect_ratio [11.22091] input unitless traj.descent.rhs_all.aircraft:wing:aspect_ratio - aircraft:wing:span_efficiency_factor [1.] input unitless traj.descent.rhs_all.aircraft:wing:span_efficiency_factor - aircraft:wing:sweep [25.] input deg traj.descent.rhs_all.aircraft:wing:sweep - aircraft:wing:taper_ratio [0.278] input unitless traj.descent.rhs_all.aircraft:wing:taper_ratio - induced_drag_coeff |0.02027026| output unitless traj.descent.rhs_all.core_aerodynamics.InducedDrag.induced_drag_coeff - val: - array([0.00551076, 0.00524737, 0.00493175, 0.00484241, 0.00484241, - 0.00448508, 0.00413559, 0.00405585, 0.00405585, 0.0039082 , - 0.00386851, 0.00389758, 0.00389758, 0.00401743, 0.00434986, - 0.00450582, 0.00450582, 0.00471692, 0.00508363, 0.00522122]) - CompressibilityDrag - mach |2.45889929| input unitless traj.descent.rhs_all.mach - val: - array([0.72 , 0.70498488, 0.68426707, 0.67770996, 0.67770996, - 0.64704481, 0.60473316, 0.59134167, 0.59134167, 0.55488385, - 0.50457949, 0.48865833, 0.48865833, 0.45799318, 0.41568153, - 0.40229004, 0.40229004, 0.38727492, 0.36655711, 0.36 ]) - mission:design:mach [0.80017085] input unitless traj.descent.rhs_all.mission:design:mach - aircraft:design:base_area [0.] input ft**2 traj.descent.rhs_all.aircraft:design:base_area - aircraft:wing:area [1370.] input ft**2 traj.descent.rhs_all.aircraft:wing:area - aircraft:wing:aspect_ratio [11.22091] input unitless traj.descent.rhs_all.aircraft:wing:aspect_ratio - aircraft:wing:max_camber_at_70_semispan [0.] input unitless traj.descent.rhs_all.aircraft:wing:max_camber_at_70_semispan - aircraft:wing:sweep [25.] input deg traj.descent.rhs_all.aircraft:wing:sweep - aircraft:wing:taper_ratio [0.278] input unitless traj.descent.rhs_all.aircraft:wing:taper_ratio - aircraft:wing:thickness_to_chord [0.13] input unitless traj.descent.rhs_all.aircraft:wing:thickness_to_chord - aircraft:fuselage:cross_section [127.67628894] input ft**2 traj.descent.rhs_all.aircraft:fuselage:cross_section - aircraft:fuselage:diameter_to_wing_span [0.10826471] input unitless traj.descent.rhs_all.aircraft:fuselage:diameter_to_wing_span - aircraft:fuselage:length_to_diameter [10.03921569] input unitless traj.descent.rhs_all.aircraft:fuselage:length_to_diameter - compress_drag_coeff |0.00179297| output unitless traj.descent.rhs_all.core_aerodynamics.CompressibilityDrag.compress_drag_coeff - val: - array([0.00094091, 0.00082662, 0.00069503, 0.00065674, 0.00065674, - 0.00046614, 0.00021312, 0.00013737, 0.00013737, 0. , - 0. , 0. , 0. , 0. , 0. , - 0. , 0. , 0. , 0. , 0. ]) - SkinFrictionCoef - temperature |2057.90503542| input degR traj.descent.rhs_all.temperature - val: - array([397.61833789, 402.58502389, 409.43912788, 411.60869197, - 411.60869197, 421.75760711, 435.76421298, 440.19835649, - 440.19835649, 452.27382677, 468.94157663, 474.21810376, - 474.21810376, 484.38346865, 498.41437443, 502.85599996, - 502.85599996, 507.83777076, 514.7113234 , 516.88704275]) - static_pressure |5857.65596001| input lbf/ft**2 traj.descent.rhs_all.static_pressure - val: - array([ 523.4789226 , 558.77415991, 610.62196946, 627.82291255, - 627.82291255, 713.56354112, 847.24664051, 893.5518483 , - 893.5518483 , 1030.12408532, 1245.93829696, 1321.41240663, - 1321.41240663, 1477.24648833, 1716.44593554, 1798.38152578, - 1798.38152578, 1894.006267 , 2032.69152116, 2078.25710533]) - mach |2.45889929| input unitless traj.descent.rhs_all.mach - val: - array([0.72 , 0.70498488, 0.68426707, 0.67770996, 0.67770996, - 0.64704481, 0.60473316, 0.59134167, 0.59134167, 0.55488385, - 0.50457949, 0.48865833, 0.48865833, 0.45799318, 0.41568153, - 0.40229004, 0.40229004, 0.38727492, 0.36655711, 0.36 ]) - characteristic_lengths |130.45376144| input ft traj.descent.rhs_all.core_aerodynamics.characteristic_lengths - val: - array([ 10.49530819, 7.69198717, 12.73914103, 128. , - 12.3 , 12.3 ]) - cf_iter |0.02697932| output unitless traj.descent.rhs_all.core_aerodynamics.SkinFrictionCoef.cf_iter - val: - array([[0.00269609, 0.00283249, 0.00261572, 0.00187431, 0.00263002, - 0.00263002], - [0.0026826 , 0.00281803, 0.0026028 , 0.00186629, 0.002617 , - 0.002617 ], - [0.0026649 , 0.00279905, 0.00258585, 0.00185574, 0.00259991, - 0.00259991], - [0.00265952, 0.00279328, 0.00258069, 0.00185253, 0.00259471, - 0.00259471], - [0.00265952, 0.00279328, 0.00258069, 0.00185253, 0.00259471, - 0.00259471], - [0.00263571, 0.00276775, 0.00255788, 0.00183832, 0.00257172, - 0.00257172], - [0.0026065 , 0.00273644, 0.00252988, 0.00182084, 0.00254352, - 0.00254352], - [0.00259813, 0.00272747, 0.00252186, 0.00181583, 0.00253543, - 0.00253543], - [0.00259813, 0.00272747, 0.00252186, 0.00181583, 0.00253543, - 0.00253543], - [0.00257749, 0.00270535, 0.00250207, 0.00180345, 0.00251549, - 0.00251549], - [0.00255423, 0.00268044, 0.00247978, 0.00178947, 0.00249303, - 0.00249303], - [0.00254817, 0.00267395, 0.00247397, 0.00178582, 0.00248717, - 0.00248717], - [0.00254817, 0.00267395, 0.00247397, 0.00178582, 0.00248717, - 0.00248717], - [0.00253835, 0.00266344, 0.00246455, 0.00177991, 0.00247769, - 0.00247769], - [0.00252906, 0.00265349, 0.00245564, 0.0017743 , 0.00246871, - 0.00246871], - [0.00252722, 0.00265152, 0.00245388, 0.00177319, 0.00246693, - 0.00246693], - [0.00252722, 0.00265152, 0.00245388, 0.00177319, 0.00246693, - 0.00246693], - [0.00252583, 0.00265004, 0.00245255, 0.00177235, 0.00246559, - 0.00246559], - [0.00252516, 0.00264932, 0.0024519 , 0.00177194, 0.00246494, - 0.00246494], - [0.00252527, 0.00264944, 0.002452 , 0.001772 , 0.00246504, - 0.00246504]]) - skin_friction_coeff |0.02613897| output unitless traj.descent.rhs_all.core_aerodynamics.skin_friction_coeff - val: - array([[0.00255188, 0.0026807 , 0.00247599, 0.00177581, 0.00248949, - 0.00248949], - [0.00254494, 0.00267312, 0.0024694 , 0.00177225, 0.00248284, - 0.00248284], - [0.00253598, 0.00266334, 0.00246091, 0.00176767, 0.00247427, - 0.00247427], - [0.00253329, 0.00266041, 0.00245837, 0.0017663 , 0.00247169, - 0.00247169], - [0.00253329, 0.00266041, 0.00245837, 0.0017663 , 0.00247169, - 0.00247169], - [0.00252165, 0.0026477 , 0.00244735, 0.00176044, 0.00246057, - 0.00246057], - [0.00250813, 0.00263289, 0.00243457, 0.00175376, 0.00244766, - 0.00244766], - [0.00250446, 0.00262887, 0.00243111, 0.001752 , 0.00244416, - 0.00244416], - [0.00250446, 0.00262887, 0.00243111, 0.001752 , 0.00244416, - 0.00244416], - [0.00249601, 0.00261957, 0.00242315, 0.00174807, 0.00243611, - 0.00243611], - [0.00248817, 0.00261085, 0.00241581, 0.00174482, 0.00242869, - 0.00242869], - [0.00248667, 0.00260914, 0.00241442, 0.00174436, 0.00242728, - 0.00242728], - [0.00248667, 0.00260914, 0.00241442, 0.00174436, 0.00242728, - 0.00242728], - [0.00248519, 0.00260738, 0.00241311, 0.00174429, 0.00242593, - 0.00242593], - [0.00248652, 0.00260857, 0.00241451, 0.00174616, 0.00242732, - 0.00242732], - [0.00248784, 0.00260991, 0.00241581, 0.00174728, 0.00242863, - 0.00242863], - [0.00248784, 0.00260991, 0.00241581, 0.00174728, 0.00242863, - 0.00242863], - [0.00248987, 0.00261202, 0.0024178 , 0.00174886, 0.00243063, - 0.00243063], - [0.00249373, 0.00261604, 0.00242156, 0.00175167, 0.0024344 , - 0.0024344 ], - [0.00249522, 0.00261761, 0.00242301, 0.00175271, 0.00243586, - 0.00243586]]) - Re |1325371462.626787| output unitless traj.descent.rhs_all.core_aerodynamics.Re - val: - array([[1.87740162e+07, 1.37594332e+07, 2.27877863e+07, 2.28966508e+08, - 2.20022504e+07, 2.20022504e+07], - [1.93001769e+07, 1.41450551e+07, 2.34264369e+07, 2.35383525e+08, - 2.26188856e+07, 2.26188856e+07], - [2.00171471e+07, 1.46705210e+07, 2.42966911e+07, 2.44127642e+08, - 2.34591406e+07, 2.34591406e+07], - [2.02414357e+07, 1.48349015e+07, 2.45689311e+07, 2.46863048e+08, - 2.37219960e+07, 2.37219960e+07], - [2.02414357e+07, 1.48349015e+07, 2.45689311e+07, 2.46863048e+08, - 2.37219960e+07, 2.37219960e+07], - [2.12683033e+07, 1.55874905e+07, 2.58153368e+07, 2.59386649e+08, - 2.49254358e+07, 2.49254358e+07], - [2.26077276e+07, 1.65691514e+07, 2.74411218e+07, 2.75722169e+08, - 2.64951771e+07, 2.64951771e+07], - [2.30076545e+07, 1.68622569e+07, 2.79265506e+07, 2.80599647e+08, - 2.69638724e+07, 2.69638724e+07], - [2.30076545e+07, 1.68622569e+07, 2.79265506e+07, 2.80599647e+08, - 2.69638724e+07, 2.69638724e+07], - [2.40232164e+07, 1.76065599e+07, 2.91592335e+07, 2.92985365e+08, - 2.81540624e+07, 2.81540624e+07], - [2.52063871e+07, 1.84737030e+07, 3.05953588e+07, 3.07415227e+08, - 2.95406819e+07, 2.95406819e+07], - [2.55169120e+07, 1.87012860e+07, 3.09722721e+07, 3.11202366e+08, - 2.99046024e+07, 2.99046024e+07], - [2.55169120e+07, 1.87012860e+07, 3.09722721e+07, 3.11202366e+08, - 2.99046024e+07, 2.99046024e+07], - [2.60126988e+07, 1.90646470e+07, 3.15740551e+07, 3.17248945e+08, - 3.04856408e+07, 3.04856408e+07], - [2.64418484e+07, 1.93791697e+07, 3.20949542e+07, 3.22482821e+08, - 3.09885836e+07, 3.09885836e+07], - [2.65078276e+07, 1.94275257e+07, 3.21750394e+07, 3.23287499e+08, - 3.10659081e+07, 3.10659081e+07], - [2.65078276e+07, 1.94275257e+07, 3.21750394e+07, 3.23287499e+08, - 3.10659081e+07, 3.10659081e+07], - [2.65377461e+07, 1.94494529e+07, 3.22113543e+07, 3.23652383e+08, - 3.11009712e+07, 3.11009712e+07], - [2.64974101e+07, 1.94198908e+07, 3.21623947e+07, 3.23160448e+08, - 3.10536993e+07, 3.10536993e+07], - [2.64637059e+07, 1.93951890e+07, 3.21214847e+07, 3.22749394e+08, - 3.10141996e+07, 3.10141996e+07]]) - wall_temp |5259.05648112| output degR traj.descent.rhs_all.core_aerodynamics.SkinFrictionCoef.wall_temp - val: - array([[431.51809847, 431.62111275, 431.45259477, 430.59767514, - 431.46452722, 431.46452722], - [435.41657999, 435.51966045, 435.35103624, 434.49570326, - 435.36297587, 435.36297587], - [440.78626444, 440.88955317, 440.72059102, 439.86371601, - 440.73255412, 440.73255412], - [442.48389514, 442.58727866, 442.4181623 , 441.56055947, - 442.43013618, 442.43013618], - [442.48389514, 442.58727866, 442.4181623 , 441.56055947, - 442.43013618, 442.43013618], - [450.41582992, 450.51985322, 450.34969428, 449.4870573 , - 450.36174131, 450.36174131], - [461.3496913 , 461.45516136, 461.28264124, 460.40838221, - 461.29485454, 461.29485454], - [464.81144234, 464.91751935, 464.74400809, 463.86483597, - 464.75629127, 464.75629127], - [464.81144234, 464.91751935, 464.74400809, 463.86483597, - 464.75629127, 464.75629127], - [474.24868136, 474.35681485, 474.17994433, 473.28405316, - 474.19246456, 474.19246456], - [487.31995591, 487.43203244, 487.24871868, 486.32062011, - 487.26169396, 487.26169396], - [491.4740523 , 491.58768629, 491.40182709, 490.46097913, - 491.41498221, 491.41498221], - [491.4740523 , 491.58768629, 491.40182709, 490.46097913, - 491.41498221, 491.41498221], - [499.50540011, 499.62252492, 499.43096001, 498.46150476, - 499.44451833, 499.44451833], - [510.66352956, 510.78672108, 510.58523924, 509.56600731, - 510.59949851, 510.59949851], - [514.21572589, 514.34119425, 514.13599039, 513.09806622, - 514.15051278, 514.15051278], - [514.21572589, 514.34119425, 514.13599039, 513.09806622, - 514.15051278, 514.15051278], - [518.21255964, 518.34081825, 518.13105299, 517.07021675, - 518.14589784, 518.14589784], - [523.74947199, 523.88203852, 523.66523073, 522.56901372, - 523.68057346, 523.68057346], - [525.50771831, 525.64177125, 525.42253345, 524.3141074 , - 525.43804798, 525.43804798]]) - SkinFrictionDrag - skin_friction_coeff |0.02613897| input unitless traj.descent.rhs_all.core_aerodynamics.skin_friction_coeff - val: - array([[0.00255188, 0.0026807 , 0.00247599, 0.00177581, 0.00248949, - 0.00248949], - [0.00254494, 0.00267312, 0.0024694 , 0.00177225, 0.00248284, - 0.00248284], - [0.00253598, 0.00266334, 0.00246091, 0.00176767, 0.00247427, - 0.00247427], - [0.00253329, 0.00266041, 0.00245837, 0.0017663 , 0.00247169, - 0.00247169], - [0.00253329, 0.00266041, 0.00245837, 0.0017663 , 0.00247169, - 0.00247169], - [0.00252165, 0.0026477 , 0.00244735, 0.00176044, 0.00246057, - 0.00246057], - [0.00250813, 0.00263289, 0.00243457, 0.00175376, 0.00244766, - 0.00244766], - [0.00250446, 0.00262887, 0.00243111, 0.001752 , 0.00244416, - 0.00244416], - [0.00250446, 0.00262887, 0.00243111, 0.001752 , 0.00244416, - 0.00244416], - [0.00249601, 0.00261957, 0.00242315, 0.00174807, 0.00243611, - 0.00243611], - [0.00248817, 0.00261085, 0.00241581, 0.00174482, 0.00242869, - 0.00242869], - [0.00248667, 0.00260914, 0.00241442, 0.00174436, 0.00242728, - 0.00242728], - [0.00248667, 0.00260914, 0.00241442, 0.00174436, 0.00242728, - 0.00242728], - [0.00248519, 0.00260738, 0.00241311, 0.00174429, 0.00242593, - 0.00242593], - [0.00248652, 0.00260857, 0.00241451, 0.00174616, 0.00242732, - 0.00242732], - [0.00248784, 0.00260991, 0.00241581, 0.00174728, 0.00242863, - 0.00242863], - [0.00248784, 0.00260991, 0.00241581, 0.00174728, 0.00242863, - 0.00242863], - [0.00248987, 0.00261202, 0.0024178 , 0.00174886, 0.00243063, - 0.00243063], - [0.00249373, 0.00261604, 0.00242156, 0.00175167, 0.0024344 , - 0.0024344 ], - [0.00249522, 0.00261761, 0.00242301, 0.00175271, 0.00243586, - 0.00243586]]) - Re |1325371462.626787| input unitless traj.descent.rhs_all.core_aerodynamics.Re - val: - array([[1.87740162e+07, 1.37594332e+07, 2.27877863e+07, 2.28966508e+08, - 2.20022504e+07, 2.20022504e+07], - [1.93001769e+07, 1.41450551e+07, 2.34264369e+07, 2.35383525e+08, - 2.26188856e+07, 2.26188856e+07], - [2.00171471e+07, 1.46705210e+07, 2.42966911e+07, 2.44127642e+08, - 2.34591406e+07, 2.34591406e+07], - [2.02414357e+07, 1.48349015e+07, 2.45689311e+07, 2.46863048e+08, - 2.37219960e+07, 2.37219960e+07], - [2.02414357e+07, 1.48349015e+07, 2.45689311e+07, 2.46863048e+08, - 2.37219960e+07, 2.37219960e+07], - [2.12683033e+07, 1.55874905e+07, 2.58153368e+07, 2.59386649e+08, - 2.49254358e+07, 2.49254358e+07], - [2.26077276e+07, 1.65691514e+07, 2.74411218e+07, 2.75722169e+08, - 2.64951771e+07, 2.64951771e+07], - [2.30076545e+07, 1.68622569e+07, 2.79265506e+07, 2.80599647e+08, - 2.69638724e+07, 2.69638724e+07], - [2.30076545e+07, 1.68622569e+07, 2.79265506e+07, 2.80599647e+08, - 2.69638724e+07, 2.69638724e+07], - [2.40232164e+07, 1.76065599e+07, 2.91592335e+07, 2.92985365e+08, - 2.81540624e+07, 2.81540624e+07], - [2.52063871e+07, 1.84737030e+07, 3.05953588e+07, 3.07415227e+08, - 2.95406819e+07, 2.95406819e+07], - [2.55169120e+07, 1.87012860e+07, 3.09722721e+07, 3.11202366e+08, - 2.99046024e+07, 2.99046024e+07], - [2.55169120e+07, 1.87012860e+07, 3.09722721e+07, 3.11202366e+08, - 2.99046024e+07, 2.99046024e+07], - [2.60126988e+07, 1.90646470e+07, 3.15740551e+07, 3.17248945e+08, - 3.04856408e+07, 3.04856408e+07], - [2.64418484e+07, 1.93791697e+07, 3.20949542e+07, 3.22482821e+08, - 3.09885836e+07, 3.09885836e+07], - [2.65078276e+07, 1.94275257e+07, 3.21750394e+07, 3.23287499e+08, - 3.10659081e+07, 3.10659081e+07], - [2.65078276e+07, 1.94275257e+07, 3.21750394e+07, 3.23287499e+08, - 3.10659081e+07, 3.10659081e+07], - [2.65377461e+07, 1.94494529e+07, 3.22113543e+07, 3.23652383e+08, - 3.11009712e+07, 3.11009712e+07], - [2.64974101e+07, 1.94198908e+07, 3.21623947e+07, 3.23160448e+08, - 3.10536993e+07, 3.10536993e+07], - [2.64637059e+07, 1.93951890e+07, 3.21214847e+07, 3.22749394e+08, - 3.10141996e+07, 3.10141996e+07]]) - fineness_ratios |10.2777523| input unitless traj.descent.rhs_all.core_aerodynamics.fineness_ratios - val: - array([ 0.13 , 0.125 , 0.1195 , 10.03921569, 1.54911839, - 1.54911839]) - wetted_areas |4886.31967641| input ft**2 traj.descent.rhs_all.core_aerodynamics.wetted_areas - val: - array([2396.56 , 592.65 , 581.13 , 4158.62 , 273.4536, 273.4536]) - laminar_fractions_upper |0.0| input unitless traj.descent.rhs_all.core_aerodynamics.laminar_fractions_upper - val: - array([0., 0., 0., 0., 0., 0.]) - laminar_fractions_lower |0.0| input unitless traj.descent.rhs_all.core_aerodynamics.laminar_fractions_lower - val: - array([0., 0., 0., 0., 0., 0.]) - aircraft:wing:area [1370.] input ft**2 traj.descent.rhs_all.aircraft:wing:area - skin_friction_drag_coeff |0.08911326| output unitless traj.descent.rhs_all.core_aerodynamics.SkinFrictionDrag.skin_friction_drag_coeff - val: - array([0.02025187, 0.02020131, 0.02013615, 0.02011662, 0.02011662, - 0.02003231, 0.01993483, 0.01990857, 0.01990857, 0.0198485 , - 0.01979423, 0.01978438, 0.01978438, 0.01977612, 0.01979006, - 0.01980122, 0.01980122, 0.01981798, 0.01984902, 0.0198609 ]) - Drag - CDI - induced_drag_coeff |0.02027026| input unitless traj.descent.rhs_all.core_aerodynamics.Drag.induced_drag_coeff - val: - array([0.00551076, 0.00524737, 0.00493175, 0.00484241, 0.00484241, - 0.00448508, 0.00413559, 0.00405585, 0.00405585, 0.0039082 , - 0.00386851, 0.00389758, 0.00389758, 0.00401743, 0.00434986, - 0.00450582, 0.00450582, 0.00471692, 0.00508363, 0.00522122]) - pressure_drag_coeff |0.0029774| input unitless traj.descent.rhs_all.core_aerodynamics.Drag.pressure_drag_coeff - val: - array([0.00093663, 0.0008723 , 0.00079139, 0.00076681, 0.00076681, - 0.00065978, 0.0005458 , 0.00051791, 0.00051791, 0.00045833, - 0.00043096, 0.00043829, 0.00043829, 0.00047777, 0.00059396, - 0.00064705, 0.00064705, 0.00071638, 0.00082929, 0.00086917]) - CDI |0.02322507| output unitless traj.descent.rhs_all.core_aerodynamics.CDI - val: - array([0.00644739, 0.00611967, 0.00572314, 0.00560922, 0.00560922, - 0.00514486, 0.00468139, 0.00457376, 0.00457376, 0.00436653, - 0.00429947, 0.00433587, 0.00433587, 0.00449519, 0.00494382, - 0.00515287, 0.00515287, 0.00543331, 0.00591292, 0.00609039]) - CD0 - compress_drag_coeff |0.00179297| input unitless traj.descent.rhs_all.core_aerodynamics.Drag.compress_drag_coeff - val: - array([0.00094091, 0.00082662, 0.00069503, 0.00065674, 0.00065674, - 0.00046614, 0.00021312, 0.00013737, 0.00013737, 0. , - 0. , 0. , 0. , 0. , 0. , - 0. , 0. , 0. , 0. , 0. ]) - skin_friction_drag_coeff |0.08911326| input unitless traj.descent.rhs_all.core_aerodynamics.Drag.skin_friction_drag_coeff - val: - array([0.02025187, 0.02020131, 0.02013615, 0.02011662, 0.02011662, - 0.02003231, 0.01993483, 0.01990857, 0.01990857, 0.0198485 , - 0.01979423, 0.01978438, 0.01978438, 0.01977612, 0.01979006, - 0.01980122, 0.01980122, 0.01981798, 0.01984902, 0.0198609 ]) - CD0 |0.09019337| output unitless traj.descent.rhs_all.core_aerodynamics.CD0 - val: - array([0.02119279, 0.02102793, 0.02083118, 0.02077336, 0.02077336, - 0.02049845, 0.02014795, 0.02004594, 0.02004594, 0.0198485 , - 0.01979423, 0.01978438, 0.01978438, 0.01977612, 0.01979006, - 0.01980122, 0.01980122, 0.01981798, 0.01984902, 0.0198609 ]) - drag - total_drag_coeff - CD0 |0.09019337| input unitless traj.descent.rhs_all.core_aerodynamics.Drag.CD0 - val: - array([0.02119279, 0.02102793, 0.02083118, 0.02077336, 0.02077336, - 0.02049845, 0.02014795, 0.02004594, 0.02004594, 0.0198485 , - 0.01979423, 0.01978438, 0.01978438, 0.01977612, 0.01979006, - 0.01980122, 0.01980122, 0.01981798, 0.01984902, 0.0198609 ]) - CDI |0.02322507| input unitless traj.descent.rhs_all.core_aerodynamics.Drag.CDI - val: - array([0.00644739, 0.00611967, 0.00572314, 0.00560922, 0.00560922, - 0.00514486, 0.00468139, 0.00457376, 0.00457376, 0.00436653, - 0.00429947, 0.00433587, 0.00433587, 0.00449519, 0.00494382, - 0.00515287, 0.00515287, 0.00543331, 0.00591292, 0.00609039]) - FCD0 [0.93089003] input unitless traj.descent.rhs_all.aircraft:design:zero_lift_drag_coeff_factor - FCDI [0.90983938] input unitless traj.descent.rhs_all.aircraft:design:lift_dependent_drag_coeff_factor - CD_prescaled |0.1049794| output unitless traj.descent.rhs_all.core_aerodynamics.Drag.drag.CD_prescaled - val: - array([0.02559425, 0.0251426 , 0.02459867, 0.0244412 , 0.0244412 , - 0.0237628 , 0.02301483, 0.02282195, 0.02282195, 0.02244961, - 0.02233808, 0.02236203, 0.02236203, 0.0224993 , 0.02292045, - 0.02312104, 0.02312104, 0.0233918 , 0.02385706, 0.02402959]) - simple_CD - aircraft:design:subsonic_drag_coeff_factor [1.] input unitless traj.descent.rhs_all.aircraft:design:subsonic_drag_coeff_factor - aircraft:design:supersonic_drag_coeff_factor [1.] input unitless traj.descent.rhs_all.aircraft:design:supersonic_drag_coeff_factor - mach |2.45889929| input unitless traj.descent.rhs_all.mach - val: - array([0.72 , 0.70498488, 0.68426707, 0.67770996, 0.67770996, - 0.64704481, 0.60473316, 0.59134167, 0.59134167, 0.55488385, - 0.50457949, 0.48865833, 0.48865833, 0.45799318, 0.41568153, - 0.40229004, 0.40229004, 0.38727492, 0.36655711, 0.36 ]) - CD_prescaled |0.1049794| input unitless traj.descent.rhs_all.core_aerodynamics.Drag.drag.CD_prescaled - val: - array([0.02559425, 0.0251426 , 0.02459867, 0.0244412 , 0.0244412 , - 0.0237628 , 0.02301483, 0.02282195, 0.02282195, 0.02244961, - 0.02233808, 0.02236203, 0.02236203, 0.0224993 , 0.02292045, - 0.02312104, 0.02312104, 0.0233918 , 0.02385706, 0.02402959]) - CD |0.1049794| output unitless traj.descent.rhs_all.core_aerodynamics.CD - val: - array([0.02559425, 0.0251426 , 0.02459867, 0.0244412 , 0.0244412 , - 0.0237628 , 0.02301483, 0.02282195, 0.02282195, 0.02244961, - 0.02233808, 0.02236203, 0.02236203, 0.0224993 , 0.02292045, - 0.02312104, 0.02312104, 0.0233918 , 0.02385706, 0.02402959]) - simple_drag - aircraft:wing:area [127.2771648] input m**2 traj.descent.rhs_all.aircraft:wing:area - dynamic_pressure |44475.56132351| input N/m**2 traj.descent.rhs_all.core_aerodynamics.dynamic_pressure - val: - array([ 9095.33551064, 9307.87296998, 9582.48704743, 9664.50081633, - 9664.50081633, 10012.80825307, 10384.65228946, 10472.52148539, - 10472.52148539, 10630.36644494, 10631.88437784, 10575.56354086, - 10575.56354086, 10385.45473119, 9940.45175416, 9754.72270062, - 9754.72270062, 9520.82727965, 9153.9663749 , 9027.31936006]) - CD |0.1049794| input unitless traj.descent.rhs_all.core_aerodynamics.Drag.drag.CD - val: - array([0.02559425, 0.0251426 , 0.02459867, 0.0244412 , 0.0244412 , - 0.0237628 , 0.02301483, 0.02282195, 0.02282195, 0.02244961, - 0.02233808, 0.02236203, 0.02236203, 0.0224993 , 0.02292045, - 0.02312104, 0.02312104, 0.0233918 , 0.02385706, 0.02402959]) - drag |132386.47842047| output N traj.descent.rhs_all.drag - val: - array([29628.63095587, 29785.93321944, 30001.32401744, 30064.39827281, - 30064.39827281, 30283.35611481, 30419.37652939, 30419.67465515, - 30419.67465515, 30374.39124359, 30227.80491759, 30099.91140717, - 30099.91140717, 29740.27925815, 28998.78423975, 28706.00892746, - 28706.00892746, 28345.80074073, 27795.64338534, 27609.31432996]) - Buffet - mach |2.45889929| input unitless traj.descent.rhs_all.mach - val: - array([0.72 , 0.70498488, 0.68426707, 0.67770996, 0.67770996, - 0.64704481, 0.60473316, 0.59134167, 0.59134167, 0.55488385, - 0.50457949, 0.48865833, 0.48865833, 0.45799318, 0.41568153, - 0.40229004, 0.40229004, 0.38727492, 0.36655711, 0.36 ]) - mission:design:mach [0.80017085] input unitless traj.descent.rhs_all.mission:design:mach - aircraft:wing:aspect_ratio [11.22091] input unitless traj.descent.rhs_all.aircraft:wing:aspect_ratio - aircraft:wing:max_camber_at_70_semispan [0.] input unitless traj.descent.rhs_all.aircraft:wing:max_camber_at_70_semispan - aircraft:wing:sweep [25.] input deg traj.descent.rhs_all.aircraft:wing:sweep - aircraft:wing:thickness_to_chord [0.13] input unitless traj.descent.rhs_all.aircraft:wing:thickness_to_chord - DELCLB |2.44711534| output unitless traj.descent.rhs_all.core_aerodynamics.Buffet.DELCLB - val: - array([0.28257367, 0.30907612, 0.34536323, 0.35641629, 0.35641629, - 0.40257916, 0.45131983, 0.46659408, 0.46659408, 0.51019085, - 0.56492696, 0.58326658, 0.58326658, 0.62087321, 0.67452094, - 0.69192503, 0.69192503, 0.70891871, 0.73083965, 0.73753993]) - core_propulsion - turbofan_28k - interpolation - mach |2.45889929| input unitless traj.descent.rhs_all.mach - val: - array([0.72 , 0.70498488, 0.68426707, 0.67770996, 0.67770996, - 0.64704481, 0.60473316, 0.59134167, 0.59134167, 0.55488385, - 0.50457949, 0.48865833, 0.48865833, 0.45799318, 0.41568153, - 0.40229004, 0.40229004, 0.38727492, 0.36655711, 0.36 ]) - altitude |90819.35928076| input ft traj.descent.rhs_all.altitude - val: - array([34000. , 32602.7594172 , 30674.85259378, 30064.67667582, - 30064.67667582, 27211.11426456, 23273.78055735, 22027.62790105, - 22027.62790105, 18635.02452748, 13953.9243121 , 12472.37209895, - 12472.37209895, 9618.80968769, 5681.47598048, 4435.32332418, - 4435.32332418, 3038.08274138, 1110.17591796, 500. ]) - throttle |1.37898255| input unitless traj.descent.rhs_all.throttle - val: - array([0.49865618, 0.47293083, 0.44177524, 0.43279925, 0.43279925, - 0.3879603 , 0.33465308, 0.31905442, 0.31905442, 0.28076346, - 0.23449042, 0.21972804, 0.21972804, 0.19416101, 0.16162186, - 0.15241077, 0.15241077, 0.14229545, 0.12937745, 0.12545435]) - fuel_flow_rate_unscaled |6808.33095172| output lbm/h traj.descent.rhs_all.turbofan_28k.interpolation.fuel_flow_rate_unscaled - val: - array([1503.37955121, 1517.94092873, 1533.53048705, 1537.17850813, - 1537.17850813, 1559.03492417, 1577.0590553 , 1580.42268385, - 1580.42268385, 1583.96652651, 1577.8361375 , 1570.86895491, - 1570.86895491, 1544.90154793, 1489.1042658 , 1464.85730748, - 1464.85730748, 1437.76799322, 1400.80973616, 1392.60948422]) - nox_rate_unscaled |39.79090373| output lbm/h traj.descent.rhs_all.turbofan_28k.interpolation.nox_rate_unscaled - val: - array([9.35086631, 9.45404569, 9.51787795, 9.52279819, 9.52279819, - 9.34463144, 9.38766488, 9.41726059, 9.41726059, 9.30673318, - 9.06982852, 8.95934038, 8.95934038, 8.7569042 , 8.26810275, - 8.10558757, 8.10558757, 7.91353105, 7.59854458, 7.44959767]) - thrust_net_unscaled |10829.88540743| output lbf traj.descent.rhs_all.turbofan_28k.interpolation.thrust_net_unscaled - val: - array([2592.38405619, 2601.25619987, 2612.61858663, 2615.46381809, - 2615.46381809, 2618.99352049, 2601.42829759, 2590.02168952, - 2590.02168952, 2550.8318053 , 2478.80852562, 2444.37153188, - 2444.37153188, 2361.22340177, 2208.19330616, 2150.07646149, - 2150.07646149, 2079.18894078, 1971.20719177, 1934.52722757]) - interp_max_throttles - mach |2.45889929| input unitless traj.descent.rhs_all.mach - val: - array([0.72 , 0.70498488, 0.68426707, 0.67770996, 0.67770996, - 0.64704481, 0.60473316, 0.59134167, 0.59134167, 0.55488385, - 0.50457949, 0.48865833, 0.48865833, 0.45799318, 0.41568153, - 0.40229004, 0.40229004, 0.38727492, 0.36655711, 0.36 ]) - altitude |90819.35928076| input ft traj.descent.rhs_all.altitude - val: - array([34000. , 32602.7594172 , 30674.85259378, 30064.67667582, - 30064.67667582, 27211.11426456, 23273.78055735, 22027.62790105, - 22027.62790105, 18635.02452748, 13953.9243121 , 12472.37209895, - 12472.37209895, 9618.80968769, 5681.47598048, 4435.32332418, - 4435.32332418, 3038.08274138, 1110.17591796, 500. ]) - throttle_max |4.47213595| output unitless traj.descent.rhs_all.turbofan_28k.throttle_max - val: - array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - 1., 1., 1.]) - max_interpolation - mach |2.45889929| input unitless traj.descent.rhs_all.mach - val: - array([0.72 , 0.70498488, 0.68426707, 0.67770996, 0.67770996, - 0.64704481, 0.60473316, 0.59134167, 0.59134167, 0.55488385, - 0.50457949, 0.48865833, 0.48865833, 0.45799318, 0.41568153, - 0.40229004, 0.40229004, 0.38727492, 0.36655711, 0.36 ]) - altitude |90819.35928076| input ft traj.descent.rhs_all.altitude - val: - array([34000. , 32602.7594172 , 30674.85259378, 30064.67667582, - 30064.67667582, 27211.11426456, 23273.78055735, 22027.62790105, - 22027.62790105, 18635.02452748, 13953.9243121 , 12472.37209895, - 12472.37209895, 9618.80968769, 5681.47598048, 4435.32332418, - 4435.32332418, 3038.08274138, 1110.17591796, 500. ]) - throttle_max |4.47213595| input unitless traj.descent.rhs_all.throttle_max - val: - array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., - 1., 1., 1.]) - thrust_net_max_unscaled |63857.67198423| output lbf traj.descent.rhs_all.turbofan_28k.max_interpolation.thrust_net_max_unscaled - val: - array([ 5552.244 , 5917.97201101, 6428.32524261, 6590.10881811, - 6590.10881811, 7500.11461522, 8893.43548808, 9386.73222571, - 9386.73222571, 10844.87696627, 13226.95369831, 14106.4081819 , - 14106.4081819 , 15866.98242317, 18765.32961914, 19751.11014998, - 19751.11014998, 20964.54618415, 22706.21234893, 23290.83 ]) - engine_scaling - aircraft:engine:scale_factor [1.] input unitless traj.descent.rhs_all.aircraft:engine:scale_factor - mach |2.45889929| input unitless traj.descent.rhs_all.mach - val: - array([0.72 , 0.70498488, 0.68426707, 0.67770996, 0.67770996, - 0.64704481, 0.60473316, 0.59134167, 0.59134167, 0.55488385, - 0.50457949, 0.48865833, 0.48865833, 0.45799318, 0.41568153, - 0.40229004, 0.40229004, 0.38727492, 0.36655711, 0.36 ]) - fuel_flow_rate_unscaled |6808.33095172| input lbm/h traj.descent.rhs_all.engine_scaling.fuel_flow_rate_unscaled - val: - array([1503.37955121, 1517.94092873, 1533.53048705, 1537.17850813, - 1537.17850813, 1559.03492417, 1577.0590553 , 1580.42268385, - 1580.42268385, 1583.96652651, 1577.8361375 , 1570.86895491, - 1570.86895491, 1544.90154793, 1489.1042658 , 1464.85730748, - 1464.85730748, 1437.76799322, 1400.80973616, 1392.60948422]) - nox_rate_unscaled |39.79090373| input lbm/h traj.descent.rhs_all.engine_scaling.nox_rate_unscaled - val: - array([9.35086631, 9.45404569, 9.51787795, 9.52279819, 9.52279819, - 9.34463144, 9.38766488, 9.41726059, 9.41726059, 9.30673318, - 9.06982852, 8.95934038, 8.95934038, 8.7569042 , 8.26810275, - 8.10558757, 8.10558757, 7.91353105, 7.59854458, 7.44959767]) - thrust_net_unscaled |10829.88540743| input lbf traj.descent.rhs_all.engine_scaling.thrust_net_unscaled - val: - array([2592.38405619, 2601.25619987, 2612.61858663, 2615.46381809, - 2615.46381809, 2618.99352049, 2601.42829759, 2590.02168952, - 2590.02168952, 2550.8318053 , 2478.80852562, 2444.37153188, - 2444.37153188, 2361.22340177, 2208.19330616, 2150.07646149, - 2150.07646149, 2079.18894078, 1971.20719177, 1934.52722757]) - thrust_net_max_unscaled |63857.67198423| input lbf traj.descent.rhs_all.engine_scaling.thrust_net_max_unscaled - val: - array([ 5552.244 , 5917.97201101, 6428.32524261, 6590.10881811, - 6590.10881811, 7500.11461522, 8893.43548808, 9386.73222571, - 9386.73222571, 10844.87696627, 13226.95369831, 14106.4081819 , - 14106.4081819 , 15866.98242317, 18765.32961914, 19751.11014998, - 19751.11014998, 20964.54618415, 22706.21234893, 23290.83 ]) - fuel_flow_rate_negative |6808.33095172| output lbm/h traj.descent.rhs_all.turbofan_28k.fuel_flow_rate_negative - val: - array([-1503.37955121, -1517.94092873, -1533.53048705, -1537.17850813, - -1537.17850813, -1559.03492417, -1577.0590553 , -1580.42268385, - -1580.42268385, -1583.96652651, -1577.8361375 , -1570.86895491, - -1570.86895491, -1544.90154793, -1489.1042658 , -1464.85730748, - -1464.85730748, -1437.76799322, -1400.80973616, -1392.60948422]) - nox_rate |39.79090373| output lbm/h traj.descent.rhs_all.turbofan_28k.nox_rate - val: - array([9.35086631, 9.45404569, 9.51787795, 9.52279819, 9.52279819, - 9.34463144, 9.38766488, 9.41726059, 9.41726059, 9.30673318, - 9.06982852, 8.95934038, 8.95934038, 8.7569042 , 8.26810275, - 8.10558757, 8.10558757, 7.91353105, 7.59854458, 7.44959767]) - thrust_net |10829.88540743| output lbf traj.descent.rhs_all.turbofan_28k.thrust_net - val: - array([2592.38405619, 2601.25619987, 2612.61858663, 2615.46381809, - 2615.46381809, 2618.99352049, 2601.42829759, 2590.02168952, - 2590.02168952, 2550.8318053 , 2478.80852562, 2444.37153188, - 2444.37153188, 2361.22340177, 2208.19330616, 2150.07646149, - 2150.07646149, 2079.18894078, 1971.20719177, 1934.52722757]) - thrust_net_max |63857.67198423| output lbf traj.descent.rhs_all.turbofan_28k.thrust_net_max - val: - array([ 5552.244 , 5917.97201101, 6428.32524261, 6590.10881811, - 6590.10881811, 7500.11461522, 8893.43548808, 9386.73222571, - 9386.73222571, 10844.87696627, 13226.95369831, 14106.4081819 , - 14106.4081819 , 15866.98242317, 18765.32961914, 19751.11014998, - 19751.11014998, 20964.54618415, 22706.21234893, 23290.83 ]) - vectorize_performance - thrust_net_0 |10829.88540743| input lbf traj.descent.rhs_all.vectorize_performance.thrust_net_0 - val: - array([2592.38405619, 2601.25619987, 2612.61858663, 2615.46381809, - 2615.46381809, 2618.99352049, 2601.42829759, 2590.02168952, - 2590.02168952, 2550.8318053 , 2478.80852562, 2444.37153188, - 2444.37153188, 2361.22340177, 2208.19330616, 2150.07646149, - 2150.07646149, 2079.18894078, 1971.20719177, 1934.52722757]) - thrust_net_max_0 |63857.67198423| input lbf traj.descent.rhs_all.vectorize_performance.thrust_net_max_0 - val: - array([ 5552.244 , 5917.97201101, 6428.32524261, 6590.10881811, - 6590.10881811, 7500.11461522, 8893.43548808, 9386.73222571, - 9386.73222571, 10844.87696627, 13226.95369831, 14106.4081819 , - 14106.4081819 , 15866.98242317, 18765.32961914, 19751.11014998, - 19751.11014998, 20964.54618415, 22706.21234893, 23290.83 ]) - fuel_flow_rate_negative_0 |6808.33095172| input lbm/h traj.descent.rhs_all.vectorize_performance.fuel_flow_rate_negative_0 - val: - array([-1503.37955121, -1517.94092873, -1533.53048705, -1537.17850813, - -1537.17850813, -1559.03492417, -1577.0590553 , -1580.42268385, - -1580.42268385, -1583.96652651, -1577.8361375 , -1570.86895491, - -1570.86895491, -1544.90154793, -1489.1042658 , -1464.85730748, - -1464.85730748, -1437.76799322, -1400.80973616, -1392.60948422]) - electric_power_in_0 |0.0| input kW traj.descent.rhs_all.vectorize_performance.electric_power_in_0 - val: - array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., - 0., 0., 0.]) - nox_rate_0 |39.79090373| input lbm/h traj.descent.rhs_all.vectorize_performance.nox_rate_0 - val: - array([9.35086631, 9.45404569, 9.51787795, 9.52279819, 9.52279819, - 9.34463144, 9.38766488, 9.41726059, 9.41726059, 9.30673318, - 9.06982852, 8.95934038, 8.95934038, 8.7569042 , 8.26810275, - 8.10558757, 8.10558757, 7.91353105, 7.59854458, 7.44959767]) - t4_0 |0.0| input degR traj.descent.rhs_all.vectorize_performance.t4_0 - val: - array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., - 0., 0., 0.]) - shaft_power_0 |0.0| input hp traj.descent.rhs_all.vectorize_performance.shaft_power_0 - val: - array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., - 0., 0., 0.]) - shaft_power_max_0 |0.0| input hp traj.descent.rhs_all.vectorize_performance.shaft_power_max_0 - val: - array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., - 0., 0., 0.]) - thrust_net |10829.88540743| output lbf traj.descent.rhs_all.thrust_net - val: - array([[2592.38405619], - [2601.25619987], - [2612.61858663], - [2615.46381809], - [2615.46381809], - [2618.99352049], - [2601.42829759], - [2590.02168952], - [2590.02168952], - [2550.8318053 ], - [2478.80852562], - [2444.37153188], - [2444.37153188], - [2361.22340177], - [2208.19330616], - [2150.07646149], - [2150.07646149], - [2079.18894078], - [1971.20719177], - [1934.52722757]]) - thrust_net_max |63857.67198423| output lbf traj.descent.rhs_all.thrust_net_max - val: - array([[ 5552.244 ], - [ 5917.97201101], - [ 6428.32524261], - [ 6590.10881811], - [ 6590.10881811], - [ 7500.11461522], - [ 8893.43548808], - [ 9386.73222571], - [ 9386.73222571], - [10844.87696627], - [13226.95369831], - [14106.4081819 ], - [14106.4081819 ], - [15866.98242317], - [18765.32961914], - [19751.11014998], - [19751.11014998], - [20964.54618415], - [22706.21234893], - [23290.83 ]]) - fuel_flow_rate_negative |6808.33095172| output lbm/h traj.descent.rhs_all.fuel_flow_rate_negative - val: - array([[-1503.37955121], - [-1517.94092873], - [-1533.53048705], - [-1537.17850813], - [-1537.17850813], - [-1559.03492417], - [-1577.0590553 ], - [-1580.42268385], - [-1580.42268385], - [-1583.96652651], - [-1577.8361375 ], - [-1570.86895491], - [-1570.86895491], - [-1544.90154793], - [-1489.1042658 ], - [-1464.85730748], - [-1464.85730748], - [-1437.76799322], - [-1400.80973616], - [-1392.60948422]]) - electric_power_in |0.0| output kW traj.descent.rhs_all.electric_power_in - val: - array([[0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.]]) - nox_rate |39.79090373| output lbm/h traj.descent.rhs_all.nox_rate - val: - array([[9.35086631], - [9.45404569], - [9.51787795], - [9.52279819], - [9.52279819], - [9.34463144], - [9.38766488], - [9.41726059], - [9.41726059], - [9.30673318], - [9.06982852], - [8.95934038], - [8.95934038], - [8.7569042 ], - [8.26810275], - [8.10558757], - [8.10558757], - [7.91353105], - [7.59854458], - [7.44959767]]) - t4 |0.0| output degR traj.descent.rhs_all.t4 - val: - array([[0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.]]) - shaft_power |0.0| output hp traj.descent.rhs_all.shaft_power - val: - array([[0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.]]) - shaft_power_max |0.0| output hp traj.descent.rhs_all.shaft_power_max - val: - array([[0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.]]) - propulsion_sum - thrust_net |10829.88540743| input lbf traj.descent.rhs_all.thrust_net - val: - array([[2592.38405619], - [2601.25619987], - [2612.61858663], - [2615.46381809], - [2615.46381809], - [2618.99352049], - [2601.42829759], - [2590.02168952], - [2590.02168952], - [2550.8318053 ], - [2478.80852562], - [2444.37153188], - [2444.37153188], - [2361.22340177], - [2208.19330616], - [2150.07646149], - [2150.07646149], - [2079.18894078], - [1971.20719177], - [1934.52722757]]) - thrust_net_max |63857.67198423| input lbf traj.descent.rhs_all.thrust_net_max - val: - array([[ 5552.244 ], - [ 5917.97201101], - [ 6428.32524261], - [ 6590.10881811], - [ 6590.10881811], - [ 7500.11461522], - [ 8893.43548808], - [ 9386.73222571], - [ 9386.73222571], - [10844.87696627], - [13226.95369831], - [14106.4081819 ], - [14106.4081819 ], - [15866.98242317], - [18765.32961914], - [19751.11014998], - [19751.11014998], - [20964.54618415], - [22706.21234893], - [23290.83 ]]) - fuel_flow_rate_negative |6808.33095172| input lbm/h traj.descent.rhs_all.fuel_flow_rate_negative - val: - array([[-1503.37955121], - [-1517.94092873], - [-1533.53048705], - [-1537.17850813], - [-1537.17850813], - [-1559.03492417], - [-1577.0590553 ], - [-1580.42268385], - [-1580.42268385], - [-1583.96652651], - [-1577.8361375 ], - [-1570.86895491], - [-1570.86895491], - [-1544.90154793], - [-1489.1042658 ], - [-1464.85730748], - [-1464.85730748], - [-1437.76799322], - [-1400.80973616], - [-1392.60948422]]) - electric_power_in |0.0| input kW traj.descent.rhs_all.electric_power_in - val: - array([[0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.]]) - nox_rate |39.79090373| input lbm/h traj.descent.rhs_all.nox_rate - val: - array([[9.35086631], - [9.45404569], - [9.51787795], - [9.52279819], - [9.52279819], - [9.34463144], - [9.38766488], - [9.41726059], - [9.41726059], - [9.30673318], - [9.06982852], - [8.95934038], - [8.95934038], - [8.7569042 ], - [8.26810275], - [8.10558757], - [8.10558757], - [7.91353105], - [7.59854458], - [7.44959767]]) - thrust_net_total |21659.77081486| output lbf traj.descent.rhs_all.thrust_net_total - val: - array([5184.76811238, 5202.51239973, 5225.23717327, 5230.92763617, - 5230.92763617, 5237.98704098, 5202.85659519, 5180.04337904, - 5180.04337904, 5101.6636106 , 4957.61705125, 4888.74306376, - 4888.74306376, 4722.44680354, 4416.38661232, 4300.15292299, - 4300.15292299, 4158.37788155, 3942.41438355, 3869.05445515]) - thrust_net_max_total |127715.34396845| output lbf traj.descent.rhs_all.thrust_net_max_total - val: - array([11104.488 , 11835.94402202, 12856.65048522, 13180.21763622, - 13180.21763622, 15000.22923043, 17786.87097616, 18773.46445142, - 18773.46445142, 21689.75393255, 26453.90739662, 28212.8163638 , - 28212.8163638 , 31733.96484634, 37530.65923828, 39502.22029996, - 39502.22029996, 41929.09236831, 45412.42469786, 46581.66 ]) - fuel_flow_rate_negative_total |13616.66190343| output lbm/h traj.descent.rhs_all.fuel_flow_rate_negative_total - val: - array([-3006.75910243, -3035.88185747, -3067.0609741 , -3074.35701626, - -3074.35701626, -3118.06984835, -3154.1181106 , -3160.84536771, - -3160.84536771, -3167.93305303, -3155.67227501, -3141.73790983, - -3141.73790983, -3089.80309587, -2978.2085316 , -2929.71461497, - -2929.71461497, -2875.53598644, -2801.61947232, -2785.21896845]) - electric_power_in_total |0.0| output kW traj.descent.rhs_all.electric_power_in_total - val: - array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., - 0., 0., 0.]) - nox_rate_total |79.58180746| output lbm/h traj.descent.rhs_all.nox_rate_total - val: - array([18.70173262, 18.90809138, 19.03575591, 19.04559638, 19.04559638, - 18.68926287, 18.77532976, 18.83452118, 18.83452118, 18.61346637, - 18.13965705, 17.91868076, 17.91868076, 17.5138084 , 16.53620549, - 16.21117515, 16.21117515, 15.8270621 , 15.19708917, 14.89919533]) - mission_EOM - required_thrust - drag |132386.47842047| input N traj.descent.rhs_all.drag - val: - array([29628.63095587, 29785.93321944, 30001.32401744, 30064.39827281, - 30064.39827281, 30283.35611481, 30419.37652939, 30419.67465515, - 30419.67465515, 30374.39124359, 30227.80491759, 30099.91140717, - 30099.91140717, 29740.27925815, 28998.78423975, 28706.00892746, - 28706.00892746, 28345.80074073, 27795.64338534, 27609.31432996]) - altitude_rate |10.0383886| input m/s traj.descent.rhs_all.altitude_rate - val: - array([-2.24465193, -2.24465193, -2.24465193, -2.24465193, -2.24465193, - -2.24465193, -2.24465193, -2.24465193, -2.24465193, -2.24465193, - -2.24465193, -2.24465193, -2.24465193, -2.24465193, -2.24465193, - -2.24465193, -2.24465193, -2.24465193, -2.24465193, -2.24465193]) - velocity |771.73974523| input m/s traj.descent.rhs_all.velocity - val: - array([214.51878007, 211.35290813, 206.88067906, 205.44035421, - 205.44035421, 198.54796477, 188.62062791, 185.37975905, - 185.37975905, 176.32034566, 163.26330289, 158.99885174, - 158.99885174, 150.60981862, 138.66141566, 134.79094549, - 134.79094549, 130.40117072, 124.25764936, 122.29253366]) - velocity_rate |0.11322376| input m/s**2 traj.descent.rhs_all.velocity_rate - val: - array([-0.02357896, -0.02372576, -0.02392688, -0.02399019, -0.02399019, - -0.02428415, -0.02468409, -0.02480936, -0.02480936, -0.02514734, - -0.02560653, -0.02575019, -0.02575019, -0.02602472, -0.02639895, - -0.02651632, -0.02651632, -0.02664734, -0.02682707, -0.02688371]) - mass |228638.93848721| input kg traj.descent.rhs_all.mass - val: - array([52028.74471935, 51956.50719188, 51855.82599664, 51823.76601249, - 51823.76601249, 51672.54219645, 51461.12266693, 51393.8106793 , - 51393.8106793 , 51210.06984292, 50956.67116637, 50876.7919899 , - 50876.7919899 , 50724.57452871, 50519.93012614, 50456.90390387, - 50456.90390387, 50387.51580428, 50293.8882617 , 50264.76158872]) - thrust_required |96347.46082289| output N traj.descent.rhs_all.thrust_required - val: - array([23062.9976122 , 23141.92813481, 23243.01296376, 23268.32540388, - 23268.32540388, 23299.72720096, 23143.45919248, 23041.98095119, - 23041.98095119, 22693.33037066, 22052.57935105, 21746.21259086, - 21746.21259086, 21006.48997083, 19645.06641118, 19128.03320134, - 19128.03320134, 18497.38639685, 17536.73289589, 17210.41167636]) - groundspeed - altitude_rate |10.0383886| input m/s traj.descent.rhs_all.altitude_rate - val: - array([-2.24465193, -2.24465193, -2.24465193, -2.24465193, -2.24465193, - -2.24465193, -2.24465193, -2.24465193, -2.24465193, -2.24465193, - -2.24465193, -2.24465193, -2.24465193, -2.24465193, -2.24465193, - -2.24465193, -2.24465193, -2.24465193, -2.24465193, -2.24465193]) - velocity |771.73974523| input m/s traj.descent.rhs_all.velocity - val: - array([214.51878007, 211.35290813, 206.88067906, 205.44035421, - 205.44035421, 198.54796477, 188.62062791, 185.37975905, - 185.37975905, 176.32034566, 163.26330289, 158.99885174, - 158.99885174, 150.60981862, 138.66141566, 134.79094549, - 134.79094549, 130.40117072, 124.25764936, 122.29253366]) - distance_rate |771.67445541| output m/s traj.descent.rhs_all.distance_rate - val: - array([214.5070361 , 211.34098824, 206.86850148, 205.42809125, - 205.42809125, 198.53527609, 188.60727137, 185.36616898, - 185.36616898, 176.30605727, 163.24787168, 158.98300661, - 158.98300661, 150.59309082, 138.64324625, 134.77225428, - 134.77225428, 130.38185021, 124.23737345, 122.27193189]) - excess_specific_power - velocity |771.73974523| input m/s traj.descent.rhs_all.velocity - val: - array([214.51878007, 211.35290813, 206.88067906, 205.44035421, - 205.44035421, 198.54796477, 188.62062791, 185.37975905, - 185.37975905, 176.32034566, 163.26330289, 158.99885174, - 158.99885174, 150.60981862, 138.66141566, 134.79094549, - 134.79094549, 130.40117072, 124.25764936, 122.29253366]) - mass |228638.93848721| input kg traj.descent.rhs_all.mass - val: - array([52028.74471935, 51956.50719188, 51855.82599664, 51823.76601249, - 51823.76601249, 51672.54219645, 51461.12266693, 51393.8106793 , - 51393.8106793 , 51210.06984292, 50956.67116637, 50876.7919899 , - 50876.7919899 , 50724.57452871, 50519.93012614, 50456.90390387, - 50456.90390387, 50387.51580428, 50293.8882617 , 50264.76158872]) - thrust_net_total |568106.15424621| input N traj.descent.rhs_all.thrust_net_max_total - val: - array([ 49395.22360063, 52648.90209187, 57189.23064916, 58628.52904574, - 58628.52904574, 66724.34396776, 79119.94402832, 83508.53045513, - 83508.53045513, 96480.83237524, 117672.84281513, 125496.85971055, - 125496.85971055, 141159.70851781, 166944.68983655, 175714.6303763 , - 175714.6303763 , 186509.89517967, 202004.52935762, 207205.54710749]) - drag |132386.47842047| input N traj.descent.rhs_all.drag - val: - array([29628.63095587, 29785.93321944, 30001.32401744, 30064.39827281, - 30064.39827281, 30283.35611481, 30419.37652939, 30419.67465515, - 30419.67465515, 30374.39124359, 30227.80491759, 30099.91140717, - 30099.91140717, 29740.27925815, 28998.78423975, 28706.00892746, - 28706.00892746, 28345.80074073, 27795.64338534, 27609.31432996]) - specific_energy_rate |128.60366435| output m/s traj.descent.rhs_all.specific_energy_rate_excess - val: - array([ 8.31061392, 9.4837529 , 11.06056904, 11.5466798 , 11.5466798 , - 14.27825313, 18.20217461, 19.52693959, 19.52693959, 23.20973395, - 28.56945948, 30.4010144 , 30.4010144 , 33.73456594, 38.60833097, - 40.04628659, 40.04628659, 41.73935818, 43.8891883 , 44.55668406]) - altitude_rate_max - specific_energy_rate |128.60366435| input m/s traj.descent.rhs_all.mission_EOM.specific_energy_rate_excess - val: - array([ 8.31061392, 9.4837529 , 11.06056904, 11.5466798 , 11.5466798 , - 14.27825313, 18.20217461, 19.52693959, 19.52693959, 23.20973395, - 28.56945948, 30.4010144 , 30.4010144 , 33.73456594, 38.60833097, - 40.04628659, 40.04628659, 41.73935818, 43.8891883 , 44.55668406]) - velocity_rate |0.11322376| input m/s**2 traj.descent.rhs_all.velocity_rate - val: - array([-0.02357896, -0.02372576, -0.02392688, -0.02399019, -0.02399019, - -0.02428415, -0.02468409, -0.02480936, -0.02480936, -0.02514734, - -0.02560653, -0.02575019, -0.02575019, -0.02602472, -0.02639895, - -0.02651632, -0.02651632, -0.02664734, -0.02682707, -0.02688371]) - velocity |771.73974523| input m/s traj.descent.rhs_all.velocity - val: - array([214.51878007, 211.35290813, 206.88067906, 205.44035421, - 205.44035421, 198.54796477, 188.62062791, 185.37975905, - 185.37975905, 176.32034566, 163.26330289, 158.99885174, - 158.99885174, 150.60981862, 138.66141566, 134.79094549, - 134.79094549, 130.40117072, 124.25764936, 122.29253366]) - altitude_rate |130.2418282| output m/s traj.descent.rhs_all.altitude_rate_max - val: - array([ 8.82639951, 9.99509048, 11.56532945, 12.04925228, 12.04925228, - 14.76991619, 18.67694721, 19.9959227 , 19.9959227 , 23.66187489, - 28.99576271, 30.81851176, 30.81851176, 34.13425165, 38.98159969, - 40.4107494 , 40.4107494 , 42.09369368, 44.22910749, 44.8919338 ]) - throttle_balance - thrust_required |21659.77081486| input lbf traj.descent.rhs_all.thrust_required - val: - array([5184.76811238, 5202.51239973, 5225.23717327, 5230.92763617, - 5230.92763617, 5237.98704098, 5202.85659519, 5180.04337904, - 5180.04337904, 5101.6636106 , 4957.61705125, 4888.74306376, - 4888.74306376, 4722.44680354, 4416.38661232, 4300.15292299, - 4300.15292299, 4158.37788155, 3942.41438355, 3869.05445515]) - thrust_net_total |21659.77081486| input lbf traj.descent.rhs_all.thrust_net_total - val: - array([5184.76811238, 5202.51239973, 5225.23717327, 5230.92763617, - 5230.92763617, 5237.98704098, 5202.85659519, 5180.04337904, - 5180.04337904, 5101.6636106 , 4957.61705125, 4888.74306376, - 4888.74306376, 4722.44680354, 4416.38661232, 4300.15292299, - 4300.15292299, 4158.37788155, 3942.41438355, 3869.05445515]) - throttle |1.37898255| output unitless traj.descent.rhs_all.throttle - val: - array([0.49865618, 0.47293083, 0.44177524, 0.43279925, 0.43279925, - 0.3879603 , 0.33465308, 0.31905442, 0.31905442, 0.28076346, - 0.23449042, 0.21972804, 0.21972804, 0.19416101, 0.16162186, - 0.15241077, 0.15241077, 0.14229545, 0.12937745, 0.12545435]) - initial_mass_residual_constraint - initial_mass [1.] input kg traj.descent.rhs_all.mission:summary:gross_mass - mass |228638.93848721| input kg traj.descent.rhs_all.mass - val: - array([52028.74471935, 51956.50719188, 51855.82599664, 51823.76601249, - 51823.76601249, 51672.54219645, 51461.12266693, 51393.8106793 , - 51393.8106793 , 51210.06984292, 50956.67116637, 50876.7919899 , - 50876.7919899 , 50724.57452871, 50519.93012614, 50456.90390387, - 50456.90390387, 50387.51580428, 50293.8882617 , 50264.76158872]) - initial_mass_residual [-52127.74471935] output kg traj.descent.rhs_all.initial_mass_residual - timeseries - dt_dstau |2153.29990796| input s traj.descent.timeseries.dt_dstau - val: - array([267.18765032, 267.18765032, 267.18765032, 267.18765032, - 545.67312537, 545.67312537, 545.67312537, 545.67312537, - 648.75135679, 648.75135679, 648.75135679, 648.75135679, - 545.67312537, 545.67312537, 545.67312537, 545.67312537, - 267.18765032, 267.18765032, 267.18765032, 267.18765032]) - input_values:mach |2.45889929| input unitless traj.descent.timeseries.input_values:mach - val: - array([[0.72 ], - [0.70498488], - [0.68426707], - [0.67770996], - [0.67770996], - [0.64704481], - [0.60473316], - [0.59134167], - [0.59134167], - [0.55488385], - [0.50457949], - [0.48865833], - [0.48865833], - [0.45799318], - [0.41568153], - [0.40229004], - [0.40229004], - [0.38727492], - [0.36655711], - [0.36 ]]) - input_values:thrust_net_total |21659.77081486| input lbf traj.descent.timeseries.input_values:thrust_net_total - val: - array([[5184.76811238], - [5202.51239973], - [5225.23717327], - [5230.92763617], - [5230.92763617], - [5237.98704098], - [5202.85659519], - [5180.04337904], - [5180.04337904], - [5101.6636106 ], - [4957.61705125], - [4888.74306376], - [4888.74306376], - [4722.44680354], - [4416.38661232], - [4300.15292299], - [4300.15292299], - [4158.37788155], - [3942.41438355], - [3869.05445515]]) - input_values:drag |29761.66426269| input lbf traj.descent.timeseries.input_values:drag - val: - array([[6660.78120358], - [6696.14415917], - [6744.56593677], - [6758.74559344], - [6758.74559344], - [6807.96927443], - [6838.54788004], - [6838.61490138], - [6838.61490138], - [6828.43478549], - [6795.48086851], - [6766.72926363], - [6766.72926363], - [6685.88074039], - [6519.18602917], - [6453.36752072], - [6453.36752072], - [6372.38949905], - [6248.70920558], - [6206.82076761]]) - input_values:specific_energy_rate_excess |128.60366435| input m/s traj.descent.timeseries.input_values:specific_energy_rate_excess - val: - array([[ 8.31061392], - [ 9.4837529 ], - [11.06056904], - [11.5466798 ], - [11.5466798 ], - [14.27825313], - [18.20217461], - [19.52693959], - [19.52693959], - [23.20973395], - [28.56945948], - [30.4010144 ], - [30.4010144 ], - [33.73456594], - [38.60833097], - [40.04628659], - [40.04628659], - [41.73935818], - [43.8891883 ], - [44.55668406]]) - input_values:fuel_flow_rate_negative_total |13616.66190343| input lbm/h traj.descent.timeseries.input_values:fuel_flow_rate_negative_total - val: - array([[-3006.75910243], - [-3035.88185747], - [-3067.0609741 ], - [-3074.35701626], - [-3074.35701626], - [-3118.06984835], - [-3154.1181106 ], - [-3160.84536771], - [-3160.84536771], - [-3167.93305303], - [-3155.67227501], - [-3141.73790983], - [-3141.73790983], - [-3089.80309587], - [-2978.2085316 ], - [-2929.71461497], - [-2929.71461497], - [-2875.53598644], - [-2801.61947232], - [-2785.21896845]]) - input_values:electric_power_in_total |0.0| input kW traj.descent.timeseries.input_values:electric_power_in_total - val: - array([[0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.]]) - input_values:altitude_rate |32.93434579| input ft/s traj.descent.timeseries.input_values:altitude_rate - val: - array([[-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436]]) - input_values:throttle |1.37898255| input unitless traj.descent.timeseries.input_values:throttle - val: - array([[0.49865618], - [0.47293083], - [0.44177524], - [0.43279925], - [0.43279925], - [0.3879603 ], - [0.33465308], - [0.31905442], - [0.31905442], - [0.28076346], - [0.23449042], - [0.21972804], - [0.21972804], - [0.19416101], - [0.16162186], - [0.15241077], - [0.15241077], - [0.14229545], - [0.12937745], - [0.12545435]]) - input_values:velocity |771.73974523| input m/s traj.descent.timeseries.input_values:velocity - val: - array([[214.51878007], - [211.35290813], - [206.88067906], - [205.44035421], - [205.44035421], - [198.54796477], - [188.62062791], - [185.37975905], - [185.37975905], - [176.32034566], - [163.26330289], - [158.99885174], - [158.99885174], - [150.60981862], - [138.66141566], - [134.79094549], - [134.79094549], - [130.40117072], - [124.25764936], - [122.29253366]]) - input_values:altitude |90819.35928076| input ft traj.descent.timeseries.input_values:altitude - val: - array([[34000. ], - [32602.7594172 ], - [30674.85259378], - [30064.67667582], - [30064.67667582], - [27211.11426456], - [23273.78055735], - [22027.62790105], - [22027.62790105], - [18635.02452748], - [13953.9243121 ], - [12472.37209895], - [12472.37209895], - [ 9618.80968769], - [ 5681.47598048], - [ 4435.32332418], - [ 4435.32332418], - [ 3038.08274138], - [ 1110.17591796], - [ 500. ]]) - input_values:time |73347.98069351| input s traj.descent.timeseries.input_values:time - val: - array([[14010. ], - [14199.73049861], - [14461.51986216], - [14544.37530064], - [14544.37530064], - [14931.85890638], - [15466.50719578], - [15635.72155138], - [15635.72155138], - [16096.40122071], - [16732.04513834], - [16933.22426496], - [16933.22426496], - [17320.7078707 ], - [17855.3561601 ], - [18024.5705157 ], - [18024.5705157 ], - [18214.30101431], - [18476.09037785], - [18558.94581634]]) - input_values:time_phase |12418.42831132| input s traj.descent.timeseries.input_values:time_phase - val: - array([[ 0. ], - [ 189.73049861], - [ 451.51986216], - [ 534.37530064], - [ 534.37530064], - [ 921.85890638], - [1456.50719578], - [1625.72155138], - [1625.72155138], - [2086.40122071], - [2722.04513834], - [2923.22426496], - [2923.22426496], - [3310.7078707 ], - [3845.3561601 ], - [4014.5705157 ], - [4014.5705157 ], - [4204.30101431], - [4466.09037785], - [4548.94581634]]) - input_values:mach_rate |0.00035392| input unitless/s traj.descent.timeseries.input_values:mach_rate - val: - array([[-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05]]) - input_values:mass |228638.93848721| input kg traj.descent.timeseries.input_values:mass - val: - array([[52028.74471935], - [51956.50719188], - [51855.82599664], - [51823.76601249], - [51823.76601249], - [51672.54219645], - [51461.12266693], - [51393.8106793 ], - [51393.8106793 ], - [51210.06984292], - [50956.67116637], - [50876.7919899 ], - [50876.7919899 ], - [50724.57452871], - [50519.93012614], - [50456.90390387], - [50456.90390387], - [50387.51580428], - [50293.8882617 ], - [50264.76158872]]) - input_values:distance |14257384.99570313| input m traj.descent.timeseries.input_values:distance - val: - array([[2751418.23144865], - [2791817.41185045], - [2846561.44051968], - [2863642.02155273], - [2863642.02155273], - [2941914.82037522], - [3045428.93171548], - [3077070.29224964], - [3077070.29224964], - [3160390.83905457], - [3268342.75197541], - [3300756.63996977], - [3300756.63996977], - [3360741.81646801], - [3438080.96818847], - [3461214.38233449], - [3461214.38233449], - [3486369.12667608], - [3519699.62007001], - [3529912. ]]) - mach |2.45889929| output unitless traj.descent.timeseries.mach - val: - array([[0.72 ], - [0.70498488], - [0.68426707], - [0.67770996], - [0.67770996], - [0.64704481], - [0.60473316], - [0.59134167], - [0.59134167], - [0.55488385], - [0.50457949], - [0.48865833], - [0.48865833], - [0.45799318], - [0.41568153], - [0.40229004], - [0.40229004], - [0.38727492], - [0.36655711], - [0.36 ]]) - thrust_net_total |21659.77081486| output lbf traj.descent.timeseries.thrust_net_total - val: - array([[5184.76811238], - [5202.51239973], - [5225.23717327], - [5230.92763617], - [5230.92763617], - [5237.98704098], - [5202.85659519], - [5180.04337904], - [5180.04337904], - [5101.6636106 ], - [4957.61705125], - [4888.74306376], - [4888.74306376], - [4722.44680354], - [4416.38661232], - [4300.15292299], - [4300.15292299], - [4158.37788155], - [3942.41438355], - [3869.05445515]]) - drag |29761.66426269| output lbf traj.descent.timeseries.drag - val: - array([[6660.78120358], - [6696.14415917], - [6744.56593677], - [6758.74559344], - [6758.74559344], - [6807.96927443], - [6838.54788004], - [6838.61490138], - [6838.61490138], - [6828.43478549], - [6795.48086851], - [6766.72926363], - [6766.72926363], - [6685.88074039], - [6519.18602917], - [6453.36752072], - [6453.36752072], - [6372.38949905], - [6248.70920558], - [6206.82076761]]) - specific_energy_rate_excess |128.60366435| output m/s traj.descent.timeseries.specific_energy_rate_excess - val: - array([[ 8.31061392], - [ 9.4837529 ], - [11.06056904], - [11.5466798 ], - [11.5466798 ], - [14.27825313], - [18.20217461], - [19.52693959], - [19.52693959], - [23.20973395], - [28.56945948], - [30.4010144 ], - [30.4010144 ], - [33.73456594], - [38.60833097], - [40.04628659], - [40.04628659], - [41.73935818], - [43.8891883 ], - [44.55668406]]) - fuel_flow_rate_negative_total |13616.66190343| output lbm/h traj.descent.timeseries.fuel_flow_rate_negative_total - val: - array([[-3006.75910243], - [-3035.88185747], - [-3067.0609741 ], - [-3074.35701626], - [-3074.35701626], - [-3118.06984835], - [-3154.1181106 ], - [-3160.84536771], - [-3160.84536771], - [-3167.93305303], - [-3155.67227501], - [-3141.73790983], - [-3141.73790983], - [-3089.80309587], - [-2978.2085316 ], - [-2929.71461497], - [-2929.71461497], - [-2875.53598644], - [-2801.61947232], - [-2785.21896845]]) - electric_power_in_total |0.0| output kW traj.descent.timeseries.electric_power_in_total - val: - array([[0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.]]) - altitude_rate |32.93434579| output ft/s traj.descent.timeseries.altitude_rate - val: - array([[-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436]]) - throttle |1.37898255| output unitless traj.descent.timeseries.throttle - val: - array([[0.49865618], - [0.47293083], - [0.44177524], - [0.43279925], - [0.43279925], - [0.3879603 ], - [0.33465308], - [0.31905442], - [0.31905442], - [0.28076346], - [0.23449042], - [0.21972804], - [0.21972804], - [0.19416101], - [0.16162186], - [0.15241077], - [0.15241077], - [0.14229545], - [0.12937745], - [0.12545435]]) - velocity |771.73974523| output m/s traj.descent.timeseries.velocity - val: - array([[214.51878007], - [211.35290813], - [206.88067906], - [205.44035421], - [205.44035421], - [198.54796477], - [188.62062791], - [185.37975905], - [185.37975905], - [176.32034566], - [163.26330289], - [158.99885174], - [158.99885174], - [150.60981862], - [138.66141566], - [134.79094549], - [134.79094549], - [130.40117072], - [124.25764936], - [122.29253366]]) - altitude |90819.35928076| output ft traj.descent.timeseries.altitude - val: - array([[34000. ], - [32602.7594172 ], - [30674.85259378], - [30064.67667582], - [30064.67667582], - [27211.11426456], - [23273.78055735], - [22027.62790105], - [22027.62790105], - [18635.02452748], - [13953.9243121 ], - [12472.37209895], - [12472.37209895], - [ 9618.80968769], - [ 5681.47598048], - [ 4435.32332418], - [ 4435.32332418], - [ 3038.08274138], - [ 1110.17591796], - [ 500. ]]) - time |73347.98069351| output s traj.descent.timeseries.time - val: - array([[14010. ], - [14199.73049861], - [14461.51986216], - [14544.37530064], - [14544.37530064], - [14931.85890638], - [15466.50719578], - [15635.72155138], - [15635.72155138], - [16096.40122071], - [16732.04513834], - [16933.22426496], - [16933.22426496], - [17320.7078707 ], - [17855.3561601 ], - [18024.5705157 ], - [18024.5705157 ], - [18214.30101431], - [18476.09037785], - [18558.94581634]]) - time_phase |12418.42831132| output s traj.descent.timeseries.time_phase - val: - array([[ 0. ], - [ 189.73049861], - [ 451.51986216], - [ 534.37530064], - [ 534.37530064], - [ 921.85890638], - [1456.50719578], - [1625.72155138], - [1625.72155138], - [2086.40122071], - [2722.04513834], - [2923.22426496], - [2923.22426496], - [3310.7078707 ], - [3845.3561601 ], - [4014.5705157 ], - [4014.5705157 ], - [4204.30101431], - [4466.09037785], - [4548.94581634]]) - mach_rate |0.00035392| output unitless/s traj.descent.timeseries.mach_rate - val: - array([[-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05]]) - mass |228638.93848721| output kg traj.descent.timeseries.mass - val: - array([[52028.74471935], - [51956.50719188], - [51855.82599664], - [51823.76601249], - [51823.76601249], - [51672.54219645], - [51461.12266693], - [51393.8106793 ], - [51393.8106793 ], - [51210.06984292], - [50956.67116637], - [50876.7919899 ], - [50876.7919899 ], - [50724.57452871], - [50519.93012614], - [50456.90390387], - [50456.90390387], - [50387.51580428], - [50293.8882617 ], - [50264.76158872]]) - distance |14257384.99570313| output m traj.descent.timeseries.distance - val: - array([[2751418.23144865], - [2791817.41185045], - [2846561.44051968], - [2863642.02155273], - [2863642.02155273], - [2941914.82037522], - [3045428.93171548], - [3077070.29224964], - [3077070.29224964], - [3160390.83905457], - [3268342.75197541], - [3300756.63996977], - [3300756.63996977], - [3360741.81646801], - [3438080.96818847], - [3461214.38233449], - [3461214.38233449], - [3486369.12667608], - [3519699.62007001], - [3529912. ]]) - mission_bus_variables - dt_dstau |2153.29990796| input s traj.descent.mission_bus_variables.dt_dstau - val: - array([267.18765032, 267.18765032, 267.18765032, 267.18765032, - 545.67312537, 545.67312537, 545.67312537, 545.67312537, - 648.75135679, 648.75135679, 648.75135679, 648.75135679, - 545.67312537, 545.67312537, 545.67312537, 545.67312537, - 267.18765032, 267.18765032, 267.18765032, 267.18765032]) - input_values:mach |2.45889929| input unitless traj.descent.mission_bus_variables.input_values:mach - val: - array([[0.72 ], - [0.70498488], - [0.68426707], - [0.67770996], - [0.67770996], - [0.64704481], - [0.60473316], - [0.59134167], - [0.59134167], - [0.55488385], - [0.50457949], - [0.48865833], - [0.48865833], - [0.45799318], - [0.41568153], - [0.40229004], - [0.40229004], - [0.38727492], - [0.36655711], - [0.36 ]]) - input_values:thrust_net_total |21659.77081486| input lbf traj.descent.mission_bus_variables.input_values:thrust_net_total - val: - array([[5184.76811238], - [5202.51239973], - [5225.23717327], - [5230.92763617], - [5230.92763617], - [5237.98704098], - [5202.85659519], - [5180.04337904], - [5180.04337904], - [5101.6636106 ], - [4957.61705125], - [4888.74306376], - [4888.74306376], - [4722.44680354], - [4416.38661232], - [4300.15292299], - [4300.15292299], - [4158.37788155], - [3942.41438355], - [3869.05445515]]) - input_values:drag |29761.66426269| input lbf traj.descent.mission_bus_variables.input_values:drag - val: - array([[6660.78120358], - [6696.14415917], - [6744.56593677], - [6758.74559344], - [6758.74559344], - [6807.96927443], - [6838.54788004], - [6838.61490138], - [6838.61490138], - [6828.43478549], - [6795.48086851], - [6766.72926363], - [6766.72926363], - [6685.88074039], - [6519.18602917], - [6453.36752072], - [6453.36752072], - [6372.38949905], - [6248.70920558], - [6206.82076761]]) - input_values:specific_energy_rate_excess |128.60366435| input m/s traj.descent.mission_bus_variables.input_values:specific_energy_rate_excess - val: - array([[ 8.31061392], - [ 9.4837529 ], - [11.06056904], - [11.5466798 ], - [11.5466798 ], - [14.27825313], - [18.20217461], - [19.52693959], - [19.52693959], - [23.20973395], - [28.56945948], - [30.4010144 ], - [30.4010144 ], - [33.73456594], - [38.60833097], - [40.04628659], - [40.04628659], - [41.73935818], - [43.8891883 ], - [44.55668406]]) - input_values:fuel_flow_rate_negative_total |13616.66190343| input lbm/h traj.descent.mission_bus_variables.input_values:fuel_flow_rate_negative_total - val: - array([[-3006.75910243], - [-3035.88185747], - [-3067.0609741 ], - [-3074.35701626], - [-3074.35701626], - [-3118.06984835], - [-3154.1181106 ], - [-3160.84536771], - [-3160.84536771], - [-3167.93305303], - [-3155.67227501], - [-3141.73790983], - [-3141.73790983], - [-3089.80309587], - [-2978.2085316 ], - [-2929.71461497], - [-2929.71461497], - [-2875.53598644], - [-2801.61947232], - [-2785.21896845]]) - input_values:electric_power_in_total |0.0| input kW traj.descent.mission_bus_variables.input_values:electric_power_in_total - val: - array([[0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.]]) - input_values:altitude_rate |32.93434579| input ft/s traj.descent.mission_bus_variables.input_values:altitude_rate - val: - array([[-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436]]) - input_values:throttle |1.37898255| input unitless traj.descent.mission_bus_variables.input_values:throttle - val: - array([[0.49865618], - [0.47293083], - [0.44177524], - [0.43279925], - [0.43279925], - [0.3879603 ], - [0.33465308], - [0.31905442], - [0.31905442], - [0.28076346], - [0.23449042], - [0.21972804], - [0.21972804], - [0.19416101], - [0.16162186], - [0.15241077], - [0.15241077], - [0.14229545], - [0.12937745], - [0.12545435]]) - input_values:velocity |771.73974523| input m/s traj.descent.mission_bus_variables.input_values:velocity - val: - array([[214.51878007], - [211.35290813], - [206.88067906], - [205.44035421], - [205.44035421], - [198.54796477], - [188.62062791], - [185.37975905], - [185.37975905], - [176.32034566], - [163.26330289], - [158.99885174], - [158.99885174], - [150.60981862], - [138.66141566], - [134.79094549], - [134.79094549], - [130.40117072], - [124.25764936], - [122.29253366]]) - input_values:altitude |90819.35928076| input ft traj.descent.mission_bus_variables.input_values:altitude - val: - array([[34000. ], - [32602.7594172 ], - [30674.85259378], - [30064.67667582], - [30064.67667582], - [27211.11426456], - [23273.78055735], - [22027.62790105], - [22027.62790105], - [18635.02452748], - [13953.9243121 ], - [12472.37209895], - [12472.37209895], - [ 9618.80968769], - [ 5681.47598048], - [ 4435.32332418], - [ 4435.32332418], - [ 3038.08274138], - [ 1110.17591796], - [ 500. ]]) - input_values:time |73347.98069351| input s traj.descent.mission_bus_variables.input_values:time - val: - array([[14010. ], - [14199.73049861], - [14461.51986216], - [14544.37530064], - [14544.37530064], - [14931.85890638], - [15466.50719578], - [15635.72155138], - [15635.72155138], - [16096.40122071], - [16732.04513834], - [16933.22426496], - [16933.22426496], - [17320.7078707 ], - [17855.3561601 ], - [18024.5705157 ], - [18024.5705157 ], - [18214.30101431], - [18476.09037785], - [18558.94581634]]) - input_values:time_phase |12418.42831132| input s traj.descent.mission_bus_variables.input_values:time_phase - val: - array([[ 0. ], - [ 189.73049861], - [ 451.51986216], - [ 534.37530064], - [ 534.37530064], - [ 921.85890638], - [1456.50719578], - [1625.72155138], - [1625.72155138], - [2086.40122071], - [2722.04513834], - [2923.22426496], - [2923.22426496], - [3310.7078707 ], - [3845.3561601 ], - [4014.5705157 ], - [4014.5705157 ], - [4204.30101431], - [4466.09037785], - [4548.94581634]]) - input_values:mach_rate |0.00035392| input unitless/s traj.descent.mission_bus_variables.input_values:mach_rate - val: - array([[-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05]]) - input_values:mass |228638.93848721| input kg traj.descent.mission_bus_variables.input_values:mass - val: - array([[52028.74471935], - [51956.50719188], - [51855.82599664], - [51823.76601249], - [51823.76601249], - [51672.54219645], - [51461.12266693], - [51393.8106793 ], - [51393.8106793 ], - [51210.06984292], - [50956.67116637], - [50876.7919899 ], - [50876.7919899 ], - [50724.57452871], - [50519.93012614], - [50456.90390387], - [50456.90390387], - [50387.51580428], - [50293.8882617 ], - [50264.76158872]]) - input_values:distance |14257384.99570313| input m traj.descent.mission_bus_variables.input_values:distance - val: - array([[2751418.23144865], - [2791817.41185045], - [2846561.44051968], - [2863642.02155273], - [2863642.02155273], - [2941914.82037522], - [3045428.93171548], - [3077070.29224964], - [3077070.29224964], - [3160390.83905457], - [3268342.75197541], - [3300756.63996977], - [3300756.63996977], - [3360741.81646801], - [3438080.96818847], - [3461214.38233449], - [3461214.38233449], - [3486369.12667608], - [3519699.62007001], - [3529912. ]]) - mach |2.13130946| output unitless traj.descent.mission_bus_variables.mach - val: - array([[0.72 ], - [0.684], - [0.648], - [0.648], - [0.612], - [0.576], - [0.576], - [0.54 ], - [0.504], - [0.504], - [0.468], - [0.432], - [0.432], - [0.396], - [0.36 ]]) - thrust_net_total |19003.91342407| output lbf traj.descent.mission_bus_variables.thrust_net_total - val: - array([[5184.76811238], - [5225.48807372], - [5238.16325545], - [5238.16325545], - [5212.81280251], - [5146.60278852], - [5146.60278852], - [5067.03275078], - [4955.36760416], - [4955.36760416], - [4781.69778451], - [4545.27003905], - [4545.27003905], - [4242.24945088], - [3869.05445515]]) - drag |25947.60606281| output lbf traj.descent.mission_bus_variables.drag - val: - array([[6660.78120358], - [6745.15915969], - [6806.7679329 ], - [6806.7679329 ], - [6836.52910852], - [6832.79516112], - [6832.79516112], - [6824.40689005], - [6794.64634346], - [6794.64634346], - [6715.9990443 ], - [6590.95312626], - [6590.95312626], - [6420.36076088], - [6206.82076761]]) - specific_energy_rate_excess |107.0223294| output m/s traj.descent.mission_bus_variables.specific_energy_rate_excess - val: - array([[ 8.31061392], - [11.08050322], - [14.19260943], - [14.19260943], - [17.5036815 ], - [21.0705639 ], - [21.0705639 ], - [24.74493902], - [28.63469861], - [28.63469861], - [32.59971581], - [36.75470499], - [36.75470499], - [40.7761994 ], - [44.55668406]]) - fuel_flow_rate_negative_total |11916.19897582| output lbm/h traj.descent.mission_bus_variables.fuel_flow_rate_negative_total - val: - array([[-3006.75910243], - [-3067.38415203], - [-3116.95375848], - [-3116.95375848], - [-3149.62176437], - [-3164.45318511], - [-3164.45318511], - [-3168.14998767], - [-3155.26963505], - [-3155.26963505], - [-3108.83228807], - [-3028.04915148], - [-3028.04915148], - [-2908.40713121], - [-2785.21896845]]) - electric_power_in_total |0.0| output kW traj.descent.mission_bus_variables.electric_power_in_total - val: - array([[0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.], - [0.]]) - altitude_rate |28.52198011| output ft/s traj.descent.mission_bus_variables.altitude_rate - val: - array([[-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436], - [-7.3643436]]) - throttle |1.1689564| output unitless traj.descent.mission_bus_variables.throttle - val: - array([[0.49865618], - [0.4414021 ], - [0.38926315], - [0.38926315], - [0.34330884], - [0.30209065], - [0.30209065], - [0.26670543], - [0.23396121], - [0.23396121], - [0.20239237], - [0.1736363 ], - [0.1736363 ], - [0.148078 ], - [0.12545435]]) - velocity |670.98612095| output m/s traj.descent.mission_bus_variables.velocity - val: - array([[214.51878007], - [206.82224691], - [198.76652705], - [198.76652705], - [190.35952306], - [181.60939417], - [181.60939417], - [172.52370169], - [163.10919058], - [163.10919058], - [153.37258632], - [143.32037213], - [143.32037213], - [132.95846386], - [122.29253366]]) - altitude |76956.88728113| output ft traj.descent.mission_bus_variables.altitude - val: - array([[34000.], - [30650.], - [27300.], - [27300.], - [23950.], - [20600.], - [20600.], - [17250.], - [13900.], - [13900.], - [10550.], - [ 7200.], - [ 7200.], - [ 3850.], - [ 500.]]) - time |63282.3960427| output s traj.descent.mission_bus_variables.time - val: - array([[14010. ], - [14464.89458163], - [14919.78916327], - [14919.78916327], - [15374.6837449 ], - [15829.57832653], - [15829.57832653], - [16284.47290817], - [16739.3674898 ], - [16739.3674898 ], - [17194.26207144], - [17649.15665307], - [17649.15665307], - [18104.0512347 ], - [18558.94581634]]) - time_phase |10222.48431654| output s traj.descent.mission_bus_variables.time_phase - val: - array([[ 0. ], - [ 454.89458163], - [ 909.78916327], - [ 909.78916327], - [1364.6837449 ], - [1819.57832653], - [1819.57832653], - [2274.47290817], - [2729.3674898 ], - [2729.3674898 ], - [3184.26207144], - [3639.15665307], - [3639.15665307], - [4094.0512347 ], - [4548.94581634]]) - mach_rate |0.0003065| output unitless/s traj.descent.mission_bus_variables.mach_rate - val: - array([[-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05], - [-7.91392148e-05]]) - mass |198067.91745372| output kg traj.descent.mission_bus_variables.mass - val: - array([[52028.74471935], - [51854.52178828], - [51677.2831748 ], - [51677.2831748 ], - [51497.59098981], - [51316.54407232], - [51316.54407232], - [51135.00751291], - [50953.7598743 ], - [50953.7598743 ], - [50773.96071216], - [50597.95134026], - [50597.95134026], - [50427.67859411], - [50264.76158872]]) - distance |12328970.76725104| output m traj.descent.mission_bus_variables.distance - val: - array([[2751418.23144865], - [2847259.46507397], - [2939517.23148407], - [2939517.23148407], - [3028030.38808647], - [3112640.21428723], - [3112640.21428723], - [3193192.91369784], - [3269537.54580838], - [3269537.54580838], - [3341525.02224903], - [3409011.24339885], - [3409011.24339885], - [3471853.40400242], - [3529912. ]]) - collocation_constraint - dt_dstau |1864.81242226| input s traj.descent.collocation_constraint.dt_dstau - val: - array([267.18765032, 267.18765032, 267.18765032, 545.67312537, - 545.67312537, 545.67312537, 648.75135679, 648.75135679, - 648.75135679, 545.67312537, 545.67312537, 545.67312537, - 267.18765032, 267.18765032, 267.18765032]) - f_approx:mass |1.48954691| input kg/s traj.descent.collocation_constraint.f_approx:mass - val: - array([[-0.37884527], - [-0.38251468], - [-0.38644318], - [-0.38736247], - [-0.39287019], - [-0.3974122 ], - [-0.39825982], - [-0.39915285], - [-0.39760802], - [-0.39585232], - [-0.38930864], - [-0.37524796], - [-0.36913783], - [-0.36231144], - [-0.35299812]]) - f_computed:mass |1.48954691| input kg/s traj.descent.collocation_constraint.f_computed:mass - val: - array([[-0.37884527], - [-0.38251468], - [-0.38644318], - [-0.38736247], - [-0.39287019], - [-0.3974122 ], - [-0.39825982], - [-0.39915285], - [-0.39760802], - [-0.39585232], - [-0.38930864], - [-0.37524796], - [-0.36913783], - [-0.36231144], - [-0.35299812]]) - f_approx:distance |678.62402375| input m/s traj.descent.collocation_constraint.f_approx:distance - val: - array([[214.5070361 ], - [211.34098824], - [206.86850148], - [205.42809125], - [198.53527609], - [188.60727137], - [185.36616898], - [176.30605727], - [163.24787168], - [158.98300661], - [150.59309082], - [138.64324625], - [134.77225428], - [130.38185021], - [124.23737345]]) - f_computed:distance |678.62402375| input m/s traj.descent.collocation_constraint.f_computed:distance - val: - array([[214.5070361 ], - [211.34098824], - [206.86850148], - [205.42809125], - [198.53527609], - [188.60727137], - [185.36616898], - [176.30605727], - [163.24787168], - [158.98300661], - [150.59309082], - [138.64324625], - [134.77225428], - [130.38185021], - [124.23737345]]) - defects:mass |0.0| output kg traj.descent.collocation_constraint.defects:mass - val: - array([[-2.19067075e-11], - [ 1.48318941e-12], - [ 2.28114531e-11], - [-1.22072502e-11], - [-9.39019245e-12], - [ 3.03212343e-11], - [-2.99267487e-11], - [ 4.32155216e-13], - [-3.70933227e-12], - [ 7.60302679e-12], - [ 3.30171283e-12], - [-5.78557019e-12], - [ 1.03823258e-12], - [-9.55173978e-12], - [-8.40968393e-12]]) - defects:distance |1e-08| output m traj.descent.collocation_constraint.defects:distance - val: - array([[ 9.03677642e-10], - [ 1.51878595e-10], - [-4.70823645e-10], - [-2.55897890e-09], - [ 3.41197186e-10], - [ 3.41197186e-10], - [ 2.93174099e-09], - [-1.16163322e-09], - [ 9.77246995e-10], - [ 1.79903971e-09], - [ 1.70598593e-10], - [ 1.39580667e-09], - [-1.52637988e-09], - [ 8.35332274e-11], - [ 3.79696488e-11]]) -post_mission - fuel_burned - initial_mass [130904.19882744] input lbm fuel_burned.initial_mass - mass_final [110814.83048032] input lbm fuel_burned.mass_final - fuel_burned [20089.36834711] output lbm mission:summary:fuel_burned - reserve_fuel - reserve_fuel_additional [3000.] input lbm aircraft:design:reserve_fuel_additional - reserve_fuel_burned [0.] input lbm mission:summary:reserve_fuel_burned - reserve_fuel_frac_mass [0.] input lbm reserve_fuel_frac_mass - reserve_fuel [3000.] output lbm mission:design:reserve_fuel - fuel_calc - fuel_burned [20089.36834711] input lbm mission:summary:fuel_burned - fuel_margin [0.] input unitless aircraft:fuel:fuel_margin - reserve_fuel [3000.] input lbm mission:design:reserve_fuel - overall_fuel [23089.36834711] output lbm mission:summary:total_fuel_mass - mass_constraint - initial_mass [130904.19882744] input lbm mission:summary:gross_mass - operating_empty_mass [69789.83048032] input lbm aircraft:design:operating_mass - overall_fuel [23089.36834711] input lbm mission:summary:total_fuel_mass - payload_mass [38025.] input lbm aircraft:crew_and_payload:total_payload_mass - mass_resid [0.] output lbm mission:constraints:mass_residual -link_climb_mass - lhs:mass [130904.19882744] input lbm link_climb_mass.lhs:mass - rhs:mass [130904.19882744] input lbm mission:summary:gross_mass - mass [-1.45519152e-11] output None link_climb_mass.mass -range_constraint - actual_range [1906.] input nmi mission:summary:range - target_range [1906.] input nmi target_range - range_resid [2.27373675e-13] output nmi mission:constraints:range_residual -gtow_constraint - lhs:GTOW [130904.19882744] input lbm mission:design:gross_mass - rhs:GTOW [130904.19882744] input lbm mission:summary:gross_mass - GTOW [0.] output None gtow_constraint.GTOW -fuel_obj - ascent_duration [0.] input s mission:takeoff:ascent_duration - overall_fuel [23089.36834711] input lbm mission:summary:total_fuel_mass - reg_objective [2.30893683] output unitless mission:objectives:fuel -range_obj - actual_range [1906.] input nmi mission:summary:range - ascent_duration [0.] input s mission:takeoff:ascent_duration - reg_objective [-1.906] output unitless mission:objectives:range - - -Wing Mass [2.24666] -Horizontal Tail Mass [0.] -Fuselage Mass [5209.12373908] -done From 9dc278e48882b1668ac886c0f4748280ba3c5f77 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 8 Jul 2025 08:16:16 -0400 Subject: [PATCH 103/147] Update aviary/subsystems/mass/simple_mass/fuselage.py Co-authored-by: Jason Kirk <110835404+jkirk5@users.noreply.github.com> --- aviary/subsystems/mass/simple_mass/fuselage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aviary/subsystems/mass/simple_mass/fuselage.py b/aviary/subsystems/mass/simple_mass/fuselage.py index cc7ecbd65..2b1e422c8 100644 --- a/aviary/subsystems/mass/simple_mass/fuselage.py +++ b/aviary/subsystems/mass/simple_mass/fuselage.py @@ -99,7 +99,7 @@ def compute_primal(self, aircraft__fuselage__length, base_diameter, tip_diameter self.validate_inputs(aircraft__fuselage__length, base_diameter, thickness, tip_diameter, is_hollow) - density, _ = materials.get_item(material) + density = materials.get_val(material, 'kg/m**3') section_locations = jnp.linspace(0, aircraft__fuselage__length, num_sections) From 5ba6b5bf4ba2d04ecc580c66ae68cda512661f54 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 8 Jul 2025 08:17:23 -0400 Subject: [PATCH 104/147] Update aviary/subsystems/mass/simple_mass/fuselage.py Co-authored-by: Jason Kirk <110835404+jkirk5@users.noreply.github.com> --- aviary/subsystems/mass/simple_mass/fuselage.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/fuselage.py b/aviary/subsystems/mass/simple_mass/fuselage.py index 2b1e422c8..93f5e25a2 100644 --- a/aviary/subsystems/mass/simple_mass/fuselage.py +++ b/aviary/subsystems/mass/simple_mass/fuselage.py @@ -139,11 +139,12 @@ def load_fuselage_data(self, custom_fuselage_data_file): try: # Load the file custom_data = np.loadtxt(custom_fuselage_data_file) + except FileNotFoundError as e: + raise FileNotFoundError(f'Fuselage data file {e}') + else: fuselage_locations = custom_data[:, 0] fuselage_diameters = custom_data[:, 1] return jinterp.RegularGridInterpolator(fuselage_locations, fuselage_diameters, kind='linear', fill_value='extrapolate') - except Exception as e: - raise ValueError(f"Error loading fuselage data file: {e}") else: return None From a3745799022f9b74e29483711589a74ed2506e9f Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 8 Jul 2025 08:17:31 -0400 Subject: [PATCH 105/147] Update aviary/subsystems/mass/simple_mass/wing.py Co-authored-by: Jason Kirk <110835404+jkirk5@users.noreply.github.com> --- aviary/subsystems/mass/simple_mass/wing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aviary/subsystems/mass/simple_mass/wing.py b/aviary/subsystems/mass/simple_mass/wing.py index 47f59141c..b282b2ea1 100644 --- a/aviary/subsystems/mass/simple_mass/wing.py +++ b/aviary/subsystems/mass/simple_mass/wing.py @@ -77,7 +77,7 @@ def compute_primal(self, aircraft__wing__span, aircraft__wing__root_chord, tip_c airfoil_data_file = self.options['airfoil_data_file'] # Get material density - density, _ = materials.get_item(material) # in kg/m^3 + density = materials.get_val(material, 'kg/m**3') if airfoil_data_file and os.path.exists(airfoil_data_file): airfoil_data = np.loadtxt(airfoil_data_file) From b8eb933983f9f858e9a89c42a1839d04de5702cd Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 8 Jul 2025 08:17:52 -0400 Subject: [PATCH 106/147] Update aviary/subsystems/mass/simple_mass/fuselage.py Co-authored-by: Jason Kirk <110835404+jkirk5@users.noreply.github.com> --- aviary/subsystems/mass/simple_mass/fuselage.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/fuselage.py b/aviary/subsystems/mass/simple_mass/fuselage.py index 93f5e25a2..f5740f9f2 100644 --- a/aviary/subsystems/mass/simple_mass/fuselage.py +++ b/aviary/subsystems/mass/simple_mass/fuselage.py @@ -32,10 +32,11 @@ def initialize(self): default='Aluminum Oxide', values=list(get_keys(materials))) - self.options.declare('custom_fuselage_data_file', - types=(str, type(None)), + self.options.declare('fuselage_data_file', + types=(Path, str), default=None, - allow_none=True) + allow_none=True, + desc='optional data file of fuselage geometry') self.custom_fuselage_function = None From 3ff430b19b84f6cb75882cf53ebc4243f1859b30 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 8 Jul 2025 08:18:03 -0400 Subject: [PATCH 107/147] Update aviary/subsystems/mass/simple_mass/tail.py Co-authored-by: Jason Kirk <110835404+jkirk5@users.noreply.github.com> --- aviary/subsystems/mass/simple_mass/tail.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aviary/subsystems/mass/simple_mass/tail.py b/aviary/subsystems/mass/simple_mass/tail.py index a72b3dd52..5e64f1142 100644 --- a/aviary/subsystems/mass/simple_mass/tail.py +++ b/aviary/subsystems/mass/simple_mass/tail.py @@ -120,7 +120,7 @@ def compute_primal(self, tail_type = self.options["tail_type"] airfoil_type = self.options["airfoil_type"] material = self.options['material'] - density, _ = materials.get_item(material) + density = materials.get_val(material, 'kg/m**3') airfoil_file = self.options['airfoil_file'] num_sections = self.options['num_sections'] NACA_digits = self.options['NACA_digits'] From feaeb8824e97eba69c2d7c287f4f0f131c0d2377 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 8 Jul 2025 11:51:25 -0400 Subject: [PATCH 108/147] Update aviary/subsystems/mass/simple_mass/fuselage.py Co-authored-by: Jason Kirk <110835404+jkirk5@users.noreply.github.com> --- aviary/subsystems/mass/simple_mass/fuselage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aviary/subsystems/mass/simple_mass/fuselage.py b/aviary/subsystems/mass/simple_mass/fuselage.py index f5740f9f2..7af8830b4 100644 --- a/aviary/subsystems/mass/simple_mass/fuselage.py +++ b/aviary/subsystems/mass/simple_mass/fuselage.py @@ -86,7 +86,7 @@ def setup(self): def compute_primal(self, aircraft__fuselage__length, base_diameter, tip_diameter, curvature, thickness, y_offset, z_offset, is_hollow): # Input validation checks if aircraft__fuselage__length <= 0: - raise ValueError("Length must be greater than zero.") + raise AnalysisError("Length must be greater than zero.") if base_diameter <= 0 or tip_diameter <= 0: raise ValueError("Diameter must be greater than zero.") From 67f5f760e18068e421bc0ed0de67cc4df72180bc Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 8 Jul 2025 13:18:18 -0400 Subject: [PATCH 109/147] Update fuselage.py --- .../subsystems/mass/simple_mass/fuselage.py | 29 +------------------ 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/fuselage.py b/aviary/subsystems/mass/simple_mass/fuselage.py index 7af8830b4..0cb7a4a7d 100644 --- a/aviary/subsystems/mass/simple_mass/fuselage.py +++ b/aviary/subsystems/mass/simple_mass/fuselage.py @@ -89,7 +89,7 @@ def compute_primal(self, aircraft__fuselage__length, base_diameter, tip_diameter raise AnalysisError("Length must be greater than zero.") if base_diameter <= 0 or tip_diameter <= 0: - raise ValueError("Diameter must be greater than zero.") + raise AnalysisError("Diameter must be greater than zero.") custom_fuselage_function = getattr(self, 'custom_fuselage_function', None) # Custom fuselage model function -- if provided @@ -164,32 +164,5 @@ def compute_centroid(self, location, length, y_offset, z_offset, curvature, base return centroid_x, centroid_y, centroid_z -if __name__ == "__main__": - prob = om.Problem() - prob.model.add_subsystem('fuselage_cg', FuselageMassAndCOG(), promotes_inputs=['*'], promotes_outputs=['*']) - - prob.setup() - - prob.set_val(Aircraft.Fuselage.LENGTH, 2.5) - prob.set_val('base_diameter', 0.5) - prob.set_val('tip_diameter', 0.3) - prob.set_val('curvature', 0.0) - prob.set_val('thickness', 0.05) # Wall thickness of 5 cm - #prob.set_val('is_hollow', False) # Default is True, uncomment to use False -- for testing purposes - - # Example using custom function -- uncomment to run - #def custom_fuselage_model(location): - # return 0.5 * jnp.exp(-0.1 * location) - - #prob.model.fuselage_cg.custom_fuselage_function = custom_fuselage_model - - # Example for custom .dat file -- uncomment to run - #prob.model.fuselage_cg.options['custom_fuselage_data_file'] = 'Custom_Fuselage.dat' - - prob.run_model() - - total_weight = prob.get_val(Aircraft.Fuselage.MASS) - - print(f"Total mass of the fuselage: {total_weight} kg") From 9e9b1d0be82e8edb6b7d436d12fdcc8db4a9deba Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 8 Jul 2025 13:18:33 -0400 Subject: [PATCH 110/147] Update aviary/subsystems/mass/simple_mass/mass_summation.py Co-authored-by: Jason Kirk <110835404+jkirk5@users.noreply.github.com> --- aviary/subsystems/mass/simple_mass/mass_summation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aviary/subsystems/mass/simple_mass/mass_summation.py b/aviary/subsystems/mass/simple_mass/mass_summation.py index 67a499ec5..62f1dec06 100644 --- a/aviary/subsystems/mass/simple_mass/mass_summation.py +++ b/aviary/subsystems/mass/simple_mass/mass_summation.py @@ -10,7 +10,7 @@ from aviary.variable_info.functions import add_aviary_input -class MassSummation(om.Group): +class SimpleMassSummation(om.Group): """ Group to compute various design masses for this mass group. From 6fd0d815091ce930f32072ac92828b20d6489bcb Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 8 Jul 2025 13:19:15 -0400 Subject: [PATCH 111/147] Update mass_summation.py --- aviary/subsystems/mass/simple_mass/mass_summation.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/mass_summation.py b/aviary/subsystems/mass/simple_mass/mass_summation.py index 62f1dec06..761bcf46d 100644 --- a/aviary/subsystems/mass/simple_mass/mass_summation.py +++ b/aviary/subsystems/mass/simple_mass/mass_summation.py @@ -23,21 +23,21 @@ def setup(self): self.add_subsystem( 'fuse_mass', - FuselageMassAndCOG(), + FuselageMass(), promotes_inputs=['*'], promotes_outputs=[Aircraft.Fuselage.MASS] ) self.add_subsystem( 'wing_mass', - WingMassAndCOG(), + WingMass(), promotes_inputs=['*'], promotes_outputs=[Aircraft.Wing.MASS] ) self.add_subsystem( 'tail_mass', - TailMassAndCOG(), + TailMass(), promotes_inputs=['*'], promotes_outputs=[Aircraft.HorizontalTail.MASS] ) @@ -94,4 +94,4 @@ def compute_primal(self, aircraft__wing__mass, aircraft__fuselage__mass, aircraf else: structure_mass = aircraft__wing__mass + aircraft__fuselage__mass + aircraft__vertical_tail__mass - return structure_mass \ No newline at end of file + return structure_mass From 093baa052d19dd3826bf1c19c471dd8648aa8abd Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 8 Jul 2025 13:19:37 -0400 Subject: [PATCH 112/147] Update aviary/subsystems/mass/simple_mass/mass_premission.py Co-authored-by: Jason Kirk <110835404+jkirk5@users.noreply.github.com> --- aviary/subsystems/mass/simple_mass/mass_premission.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aviary/subsystems/mass/simple_mass/mass_premission.py b/aviary/subsystems/mass/simple_mass/mass_premission.py index fa29c81a4..6a75c9698 100644 --- a/aviary/subsystems/mass/simple_mass/mass_premission.py +++ b/aviary/subsystems/mass/simple_mass/mass_premission.py @@ -4,7 +4,7 @@ from aviary.subsystems.mass.simple_mass.fuselage import FuselageMassAndCOG from aviary.subsystems.mass.simple_mass.tail import TailMassAndCOG -class MassPremission(om.Group): +class SimpleMassPremission(om.Group): """ Pre-mission group of top-level mass estimation groups and components for the simple small-scale aircraft mass build-up. From 555d280dca3aeaea84b10021c2a5a84547c458bc Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 8 Jul 2025 13:20:04 -0400 Subject: [PATCH 113/147] Update mass_premission.py --- aviary/subsystems/mass/simple_mass/mass_premission.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/mass_premission.py b/aviary/subsystems/mass/simple_mass/mass_premission.py index 6a75c9698..41ec70e0d 100644 --- a/aviary/subsystems/mass/simple_mass/mass_premission.py +++ b/aviary/subsystems/mass/simple_mass/mass_premission.py @@ -14,18 +14,18 @@ def setup(self): self.add_subsystem( 'Wing', - WingMassAndCOG(), + WingMass(), promotes_inputs=['*'], promotes_outputs=['*'] ) self.add_subsystem( 'Fuselage', - FuselageMassAndCOG(), + FuselageMass(), promotes_inputs=['*'], promotes_outputs=['*'] ) self.add_subsystem( 'Tail', - TailMassAndCOG(tail_type='horizontal'), + TailMass(tail_type='horizontal'), promotes_inputs=['*'], promotes_outputs=['*'] - ) \ No newline at end of file + ) From e3ceffb77e45f67221291e720f2c59751032d0a7 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 8 Jul 2025 13:21:13 -0400 Subject: [PATCH 114/147] Update test_fuselage.py --- aviary/subsystems/mass/simple_mass/test/test_fuselage.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/test/test_fuselage.py b/aviary/subsystems/mass/simple_mass/test/test_fuselage.py index 145e1f679..823b33053 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_fuselage.py +++ b/aviary/subsystems/mass/simple_mass/test/test_fuselage.py @@ -17,7 +17,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "fuselage", - FuselageMassAndCOG(), + FuselageMass(), promotes_inputs=["*"], promotes_outputs=["*"], ) @@ -86,4 +86,4 @@ def test_case(self): rtol=1e-12) if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main() From 8c23aabdd3f1022c2b6364174defc52d5b80228a Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 8 Jul 2025 13:21:36 -0400 Subject: [PATCH 115/147] Update test_mass_summation.py --- aviary/subsystems/mass/simple_mass/test/test_mass_summation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py b/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py index 9a08fc00d..b2897ec5e 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py +++ b/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py @@ -20,7 +20,7 @@ def test_case(self): self.prob.model.add_subsystem( 'tot', - MassSummation(), + SimpleMassSummation(), promotes=['*'] ) From 1a6cc35c0c5cc60320ded82a1631083ae90b2f3d Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 8 Jul 2025 13:22:08 -0400 Subject: [PATCH 116/147] Update test_tail.py --- aviary/subsystems/mass/simple_mass/test/test_tail.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/test/test_tail.py b/aviary/subsystems/mass/simple_mass/test/test_tail.py index 2b8eb3bd9..8ede8ed9f 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_tail.py +++ b/aviary/subsystems/mass/simple_mass/test/test_tail.py @@ -19,7 +19,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "Tail", - TailMassAndCOG(), + TailMass(), promotes_inputs=["*"], promotes_outputs=["*"], ) @@ -103,4 +103,4 @@ def test_case(self): rtol=1e-15) if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main() From aff52f212721e21fd9f931a7684a636a32290acd Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 8 Jul 2025 13:22:36 -0400 Subject: [PATCH 117/147] Update test_wing.py --- aviary/subsystems/mass/simple_mass/test/test_wing.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/test/test_wing.py b/aviary/subsystems/mass/simple_mass/test/test_wing.py index 79c5d5870..86c8a3ae6 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_wing.py +++ b/aviary/subsystems/mass/simple_mass/test/test_wing.py @@ -22,7 +22,7 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( "wing_mass", - WingMassAndCOG(), + WingMass(), promotes_inputs=["*"], promotes_outputs=['*'], ) @@ -87,4 +87,4 @@ def test_case(self): if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main() From 39f392bf0e2f9b8bdf9f8a585646a656666a330b Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 8 Jul 2025 13:23:03 -0400 Subject: [PATCH 118/147] Update aviary/subsystems/mass/simple_mass/mass_builder.py Co-authored-by: Jason Kirk <110835404+jkirk5@users.noreply.github.com> --- aviary/subsystems/mass/simple_mass/mass_builder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aviary/subsystems/mass/simple_mass/mass_builder.py b/aviary/subsystems/mass/simple_mass/mass_builder.py index 9231bada3..7570c9397 100644 --- a/aviary/subsystems/mass/simple_mass/mass_builder.py +++ b/aviary/subsystems/mass/simple_mass/mass_builder.py @@ -1,4 +1,4 @@ -from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase +from aviary.subsystems.mass.mass_builder import MassBuilderBase from aviary.subsystems.mass.simple_mass.mass_premission import MassPremission From a5baed2df0cd2e69c19a032eb4a8764a70714aec Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 8 Jul 2025 13:23:41 -0400 Subject: [PATCH 119/147] Update aviary/subsystems/mass/simple_mass/mass_builder.py Co-authored-by: Jason Kirk <110835404+jkirk5@users.noreply.github.com> --- aviary/subsystems/mass/simple_mass/mass_builder.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aviary/subsystems/mass/simple_mass/mass_builder.py b/aviary/subsystems/mass/simple_mass/mass_builder.py index 7570c9397..6b00ca1aa 100644 --- a/aviary/subsystems/mass/simple_mass/mass_builder.py +++ b/aviary/subsystems/mass/simple_mass/mass_builder.py @@ -17,7 +17,7 @@ _default_name = 'simple_mass' -class MassBuilderBase(SubsystemBuilderBase): +class SimpleMassBuilder(MassBuilderBase): """ Base mass builder From 80c6ffb0cf8913f7e8bfb78443a01c1ace79eb94 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 8 Jul 2025 13:23:53 -0400 Subject: [PATCH 120/147] Update aviary/subsystems/mass/simple_mass/mass_builder.py Co-authored-by: Jason Kirk <110835404+jkirk5@users.noreply.github.com> --- aviary/subsystems/mass/simple_mass/mass_builder.py | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/mass_builder.py b/aviary/subsystems/mass/simple_mass/mass_builder.py index 6b00ca1aa..cc70b2525 100644 --- a/aviary/subsystems/mass/simple_mass/mass_builder.py +++ b/aviary/subsystems/mass/simple_mass/mass_builder.py @@ -3,16 +3,11 @@ """ - -Define subsystem builder for Aviary core mass. +Define subsystem builder for Aviary simple mass. Classes --------------------------------------------------------------------------------------------------- - -MassBuilderBase: the interface for a mass subsystem builder. **Not sure how necessary this is for - my work right now, but wanted to include it as a just in case. I basically copied - it over from the mass_builder.py under the mass subsystems folder in Aviary github. - +-------- +SimpleMassBuilderBase: the interface for the simple mass subsystem builder. """ _default_name = 'simple_mass' From 40ad053e331361e777a2e64aaa7d643770731658 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 8 Jul 2025 13:25:55 -0400 Subject: [PATCH 121/147] Update tail.py --- aviary/subsystems/mass/simple_mass/tail.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/tail.py b/aviary/subsystems/mass/simple_mass/tail.py index 5e64f1142..468ef569d 100644 --- a/aviary/subsystems/mass/simple_mass/tail.py +++ b/aviary/subsystems/mass/simple_mass/tail.py @@ -153,10 +153,6 @@ def compute_primal(self, camber_location = int(NACA_digits[1]) / 10.0 # Location of max camber max_thickness = int(NACA_digits[2:4]) / 100.0 # Max thickness - # Tail type check - if tail_type not in ['horizontal', 'vertical']: - raise ValueError("Invalid tail_type. Must be 'horizontal' or 'vertical'.") - if tail_type == 'horizontal': span_locations = jnp.linspace(0, aircraft__horizontal_tail__span, num_sections) elif tail_type == 'vertical': @@ -278,4 +274,4 @@ def extract_airfoil_features(self, x_coords, y_coords): if prob.model.tail.options['tail_type'] == 'horizontal': print(f"Total mass of the horizontal tail: {prob.get_val(Aircraft.HorizontalTail.MASS)} kg") elif prob.model.tail.options['tail_type'] == 'vertical': - print(f"Total mass of the vertical tail: {prob.get_val(Aircraft.VerticalTail.MASS)} kg") \ No newline at end of file + print(f"Total mass of the vertical tail: {prob.get_val(Aircraft.VerticalTail.MASS)} kg") From ada3042027b7583e845a11755a544b3034c02544 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 8 Jul 2025 13:29:48 -0400 Subject: [PATCH 122/147] Update tail.py --- aviary/subsystems/mass/simple_mass/tail.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/tail.py b/aviary/subsystems/mass/simple_mass/tail.py index 468ef569d..bf5ee3b06 100644 --- a/aviary/subsystems/mass/simple_mass/tail.py +++ b/aviary/subsystems/mass/simple_mass/tail.py @@ -191,18 +191,6 @@ def precompute_airfoil_geometry(self): dx = 1 / (n_points - 1) return x_points, dx - def compute_airfoil_geometry(self, chord, camber, camber_location, thickness_dist, x_points, dx): - - section_area = jnp.trapezoid(thickness_dist, x_points, dx=dx) - section_area *= chord - - centroid_x = jnp.trapezoid(x_points * thickness_dist, x_points, dx=dx) - centroid_x = (centroid_x * chord) / section_area - - centroid_z = jnp.trapezoid(self.airfoil_camber_line(x_points, camber, camber_location) * thickness_dist, x_points, dx=dx) - centroid_z = (centroid_z * chord) / section_area - return section_area, centroid_x, centroid_z - def airfoil_thickness(self, x, max_thickness): return 5 * max_thickness * (0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) From 8e58ad717cfb16f6a074d4e84b63b40ce39d0ab5 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 8 Jul 2025 13:30:50 -0400 Subject: [PATCH 123/147] Update tail.py --- aviary/subsystems/mass/simple_mass/tail.py | 31 ---------------------- 1 file changed, 31 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/tail.py b/aviary/subsystems/mass/simple_mass/tail.py index bf5ee3b06..2909b7d38 100644 --- a/aviary/subsystems/mass/simple_mass/tail.py +++ b/aviary/subsystems/mass/simple_mass/tail.py @@ -232,34 +232,3 @@ def extract_airfoil_features(self, x_coords, y_coords): return camber, camber_location, max_thickness_value -if __name__ == "__main__": - prob = om.Problem() - - prob.model.add_subsystem('tail', TailMassAndCOG(), promotes_inputs=['*'], promotes_outputs=['*']) - - prob.setup() - - # Input values - #tail_type = prob.model.tail.options['tail_type'] - prob.model.tail.options['tail_type'] = 'vertical' - - if prob.model.tail.options['tail_type'] == 'horizontal': - prob.set_val(Aircraft.HorizontalTail.SPAN, 1.0) - prob.set_val(Aircraft.HorizontalTail.ROOT_CHORD, 1.0) - elif prob.model.tail.options['tail_type'] == 'vertical': - prob.set_val(Aircraft.VerticalTail.SPAN, 1.0) - prob.set_val(Aircraft.VerticalTail.ROOT_CHORD, 1.0) - - prob.set_val('tip_chord_tail', 0.5) - prob.set_val('thickness_ratio', 0.12) - prob.set_val('skin_thickness', 0.002) - - prob.model.tail.options['material'] = 'Balsa' - - prob.run_model() - - # Print - if prob.model.tail.options['tail_type'] == 'horizontal': - print(f"Total mass of the horizontal tail: {prob.get_val(Aircraft.HorizontalTail.MASS)} kg") - elif prob.model.tail.options['tail_type'] == 'vertical': - print(f"Total mass of the vertical tail: {prob.get_val(Aircraft.VerticalTail.MASS)} kg") From 98de1a25f50ba97e952241b64122593ceaf5f3e5 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 8 Jul 2025 13:31:37 -0400 Subject: [PATCH 124/147] Update aviary/subsystems/mass/simple_mass/fuselage.py Co-authored-by: Jason Kirk <110835404+jkirk5@users.noreply.github.com> --- aviary/subsystems/mass/simple_mass/fuselage.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/fuselage.py b/aviary/subsystems/mass/simple_mass/fuselage.py index 0cb7a4a7d..13c8e5276 100644 --- a/aviary/subsystems/mass/simple_mass/fuselage.py +++ b/aviary/subsystems/mass/simple_mass/fuselage.py @@ -152,8 +152,8 @@ def load_fuselage_data(self, custom_fuselage_data_file): def get_section_diameter(self, location, length, base_diameter, tip_diameter, interpolate_diameter): if self.custom_fuselage_function: return self.custom_fuselage_function(location) - elif self.load_fuselage_data: - return interpolate_diameter(location) if interpolate_diameter is not None else base_diameter + ((tip_diameter - base_diameter) / length) * location + elif self.load_fuselage_data and interpolate_diameter is not None: + return interpolate_diameter(location) else: return base_diameter + ((tip_diameter - base_diameter) / length) * location From 792327f6ebfc5cb60b3296a5665d88410544c241 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 8 Jul 2025 13:32:25 -0400 Subject: [PATCH 125/147] Update wing.py --- aviary/subsystems/mass/simple_mass/wing.py | 35 ---------------------- 1 file changed, 35 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/wing.py b/aviary/subsystems/mass/simple_mass/wing.py index b282b2ea1..3ff08058a 100644 --- a/aviary/subsystems/mass/simple_mass/wing.py +++ b/aviary/subsystems/mass/simple_mass/wing.py @@ -158,41 +158,6 @@ def extract_airfoil_features(self, x_coords, y_coords): return camber, camber_location, max_thickness_value, thickness, camber_line -if __name__ == '__main__': - # Build OpenMDAO problem - prob = om.Problem() - - # Add the center of gravity component - prob.model.add_subsystem('cog', WingMassAndCOG() , promotes_inputs=['*'], promotes_outputs=['*']) - - n_points = 10 # = num_sections - x = jnp.linspace(0, 1, n_points) - max_thickness_chord_ratio = 0.12 - thickness_dist = 5 * max_thickness_chord_ratio * ( - 0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) - - # Setup the problem - prob.setup() - - # Define some example inputs - prob.set_val(Aircraft.Wing.SPAN, 3.74904) - prob.set_val(Aircraft.Wing.ROOT_CHORD, 0.40005) - prob.set_val('tip_chord', 0.100076) - prob.set_val('twist', jnp.linspace(0,0,10)) - prob.set_val('thickness_dist', thickness_dist) - - - #prob.model.cog.options['airfoil_data_file'] = 'Clark_Y.dat' - prob.model.cog.options['material'] = 'Balsa' - prob.model.cog.options['airfoil_type'] = '2412' - - # Run the model - prob.run_model() - - # Get the results - total_weight = prob.get_val(Aircraft.Wing.MASS) - - print(f"Total mass of the wing: {total_weight} kg") From 40384a2c12795ebe4944e2ddf2de8d527de45d63 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 8 Jul 2025 13:33:56 -0400 Subject: [PATCH 126/147] Update test_mass_summation.py --- aviary/subsystems/mass/simple_mass/test/test_mass_summation.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py b/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py index b2897ec5e..795b35a67 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py +++ b/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py @@ -218,7 +218,7 @@ def setUp(self): val=4.25) self.prob.set_val(Aircraft.VerticalTail.MASS, - val=4.25) + val=4.5) def test_case(self): From d2cb4263a4f23f72fd69ce8647c4214ca7a0ae07 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 8 Jul 2025 13:34:53 -0400 Subject: [PATCH 127/147] Update test_tail.py --- aviary/subsystems/mass/simple_mass/test/test_tail.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aviary/subsystems/mass/simple_mass/test/test_tail.py b/aviary/subsystems/mass/simple_mass/test/test_tail.py index 8ede8ed9f..d9c7b6ee7 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_tail.py +++ b/aviary/subsystems/mass/simple_mass/test/test_tail.py @@ -35,7 +35,7 @@ def setUp(self): val=1, units="m" ) - #else: + self.prob.model.set_input_defaults( Aircraft.VerticalTail.SPAN, val=1, From 1f84990d069b17df4d2d411a8b3730ffed8ab66e Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 8 Jul 2025 13:50:22 -0400 Subject: [PATCH 128/147] Update fuselage.py --- aviary/subsystems/mass/simple_mass/fuselage.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/fuselage.py b/aviary/subsystems/mass/simple_mass/fuselage.py index 13c8e5276..28ca6bae1 100644 --- a/aviary/subsystems/mass/simple_mass/fuselage.py +++ b/aviary/subsystems/mass/simple_mass/fuselage.py @@ -131,9 +131,9 @@ def compute_primal(self, aircraft__fuselage__length, base_diameter, tip_diameter def validate_inputs(self, length, base_diameter, thickness, tip_diameter, is_hollow): if length <= 0 or base_diameter <= 0 or tip_diameter <= 0 or thickness <= 0: - raise ValueError("Length, diameter, and thickness must be positive values.") + raise AnalysisError("Length, diameter, and thickness must be positive values.") if is_hollow and thickness >= base_diameter / 2: - raise ValueError("Wall thickness is too large for a hollow fuselage.") + raise AnalysisError("Wall thickness is too large for a hollow fuselage.") def load_fuselage_data(self, custom_fuselage_data_file): if custom_fuselage_data_file: From 24bf21ecebae49ce354e7bc1e3529719e8ee2784 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Tue, 8 Jul 2025 16:03:16 -0400 Subject: [PATCH 129/147] Update tail.py --- aviary/subsystems/mass/simple_mass/tail.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/tail.py b/aviary/subsystems/mass/simple_mass/tail.py index 2909b7d38..78d5734e0 100644 --- a/aviary/subsystems/mass/simple_mass/tail.py +++ b/aviary/subsystems/mass/simple_mass/tail.py @@ -185,8 +185,7 @@ def compute_primal(self, return aircraft__horizontal_tail__mass, aircraft__vertical_tail__mass def precompute_airfoil_geometry(self): - num_sections = self.options['num_sections'] - n_points = num_sections + n_points = self.options['num_sections'] x_points = jnp.linspace(0, 1, n_points) dx = 1 / (n_points - 1) return x_points, dx From f2123a2fbeea09aaf754b3b8e65ff1c30c61c992 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Wed, 9 Jul 2025 10:34:12 -0400 Subject: [PATCH 130/147] Update wing.py --- aviary/subsystems/mass/simple_mass/wing.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/wing.py b/aviary/subsystems/mass/simple_mass/wing.py index 3ff08058a..eacbba19c 100644 --- a/aviary/subsystems/mass/simple_mass/wing.py +++ b/aviary/subsystems/mass/simple_mass/wing.py @@ -101,11 +101,16 @@ def compute_primal(self, aircraft__wing__span, aircraft__wing__root_chord, tip_c x_points = jnp.linspace(0, 1, n_points) dx = 1 / (n_points - 1) - weight_function = lambda x: density * self.airfoil_thickness(x, max_thickness) * (aircraft__wing__root_chord - - (aircraft__wing__root_chord - tip_chord) * (x / aircraft__wing__span) - ) * aircraft__wing__span - - aircraft__wing__mass, _ = quadgk(weight_function, [0, 1], epsabs=1e-9, epsrel=1e-9) + if airfoil_type: + aircraft__wing__mass_first_part, _ = quadgk(lambda x: density * 2 * jnp.atleast_1d(self.airfoil_thickness(x, max_thickness)) * jnp.sqrt(1 + ( + (camber / camber_location**2) * (2 * camber_location - 2 * x))**2), [0, camber_location], epsabs=1e-9, epsrel=1e-9) + aircraft__wing__mass_second_part, _ = quadgk(lambda x: density * 2 * jnp.atleast_1d(self.airfoil_thickness(x, max_thickness)) * jnp.sqrt(1 + ( + (camber / (1 - camber_location)**2 * (2 * camber_location - 2 * x)))**2), [camber_location, 1], epsabs=1e-9, epsrel=1e-9) + + aircraft__wing__mass = aircraft__wing__mass_first_part + aircraft__wing__mass_second_part + + elif airfoil_data_file is not None: + aircraft__wing__mass, _ = quadgk(density * 2 * thickness_dist * jnp.sqrt(1 + jnp.gradient(camber_line)**2), [0, 1], epsabs=1e-9, epsrel=1e-9) return aircraft__wing__mass From f85f17818bb427693463670ad66c393c35da24bb Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Wed, 9 Jul 2025 10:34:37 -0400 Subject: [PATCH 131/147] Update test_wing.py --- aviary/subsystems/mass/simple_mass/test/test_wing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aviary/subsystems/mass/simple_mass/test/test_wing.py b/aviary/subsystems/mass/simple_mass/test/test_wing.py index 86c8a3ae6..9845016bb 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_wing.py +++ b/aviary/subsystems/mass/simple_mass/test/test_wing.py @@ -75,7 +75,7 @@ def test_case(self): tol = 1e-10 assert_near_equal(self.prob[Aircraft.Wing.MASS], - 4.22032, + 10.6966719, tol) partial_data = self.prob.check_partials( From cc7f7e01aca6695f80ec1f26014ff730dffae91d Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Wed, 9 Jul 2025 10:50:05 -0400 Subject: [PATCH 132/147] Update tail.py --- aviary/subsystems/mass/simple_mass/tail.py | 37 ++++++++++++---------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/tail.py b/aviary/subsystems/mass/simple_mass/tail.py index 78d5734e0..851b23753 100644 --- a/aviary/subsystems/mass/simple_mass/tail.py +++ b/aviary/subsystems/mass/simple_mass/tail.py @@ -146,7 +146,7 @@ def compute_primal(self, x_coords = airfoil_data[:, 0] y_coords = airfoil_data[:, 1] - camber, camber_location, max_thickness = self.extract_airfoil_features(x_coords, y_coords) + camber, camber_location, max_thickness, camber_line, thickness = self.extract_airfoil_features(x_coords, y_coords) else: # Parse the NACA airfoil type (4-digit) camber = int(NACA_digits[0]) / 100.0 # Maximum camber @@ -165,24 +165,27 @@ def compute_primal(self, thickness_dist = self.airfoil_thickness(x_points, max_thickness) if tail_type == 'horizontal': - total_mass, _ = quadgk( - lambda x: density * self.airfoil_thickness(x, max_thickness) * ( - aircraft__horizontal_tail__root_chord - (aircraft__horizontal_tail__root_chord - tip_chord_tail) * (x / aircraft__horizontal_tail__span) - ) * aircraft__horizontal_tail__span, [0, 1], epsabs=1e-9, epsrel=1e-9 - ) + if airfoil_type: + total_mass_first_part, _ = quadgk(lambda x: density * 2 * jnp.atleast_1d(self.airfoil_thickness(x, max_thickness)) * jnp.sqrt(1 + ( + (camber / camber_location**2) * (2 * camber_location - 2 * x))**2), [0, camber_location], epsabs=1e-9, epsrel=1e-9) + total_mass_second_part, _ = quadgk(lambda x: density * 2 * jnp.atleast_1d(self.airfoil_thickness(x, max_thickness)) * jnp.sqrt(1 + ( + (camber / (1 - camber_location)**2 * (2 * camber_location - 2 * x)))**2), [camber_location, 1], epsabs=1e-9, epsrel=1e-9) - aircraft__horizontal_tail__mass = total_mass - + aircraft__horizontal_tail__mass = total_mass_first_part + total_mass_second_part + elif airfoil_file is not None: + aircraft__horizontal_tail__mass, _ = quadgk(density * 2 * thickness * jnp.sqrt(1 + jnp.gradient(camber_line)**2), [0, 1], epsabs=1e-9, epsrel=1e-9) elif tail_type == 'vertical': - total_mass, _ = quadgk( - lambda x: density * self.airfoil_thickness(x, max_thickness) * ( - aircraft__vertical_tail__root_chord - (aircraft__vertical_tail__root_chord - tip_chord_tail) * (x / aircraft__vertical_tail__span) - ) * aircraft__vertical_tail__span, [0, 1], epsabs=1e-9, epsrel=1e-9 - ) - - aircraft__vertical_tail__mass = total_mass + if airfoil_type: + total_mass_first_part, _ = quadgk(lambda x: density * 2 * jnp.atleast_1d(self.airfoil_thickness(x, max_thickness)) * jnp.sqrt(1 + ( + (camber / camber_location**2) * (2 * camber_location - 2 * x))**2), [0, camber_location], epsabs=1e-9, epsrel=1e-9) + total_mass_second_part, _ = quadgk(lambda x: density * 2 * jnp.atleast_1d(self.airfoil_thickness(x, max_thickness)) * jnp.sqrt(1 + ( + (camber / (1 - camber_location)**2 * (2 * camber_location - 2 * x)))**2), [camber_location, 1], epsabs=1e-9, epsrel=1e-9) + + aircraft__vertical_tail__mass = total_mass_first_part + total_mass_second_part + elif airfoil_file is not None: + aircraft__vertical_tail__mass, _ = quadgk(density * 2 * thickness * jnp.sqrt(1 + jnp.gradient(camber_line)**2), [0, 1], epsabs=1e-9, epsrel=1e-9) - return aircraft__horizontal_tail__mass, aircraft__vertical_tail__mass + return aircraft__horizontal_tail__mass, aircraft__vertical_tail__masss def precompute_airfoil_geometry(self): n_points = self.options['num_sections'] @@ -229,5 +232,5 @@ def extract_airfoil_features(self, x_coords, y_coords): camber = camber_line[camber_location_index] - return camber, camber_location, max_thickness_value + return camber, camber_location, max_thickness_value, camber_line, thickness From dbce6e6f4517bd4494f375d1e7d21820d8ced29e Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Wed, 9 Jul 2025 10:50:29 -0400 Subject: [PATCH 133/147] Update test_tail.py --- aviary/subsystems/mass/simple_mass/test/test_tail.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/test/test_tail.py b/aviary/subsystems/mass/simple_mass/test/test_tail.py index d9c7b6ee7..c2c0d9838 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_tail.py +++ b/aviary/subsystems/mass/simple_mass/test/test_tail.py @@ -85,12 +85,12 @@ def test_case(self): if self.prob.model.Tail.options['tail_type'] == 'horizontal': assert_near_equal( self.prob[Aircraft.HorizontalTail.MASS], - 4.22032, + 10.6966719, tol) else: assert_near_equal( self.prob[Aircraft.VerticalTail.MASS], - 4.22032, + 10.6966719, tol) partial_data = self.prob.check_partials( From 02308f513c4011334575df2354594f4fda83d053 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Wed, 9 Jul 2025 10:51:21 -0400 Subject: [PATCH 134/147] Update test_mass_summation.py --- .../subsystems/mass/simple_mass/test/test_mass_summation.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py b/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py index 795b35a67..3fcc2004b 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py +++ b/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py @@ -167,13 +167,13 @@ def test_case(self): if self.prob.model.tot.tail_mass.options['tail_type'] == 'horizontal': assert_near_equal( self.prob['structure_mass'], - 342.23558104, + 355.18828485, tol ) else: assert_near_equal( self.prob['structure_mass'], - 342.23558104, + 355.18828485, tol ) From 695ec839506de12e6a1bca74f8b4434675331e41 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Wed, 9 Jul 2025 14:38:58 -0400 Subject: [PATCH 135/147] Update tail.py --- aviary/subsystems/mass/simple_mass/tail.py | 75 ++++++++++++++++------ 1 file changed, 55 insertions(+), 20 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/tail.py b/aviary/subsystems/mass/simple_mass/tail.py index 851b23753..90bdd1ab6 100644 --- a/aviary/subsystems/mass/simple_mass/tail.py +++ b/aviary/subsystems/mass/simple_mass/tail.py @@ -108,6 +108,38 @@ def setup(self): units='kg', desc="Total mass of the tail") + # File check + if airfoil_type == 'file': + if airfoil_type == 'file' and (airfoil_file is None or not os.path.isfile(airfoil_file)): + raise FileNotFoundError(f"Airfoil file '{airfoil_file}' not found or not provided.") + try: + airfoil_data = np.loadtxt(airfoil_file, skiprows=1) # Assume a header + x_coords, y_coords = airfoil_data[:, 0], airfoil_data[:, 1] + except Exception as e: + raise ValueError(f"Error reading airfoil file: {e}") + + # Compute section airfoil geometry + if airfoil_file and os.path.exists(airfoil_file): + airfoil_data = np.loadtxt(airfoil_file) + x_coords = airfoil_data[:, 0] + y_coords = airfoil_data[:, 1] + + self.camber, self.camber_location, self.max_thickness, camber_line, thickness = self.extract_airfoil_features(x_coords, y_coords) + else: + # Parse the NACA airfoil type (4-digit) + self.camber = int(NACA_digits[0]) / 100.0 # Maximum camber + self.camber_location = int(NACA_digits[1]) / 10.0 # Location of max camber + self.max_thickness = int(NACA_digits[2:4]) / 100.0 # Max thickness + + def get_self_statics(self): + return (self.camber, + self.camber_location, + self.max_thickness, + self.options['tail_type'], + self.options['material'], + self.options['num_sections'], + self.options['NACA_digits']) + def compute_primal(self, aircraft__horizontal_tail__span, aircraft__horizontal_tail__root_chord, @@ -124,34 +156,37 @@ def compute_primal(self, airfoil_file = self.options['airfoil_file'] num_sections = self.options['num_sections'] NACA_digits = self.options['NACA_digits'] + camber = self.camber + camber_location = self.camber_location + max_thickness = self.max_thickness # This is just so that the differentiation and unittest do not break. If tail_type = horizontal, ignore the vertical tail mass and vice versa. # TODO: Potentially write these tails as separate files. aircraft__horizontal_tail__mass = 0.0 * thickness_ratio aircraft__vertical_tail__mass = 0.0 * thickness_ratio - # File check - if airfoil_type == 'file': - if airfoil_type == 'file' and (airfoil_file is None or not os.path.isfile(airfoil_file)): - raise FileNotFoundError(f"Airfoil file '{airfoil_file}' not found or not provided.") - try: - airfoil_data = np.loadtxt(airfoil_file, skiprows=1) # Assume a header - x_coords, y_coords = airfoil_data[:, 0], airfoil_data[:, 1] - except Exception as e: - raise ValueError(f"Error reading airfoil file: {e}") + # # File check + # if airfoil_type == 'file': + # if airfoil_type == 'file' and (airfoil_file is None or not os.path.isfile(airfoil_file)): + # raise FileNotFoundError(f"Airfoil file '{airfoil_file}' not found or not provided.") + # try: + # airfoil_data = np.loadtxt(airfoil_file, skiprows=1) # Assume a header + # x_coords, y_coords = airfoil_data[:, 0], airfoil_data[:, 1] + # except Exception as e: + # raise ValueError(f"Error reading airfoil file: {e}") - # Compute section airfoil geometry - if airfoil_file and os.path.exists(airfoil_file): - airfoil_data = np.loadtxt(airfoil_file) - x_coords = airfoil_data[:, 0] - y_coords = airfoil_data[:, 1] + # # Compute section airfoil geometry + # if airfoil_file and os.path.exists(airfoil_file): + # airfoil_data = np.loadtxt(airfoil_file) + # x_coords = airfoil_data[:, 0] + # y_coords = airfoil_data[:, 1] - camber, camber_location, max_thickness, camber_line, thickness = self.extract_airfoil_features(x_coords, y_coords) - else: - # Parse the NACA airfoil type (4-digit) - camber = int(NACA_digits[0]) / 100.0 # Maximum camber - camber_location = int(NACA_digits[1]) / 10.0 # Location of max camber - max_thickness = int(NACA_digits[2:4]) / 100.0 # Max thickness + # camber, camber_location, max_thickness, camber_line, thickness = self.extract_airfoil_features(x_coords, y_coords) + # else: + # # Parse the NACA airfoil type (4-digit) + # camber = int(NACA_digits[0]) / 100.0 # Maximum camber + # camber_location = int(NACA_digits[1]) / 10.0 # Location of max camber + # max_thickness = int(NACA_digits[2:4]) / 100.0 # Max thickness if tail_type == 'horizontal': span_locations = jnp.linspace(0, aircraft__horizontal_tail__span, num_sections) From 4e6eb13053813f646439da545b0d5afd35d97b38 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Wed, 9 Jul 2025 15:01:25 -0400 Subject: [PATCH 136/147] Update fuselage.py --- aviary/subsystems/mass/simple_mass/fuselage.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/fuselage.py b/aviary/subsystems/mass/simple_mass/fuselage.py index 28ca6bae1..84277e821 100644 --- a/aviary/subsystems/mass/simple_mass/fuselage.py +++ b/aviary/subsystems/mass/simple_mass/fuselage.py @@ -38,7 +38,10 @@ def initialize(self): allow_none=True, desc='optional data file of fuselage geometry') - self.custom_fuselage_function = None + self.options.declare('custom_fuselage_function', + types=FunctionType, + allow_none=True, + desc='optional custom function generation for fuselage geometry') def setup(self): self.options['use_jit'] = not(Debug) @@ -91,7 +94,8 @@ def compute_primal(self, aircraft__fuselage__length, base_diameter, tip_diameter if base_diameter <= 0 or tip_diameter <= 0: raise AnalysisError("Diameter must be greater than zero.") - custom_fuselage_function = getattr(self, 'custom_fuselage_function', None) # Custom fuselage model function -- if provided + # custom_fuselage_function = getattr(self, 'custom_fuselage_function', None) # Custom fuselage model function -- if provided + custom_fuselage_function = self.options['custom_fuselage_function'] custom_fuselage_data_file = self.options['custom_fuselage_data_file'] From cff723bd776529a9788f73ac53d7d29e7ffdb4c5 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Wed, 9 Jul 2025 15:03:04 -0400 Subject: [PATCH 137/147] Update fuselage.py --- aviary/subsystems/mass/simple_mass/fuselage.py | 1 + 1 file changed, 1 insertion(+) diff --git a/aviary/subsystems/mass/simple_mass/fuselage.py b/aviary/subsystems/mass/simple_mass/fuselage.py index 84277e821..ccb3955ad 100644 --- a/aviary/subsystems/mass/simple_mass/fuselage.py +++ b/aviary/subsystems/mass/simple_mass/fuselage.py @@ -40,6 +40,7 @@ def initialize(self): self.options.declare('custom_fuselage_function', types=FunctionType, + default=None, allow_none=True, desc='optional custom function generation for fuselage geometry') From bbf5b48d5a97137d51794efa72581960937b2ea3 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Wed, 9 Jul 2025 15:10:02 -0400 Subject: [PATCH 138/147] Update fuselage.py --- aviary/subsystems/mass/simple_mass/fuselage.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/fuselage.py b/aviary/subsystems/mass/simple_mass/fuselage.py index ccb3955ad..762b21dcd 100644 --- a/aviary/subsystems/mass/simple_mass/fuselage.py +++ b/aviary/subsystems/mass/simple_mass/fuselage.py @@ -155,8 +155,8 @@ def load_fuselage_data(self, custom_fuselage_data_file): return None def get_section_diameter(self, location, length, base_diameter, tip_diameter, interpolate_diameter): - if self.custom_fuselage_function: - return self.custom_fuselage_function(location) + if options['custom_fuselage_function'] is not None: + return options['custom_fuselage_function'](location) elif self.load_fuselage_data and interpolate_diameter is not None: return interpolate_diameter(location) else: From 96fe4f2a88df5a6eac3471a13a864e6f8eb63d06 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Wed, 9 Jul 2025 15:44:00 -0400 Subject: [PATCH 139/147] Update tail.py --- aviary/subsystems/mass/simple_mass/tail.py | 29 ++++------------------ 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/tail.py b/aviary/subsystems/mass/simple_mass/tail.py index 90bdd1ab6..5756150db 100644 --- a/aviary/subsystems/mass/simple_mass/tail.py +++ b/aviary/subsystems/mass/simple_mass/tail.py @@ -124,7 +124,7 @@ def setup(self): x_coords = airfoil_data[:, 0] y_coords = airfoil_data[:, 1] - self.camber, self.camber_location, self.max_thickness, camber_line, thickness = self.extract_airfoil_features(x_coords, y_coords) + self.camber, self.camber_location, self.max_thickness, self.camber_line, self.thickness = self.extract_airfoil_features(x_coords, y_coords) else: # Parse the NACA airfoil type (4-digit) self.camber = int(NACA_digits[0]) / 100.0 # Maximum camber @@ -135,6 +135,8 @@ def get_self_statics(self): return (self.camber, self.camber_location, self.max_thickness, + self.camber_line, + self.thickness, self.options['tail_type'], self.options['material'], self.options['num_sections'], @@ -159,34 +161,13 @@ def compute_primal(self, camber = self.camber camber_location = self.camber_location max_thickness = self.max_thickness + camber_line = self.camber_line + thickness = self.thickness # This is just so that the differentiation and unittest do not break. If tail_type = horizontal, ignore the vertical tail mass and vice versa. # TODO: Potentially write these tails as separate files. aircraft__horizontal_tail__mass = 0.0 * thickness_ratio aircraft__vertical_tail__mass = 0.0 * thickness_ratio - - # # File check - # if airfoil_type == 'file': - # if airfoil_type == 'file' and (airfoil_file is None or not os.path.isfile(airfoil_file)): - # raise FileNotFoundError(f"Airfoil file '{airfoil_file}' not found or not provided.") - # try: - # airfoil_data = np.loadtxt(airfoil_file, skiprows=1) # Assume a header - # x_coords, y_coords = airfoil_data[:, 0], airfoil_data[:, 1] - # except Exception as e: - # raise ValueError(f"Error reading airfoil file: {e}") - - # # Compute section airfoil geometry - # if airfoil_file and os.path.exists(airfoil_file): - # airfoil_data = np.loadtxt(airfoil_file) - # x_coords = airfoil_data[:, 0] - # y_coords = airfoil_data[:, 1] - - # camber, camber_location, max_thickness, camber_line, thickness = self.extract_airfoil_features(x_coords, y_coords) - # else: - # # Parse the NACA airfoil type (4-digit) - # camber = int(NACA_digits[0]) / 100.0 # Maximum camber - # camber_location = int(NACA_digits[1]) / 10.0 # Location of max camber - # max_thickness = int(NACA_digits[2:4]) / 100.0 # Max thickness if tail_type == 'horizontal': span_locations = jnp.linspace(0, aircraft__horizontal_tail__span, num_sections) From 2aa92ab182ca8b172c9dfdabc18bf2673db1daca Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Wed, 9 Jul 2025 15:47:38 -0400 Subject: [PATCH 140/147] Update wing.py --- aviary/subsystems/mass/simple_mass/wing.py | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/aviary/subsystems/mass/simple_mass/wing.py b/aviary/subsystems/mass/simple_mass/wing.py index eacbba19c..5a88fe18a 100644 --- a/aviary/subsystems/mass/simple_mass/wing.py +++ b/aviary/subsystems/mass/simple_mass/wing.py @@ -71,6 +71,29 @@ def setup(self): Aircraft.Wing.MASS, units='kg') + if airfoil_data_file and os.path.exists(airfoil_data_file): + airfoil_data = np.loadtxt(airfoil_data_file) + x_coords = airfoil_data[:, 0] + y_coords = airfoil_data[:, 1] + + self.camber, self.camber_location, self.max_thickness, self.thickness, self.camber_line = self.extract_airfoil_features(x_coords, y_coords) + num_sections = len(x_coords) + else: + # Parse the NACA airfoil type (4-digit) + self.camber = int(airfoil_type[0]) / 100.0 # Maximum camber + self.camber_location = int(airfoil_type[1]) / 10.0 # Location of max camber + self.max_thickness = int(airfoil_type[2:4]) / 100.0 # Max thickness + num_sections = self.options['num_sections'] + + def get_self_statics(self): + return (self.camber, + self.camber_location, + self.max_thickness, + self.thickness, + self.camber_line, + self.options['material']) + + def compute_primal(self, aircraft__wing__span, aircraft__wing__root_chord, tip_chord, twist, thickness_dist): material = self.options['material'] # Material is taken from options airfoil_type = self.options['airfoil_type'] # NACA airfoil type From 77ab18f76d83e5deb37a32d00d507e8d8a668276 Mon Sep 17 00:00:00 2001 From: jkirk5 Date: Fri, 18 Jul 2025 13:24:47 -0400 Subject: [PATCH 141/147] WIP code fixes --- .../examples/additional_flight_phases.ipynb | 14 - .../subsystems/mass/simple_mass/fuselage.py | 234 +++++------- .../mass/simple_mass/mass_builder.py | 14 +- .../mass/simple_mass/mass_premission.py | 18 +- .../mass/simple_mass/mass_summation.py | 87 ++--- .../mass/simple_mass/materials_database.py | 43 ++- aviary/subsystems/mass/simple_mass/tail.py | 352 ++++++++++-------- .../mass/simple_mass/test/test_fuselage.py | 97 ++--- .../simple_mass/test/test_mass_summation.py | 224 +++-------- .../mass/simple_mass/test/test_tail.py | 103 ++--- .../mass/simple_mass/test/test_wing.py | 74 ++-- aviary/subsystems/mass/simple_mass/wing.py | 213 ++++++----- pyproject.toml | 29 +- 13 files changed, 647 insertions(+), 855 deletions(-) diff --git a/aviary/docs/examples/additional_flight_phases.ipynb b/aviary/docs/examples/additional_flight_phases.ipynb index c51896dd6..9f42c3591 100644 --- a/aviary/docs/examples/additional_flight_phases.ipynb +++ b/aviary/docs/examples/additional_flight_phases.ipynb @@ -69,7 +69,6 @@ " 'time_duration_bounds': ((25.5, 76.5), 'min'),\n", " },\n", " 'initial_guesses': {'time': ([0, 51], 'min')},\n", - " 'initial_guesses': {'times': ([0, 51], 'min')},\n", " },\n", " 'cruise_1': {\n", " 'subsystem_options': {'core_aerodynamics': {'method': 'computed'}},\n", @@ -91,7 +90,6 @@ " 'time_duration_bounds': ((23.5, 70.5), 'min'),\n", " },\n", " 'initial_guesses': {'time': ([51, 47], 'min')},\n", - " 'initial_guesses': {'times': ([51, 47], 'min')},\n", " },\n", " 'climb_2': {\n", " 'subsystem_options': {'core_aerodynamics': {'method': 'computed'}},\n", @@ -113,7 +111,6 @@ " 'time_duration_bounds': ((5.0, 15.0), 'min'),\n", " },\n", " 'initial_guesses': {'time': ([98, 10], 'min')},\n", - " 'initial_guesses': {'times': ([98, 10], 'min')},\n", " },\n", " 'cruise_2': {\n", " 'subsystem_options': {'core_aerodynamics': {'method': 'computed'}},\n", @@ -135,7 +132,6 @@ " 'time_duration_bounds': ((24.0, 72.0), 'min'),\n", " },\n", " 'initial_guesses': {'time': ([108, 48], 'min')},\n", - " 'initial_guesses': {'times': ([108, 48], 'min')},\n", " },\n", " 'climb_3': {\n", " 'subsystem_options': {'core_aerodynamics': {'method': 'computed'}},\n", @@ -157,7 +153,6 @@ " 'time_duration_bounds': ((7.0, 21.0), 'min'),\n", " },\n", " 'initial_guesses': {'time': ([156, 14], 'min')},\n", - " 'initial_guesses': {'times': ([156, 14], 'min')},\n", " },\n", " 'climb_4': {\n", " 'subsystem_options': {'core_aerodynamics': {'method': 'computed'}},\n", @@ -179,7 +174,6 @@ " 'time_duration_bounds': ((43.0, 129.0), 'min'),\n", " },\n", " 'initial_guesses': {'time': ([170, 86], 'min')},\n", - " 'initial_guesses': {'times': ([170, 86], 'min')},\n", " },\n", " 'descent_1': {\n", " 'subsystem_options': {'core_aerodynamics': {'method': 'computed'}},\n", @@ -201,7 +195,6 @@ " 'time_duration_bounds': ((41.0, 123.0), 'min'),\n", " },\n", " 'initial_guesses': {'time': ([256, 82], 'min')},\n", - " 'initial_guesses': {'times': ([256, 82], 'min')},\n", " },\n", " 'post_mission': {\n", " 'include_landing': False,\n", @@ -284,13 +277,6 @@ "\n", "Playing around with a model and seeing how different settings affect the optimization and resulting aircraft design is always an enlightening experience." ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { diff --git a/aviary/subsystems/mass/simple_mass/fuselage.py b/aviary/subsystems/mass/simple_mass/fuselage.py index 762b21dcd..4d1191108 100644 --- a/aviary/subsystems/mass/simple_mass/fuselage.py +++ b/aviary/subsystems/mass/simple_mass/fuselage.py @@ -1,146 +1,95 @@ -import openmdao.api as om -import numpy as np -from scipy.interpolate import interp1d +from pathlib import Path import jax.numpy as jnp -import openmdao.jax as omj import jax.scipy.interpolate as jinterp - -from aviary.variable_info.variables import Aircraft -from aviary.variable_info.functions import add_aviary_output, add_aviary_input - -try: - from quadax import quadgk -except ImportError: - raise ImportError( - "quadax package not found. You can install it by running 'pip install quadax'." - ) +import numpy as np +import openmdao.api as om +import openmdao.jax as omj from aviary.subsystems.mass.simple_mass.materials_database import materials - from aviary.utils.named_values import get_keys +from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.variables import Aircraft -Debug = True class FuselageMass(om.JaxExplicitComponent): def initialize(self): - self.options.declare('num_sections', - types=int, - default=10) - - self.options.declare('material', - default='Aluminum Oxide', - values=list(get_keys(materials))) - - self.options.declare('fuselage_data_file', - types=(Path, str), - default=None, - allow_none=True, - desc='optional data file of fuselage geometry') - - self.options.declare('custom_fuselage_function', - types=FunctionType, - default=None, - allow_none=True, - desc='optional custom function generation for fuselage geometry') + self.options.declare('num_sections', types=int, default=10) + + self.options.declare('material', default='Aluminum Oxide', values=list(get_keys(materials))) + + self.options.declare( + 'fuselage_data_file', + types=(Path, str), + default=None, + allow_none=True, + desc='optional data file of fuselage geometry', + ) + + # TODO FunctionType is not defined? + # self.options.declare( + # 'custom_fuselage_function', + # types=FunctionType, + # default=None, + # allow_none=True, + # desc='optional custom function generation for fuselage geometry', + # ) def setup(self): - self.options['use_jit'] = not(Debug) - # Inputs - add_aviary_input(self, - Aircraft.Fuselage.LENGTH, - units='m') - - self.add_input('base_diameter', - val=0.4, - units='m') # no aviary input - - self.add_input('tip_diameter', - val=0.2, - units='m') # no aviary input - - self.add_input('curvature', - val=0.0, - units='m') # 0 for straight, positive for upward curve - - self.add_input('thickness', - val=0.05, - units='m') # Wall thickness of the fuselage - + add_aviary_input(self, Aircraft.Fuselage.LENGTH, units='m') + + self.add_input('base_diameter', val=0.4, units='m') # no aviary input + self.add_input('tip_diameter', val=0.2, units='m') # no aviary input + self.add_input('curvature', val=0.0, units='m') # 0 for straight, positive for upward curve + self.add_input('thickness', val=0.05, units='m') # Wall thickness of the fuselage # Allow for asymmetry in the y and z axes -- this value acts as a slope for linear variation along these axes - self.add_input('y_offset', - val=0.0, - units='m') - - self.add_input('z_offset', - val=0.0, - units='m') - - self.add_input('is_hollow', - val=True, - units=None) # Whether the fuselage is hollow or not (default is hollow) - + self.add_input('y_offset', val=0.0, units='m') + self.add_input('z_offset', val=0.0, units='m') + self.add_input( + 'is_hollow', val=True, units=None + ) # Whether the fuselage is hollow or not (default is hollow) # Outputs - add_aviary_output(self, - Aircraft.Fuselage.MASS, - units='kg') - - def compute_primal(self, aircraft__fuselage__length, base_diameter, tip_diameter, curvature, thickness, y_offset, z_offset, is_hollow): - # Input validation checks - if aircraft__fuselage__length <= 0: - raise AnalysisError("Length must be greater than zero.") - - if base_diameter <= 0 or tip_diameter <= 0: - raise AnalysisError("Diameter must be greater than zero.") - - # custom_fuselage_function = getattr(self, 'custom_fuselage_function', None) # Custom fuselage model function -- if provided - custom_fuselage_function = self.options['custom_fuselage_function'] - - custom_fuselage_data_file = self.options['custom_fuselage_data_file'] + add_aviary_output(self, Aircraft.Fuselage.MASS, units='kg') + + def compute_primal( + self, + aircraft__fuselage__length, + base_diameter, + tip_diameter, + curvature, + thickness, + y_offset, + z_offset, + is_hollow, + ): + # Validate inputs + if ( + aircraft__fuselage__length[0] <= 0 + or base_diameter[0] <= 0 + or tip_diameter[0] <= 0 + or thickness[0] <= 0 + ): + raise om.AnalysisError('Length, diameter, and thickness must be positive values.') + + if is_hollow and thickness >= base_diameter / 2: + raise om.AnalysisError('Wall thickness is too large for a hollow fuselage.') + custom_fuselage_data_file = self.options['fuselage_data_file'] material = self.options['material'] num_sections = self.options['num_sections'] - - self.validate_inputs(aircraft__fuselage__length, base_diameter, thickness, tip_diameter, is_hollow) density = materials.get_val(material, 'kg/m**3') section_locations = jnp.linspace(0, aircraft__fuselage__length, num_sections) - + aircraft__fuselage__mass = 0 total_moment_x = 0 total_moment_y = 0 total_moment_z = 0 - interpolate_diameter = self.load_fuselage_data(custom_fuselage_data_file) - - # Loop through each section - for location in section_locations: - section_diameter = self.get_section_diameter(location, aircraft__fuselage__length, base_diameter, tip_diameter, interpolate_diameter) - outer_radius = section_diameter / 2.0 - inner_radius = jnp.where(is_hollow, omj.smooth_max(0, outer_radius - thickness), 0) - - section_volume = jnp.pi * (outer_radius**2 - inner_radius**2) * (aircraft__fuselage__length / num_sections) - section_weight = density * section_volume - - centroid_x, centroid_y, centroid_z = self.compute_centroid(location, aircraft__fuselage__length, y_offset, z_offset, curvature, base_diameter, tip_diameter) - - aircraft__fuselage__mass += section_weight - total_moment_x += centroid_x * section_weight - total_moment_y += centroid_y * section_weight - total_moment_z += centroid_z * section_weight - - return aircraft__fuselage__mass - - def validate_inputs(self, length, base_diameter, thickness, tip_diameter, is_hollow): - if length <= 0 or base_diameter <= 0 or tip_diameter <= 0 or thickness <= 0: - raise AnalysisError("Length, diameter, and thickness must be positive values.") - if is_hollow and thickness >= base_diameter / 2: - raise AnalysisError("Wall thickness is too large for a hollow fuselage.") - - def load_fuselage_data(self, custom_fuselage_data_file): + # Load fuselage data file if present if custom_fuselage_data_file: try: # Load the file @@ -150,24 +99,47 @@ def load_fuselage_data(self, custom_fuselage_data_file): else: fuselage_locations = custom_data[:, 0] fuselage_diameters = custom_data[:, 1] - return jinterp.RegularGridInterpolator(fuselage_locations, fuselage_diameters, kind='linear', fill_value='extrapolate') + # TODO: OM interp is much more performant than scipy, use metamodel here + interpolate_diameter = jinterp.RegularGridInterpolator( + fuselage_locations, fuselage_diameters, method='linear' + ) else: - return None - - def get_section_diameter(self, location, length, base_diameter, tip_diameter, interpolate_diameter): - if options['custom_fuselage_function'] is not None: - return options['custom_fuselage_function'](location) - elif self.load_fuselage_data and interpolate_diameter is not None: - return interpolate_diameter(location) - else: - return base_diameter + ((tip_diameter - base_diameter) / length) * location - - def compute_centroid(self, location, length, y_offset, z_offset, curvature, base_diameter, tip_diameter): - centroid_x = jnp.where(tip_diameter / base_diameter != 1, (3/4) * location, location) - centroid_y = y_offset * (1 - location / length) - centroid_z = z_offset * (1 - location / length) + curvature * location**2 / length - return centroid_x, centroid_y, centroid_z + interpolate_diameter = None + + # Loop through each section + for location in section_locations: + # FunctionType is not defined, so "custom_fuselage_function" is currently broken + # if self.options['custom_fuselage_function'] is not None: + # section_diameter = self.options['custom_fuselage_function'](location) + # should be elif below once fixed + if self.options['fuselage_data_file'] and interpolate_diameter is not None: + section_diameter = interpolate_diameter(location) + else: + section_diameter = ( + base_diameter + + ((tip_diameter - base_diameter) / aircraft__fuselage__length) * location + ) + outer_radius = section_diameter / 2.0 + inner_radius = jnp.where(is_hollow, omj.smooth_max(0, outer_radius - thickness), 0) + section_volume = ( + jnp.pi + * (outer_radius**2 - inner_radius**2) + * (aircraft__fuselage__length / num_sections) + ) + section_weight = density * section_volume + centroid_x = jnp.where(tip_diameter / base_diameter != 1, (3 / 4) * location, location) + centroid_y = y_offset * (1 - location / aircraft__fuselage__length) + centroid_z = ( + z_offset * (1 - location / aircraft__fuselage__length) + + curvature * location**2 / aircraft__fuselage__length + ) + aircraft__fuselage__mass += section_weight + total_moment_x += centroid_x * section_weight + total_moment_y += centroid_y * section_weight + total_moment_z += centroid_z * section_weight + + return aircraft__fuselage__mass diff --git a/aviary/subsystems/mass/simple_mass/mass_builder.py b/aviary/subsystems/mass/simple_mass/mass_builder.py index cc70b2525..c0dd1a260 100644 --- a/aviary/subsystems/mass/simple_mass/mass_builder.py +++ b/aviary/subsystems/mass/simple_mass/mass_builder.py @@ -12,18 +12,18 @@ _default_name = 'simple_mass' + class SimpleMassBuilder(MassBuilderBase): """ Base mass builder - + """ def __init__(self, name=None): - if name is None: - name = _default_name - - super().__init__(name=name) - + if name is None: + name = _default_name + + super().__init__(name=name) + def build_pre_mission(self, aviary_inputs): return MassPremission() - diff --git a/aviary/subsystems/mass/simple_mass/mass_premission.py b/aviary/subsystems/mass/simple_mass/mass_premission.py index 41ec70e0d..72acafdd6 100644 --- a/aviary/subsystems/mass/simple_mass/mass_premission.py +++ b/aviary/subsystems/mass/simple_mass/mass_premission.py @@ -4,28 +4,20 @@ from aviary.subsystems.mass.simple_mass.fuselage import FuselageMassAndCOG from aviary.subsystems.mass.simple_mass.tail import TailMassAndCOG + class SimpleMassPremission(om.Group): """ - Pre-mission group of top-level mass estimation groups and components for + Pre-mission group of top-level mass estimation groups and components for the simple small-scale aircraft mass build-up. """ def setup(self): + self.add_subsystem('Wing', WingMass(), promotes_inputs=['*'], promotes_outputs=['*']) self.add_subsystem( - 'Wing', - WingMass(), - promotes_inputs=['*'], promotes_outputs=['*'] - ) - - self.add_subsystem( - 'Fuselage', - FuselageMass(), - promotes_inputs=['*'], promotes_outputs=['*'] + 'Fuselage', FuselageMass(), promotes_inputs=['*'], promotes_outputs=['*'] ) self.add_subsystem( - 'Tail', - TailMass(tail_type='horizontal'), - promotes_inputs=['*'], promotes_outputs=['*'] + 'Tail', TailMass(tail_type='horizontal'), promotes_inputs=['*'], promotes_outputs=['*'] ) diff --git a/aviary/subsystems/mass/simple_mass/mass_summation.py b/aviary/subsystems/mass/simple_mass/mass_summation.py index 761bcf46d..44d86290d 100644 --- a/aviary/subsystems/mass/simple_mass/mass_summation.py +++ b/aviary/subsystems/mass/simple_mass/mass_summation.py @@ -1,13 +1,10 @@ -import numpy as np - import openmdao.api as om - -from aviary.subsystems.mass.simple_mass.fuselage import FuselageMassAndCOG -from aviary.subsystems.mass.simple_mass.wing import WingMassAndCOG -from aviary.subsystems.mass.simple_mass.tail import TailMassAndCOG -from aviary.variable_info.variables import Aircraft +from aviary.subsystems.mass.simple_mass.fuselage import FuselageMass +from aviary.subsystems.mass.simple_mass.tail import TailMass +from aviary.subsystems.mass.simple_mass.wing import WingMass from aviary.variable_info.functions import add_aviary_input +from aviary.variable_info.variables import Aircraft class SimpleMassSummation(om.Group): @@ -15,83 +12,69 @@ class SimpleMassSummation(om.Group): Group to compute various design masses for this mass group. - This group will be expanded greatly as more subsystems are created. + This group will be expanded greatly as more subsystems are created. """ def setup(self): - self.add_subsystem( - 'fuse_mass', + 'fuse_mass', FuselageMass(), promotes_inputs=['*'], - promotes_outputs=[Aircraft.Fuselage.MASS] + promotes_outputs=[Aircraft.Fuselage.MASS], ) self.add_subsystem( - 'wing_mass', - WingMass(), - promotes_inputs=['*'], - promotes_outputs=[Aircraft.Wing.MASS] + 'wing_mass', WingMass(), promotes_inputs=['*'], promotes_outputs=[Aircraft.Wing.MASS] ) self.add_subsystem( 'tail_mass', TailMass(), promotes_inputs=['*'], - promotes_outputs=[Aircraft.HorizontalTail.MASS] + promotes_outputs=[Aircraft.HorizontalTail.MASS], ) self.add_subsystem( - 'structure_mass', - StructureMass(), - promotes_inputs=['*'], - promotes_outputs=['*'] + 'structure_mass', StructureMass(), promotes_inputs=['*'], promotes_outputs=['*'] ) + class StructureMass(om.JaxExplicitComponent): def initialize(self): - self.options.declare('tail_type', - default='horizontal', - values=['horizontal', 'vertical'], - desc="Tail type used for the tail mass from tail.py file") + self.options.declare( + 'tail_type', + default='horizontal', + values=['horizontal', 'vertical'], + desc='Tail type used for the tail mass from tail.py file', + ) def setup(self): - tail_type = self.options['tail_type'] + add_aviary_input(self, Aircraft.Wing.MASS, val=0.0, units='kg') + add_aviary_input(self, Aircraft.Fuselage.MASS, val=0.0, units='kg') + add_aviary_input(self, Aircraft.HorizontalTail.MASS, val=0.0, units='kg') + add_aviary_input(self, Aircraft.VerticalTail.MASS, val=0.0, units='kg') - add_aviary_input(self, - Aircraft.Wing.MASS, - val=0.0, - units='kg') - - add_aviary_input(self, - Aircraft.Fuselage.MASS, - val=0.0, - units='kg') - - add_aviary_input(self, - Aircraft.HorizontalTail.MASS, - val=0.0, - units='kg') - - add_aviary_input(self, - Aircraft.VerticalTail.MASS, - val=0.0, - units='kg') - # More masses can be added, i.e., tail, spars, flaps, etc. as needed - self.add_output('structure_mass', - val=0.0, - units='kg') - - def compute_primal(self, aircraft__wing__mass, aircraft__fuselage__mass, aircraft__horizontal_tail__mass, aircraft__vertical_tail__mass): + self.add_output('structure_mass', val=0.0, units='kg') + def compute_primal( + self, + aircraft__wing__mass, + aircraft__fuselage__mass, + aircraft__horizontal_tail__mass, + aircraft__vertical_tail__mass, + ): tail_type = self.options['tail_type'] if tail_type == 'horizontal': - structure_mass = aircraft__wing__mass + aircraft__fuselage__mass + aircraft__horizontal_tail__mass + structure_mass = ( + aircraft__wing__mass + aircraft__fuselage__mass + aircraft__horizontal_tail__mass + ) else: - structure_mass = aircraft__wing__mass + aircraft__fuselage__mass + aircraft__vertical_tail__mass + structure_mass = ( + aircraft__wing__mass + aircraft__fuselage__mass + aircraft__vertical_tail__mass + ) return structure_mass diff --git a/aviary/subsystems/mass/simple_mass/materials_database.py b/aviary/subsystems/mass/simple_mass/materials_database.py index fc8bba94c..d61249593 100644 --- a/aviary/subsystems/mass/simple_mass/materials_database.py +++ b/aviary/subsystems/mass/simple_mass/materials_database.py @@ -1,9 +1,10 @@ """ -Database for various material densities that are to be used for mass calculations for small aircraft in particular. +Database for various material densities that are to be used for mass calculations for small aircraft in particular. This database will be expanded as needed. """ + from aviary.utils.named_values import NamedValues from aviary.utils.named_values import get_keys, get_values, get_items @@ -23,24 +24,28 @@ # Aluminum Compounds and Alloys materials.set_val('Aluminum Oxide', 3400, units='kg/m**3') -materials.set_val('2024-T8XX', 2800, units='kg/m**3') # aircraft-grade strength Aluminum alloy -materials.set_val('2219-T8XX', 2810, units='kg/m**3') # Exceptionally strong Aluminum alloy -materials.set_val('2024-T6', 2770, units='kg/m**3') # Another Aluminum alloy +materials.set_val('2024-T8XX', 2800, units='kg/m**3') # aircraft-grade strength Aluminum alloy +materials.set_val('2219-T8XX', 2810, units='kg/m**3') # Exceptionally strong Aluminum alloy +materials.set_val('2024-T6', 2770, units='kg/m**3') # Another Aluminum alloy materials.set_val('Aluminum Foam', 1300, units='kg/m**3') -# Steel -materials.set_val('Stainless Steel 17-4 PH', 7830, units='kg/m**3') # 17-4 PH stainless steel -materials.set_val('Stainless Steel-AISI 302', 8060, units='kg/m**3') # AISI 302 -materials.set_val('Stainless Steel-AISI 304', 7900, units='kg/m**3') # AISI 304 -materials.set_val('Steel Alloy Cast', 7830, units='kg/m**3') # General steel alloy cast -materials.set_val('Steel 321', 8030, units='kg/m**3') # Steel type 321 +# Steel +materials.set_val('Stainless Steel 17-4 PH', 7830, units='kg/m**3') # 17-4 PH stainless steel +materials.set_val('Stainless Steel-AISI 302', 8060, units='kg/m**3') # AISI 302 +materials.set_val('Stainless Steel-AISI 304', 7900, units='kg/m**3') # AISI 304 +materials.set_val('Steel Alloy Cast', 7830, units='kg/m**3') # General steel alloy cast +materials.set_val('Steel 321', 8030, units='kg/m**3') # Steel type 321 # Carbon Fibers / Carbon - Silicon Fibers -materials.set_val('Carbon/Silicon-Carbide', 2080, units='kg/m**3') # Carbon fiber reinforced SiC -materials.set_val('Silicon-Carbide/Silicon-Carbide', 2400, units='kg/m**3') # SiC fiber reinforced SiC matrix -materials.set_val('Advanced Carbon-Carbon Composite', 1600, units='kg/m**3') # ACC -materials.set_val('Reinforced Carbon-Carbon', 1580, units='kg/m**3') -materials.set_val('Reinforced Carbon-Carbon Composite', 1580, units='kg/m**3') # Generally, ACC is better, but RCC is slightly cheaper +materials.set_val('Carbon/Silicon-Carbide', 2080, units='kg/m**3') # Carbon fiber reinforced SiC +materials.set_val( + 'Silicon-Carbide/Silicon-Carbide', 2400, units='kg/m**3' +) # SiC fiber reinforced SiC matrix +materials.set_val('Advanced Carbon-Carbon Composite', 1600, units='kg/m**3') # ACC +materials.set_val('Reinforced Carbon-Carbon', 1580, units='kg/m**3') +materials.set_val( + 'Reinforced Carbon-Carbon Composite', 1580, units='kg/m**3' +) # Generally, ACC is better, but RCC is slightly cheaper """ Below are miscellaneous values that could be of importance, particularly for small aircraft. @@ -62,7 +67,7 @@ """ -materials.set_val('Wood Glue', 1080, units='kg/m**3') # Relative density value -- corresponds to 25 C (77 F) -materials.set_val('EPS Foam', 16.3388, units='kg/m**3') - - +materials.set_val( + 'Wood Glue', 1080, units='kg/m**3' +) # Relative density value -- corresponds to 25 C (77 F) +materials.set_val('EPS Foam', 16.3388, units='kg/m**3') diff --git a/aviary/subsystems/mass/simple_mass/tail.py b/aviary/subsystems/mass/simple_mass/tail.py index 5756150db..fad5993ba 100644 --- a/aviary/subsystems/mass/simple_mass/tail.py +++ b/aviary/subsystems/mass/simple_mass/tail.py @@ -1,12 +1,15 @@ -import openmdao.api as om -import openmdao.jax as omj +import os + import jax.numpy as jnp import numpy as np +import openmdao.api as om +import openmdao.jax as omj from scipy.interpolate import CubicSpline -import os +from aviary.subsystems.mass.simple_mass.materials_database import materials +from aviary.utils.named_values import get_keys +from aviary.variable_info.functions import add_aviary_input, add_aviary_output from aviary.variable_info.variables import Aircraft -from aviary.variable_info.functions import add_aviary_output, add_aviary_input try: from quadax import quadgk @@ -15,149 +18,152 @@ "quadax package not found. You can install it by running 'pip install quadax'." ) -from aviary.subsystems.mass.simple_mass.materials_database import materials - -from aviary.utils.named_values import get_keys - -Debug = True # set to enable printing class TailMass(om.JaxExplicitComponent): def initialize(self): - #self.options['default_shape'] = () # Sets the default shape to scalar - - self.options.declare('tail_type', - values=['horizontal', 'vertical'], - desc="Type of tail: 'horizontal' or 'vertical'") - - self.options.declare('airfoil_type', - default='NACA', - values=['NACA', 'file'], - desc="Airfoil type: 'NACA' for 4-digit or 'file' for user-provided coordinates") - + self.options.declare( + 'tail_type', + values=['horizontal', 'vertical'], + desc="Type of tail: 'horizontal' or 'vertical'", + ) + + self.options.declare( + 'airfoil_type', + default='NACA', + values=['NACA', 'file'], + desc="Airfoil type: 'NACA' for 4-digit or 'file' for user-provided coordinates", + ) + if self.options['airfoil_type'] == 'NACA': - self.options.declare('NACA_digits', - default='2412', - desc="4 digit code for NACA airfoil, if that is given.") - - self.options.declare('material', - default='Balsa', - values=list(get_keys(materials)), - desc="Material type") - - self.options.declare('airfoil_file', - default=None, - desc="File path for airfoil coordinates (if applicable)") - - self.options.declare('num_sections', - default=10, - desc="Number of sections for enumeration") - - def setup(self): - self.options['use_jit'] = not(Debug) + self.options.declare( + 'NACA_digits', + default='2412', + desc='4 digit code for NACA airfoil, if that is given.', + ) + + self.options.declare( + 'material', default='Balsa', values=list(get_keys(materials)), desc='Material type' + ) + + self.options.declare( + 'airfoil_file', default=None, desc='File path for airfoil coordinates (if applicable)' + ) + + self.options.declare('num_sections', default=10, desc='Number of sections for enumeration') + self.camber = 0 + self.camber_location = 0 + self.max_thickness = 0 + self.camber_line = 0 + self.thickness = 0 + + def setup(self): # Inputs - add_aviary_input(self, - Aircraft.HorizontalTail.SPAN, - units='m', - desc="Tail span") - - add_aviary_input(self, - Aircraft.HorizontalTail.ROOT_CHORD, - units='m', - desc="Root chord length") - #else: - add_aviary_input(self, - Aircraft.VerticalTail.SPAN, - units='m', - desc="Tail span") - - add_aviary_input(self, - Aircraft.VerticalTail.ROOT_CHORD, - units='m', - desc="Root chord length") - + add_aviary_input(self, Aircraft.HorizontalTail.SPAN, units='m', desc='Tail span') + + add_aviary_input( + self, Aircraft.HorizontalTail.ROOT_CHORD, units='m', desc='Root chord length' + ) + # else: + add_aviary_input(self, Aircraft.VerticalTail.SPAN, units='m', desc='Tail span') + + add_aviary_input( + self, Aircraft.VerticalTail.ROOT_CHORD, units='m', desc='Root chord length' + ) + # The inputs below have no aviary input, so there is no distinction for now - self.add_input('tip_chord_tail', - val=0.8, - units='m', - desc="Tip chord length") - - self.add_input('thickness_ratio', - val=0.12, - desc="Max thickness to chord ratio for NACA airfoil") - - self.add_input('skin_thickness', - val=0.002, - units='m', - desc="Skin panel thickness") - - self.add_input('twist_tail', - val=jnp.zeros(self.options['num_sections']), - units='deg', - desc="Twist distribution") - + self.add_input('tip_chord_tail', val=0.8, units='m', desc='Tip chord length') + + self.add_input( + 'thickness_ratio', val=0.12, desc='Max thickness to chord ratio for NACA airfoil' + ) + + self.add_input('skin_thickness', val=0.002, units='m', desc='Skin panel thickness') + + self.add_input( + 'twist_tail', + val=jnp.zeros(self.options['num_sections']), + units='deg', + desc='Twist distribution', + ) + # Outputs - add_aviary_output(self, - Aircraft.HorizontalTail.MASS, - units='kg', - desc="Total mass of the tail") - #else: - add_aviary_output(self, - Aircraft.VerticalTail.MASS, - units='kg', - desc="Total mass of the tail") + add_aviary_output( + self, Aircraft.HorizontalTail.MASS, units='kg', desc='Total mass of the tail' + ) + # else: + add_aviary_output( + self, Aircraft.VerticalTail.MASS, units='kg', desc='Total mass of the tail' + ) # File check + airfoil_file = self.options['airfoil_file'] + airfoil_type = self.options['airfoil_type'] if airfoil_type == 'file': - if airfoil_type == 'file' and (airfoil_file is None or not os.path.isfile(airfoil_file)): + if airfoil_type == 'file' and ( + airfoil_file is None or not os.path.isfile(airfoil_file) + ): raise FileNotFoundError(f"Airfoil file '{airfoil_file}' not found or not provided.") - try: - airfoil_data = np.loadtxt(airfoil_file, skiprows=1) # Assume a header + try: + airfoil_data = np.loadtxt(airfoil_file, skiprows=1) # Assume a header x_coords, y_coords = airfoil_data[:, 0], airfoil_data[:, 1] except Exception as e: - raise ValueError(f"Error reading airfoil file: {e}") - + raise ValueError(f'Error reading airfoil file: {e}') + # Compute section airfoil geometry if airfoil_file and os.path.exists(airfoil_file): airfoil_data = np.loadtxt(airfoil_file) x_coords = airfoil_data[:, 0] y_coords = airfoil_data[:, 1] - self.camber, self.camber_location, self.max_thickness, self.camber_line, self.thickness = self.extract_airfoil_features(x_coords, y_coords) - else: - # Parse the NACA airfoil type (4-digit) - self.camber = int(NACA_digits[0]) / 100.0 # Maximum camber - self.camber_location = int(NACA_digits[1]) / 10.0 # Location of max camber - self.max_thickness = int(NACA_digits[2:4]) / 100.0 # Max thickness - - def get_self_statics(self): - return (self.camber, + ( + self.camber, self.camber_location, self.max_thickness, self.camber_line, self.thickness, - self.options['tail_type'], - self.options['material'], - self.options['num_sections'], - self.options['NACA_digits']) - - def compute_primal(self, - aircraft__horizontal_tail__span, - aircraft__horizontal_tail__root_chord, - aircraft__vertical_tail__span, - aircraft__vertical_tail__root_chord, - tip_chord_tail, - thickness_ratio, - skin_thickness, - twist_tail): - tail_type = self.options["tail_type"] - airfoil_type = self.options["airfoil_type"] + ) = self.extract_airfoil_features(x_coords, y_coords) + + elif airfoil_type == 'NACA': + NACA_digits = self.options['NACA_digits'] + # Parse the NACA airfoil type (4-digit) + self.camber = int(NACA_digits[0]) / 100.0 # Maximum camber + self.camber_location = int(NACA_digits[1]) / 10.0 # Location of max camber + self.max_thickness = int(NACA_digits[2:4]) / 100.0 # Max thickness + + def get_self_statics(self): + return ( + self.camber, + self.camber_location, + self.max_thickness, + self.camber_line, + self.thickness, + self.options['tail_type'], + self.options['material'], + self.options['num_sections'], + self.options['NACA_digits'], + ) + + def compute_primal( + self, + aircraft__horizontal_tail__span, + aircraft__horizontal_tail__root_chord, + aircraft__vertical_tail__span, + aircraft__vertical_tail__root_chord, + tip_chord_tail, + thickness_ratio, + skin_thickness, + twist_tail, + ): + tail_type = self.options['tail_type'] + airfoil_type = self.options['airfoil_type'] material = self.options['material'] density = materials.get_val(material, 'kg/m**3') airfoil_file = self.options['airfoil_file'] num_sections = self.options['num_sections'] - NACA_digits = self.options['NACA_digits'] + if airfoil_type == 'NACA': + NACA_digits = self.options['NACA_digits'] camber = self.camber camber_location = self.camber_location max_thickness = self.max_thickness @@ -165,10 +171,10 @@ def compute_primal(self, thickness = self.thickness # This is just so that the differentiation and unittest do not break. If tail_type = horizontal, ignore the vertical tail mass and vice versa. - # TODO: Potentially write these tails as separate files. + # TODO: Potentially write these tails as separate files. aircraft__horizontal_tail__mass = 0.0 * thickness_ratio aircraft__vertical_tail__mass = 0.0 * thickness_ratio - + if tail_type == 'horizontal': span_locations = jnp.linspace(0, aircraft__horizontal_tail__span, num_sections) elif tail_type == 'vertical': @@ -182,42 +188,95 @@ def compute_primal(self, if tail_type == 'horizontal': if airfoil_type: - total_mass_first_part, _ = quadgk(lambda x: density * 2 * jnp.atleast_1d(self.airfoil_thickness(x, max_thickness)) * jnp.sqrt(1 + ( - (camber / camber_location**2) * (2 * camber_location - 2 * x))**2), [0, camber_location], epsabs=1e-9, epsrel=1e-9) - total_mass_second_part, _ = quadgk(lambda x: density * 2 * jnp.atleast_1d(self.airfoil_thickness(x, max_thickness)) * jnp.sqrt(1 + ( - (camber / (1 - camber_location)**2 * (2 * camber_location - 2 * x)))**2), [camber_location, 1], epsabs=1e-9, epsrel=1e-9) - + total_mass_first_part, _ = quadgk( + lambda x: density + * 2 + * jnp.atleast_1d(self.airfoil_thickness(x, max_thickness)) + * jnp.sqrt( + 1 + ((camber / camber_location**2) * (2 * camber_location - 2 * x)) ** 2 + ), + [0, camber_location], + epsabs=1e-9, + epsrel=1e-9, + ) + total_mass_second_part, _ = quadgk( + lambda x: density + * 2 + * jnp.atleast_1d(self.airfoil_thickness(x, max_thickness)) + * jnp.sqrt( + 1 + + (camber / (1 - camber_location) ** 2 * (2 * camber_location - 2 * x)) ** 2 + ), + [camber_location, 1], + epsabs=1e-9, + epsrel=1e-9, + ) + aircraft__horizontal_tail__mass = total_mass_first_part + total_mass_second_part elif airfoil_file is not None: - aircraft__horizontal_tail__mass, _ = quadgk(density * 2 * thickness * jnp.sqrt(1 + jnp.gradient(camber_line)**2), [0, 1], epsabs=1e-9, epsrel=1e-9) + aircraft__horizontal_tail__mass, _ = quadgk( + density * 2 * thickness * jnp.sqrt(1 + jnp.gradient(camber_line) ** 2), + [0, 1], + epsabs=1e-9, + epsrel=1e-9, + ) elif tail_type == 'vertical': if airfoil_type: - total_mass_first_part, _ = quadgk(lambda x: density * 2 * jnp.atleast_1d(self.airfoil_thickness(x, max_thickness)) * jnp.sqrt(1 + ( - (camber / camber_location**2) * (2 * camber_location - 2 * x))**2), [0, camber_location], epsabs=1e-9, epsrel=1e-9) - total_mass_second_part, _ = quadgk(lambda x: density * 2 * jnp.atleast_1d(self.airfoil_thickness(x, max_thickness)) * jnp.sqrt(1 + ( - (camber / (1 - camber_location)**2 * (2 * camber_location - 2 * x)))**2), [camber_location, 1], epsabs=1e-9, epsrel=1e-9) - + total_mass_first_part, _ = quadgk( + lambda x: density + * 2 + * jnp.atleast_1d(self.airfoil_thickness(x, max_thickness)) + * jnp.sqrt( + 1 + ((camber / camber_location**2) * (2 * camber_location - 2 * x)) ** 2 + ), + [0, camber_location], + epsabs=1e-9, + epsrel=1e-9, + ) + total_mass_second_part, _ = quadgk( + lambda x: density + * 2 + * jnp.atleast_1d(self.airfoil_thickness(x, max_thickness)) + * jnp.sqrt( + 1 + + (camber / (1 - camber_location) ** 2 * (2 * camber_location - 2 * x)) ** 2 + ), + [camber_location, 1], + epsabs=1e-9, + epsrel=1e-9, + ) + aircraft__vertical_tail__mass = total_mass_first_part + total_mass_second_part elif airfoil_file is not None: - aircraft__vertical_tail__mass, _ = quadgk(density * 2 * thickness * jnp.sqrt(1 + jnp.gradient(camber_line)**2), [0, 1], epsabs=1e-9, epsrel=1e-9) - - return aircraft__horizontal_tail__mass, aircraft__vertical_tail__masss - + aircraft__vertical_tail__mass, _ = quadgk( + density * 2 * thickness * jnp.sqrt(1 + jnp.gradient(camber_line) ** 2), + [0, 1], + epsabs=1e-9, + epsrel=1e-9, + ) + + return aircraft__horizontal_tail__mass, aircraft__vertical_tail__mass + def precompute_airfoil_geometry(self): n_points = self.options['num_sections'] x_points = jnp.linspace(0, 1, n_points) dx = 1 / (n_points - 1) return x_points, dx - + def airfoil_thickness(self, x, max_thickness): - return 5 * max_thickness * (0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) - + return ( + 5 + * max_thickness + * (0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) + ) + def airfoil_camber_line(self, x, camber, camber_location): - camber_location = omj.ks_max(camber_location, 1e-9) # Divide by zero check + camber_location = omj.ks_max(camber_location, 1e-9) # Divide by zero check return jnp.where( - x < camber_location, - (camber / camber_location**2) * (2 * camber_location * x - x**2), - (camber / (1 - camber_location)**2) * ((1 - 2 * camber_location) + 2 * camber_location * x - x**2) + x < camber_location, + (camber / camber_location**2) * (2 * camber_location * x - x**2), + (camber / (1 - camber_location) ** 2) + * ((1 - 2 * camber_location) + 2 * camber_location * x - x**2), ) def extract_airfoil_features(self, x_coords, y_coords): @@ -227,10 +286,10 @@ def extract_airfoil_features(self, x_coords, y_coords): """ # Approximate the camber line and max thickness from the data # Assume the camber line is the line of symmetry between the upper and lower surfaces - upper_surface = y_coords[:int(len(x_coords) // 2)] - lower_surface = y_coords[int(len(x_coords) // 2):] - x_upper = x_coords[:int(len(x_coords) // 2)] - x_lower = x_coords[int(len(x_coords) // 2):] + upper_surface = y_coords[: int(len(x_coords) // 2)] + lower_surface = y_coords[int(len(x_coords) // 2) :] + x_upper = x_coords[: int(len(x_coords) // 2)] + x_lower = x_coords[int(len(x_coords) // 2) :] upper_spline = CubicSpline(x_upper, upper_surface, bc_type='natural') lower_spline = CubicSpline(x_lower, lower_surface, bc_type='natural') @@ -249,4 +308,3 @@ def extract_airfoil_features(self, x_coords, y_coords): camber = camber_line[camber_location_index] return camber, camber_location, max_thickness_value, camber_line, thickness - diff --git a/aviary/subsystems/mass/simple_mass/test/test_fuselage.py b/aviary/subsystems/mass/simple_mass/test/test_fuselage.py index 823b33053..bcfecd803 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_fuselage.py +++ b/aviary/subsystems/mass/simple_mass/test/test_fuselage.py @@ -3,87 +3,52 @@ import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal -from aviary.subsystems.mass.simple_mass.fuselage import FuselageMassAndCOG +from aviary.subsystems.mass.simple_mass.fuselage import FuselageMass from aviary.variable_info.variables import Aircraft -class FuselageMassTestCase(unittest.TestCase): - """ - Fuselage mass test case. - """ +class FuselageMassTestCase(unittest.TestCase): + """Fuselage mass test case.""" def setUp(self): - self.prob = om.Problem() self.prob.model.add_subsystem( - "fuselage", + 'fuselage', FuselageMass(), - promotes_inputs=["*"], - promotes_outputs=["*"], + promotes_inputs=['*'], + promotes_outputs=['*'], ) - self.prob.model.set_input_defaults( - Aircraft.Fuselage.LENGTH, - val=2.0, - units="m") - - self.prob.model.set_input_defaults( - "base_diameter", - val=0.5, - units="m" - ) + self.prob.model.set_input_defaults(Aircraft.Fuselage.LENGTH, val=2.0, units='m') - self.prob.model.set_input_defaults( - "tip_diameter", - val=0.3 - ) + self.prob.model.set_input_defaults('base_diameter', val=0.5, units='m') - self.prob.model.set_input_defaults( - "curvature", - val=0.0, - units="m" - ) + self.prob.model.set_input_defaults('tip_diameter', val=0.3) - self.prob.model.set_input_defaults( - "y_offset", - val=0.0, - units="m" - ) + self.prob.model.set_input_defaults('curvature', val=0.0, units='m') - self.prob.model.set_input_defaults( - "z_offset", - val=0.0, - units="m" - ) + self.prob.model.set_input_defaults('y_offset', val=0.0, units='m') - self.prob.model.set_input_defaults( - "is_hollow", - val=True - ) - - self.prob.setup( - check=False, - force_alloc_complex=True) - - def test_case(self): + self.prob.model.set_input_defaults('z_offset', val=0.0, units='m') + + self.prob.model.set_input_defaults('is_hollow', val=True) + + self.prob.setup(check=False, force_alloc_complex=True) + def test_case(self): self.prob.run_model() - tol=1e-3 - - assert_near_equal( - self.prob[Aircraft.Fuselage.MASS], - 373.849, - tol) - - partial_data = self.prob.check_partials( - out_stream=None, - method="cs") - - assert_check_partials( - partial_data, - atol=1e-12, - rtol=1e-12) - -if __name__ == "__main__": - unittest.main() + tol = 1e-3 + + assert_near_equal(self.prob[Aircraft.Fuselage.MASS], 373.849, tol) + + partial_data = self.prob.check_partials(out_stream=None, method='cs') + + assert_check_partials(partial_data, atol=1e-12, rtol=1e-12) + + +if __name__ == '__main__': + # unittest.main() + test = FuselageMassTestCase() + test.setUp() + test.test_case() diff --git a/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py b/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py index 3fcc2004b..9b7a9a371 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py +++ b/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py @@ -8,6 +8,7 @@ from aviary.subsystems.mass.simple_mass.mass_summation import MassSummation, StructureMass from aviary.variable_info.variables import Aircraft + # Horizontal Tail Only class MassSummationTest(unittest.TestCase): """ @@ -18,173 +19,77 @@ class MassSummationTest(unittest.TestCase): def test_case(self): self.prob = om.Problem() - self.prob.model.add_subsystem( - 'tot', - SimpleMassSummation(), - promotes=['*'] - ) + self.prob.model.add_subsystem('tot', SimpleMassSummation(), promotes=['*']) - self.prob.model.set_input_defaults( - Aircraft.Wing.SPAN, - val=1.0, - units='m' - ) + self.prob.model.set_input_defaults(Aircraft.Wing.SPAN, val=1.0, units='m') - self.prob.model.set_input_defaults( - Aircraft.Wing.ROOT_CHORD, - val=1.0, - units='m' - ) + self.prob.model.set_input_defaults(Aircraft.Wing.ROOT_CHORD, val=1.0, units='m') - self.prob.model.set_input_defaults( - Aircraft.HorizontalTail.SPAN, - val=1, - units="m" - ) + self.prob.model.set_input_defaults(Aircraft.HorizontalTail.SPAN, val=1, units='m') - self.prob.model.set_input_defaults( - Aircraft.HorizontalTail.ROOT_CHORD, - val=1, - units="m" - ) - - self.prob.model.set_input_defaults( - Aircraft.VerticalTail.SPAN, - val=1, - units="m" - ) + self.prob.model.set_input_defaults(Aircraft.HorizontalTail.ROOT_CHORD, val=1, units='m') - self.prob.model.set_input_defaults( - Aircraft.VerticalTail.ROOT_CHORD, - val=1, - units="m" - ) + self.prob.model.set_input_defaults(Aircraft.VerticalTail.SPAN, val=1, units='m') - self.prob.model.set_input_defaults( - "tip_chord", - val=0.5, - units="m" - ) + self.prob.model.set_input_defaults(Aircraft.VerticalTail.ROOT_CHORD, val=1, units='m') - self.prob.model.set_input_defaults( - "tip_chord_tail", - val=0.5, - units="m" - ) + self.prob.model.set_input_defaults('tip_chord', val=0.5, units='m') - self.prob.model.set_input_defaults( - "thickness_ratio", - val=0.12 - ) + self.prob.model.set_input_defaults('tip_chord_tail', val=0.5, units='m') - self.prob.model.set_input_defaults( - "skin_thickness", - val=0.002, - units="m" - ) + self.prob.model.set_input_defaults('thickness_ratio', val=0.12) - self.prob.model.set_input_defaults( - "twist", - val=jnp.zeros(10), - units="deg" - ) + self.prob.model.set_input_defaults('skin_thickness', val=0.002, units='m') - self.prob.model.set_input_defaults( - "twist_tail", - val=jnp.zeros(10), - units="deg" - ) + self.prob.model.set_input_defaults('twist', val=jnp.zeros(10), units='deg') - self.prob.model.set_input_defaults( - Aircraft.Fuselage.LENGTH, - val=2.5, - units="m") - - self.prob.model.set_input_defaults( - "base_diameter", - val=0.4, - units="m" - ) + self.prob.model.set_input_defaults('twist_tail', val=jnp.zeros(10), units='deg') - self.prob.model.set_input_defaults( - "tip_diameter", - val=0.2 - ) + self.prob.model.set_input_defaults(Aircraft.Fuselage.LENGTH, val=2.5, units='m') - self.prob.model.set_input_defaults( - "curvature", - val=0.0, - units="m" - ) + self.prob.model.set_input_defaults('base_diameter', val=0.4, units='m') - self.prob.model.set_input_defaults( - "y_offset", - val=0.0, - units="m" - ) + self.prob.model.set_input_defaults('tip_diameter', val=0.2) - self.prob.model.set_input_defaults( - "z_offset", - val=0.0, - units="m" - ) + self.prob.model.set_input_defaults('curvature', val=0.0, units='m') - self.prob.model.set_input_defaults( - 'thickness', - val=0.05, - units='m' - ) + self.prob.model.set_input_defaults('y_offset', val=0.0, units='m') - self.prob.model.set_input_defaults( - "is_hollow", - val=True - ) + self.prob.model.set_input_defaults('z_offset', val=0.0, units='m') - n_points = 10 # = num_sections + self.prob.model.set_input_defaults('thickness', val=0.05, units='m') + + self.prob.model.set_input_defaults('is_hollow', val=True) + + n_points = 10 # = num_sections x = jnp.linspace(0, 1, n_points) max_thickness_chord_ratio = 0.12 - thickness_dist = 5 * max_thickness_chord_ratio * (0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) - - self.prob.model.set_input_defaults( - "thickness_dist", - val=thickness_dist, - units="m" + thickness_dist = ( + 5 + * max_thickness_chord_ratio + * (0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) ) - self.prob.setup( - check=False, - force_alloc_complex=True - ) + self.prob.model.set_input_defaults('thickness_dist', val=thickness_dist, units='m') + + self.prob.setup(check=False, force_alloc_complex=True) self.prob.model.tot.tail_mass.options['tail_type'] = 'horizontal' self.prob.run_model() - #om.n2(self.prob) + # om.n2(self.prob) tol = 1e-10 if self.prob.model.tot.tail_mass.options['tail_type'] == 'horizontal': - assert_near_equal( - self.prob['structure_mass'], - 355.18828485, - tol - ) + assert_near_equal(self.prob['structure_mass'], 355.18828485, tol) else: - assert_near_equal( - self.prob['structure_mass'], - 355.18828485, - tol - ) - - partial_data = self.prob.check_partials( - out_stream=None, - method="cs" - ) + assert_near_equal(self.prob['structure_mass'], 355.18828485, tol) - assert_check_partials( - partial_data - ) + partial_data = self.prob.check_partials(out_stream=None, method='cs') + + assert_check_partials(partial_data) class StructureMassTest(unittest.TestCase): @@ -197,58 +102,37 @@ def setUp(self): self.prob = om.Problem() self.prob.model.add_subsystem( - "tot", + 'tot', StructureMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) - self.prob.setup( - check=False, - force_alloc_complex=True - ) + self.prob.setup(check=False, force_alloc_complex=True) - self.prob.set_val(Aircraft.Fuselage.MASS, - val=100.0) - - self.prob.set_val(Aircraft.Wing.MASS, - val=4.2) - - self.prob.set_val(Aircraft.HorizontalTail.MASS, - val=4.25) - - self.prob.set_val(Aircraft.VerticalTail.MASS, - val=4.5) - - def test_case(self): + self.prob.set_val(Aircraft.Fuselage.MASS, val=100.0) + + self.prob.set_val(Aircraft.Wing.MASS, val=4.2) + + self.prob.set_val(Aircraft.HorizontalTail.MASS, val=4.25) + self.prob.set_val(Aircraft.VerticalTail.MASS, val=4.5) + + def test_case(self): self.prob.run_model() tol = 1e-10 self.prob.model.tot.options['tail_type'] = 'horizontal' if self.prob.model.tot.options['tail_type'] == 'horizontal': - assert_near_equal( - self.prob['structure_mass'], - 108.45, - tol - ) + assert_near_equal(self.prob['structure_mass'], 108.45, tol) else: - assert_near_equal( - self.prob['structure_mass'], - 108.45, - tol - ) - - partial_data = self.prob.check_partials( - out_stream=None, - method="cs" - ) + assert_near_equal(self.prob['structure_mass'], 108.45, tol) - assert_check_partials(partial_data) - -if __name__ == "__main__": - unittest.main() + partial_data = self.prob.check_partials(out_stream=None, method='cs') + assert_check_partials(partial_data) +if __name__ == '__main__': + unittest.main() diff --git a/aviary/subsystems/mass/simple_mass/test/test_tail.py b/aviary/subsystems/mass/simple_mass/test/test_tail.py index c2c0d9838..618743ec7 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_tail.py +++ b/aviary/subsystems/mass/simple_mass/test/test_tail.py @@ -1,106 +1,59 @@ import unittest +import numpy as np import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal -import numpy as np - -from aviary.subsystems.mass.simple_mass.tail import TailMassAndCOG +from aviary.subsystems.mass.simple_mass.tail import TailMass from aviary.variable_info.variables import Aircraft -class TailMassTestCase(unittest.TestCase): - """ - Tail mass test case. - """ +class TailMassTestCase(unittest.TestCase): + """Tail mass test case.""" def setUp(self): - self.prob = om.Problem() self.prob.model.add_subsystem( - "Tail", + 'Tail', TailMass(), - promotes_inputs=["*"], - promotes_outputs=["*"], + promotes_inputs=['*'], + promotes_outputs=['*'], ) - self.prob.model.set_input_defaults( - Aircraft.HorizontalTail.SPAN, - val=1, - units="m" - ) + self.prob.model.set_input_defaults(Aircraft.HorizontalTail.SPAN, val=1, units='m') - self.prob.model.set_input_defaults( - Aircraft.HorizontalTail.ROOT_CHORD, - val=1, - units="m" - ) - - self.prob.model.set_input_defaults( - Aircraft.VerticalTail.SPAN, - val=1, - units="m" - ) + self.prob.model.set_input_defaults(Aircraft.HorizontalTail.ROOT_CHORD, val=1, units='m') - self.prob.model.set_input_defaults( - Aircraft.VerticalTail.ROOT_CHORD, - val=1, - units="m" - ) + self.prob.model.set_input_defaults(Aircraft.VerticalTail.SPAN, val=1, units='m') - self.prob.model.set_input_defaults( - "tip_chord_tail", - val=0.5, - units="m" - ) + self.prob.model.set_input_defaults(Aircraft.VerticalTail.ROOT_CHORD, val=1, units='m') - self.prob.model.set_input_defaults( - "thickness_ratio", - val=0.12 - ) + self.prob.model.set_input_defaults('tip_chord_tail', val=0.5, units='m') - self.prob.model.set_input_defaults( - "skin_thickness", - val=0.002, - units="m" - ) + self.prob.model.set_input_defaults('thickness_ratio', val=0.12) - self.prob.model.set_input_defaults( - "twist_tail", - val=np.zeros(10), - units="deg" - ) + self.prob.model.set_input_defaults('skin_thickness', val=0.002, units='m') + + self.prob.model.set_input_defaults('twist_tail', val=np.zeros(10), units='deg') + + self.prob.setup(check=False, force_alloc_complex=True) - self.prob.setup( - check=False, - force_alloc_complex=True) - def test_case(self): self.prob.model.Tail.options['tail_type'] = 'vertical' - + self.prob.run_model() tol = 1e-4 if self.prob.model.Tail.options['tail_type'] == 'horizontal': - assert_near_equal( - self.prob[Aircraft.HorizontalTail.MASS], - 10.6966719, - tol) + assert_near_equal(self.prob[Aircraft.HorizontalTail.MASS], 10.6966719, tol) else: - assert_near_equal( - self.prob[Aircraft.VerticalTail.MASS], - 10.6966719, - tol) - - partial_data = self.prob.check_partials( - out_stream=None, - method="cs") - - assert_check_partials( - partial_data, - atol=1e-15, - rtol=1e-15) - -if __name__ == "__main__": + assert_near_equal(self.prob[Aircraft.VerticalTail.MASS], 10.6966719, tol) + + partial_data = self.prob.check_partials(out_stream=None, method='cs') + + assert_check_partials(partial_data, atol=1e-15, rtol=1e-15) + + +if __name__ == '__main__': unittest.main() diff --git a/aviary/subsystems/mass/simple_mass/test/test_wing.py b/aviary/subsystems/mass/simple_mass/test/test_wing.py index 9845016bb..cbc5c3c74 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_wing.py +++ b/aviary/subsystems/mass/simple_mass/test/test_wing.py @@ -10,7 +10,8 @@ from aviary.subsystems.mass.simple_mass.wing import WingMassAndCOG from aviary.variable_info.variables import Aircraft -#@av.skipIfMissingDependencies(WingMassAndCOG) + +# @av.skipIfMissingDependencies(WingMassAndCOG) class WingMassTestCase(unittest.TestCase): """ Wing mass test case. @@ -18,73 +19,44 @@ class WingMassTestCase(unittest.TestCase): """ def setUp(self): - self.prob = om.Problem() self.prob.model.add_subsystem( - "wing_mass", + 'wing_mass', WingMass(), - promotes_inputs=["*"], + promotes_inputs=['*'], promotes_outputs=['*'], ) - self.prob.model.set_input_defaults( - Aircraft.Wing.SPAN, - val=1, - units="m" - ) + self.prob.model.set_input_defaults(Aircraft.Wing.SPAN, val=1, units='m') - self.prob.model.set_input_defaults( - Aircraft.Wing.ROOT_CHORD, - val=1, - units="m" - ) + self.prob.model.set_input_defaults(Aircraft.Wing.ROOT_CHORD, val=1, units='m') - self.prob.model.set_input_defaults( - "tip_chord", - val=0.5, - units="m" - ) - - self.prob.model.set_input_defaults( - "twist", - val=jnp.zeros(10), - units="deg" - ) + self.prob.model.set_input_defaults('tip_chord', val=0.5, units='m') - + self.prob.model.set_input_defaults('twist', val=jnp.zeros(10), units='deg') - n_points = 10 # = num_sections + n_points = 10 # = num_sections x = jnp.linspace(0, 1, n_points) max_thickness_chord_ratio = 0.12 - thickness_dist = 5 * max_thickness_chord_ratio * (0.2969 * np.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) - - self.prob.model.set_input_defaults( - "thickness_dist", - val=thickness_dist, - units="m" + thickness_dist = ( + 5 + * max_thickness_chord_ratio + * (0.2969 * np.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) ) - self.prob.setup( - check=False, - force_alloc_complex=True - ) + self.prob.model.set_input_defaults('thickness_dist', val=thickness_dist, units='m') - def test_case(self): + self.prob.setup(check=False, force_alloc_complex=True) + def test_case(self): self.prob.run_model() tol = 1e-10 - assert_near_equal(self.prob[Aircraft.Wing.MASS], - 10.6966719, - tol) - - partial_data = self.prob.check_partials( - out_stream=None, - method="cs") - assert_check_partials( - partial_data) - - - -if __name__ == "__main__": + assert_near_equal(self.prob[Aircraft.Wing.MASS], 10.6966719, tol) + + partial_data = self.prob.check_partials(out_stream=None, method='cs') + assert_check_partials(partial_data) + + +if __name__ == '__main__': unittest.main() diff --git a/aviary/subsystems/mass/simple_mass/wing.py b/aviary/subsystems/mass/simple_mass/wing.py index 5a88fe18a..c85c06467 100644 --- a/aviary/subsystems/mass/simple_mass/wing.py +++ b/aviary/subsystems/mass/simple_mass/wing.py @@ -1,13 +1,15 @@ +import os + +import jax.numpy as jnp +import numpy as np import openmdao.api as om import openmdao.jax as omj -import numpy as np -import jax.numpy as jnp -import os from scipy.interpolate import CubicSpline - -from aviary.variable_info.variables import Aircraft +from aviary.subsystems.mass.simple_mass.materials_database import materials from aviary.utils.functions import add_aviary_input, add_aviary_output +from aviary.utils.named_values import get_keys +from aviary.variable_info.variables import Aircraft try: from quadax import quadgk @@ -16,89 +18,85 @@ "quadax package not found. You can install it by running 'pip install quadax'." ) -from aviary.subsystems.mass.simple_mass.materials_database import materials - -from aviary.utils.named_values import get_keys Debug = False + class WingMass(om.JaxExplicitComponent): def initialize(self): - self.options.declare('num_sections', - types=int, - default=10) - - self.options.declare('airfoil_type', - types=str, - default='2412') # use 2412 as example for default - - self.options.declare('material', - default='Balsa', - values=list(get_keys(materials))) - - self.options.declare('airfoil_data_file', - default=None, - types=str) # For user-provided airfoil data file + self.options.declare('num_sections', types=int, default=10) + + self.options.declare( + 'airfoil_type', types=str, default='2412' + ) # use 2412 as example for default + + self.options.declare('material', default='Balsa', values=list(get_keys(materials))) + + self.options.declare( + 'airfoil_data_file', default=None, types=str + ) # For user-provided airfoil data file def setup(self): - self.options['use_jit'] = not(Debug) + self.options['use_jit'] = not (Debug) # Inputs - add_aviary_input(self, - Aircraft.Wing.SPAN, - units='m') # Full wingspan (adjustable) - - add_aviary_input(self, - Aircraft.Wing.ROOT_CHORD, - units='m') # Root chord length - - self.add_input('tip_chord', - val=1.0, - units='m') # Tip chord length -- no aviary input - - self.add_input('twist', - val=jnp.zeros(self.options['num_sections']), - units='deg') # Twist angles -- no aviary input - - self.add_input('thickness_dist', - val=jnp.ones(self.options['num_sections']) * 0.1, - shape=(self.options['num_sections'],), - units='m') # Thickness distribution of the wing (height) -- no aviary input - + add_aviary_input(self, Aircraft.Wing.SPAN, units='m') # Full wingspan (adjustable) + + add_aviary_input(self, Aircraft.Wing.ROOT_CHORD, units='m') # Root chord length + + self.add_input('tip_chord', val=1.0, units='m') # Tip chord length -- no aviary input + + self.add_input( + 'twist', val=jnp.zeros(self.options['num_sections']), units='deg' + ) # Twist angles -- no aviary input + + self.add_input( + 'thickness_dist', + val=jnp.ones(self.options['num_sections']) * 0.1, + shape=(self.options['num_sections'],), + units='m', + ) # Thickness distribution of the wing (height) -- no aviary input # Outputs - add_aviary_output(self, - Aircraft.Wing.MASS, - units='kg') + add_aviary_output(self, Aircraft.Wing.MASS, units='kg') if airfoil_data_file and os.path.exists(airfoil_data_file): airfoil_data = np.loadtxt(airfoil_data_file) x_coords = airfoil_data[:, 0] y_coords = airfoil_data[:, 1] - self.camber, self.camber_location, self.max_thickness, self.thickness, self.camber_line = self.extract_airfoil_features(x_coords, y_coords) + ( + self.camber, + self.camber_location, + self.max_thickness, + self.thickness, + self.camber_line, + ) = self.extract_airfoil_features(x_coords, y_coords) num_sections = len(x_coords) else: # Parse the NACA airfoil type (4-digit) - self.camber = int(airfoil_type[0]) / 100.0 # Maximum camber - self.camber_location = int(airfoil_type[1]) / 10.0 # Location of max camber - self.max_thickness = int(airfoil_type[2:4]) / 100.0 # Max thickness + self.camber = int(airfoil_type[0]) / 100.0 # Maximum camber + self.camber_location = int(airfoil_type[1]) / 10.0 # Location of max camber + self.max_thickness = int(airfoil_type[2:4]) / 100.0 # Max thickness num_sections = self.options['num_sections'] def get_self_statics(self): - return (self.camber, - self.camber_location, - self.max_thickness, - self.thickness, - self.camber_line, - self.options['material']) - + return ( + self.camber, + self.camber_location, + self.max_thickness, + self.thickness, + self.camber_line, + self.options['material'], + ) - def compute_primal(self, aircraft__wing__span, aircraft__wing__root_chord, tip_chord, twist, thickness_dist): - material = self.options['material'] # Material is taken from options - airfoil_type = self.options['airfoil_type'] # NACA airfoil type + def compute_primal( + self, aircraft__wing__span, aircraft__wing__root_chord, tip_chord, twist, thickness_dist + ): + material = self.options['material'] # Material is taken from options + airfoil_type = self.options['airfoil_type'] # NACA airfoil type airfoil_data_file = self.options['airfoil_data_file'] - + # Get material density density = materials.get_val(material, 'kg/m**3') @@ -107,53 +105,84 @@ def compute_primal(self, aircraft__wing__span, aircraft__wing__root_chord, tip_c x_coords = airfoil_data[:, 0] y_coords = airfoil_data[:, 1] - camber, camber_location, max_thickness, thickness, camber_line = self.extract_airfoil_features(x_coords, y_coords) + camber, camber_location, max_thickness, thickness, camber_line = ( + self.extract_airfoil_features(x_coords, y_coords) + ) thickness_dist = thickness num_sections = len(x_coords) else: # Parse the NACA airfoil type (4-digit) - camber = int(airfoil_type[0]) / 100.0 # Maximum camber - camber_location = int(airfoil_type[1]) / 10.0 # Location of max camber - max_thickness = int(airfoil_type[2:4]) / 100.0 # Max thickness + camber = int(airfoil_type[0]) / 100.0 # Maximum camber + camber_location = int(airfoil_type[1]) / 10.0 # Location of max camber + max_thickness = int(airfoil_type[2:4]) / 100.0 # Max thickness num_sections = self.options['num_sections'] - + # Wing spanwise distribution span_locations = jnp.linspace(0, aircraft__wing__span, num_sections) n_points = num_sections x_points = jnp.linspace(0, 1, n_points) dx = 1 / (n_points - 1) - + if airfoil_type: - aircraft__wing__mass_first_part, _ = quadgk(lambda x: density * 2 * jnp.atleast_1d(self.airfoil_thickness(x, max_thickness)) * jnp.sqrt(1 + ( - (camber / camber_location**2) * (2 * camber_location - 2 * x))**2), [0, camber_location], epsabs=1e-9, epsrel=1e-9) - aircraft__wing__mass_second_part, _ = quadgk(lambda x: density * 2 * jnp.atleast_1d(self.airfoil_thickness(x, max_thickness)) * jnp.sqrt(1 + ( - (camber / (1 - camber_location)**2 * (2 * camber_location - 2 * x)))**2), [camber_location, 1], epsabs=1e-9, epsrel=1e-9) + aircraft__wing__mass_first_part, _ = quadgk( + lambda x: density + * 2 + * jnp.atleast_1d(self.airfoil_thickness(x, max_thickness)) + * jnp.sqrt( + 1 + ((camber / camber_location**2) * (2 * camber_location - 2 * x)) ** 2 + ), + [0, camber_location], + epsabs=1e-9, + epsrel=1e-9, + ) + aircraft__wing__mass_second_part, _ = quadgk( + lambda x: density + * 2 + * jnp.atleast_1d(self.airfoil_thickness(x, max_thickness)) + * jnp.sqrt( + 1 + (camber / (1 - camber_location) ** 2 * (2 * camber_location - 2 * x)) ** 2 + ), + [camber_location, 1], + epsabs=1e-9, + epsrel=1e-9, + ) + + aircraft__wing__mass = ( + aircraft__wing__mass_first_part + aircraft__wing__mass_second_part + ) - aircraft__wing__mass = aircraft__wing__mass_first_part + aircraft__wing__mass_second_part - elif airfoil_data_file is not None: - aircraft__wing__mass, _ = quadgk(density * 2 * thickness_dist * jnp.sqrt(1 + jnp.gradient(camber_line)**2), [0, 1], epsabs=1e-9, epsrel=1e-9) - - + aircraft__wing__mass, _ = quadgk( + density * 2 * thickness_dist * jnp.sqrt(1 + jnp.gradient(camber_line) ** 2), + [0, 1], + epsabs=1e-9, + epsrel=1e-9, + ) + return aircraft__wing__mass - + def precompute_airfoil_geometry(self): num_sections = self.options['num_sections'] n_points = num_sections x_points = jnp.linspace(0, 1, n_points) dx = 1 / (n_points - 1) return x_points, dx - + def airfoil_thickness(self, x, max_thickness): - return 5 * max_thickness * (0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) - + return ( + 5 + * max_thickness + * (0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) + ) + def airfoil_camber_line(self, x, camber, camber_location): - camber_location = omj.smooth_max(camber_location, 1e-9) # Divide by zero check + camber_location = omj.smooth_max(camber_location, 1e-9) # Divide by zero check return jnp.where( - x < camber_location, - (camber / camber_location**2) * (2 * camber_location * x - x**2), - (camber / (1 - camber_location)**2) * ((1 - 2 * camber_location) + 2 * camber_location * x - x**2) + x < camber_location, + (camber / camber_location**2) * (2 * camber_location * x - x**2), + (camber / (1 - camber_location) ** 2) + * ((1 - 2 * camber_location) + 2 * camber_location * x - x**2), ) def extract_airfoil_features(self, x_coords, y_coords): @@ -163,10 +192,10 @@ def extract_airfoil_features(self, x_coords, y_coords): """ # Approximate the camber line and max thickness from the data # Assume the camber line is the line of symmetry between the upper and lower surfaces - upper_surface = y_coords[:int(len(x_coords) // 2)] - lower_surface = y_coords[int(len(x_coords) // 2):] - x_upper = x_coords[:int(len(x_coords) // 2)] - x_lower = x_coords[int(len(x_coords) // 2):] + upper_surface = y_coords[: int(len(x_coords) // 2)] + lower_surface = y_coords[int(len(x_coords) // 2) :] + x_upper = x_coords[: int(len(x_coords) // 2)] + x_lower = x_coords[int(len(x_coords) // 2) :] upper_spline = CubicSpline(x_upper, upper_surface, bc_type='natural') lower_spline = CubicSpline(x_lower, lower_surface, bc_type='natural') @@ -185,7 +214,3 @@ def extract_airfoil_features(self, x_coords, y_coords): camber = camber_line[camber_location_index] return camber, camber_location, max_thickness_value, thickness, camber_line - - - - diff --git a/pyproject.toml b/pyproject.toml index 784f6c727..a51b8abdd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,39 +7,36 @@ name = "aviary" dynamic = ["version"] readme = "README.md" license = "Apache-2.0" +requires_python = ">=3.9" dependencies = [ "dymos>=1.14.0", "hvplot", "importlib_resources", + "jax", "matplotlib", "numpy<2", - "openmdao>=3.36.0", + "openmdao>=3.37.0", "pandas", "panel>=1.0.0", "parameterized", "simupy", + "quadax" ] [project.optional-dependencies] -all = [ - "ambiance", - "itables", - "myst-nb", - "openaerostruct", +docs = [ + "jupyter-book", + "itables" +] +dev = [ "pre-commit", - "sphinx_book_theme==1.1.0", "testflo", -] -examples = [ "ambiance", - "itables", "openaerostruct", ] -test = [ - "myst-nb", - "pre-commit", - "sphinx_book_theme==1.1.0", - "testflo", +all = [ + "aviary[docs]", + "aviary[dev]", ] [project.scripts] @@ -65,7 +62,7 @@ quote-style = "single" [tool.ruff.lint] # isort, pydocstyle extend-select = ["I", "D"] -# disabling these rules will help current Aviary code pass a pre-commit lint check +# disabling these rules help current Aviary code pass a lint check extend-ignore = [ "D100", "D101", From 9c5c9a652d1ec3b4c1eebd149ee22b2b2a58d306 Mon Sep 17 00:00:00 2001 From: jkirk5 Date: Fri, 18 Jul 2025 15:10:23 -0400 Subject: [PATCH 142/147] WIP fixes 2 --- .../subsystems/mass/simple_mass/fuselage.py | 12 +- .../mass/simple_mass/mass_builder.py | 10 +- .../mass/simple_mass/mass_premission.py | 6 +- aviary/subsystems/mass/simple_mass/tail.py | 475 ++++++++++-------- .../mass/simple_mass/test/test_tail.py | 57 ++- 5 files changed, 326 insertions(+), 234 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/fuselage.py b/aviary/subsystems/mass/simple_mass/fuselage.py index 4d1191108..474112458 100644 --- a/aviary/subsystems/mass/simple_mass/fuselage.py +++ b/aviary/subsystems/mass/simple_mass/fuselage.py @@ -66,10 +66,12 @@ def compute_primal( ): # Validate inputs if ( - aircraft__fuselage__length[0] <= 0 - or base_diameter[0] <= 0 - or tip_diameter[0] <= 0 - or thickness[0] <= 0 + jnp.select( + condlist=[aircraft__fuselage__length[0] <= 0], choicelist=[True], default=False + ) + or jnp.select(condlist=[base_diameter[0] <= 0], choicelist=[True], default=False) + or jnp.select(condlist=[tip_diameter[0] <= 0], choicelist=[True], default=False) + or jnp.select(condlist=[thickness[0] <= 0], choicelist=[True], default=False) ): raise om.AnalysisError('Length, diameter, and thickness must be positive values.') @@ -112,7 +114,7 @@ def compute_primal( # if self.options['custom_fuselage_function'] is not None: # section_diameter = self.options['custom_fuselage_function'](location) # should be elif below once fixed - if self.options['fuselage_data_file'] and interpolate_diameter is not None: + if self.options['fuselage_data_file'] is not None and interpolate_diameter is not None: section_diameter = interpolate_diameter(location) else: section_diameter = ( diff --git a/aviary/subsystems/mass/simple_mass/mass_builder.py b/aviary/subsystems/mass/simple_mass/mass_builder.py index c0dd1a260..2d3e5834d 100644 --- a/aviary/subsystems/mass/simple_mass/mass_builder.py +++ b/aviary/subsystems/mass/simple_mass/mass_builder.py @@ -1,6 +1,5 @@ from aviary.subsystems.mass.mass_builder import MassBuilderBase -from aviary.subsystems.mass.simple_mass.mass_premission import MassPremission - +from aviary.subsystems.mass.simple_mass.mass_premission import SimpleMassPremission """ Define subsystem builder for Aviary simple mass. @@ -14,10 +13,7 @@ class SimpleMassBuilder(MassBuilderBase): - """ - Base mass builder - - """ + """Base mass builder""" def __init__(self, name=None): if name is None: @@ -26,4 +22,4 @@ def __init__(self, name=None): super().__init__(name=name) def build_pre_mission(self, aviary_inputs): - return MassPremission() + return SimpleMassPremission() diff --git a/aviary/subsystems/mass/simple_mass/mass_premission.py b/aviary/subsystems/mass/simple_mass/mass_premission.py index 72acafdd6..edbd6fc69 100644 --- a/aviary/subsystems/mass/simple_mass/mass_premission.py +++ b/aviary/subsystems/mass/simple_mass/mass_premission.py @@ -1,8 +1,8 @@ import openmdao.api as om -from aviary.subsystems.mass.simple_mass.wing import WingMassAndCOG -from aviary.subsystems.mass.simple_mass.fuselage import FuselageMassAndCOG -from aviary.subsystems.mass.simple_mass.tail import TailMassAndCOG +from aviary.subsystems.mass.simple_mass.fuselage import FuselageMass +from aviary.subsystems.mass.simple_mass.tail import TailMass +from aviary.subsystems.mass.simple_mass.wing import WingMass class SimpleMassPremission(om.Group): diff --git a/aviary/subsystems/mass/simple_mass/tail.py b/aviary/subsystems/mass/simple_mass/tail.py index fad5993ba..8ccbde990 100644 --- a/aviary/subsystems/mass/simple_mass/tail.py +++ b/aviary/subsystems/mass/simple_mass/tail.py @@ -1,5 +1,3 @@ -import os - import jax.numpy as jnp import numpy as np import openmdao.api as om @@ -7,6 +5,7 @@ from scipy.interpolate import CubicSpline from aviary.subsystems.mass.simple_mass.materials_database import materials +from aviary.utils.functions import get_path from aviary.utils.named_values import get_keys from aviary.variable_info.functions import add_aviary_input, add_aviary_output from aviary.variable_info.variables import Aircraft @@ -19,36 +18,26 @@ ) -class TailMass(om.JaxExplicitComponent): +# BUG this component is not currently working - mass is not being properly computed +class HorizontalTailMass(om.JaxExplicitComponent): def initialize(self): self.options.declare( - 'tail_type', - values=['horizontal', 'vertical'], - desc="Type of tail: 'horizontal' or 'vertical'", + 'NACA_digits', + default='2412', + types=(str, int), + desc='4 digit code for NACA airfoil of tail', ) self.options.declare( - 'airfoil_type', - default='NACA', - values=['NACA', 'file'], - desc="Airfoil type: 'NACA' for 4-digit or 'file' for user-provided coordinates", + 'airfoil_file', + default=None, + desc='File path for airfoil coordinates (overrides NACA digits)', ) - if self.options['airfoil_type'] == 'NACA': - self.options.declare( - 'NACA_digits', - default='2412', - desc='4 digit code for NACA airfoil, if that is given.', - ) - self.options.declare( 'material', default='Balsa', values=list(get_keys(materials)), desc='Material type' ) - self.options.declare( - 'airfoil_file', default=None, desc='File path for airfoil coordinates (if applicable)' - ) - self.options.declare('num_sections', default=10, desc='Number of sections for enumeration') self.camber = 0 @@ -59,63 +48,196 @@ def initialize(self): def setup(self): # Inputs - add_aviary_input(self, Aircraft.HorizontalTail.SPAN, units='m', desc='Tail span') + # TODO unused?!? + # add_aviary_input(self, Aircraft.HorizontalTail.SPAN, units='m', desc='Tail span') + # add_aviary_input( + # self, Aircraft.HorizontalTail.ROOT_CHORD, units='m', desc='Root chord length' + # ) - add_aviary_input( - self, Aircraft.HorizontalTail.ROOT_CHORD, units='m', desc='Root chord length' + # self.add_input('tip_chord_tail', val=0.8, units='m', desc='Tip chord length') + self.add_input( + 'thickness_ratio', val=0.12, desc='Max thickness to chord ratio for NACA airfoil' ) - # else: - add_aviary_input(self, Aircraft.VerticalTail.SPAN, units='m', desc='Tail span') + # self.add_input('skin_thickness', val=0.002, units='m', desc='Skin panel thickness') + # self.add_input( + # 'twist_tail', + # val=jnp.zeros(self.options['num_sections']), + # units='deg', + # desc='Twist distribution', + # ) - add_aviary_input( - self, Aircraft.VerticalTail.ROOT_CHORD, units='m', desc='Root chord length' + # Outputs + add_aviary_output( + self, Aircraft.HorizontalTail.MASS, units='kg', desc='Total mass of the tail' ) - # The inputs below have no aviary input, so there is no distinction for now + # File check + airfoil_file = self.options['airfoil_file'] + if airfoil_file is not None: + airfoil_file = get_path(airfoil_file) + # try: + airfoil_data = np.loadtxt(airfoil_file, skiprows=1) # Assume a header + # except Exception as e: + # raise ValueError(f'Error reading airfoil file: {e}') + x_coords, y_coords = airfoil_data[:, 0], airfoil_data[:, 1] + + ( + self.camber, + self.camber_location, + self.max_thickness, + self.camber_line, + self.thickness, + ) = extract_airfoil_features(x_coords, y_coords) - self.add_input('tip_chord_tail', val=0.8, units='m', desc='Tip chord length') + else: + NACA_digits = str(self.options['NACA_digits']) + # Parse the NACA airfoil type (4-digit) + self.camber = int(NACA_digits[0]) / 100.0 # Maximum camber + self.camber_location = int(NACA_digits[1]) / 10.0 # Location of max camber + self.max_thickness = int(NACA_digits[2:4]) / 100.0 # Max thickness - self.add_input( - 'thickness_ratio', val=0.12, desc='Max thickness to chord ratio for NACA airfoil' + def get_self_statics(self): + return ( + self.camber, + self.camber_location, + self.max_thickness, + self.camber_line, + self.thickness, + self.options['material'], + self.options['num_sections'], + self.options['NACA_digits'], ) - self.add_input('skin_thickness', val=0.002, units='m', desc='Skin panel thickness') + def compute_primal( + self, + # aircraft__horizontal_tail__span, + # aircraft__horizontal_tail__root_chord, + # aircraft__vertical_tail__span, + # aircraft__vertical_tail__root_chord, + # tip_chord_tail, + thickness_ratio, + # skin_thickness, + # twist_tail, + ): + material = self.options['material'] + density = materials.get_val(material, 'kg/m**3') + airfoil_file = self.options['airfoil_file'] + # num_sections = self.options['num_sections'] + camber = self.camber + camber_location = self.camber_location + max_thickness = self.max_thickness + camber_line = self.camber_line + thickness = self.thickness + + # This is just so that the differentiation and unittest do not break. + aircraft__horizontal_tail__mass = 0.0 * thickness_ratio + + # TODO unused?? + # span_locations = jnp.linspace(0, aircraft__horizontal_tail__span, num_sections) + # Get x_points and dx for later + # x_points, dx = precompute_airfoil_geometry() + + # Thickness distribution + # thickness_dist = airfoil_thickness(x_points, max_thickness) + + if airfoil_file is not None: + aircraft__horizontal_tail__mass, _ = quadgk( + density * 2 * thickness * jnp.sqrt(1 + jnp.gradient(camber_line) ** 2), + [0, 1], + epsabs=1e-9, + epsrel=1e-9, + ) + else: + total_mass_first_part, _ = quadgk( + lambda x: density + * 2 + * jnp.atleast_1d(airfoil_thickness(x, max_thickness)) + * jnp.sqrt( + 1 + ((camber / camber_location**2) * (2 * camber_location - 2 * x)) ** 2 + ), + [0, camber_location], + epsabs=1e-9, + epsrel=1e-9, + ) + total_mass_second_part, _ = quadgk( + lambda x: density + * 2 + * jnp.atleast_1d(airfoil_thickness(x, max_thickness)) + * jnp.sqrt( + 1 + (camber / (1 - camber_location) ** 2 * (2 * camber_location - 2 * x)) ** 2 + ), + [camber_location, 1], + epsabs=1e-9, + epsrel=1e-9, + ) + + aircraft__horizontal_tail__mass = total_mass_first_part + total_mass_second_part + + return aircraft__horizontal_tail__mass + + +class VerticalTailMass(om.JaxExplicitComponent): + def initialize(self): + self.options.declare( + 'NACA_digits', + default='2412', + types=(str, int), + desc='4 digit code for NACA airfoil of tail', + ) + + self.options.declare( + 'airfoil_file', + default=None, + desc='File path for airfoil coordinates (overrides NACA digits)', + ) + + self.options.declare( + 'material', default='Balsa', values=list(get_keys(materials)), desc='Material type' + ) + + self.options.declare('num_sections', default=10, desc='Number of sections for enumeration') + + self.camber = 0 + self.camber_location = 0 + self.max_thickness = 0 + self.camber_line = 0 + self.thickness = 0 + + def setup(self): + # Inputs + # TODO unused?!? + # add_aviary_input(self, Aircraft.VerticalTail.SPAN, units='m', desc='Tail span') + # add_aviary_input( + # self, Aircraft.VerticalTail.ROOT_CHORD, units='m', desc='Root chord length' + # ) + + # self.add_input('tip_chord_tail', val=0.8, units='m', desc='Tip chord length') self.add_input( - 'twist_tail', - val=jnp.zeros(self.options['num_sections']), - units='deg', - desc='Twist distribution', + 'thickness_ratio', val=0.12, desc='Max thickness to chord ratio for NACA airfoil' ) + # self.add_input('skin_thickness', val=0.002, units='m', desc='Skin panel thickness') + # self.add_input( + # 'twist_tail', + # val=jnp.zeros(self.options['num_sections']), + # units='deg', + # desc='Twist distribution', + # ) # Outputs - add_aviary_output( - self, Aircraft.HorizontalTail.MASS, units='kg', desc='Total mass of the tail' - ) - # else: add_aviary_output( self, Aircraft.VerticalTail.MASS, units='kg', desc='Total mass of the tail' ) # File check airfoil_file = self.options['airfoil_file'] - airfoil_type = self.options['airfoil_type'] - if airfoil_type == 'file': - if airfoil_type == 'file' and ( - airfoil_file is None or not os.path.isfile(airfoil_file) - ): - raise FileNotFoundError(f"Airfoil file '{airfoil_file}' not found or not provided.") - try: - airfoil_data = np.loadtxt(airfoil_file, skiprows=1) # Assume a header - x_coords, y_coords = airfoil_data[:, 0], airfoil_data[:, 1] - except Exception as e: - raise ValueError(f'Error reading airfoil file: {e}') - - # Compute section airfoil geometry - if airfoil_file and os.path.exists(airfoil_file): - airfoil_data = np.loadtxt(airfoil_file) - x_coords = airfoil_data[:, 0] - y_coords = airfoil_data[:, 1] + if airfoil_file is not None: + airfoil_file = get_path(airfoil_file) + # try: + airfoil_data = np.loadtxt(airfoil_file, skiprows=1) # Assume a header + # except Exception as e: + # raise ValueError(f'Error reading airfoil file: {e}') + x_coords, y_coords = airfoil_data[:, 0], airfoil_data[:, 1] ( self.camber, @@ -123,10 +245,10 @@ def setup(self): self.max_thickness, self.camber_line, self.thickness, - ) = self.extract_airfoil_features(x_coords, y_coords) + ) = extract_airfoil_features(x_coords, y_coords) - elif airfoil_type == 'NACA': - NACA_digits = self.options['NACA_digits'] + else: + NACA_digits = str(self.options['NACA_digits']) # Parse the NACA airfoil type (4-digit) self.camber = int(NACA_digits[0]) / 100.0 # Maximum camber self.camber_location = int(NACA_digits[1]) / 10.0 # Location of max camber @@ -139,7 +261,6 @@ def get_self_statics(self): self.max_thickness, self.camber_line, self.thickness, - self.options['tail_type'], self.options['material'], self.options['num_sections'], self.options['NACA_digits'], @@ -147,164 +268,124 @@ def get_self_statics(self): def compute_primal( self, - aircraft__horizontal_tail__span, - aircraft__horizontal_tail__root_chord, - aircraft__vertical_tail__span, - aircraft__vertical_tail__root_chord, - tip_chord_tail, + # aircraft__vertical_tail__span, + # aircraft__vertical_tail__root_chord, + # aircraft__vertical_tail__span, + # aircraft__vertical_tail__root_chord, + # tip_chord_tail, thickness_ratio, - skin_thickness, - twist_tail, + # skin_thickness, + # twist_tail, ): - tail_type = self.options['tail_type'] - airfoil_type = self.options['airfoil_type'] material = self.options['material'] density = materials.get_val(material, 'kg/m**3') airfoil_file = self.options['airfoil_file'] - num_sections = self.options['num_sections'] - if airfoil_type == 'NACA': - NACA_digits = self.options['NACA_digits'] + # num_sections = self.options['num_sections'] camber = self.camber camber_location = self.camber_location max_thickness = self.max_thickness camber_line = self.camber_line thickness = self.thickness - # This is just so that the differentiation and unittest do not break. If tail_type = horizontal, ignore the vertical tail mass and vice versa. - # TODO: Potentially write these tails as separate files. - aircraft__horizontal_tail__mass = 0.0 * thickness_ratio + # This is just so that the differentiation and unittest do not break. aircraft__vertical_tail__mass = 0.0 * thickness_ratio - if tail_type == 'horizontal': - span_locations = jnp.linspace(0, aircraft__horizontal_tail__span, num_sections) - elif tail_type == 'vertical': - span_locations = jnp.linspace(0, aircraft__vertical_tail__span, num_sections) + # TODO unused?? + # span_locations = jnp.linspace(0, aircraft__vertical_tail__span, num_sections) # Get x_points and dx for later - x_points, dx = self.precompute_airfoil_geometry() + # x_points, dx = precompute_airfoil_geometry() # Thickness distribution - thickness_dist = self.airfoil_thickness(x_points, max_thickness) - - if tail_type == 'horizontal': - if airfoil_type: - total_mass_first_part, _ = quadgk( - lambda x: density - * 2 - * jnp.atleast_1d(self.airfoil_thickness(x, max_thickness)) - * jnp.sqrt( - 1 + ((camber / camber_location**2) * (2 * camber_location - 2 * x)) ** 2 - ), - [0, camber_location], - epsabs=1e-9, - epsrel=1e-9, - ) - total_mass_second_part, _ = quadgk( - lambda x: density - * 2 - * jnp.atleast_1d(self.airfoil_thickness(x, max_thickness)) - * jnp.sqrt( - 1 - + (camber / (1 - camber_location) ** 2 * (2 * camber_location - 2 * x)) ** 2 - ), - [camber_location, 1], - epsabs=1e-9, - epsrel=1e-9, - ) - - aircraft__horizontal_tail__mass = total_mass_first_part + total_mass_second_part - elif airfoil_file is not None: - aircraft__horizontal_tail__mass, _ = quadgk( - density * 2 * thickness * jnp.sqrt(1 + jnp.gradient(camber_line) ** 2), - [0, 1], - epsabs=1e-9, - epsrel=1e-9, - ) - elif tail_type == 'vertical': - if airfoil_type: - total_mass_first_part, _ = quadgk( - lambda x: density - * 2 - * jnp.atleast_1d(self.airfoil_thickness(x, max_thickness)) - * jnp.sqrt( - 1 + ((camber / camber_location**2) * (2 * camber_location - 2 * x)) ** 2 - ), - [0, camber_location], - epsabs=1e-9, - epsrel=1e-9, - ) - total_mass_second_part, _ = quadgk( - lambda x: density - * 2 - * jnp.atleast_1d(self.airfoil_thickness(x, max_thickness)) - * jnp.sqrt( - 1 - + (camber / (1 - camber_location) ** 2 * (2 * camber_location - 2 * x)) ** 2 - ), - [camber_location, 1], - epsabs=1e-9, - epsrel=1e-9, - ) - - aircraft__vertical_tail__mass = total_mass_first_part + total_mass_second_part - elif airfoil_file is not None: - aircraft__vertical_tail__mass, _ = quadgk( - density * 2 * thickness * jnp.sqrt(1 + jnp.gradient(camber_line) ** 2), - [0, 1], - epsabs=1e-9, - epsrel=1e-9, - ) - - return aircraft__horizontal_tail__mass, aircraft__vertical_tail__mass - - def precompute_airfoil_geometry(self): - n_points = self.options['num_sections'] - x_points = jnp.linspace(0, 1, n_points) - dx = 1 / (n_points - 1) - return x_points, dx - - def airfoil_thickness(self, x, max_thickness): - return ( - 5 - * max_thickness - * (0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) - ) + # thickness_dist = airfoil_thickness(x_points, max_thickness) + + if airfoil_file is not None: + aircraft__vertical_tail__mass, _ = quadgk( + density * 2 * thickness * jnp.sqrt(1 + jnp.gradient(camber_line) ** 2), + [0, 1], + epsabs=1e-9, + epsrel=1e-9, + ) + else: + total_mass_first_part, _ = quadgk( + lambda x: density + * 2 + * jnp.atleast_1d(airfoil_thickness(x, max_thickness)) + * jnp.sqrt( + 1 + ((camber / camber_location**2) * (2 * camber_location - 2 * x)) ** 2 + ), + [0, camber_location], + epsabs=1e-9, + epsrel=1e-9, + ) + total_mass_second_part, _ = quadgk( + lambda x: density + * 2 + * jnp.atleast_1d(airfoil_thickness(x, max_thickness)) + * jnp.sqrt( + 1 + (camber / (1 - camber_location) ** 2 * (2 * camber_location - 2 * x)) ** 2 + ), + [camber_location, 1], + epsabs=1e-9, + epsrel=1e-9, + ) + + aircraft__vertical_tail__mass = total_mass_first_part + total_mass_second_part + + return aircraft__vertical_tail__mass + + +# def precompute_airfoil_geometry(self): +# n_points = self.options['num_sections'] +# x_points = jnp.linspace(0, 1, n_points) +# dx = 1 / (n_points - 1) +# return x_points, dx + + +def airfoil_thickness(x, max_thickness): + return ( + 5 + * max_thickness + * (0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) + ) + + +# def airfoil_camber_line(self, x, camber, camber_location): +# camber_location = omj.ks_max(camber_location, 1e-9) # Divide by zero check +# return jnp.where( +# x < camber_location, +# (camber / camber_location**2) * (2 * camber_location * x - x**2), +# (camber / (1 - camber_location) ** 2) +# * ((1 - 2 * camber_location) + 2 * camber_location * x - x**2), +# ) - def airfoil_camber_line(self, x, camber, camber_location): - camber_location = omj.ks_max(camber_location, 1e-9) # Divide by zero check - return jnp.where( - x < camber_location, - (camber / camber_location**2) * (2 * camber_location * x - x**2), - (camber / (1 - camber_location) ** 2) - * ((1 - 2 * camber_location) + 2 * camber_location * x - x**2), - ) - def extract_airfoil_features(self, x_coords, y_coords): - """ - Extract camber, camber location, and max thickness from the given airfoil data. - This method assumes x_coords are normalized (ranging from 0 to 1). - """ - # Approximate the camber line and max thickness from the data - # Assume the camber line is the line of symmetry between the upper and lower surfaces - upper_surface = y_coords[: int(len(x_coords) // 2)] - lower_surface = y_coords[int(len(x_coords) // 2) :] - x_upper = x_coords[: int(len(x_coords) // 2)] - x_lower = x_coords[int(len(x_coords) // 2) :] +def extract_airfoil_features(x_coords, y_coords): + """ + Extract camber, camber location, and max thickness from the given airfoil data. + This method assumes x_coords are normalized (ranging from 0 to 1). + """ + # Approximate the camber line and max thickness from the data + # Assume the camber line is the line of symmetry between the upper and lower surfaces + upper_surface = y_coords[: int(len(x_coords) // 2)] + lower_surface = y_coords[int(len(x_coords) // 2) :] + x_upper = x_coords[: int(len(x_coords) // 2)] + x_lower = x_coords[int(len(x_coords) // 2) :] - upper_spline = CubicSpline(x_upper, upper_surface, bc_type='natural') - lower_spline = CubicSpline(x_lower, lower_surface, bc_type='natural') + upper_spline = CubicSpline(x_upper, upper_surface, bc_type='natural') + lower_spline = CubicSpline(x_lower, lower_surface, bc_type='natural') - camber_line = (upper_spline(x_coords) + lower_spline(x_coords)) / 2.0 + camber_line = (upper_spline(x_coords) + lower_spline(x_coords)) / 2.0 - thickness = upper_spline(x_coords) - lower_spline(x_coords) + thickness = upper_spline(x_coords) - lower_spline(x_coords) - max_thickness_index = omj.ks_max(thickness) - max_thickness_value = thickness[max_thickness_index] + max_thickness_index = omj.ks_max(thickness) + max_thickness_value = thickness[max_thickness_index] - camber_slope = jnp.gradient(camber_line, x_coords) - camber_location_index = omj.ks_max(omj.smooth_abs(camber_slope)) - camber_location = x_coords[camber_location_index] + camber_slope = jnp.gradient(camber_line, x_coords) + camber_location_index = omj.ks_max(omj.smooth_abs(camber_slope)) + camber_location = x_coords[camber_location_index] - camber = camber_line[camber_location_index] + camber = camber_line[camber_location_index] - return camber, camber_location, max_thickness_value, camber_line, thickness + return camber, camber_location, max_thickness_value, camber_line, thickness diff --git a/aviary/subsystems/mass/simple_mass/test/test_tail.py b/aviary/subsystems/mass/simple_mass/test/test_tail.py index 618743ec7..c76da8e42 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_tail.py +++ b/aviary/subsystems/mass/simple_mass/test/test_tail.py @@ -4,53 +4,66 @@ import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal -from aviary.subsystems.mass.simple_mass.tail import TailMass +from aviary.subsystems.mass.simple_mass.tail import HorizontalTailMass, VerticalTailMass from aviary.variable_info.variables import Aircraft class TailMassTestCase(unittest.TestCase): """Tail mass test case.""" - def setUp(self): - self.prob = om.Problem() - self.prob.model.add_subsystem( + def test_horizontal_tail(self): + prob = om.Problem() + prob.model.add_subsystem( 'Tail', - TailMass(), + HorizontalTailMass(), promotes_inputs=['*'], promotes_outputs=['*'], ) - self.prob.model.set_input_defaults(Aircraft.HorizontalTail.SPAN, val=1, units='m') + # self.prob.model.set_input_defaults(Aircraft.HorizontalTail.SPAN, val=1, units='m') + # self.prob.model.set_input_defaults(Aircraft.HorizontalTail.ROOT_CHORD, val=1, units='m') + # self.prob.model.set_input_defaults('tip_chord_tail', val=0.5, units='m') + prob.model.set_input_defaults('thickness_ratio', val=0.12) + # self.prob.model.set_input_defaults('skin_thickness', val=0.002, units='m') + # self.prob.model.set_input_defaults('twist_tail', val=np.zeros(10), units='deg') - self.prob.model.set_input_defaults(Aircraft.HorizontalTail.ROOT_CHORD, val=1, units='m') + prob.setup(check=False, force_alloc_complex=True) - self.prob.model.set_input_defaults(Aircraft.VerticalTail.SPAN, val=1, units='m') + prob.run_model() - self.prob.model.set_input_defaults(Aircraft.VerticalTail.ROOT_CHORD, val=1, units='m') + tol = 1e-4 - self.prob.model.set_input_defaults('tip_chord_tail', val=0.5, units='m') + assert_near_equal(prob[Aircraft.HorizontalTail.MASS], 10.6966719, tol) - self.prob.model.set_input_defaults('thickness_ratio', val=0.12) + partial_data = prob.check_partials(out_stream=None, method='cs') - self.prob.model.set_input_defaults('skin_thickness', val=0.002, units='m') + assert_check_partials(partial_data, atol=1e-15, rtol=1e-15) - self.prob.model.set_input_defaults('twist_tail', val=np.zeros(10), units='deg') + def test_vertical_tail(self): + prob = om.Problem() + prob.model.add_subsystem( + 'Tail', + VerticalTailMass(), + promotes_inputs=['*'], + promotes_outputs=['*'], + ) - self.prob.setup(check=False, force_alloc_complex=True) + # self.prob.model.set_input_defaults(Aircraft.VerticalTail.SPAN, val=1, units='m') + # self.prob.model.set_input_defaults(Aircraft.VerticalTail.ROOT_CHORD, val=1, units='m') + # self.prob.model.set_input_defaults('tip_chord_tail', val=0.5, units='m') + prob.model.set_input_defaults('thickness_ratio', val=0.12) + # self.prob.model.set_input_defaults('skin_thickness', val=0.002, units='m') + # self.prob.model.set_input_defaults('twist_tail', val=np.zeros(10), units='deg') - def test_case(self): - self.prob.model.Tail.options['tail_type'] = 'vertical' + prob.setup(check=False, force_alloc_complex=True) - self.prob.run_model() + prob.run_model() tol = 1e-4 - if self.prob.model.Tail.options['tail_type'] == 'horizontal': - assert_near_equal(self.prob[Aircraft.HorizontalTail.MASS], 10.6966719, tol) - else: - assert_near_equal(self.prob[Aircraft.VerticalTail.MASS], 10.6966719, tol) + assert_near_equal(prob[Aircraft.VerticalTail.MASS], 10.6966719, tol) - partial_data = self.prob.check_partials(out_stream=None, method='cs') + partial_data = prob.check_partials(out_stream=None, method='cs') assert_check_partials(partial_data, atol=1e-15, rtol=1e-15) From e0d6530fc2ad9a8e54e52ac78f523663c0110f34 Mon Sep 17 00:00:00 2001 From: jkirk5 Date: Fri, 18 Jul 2025 16:03:57 -0400 Subject: [PATCH 143/147] more bulk fixes --- .../subsystems/mass/simple_mass/fuselage.py | 69 +++++++++++---- .../mass/simple_mass/mass_builder.py | 2 +- .../mass/simple_mass/mass_premission.py | 11 ++- .../mass/simple_mass/mass_summation.py | 60 +++---------- .../mass/simple_mass/materials_database.py | 1 - aviary/subsystems/mass/simple_mass/tail.py | 2 +- .../mass/simple_mass/test/test_fuselage.py | 2 - .../simple_mass/test/test_mass_summation.py | 87 +++---------------- .../mass/simple_mass/test/test_tail.py | 1 - .../mass/simple_mass/test/test_wing.py | 12 +-- aviary/subsystems/mass/simple_mass/wing.py | 10 +-- 11 files changed, 94 insertions(+), 163 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/fuselage.py b/aviary/subsystems/mass/simple_mass/fuselage.py index 474112458..3abb31ca0 100644 --- a/aviary/subsystems/mass/simple_mass/fuselage.py +++ b/aviary/subsystems/mass/simple_mass/fuselage.py @@ -1,5 +1,6 @@ from pathlib import Path +import jax import jax.numpy as jnp import jax.scipy.interpolate as jinterp import numpy as np @@ -26,6 +27,12 @@ def initialize(self): desc='optional data file of fuselage geometry', ) + self.options.declare( + 'hollow_fuselage', + default=True, + desc='flag for if the fuselage should be hollow (wall thickness is not used if False)', + ) + # TODO FunctionType is not defined? # self.options.declare( # 'custom_fuselage_function', @@ -46,9 +53,6 @@ def setup(self): # Allow for asymmetry in the y and z axes -- this value acts as a slope for linear variation along these axes self.add_input('y_offset', val=0.0, units='m') self.add_input('z_offset', val=0.0, units='m') - self.add_input( - 'is_hollow', val=True, units=None - ) # Whether the fuselage is hollow or not (default is hollow) # Outputs add_aviary_output(self, Aircraft.Fuselage.MASS, units='kg') @@ -62,21 +66,12 @@ def compute_primal( thickness, y_offset, z_offset, - is_hollow, ): - # Validate inputs - if ( - jnp.select( - condlist=[aircraft__fuselage__length[0] <= 0], choicelist=[True], default=False - ) - or jnp.select(condlist=[base_diameter[0] <= 0], choicelist=[True], default=False) - or jnp.select(condlist=[tip_diameter[0] <= 0], choicelist=[True], default=False) - or jnp.select(condlist=[thickness[0] <= 0], choicelist=[True], default=False) - ): - raise om.AnalysisError('Length, diameter, and thickness must be positive values.') + is_hollow = self.options['hollow_fuselage'] - if is_hollow and thickness >= base_diameter / 2: - raise om.AnalysisError('Wall thickness is too large for a hollow fuselage.') + self.validate_inputs( + aircraft__fuselage__length, base_diameter, tip_diameter, thickness, is_hollow + ) custom_fuselage_data_file = self.options['fuselage_data_file'] material = self.options['material'] @@ -145,3 +140,45 @@ def compute_primal( total_moment_z += centroid_z * section_weight return aircraft__fuselage__mass + + def validate_inputs(self, length, base_diameter, tip_diameter, thickness, is_hollow): + jax.lax.cond( + length[0] <= 0, + lambda: jax.debug.callback( + raise_error, om.AnalysisError('Length must be a positive value.') + ), + lambda: None, + ) + jax.lax.cond( + base_diameter[0] <= 0, + lambda: jax.debug.callback( + raise_error, om.AnalysisError('Base Diameter must be a positive value.') + ), + lambda: None, + ) + jax.lax.cond( + tip_diameter[0] <= 0, + lambda: jax.debug.callback( + raise_error, om.AnalysisError('Tip Diameter must be a positive value.') + ), + lambda: None, + ) + jax.lax.cond( + thickness[0] <= 0, + lambda: jax.debug.callback( + raise_error, om.AnalysisError('Thickness must be a positive value.') + ), + lambda: None, + ) + + jax.lax.cond( + is_hollow and thickness[0] >= base_diameter[0] / 2, + lambda: jax.debug.callback( + raise_error, om.AnalysisError('Wall thickness is too large for a hollow fuselage.') + ), + lambda: None, + ) + + +def raise_error(exception): + raise exception diff --git a/aviary/subsystems/mass/simple_mass/mass_builder.py b/aviary/subsystems/mass/simple_mass/mass_builder.py index 2d3e5834d..c51209823 100644 --- a/aviary/subsystems/mass/simple_mass/mass_builder.py +++ b/aviary/subsystems/mass/simple_mass/mass_builder.py @@ -13,7 +13,7 @@ class SimpleMassBuilder(MassBuilderBase): - """Base mass builder""" + """Base mass builder.""" def __init__(self, name=None): if name is None: diff --git a/aviary/subsystems/mass/simple_mass/mass_premission.py b/aviary/subsystems/mass/simple_mass/mass_premission.py index edbd6fc69..fe4285d31 100644 --- a/aviary/subsystems/mass/simple_mass/mass_premission.py +++ b/aviary/subsystems/mass/simple_mass/mass_premission.py @@ -1,7 +1,8 @@ import openmdao.api as om from aviary.subsystems.mass.simple_mass.fuselage import FuselageMass -from aviary.subsystems.mass.simple_mass.tail import TailMass +from aviary.subsystems.mass.simple_mass.mass_summation import SimpleMassSummation +from aviary.subsystems.mass.simple_mass.tail import HorizontalTailMass, VerticalTailMass from aviary.subsystems.mass.simple_mass.wing import WingMass @@ -19,5 +20,11 @@ def setup(self): ) self.add_subsystem( - 'Tail', TailMass(tail_type='horizontal'), promotes_inputs=['*'], promotes_outputs=['*'] + 'HorizontalTail', HorizontalTailMass(), promotes_inputs=['*'], promotes_outputs=['*'] ) + + self.add_subsystem( + 'VerticalTail', VerticalTailMass(), promotes_inputs=['*'], promotes_outputs=['*'] + ) + + self.add_subsystem('mass_summation', SimpleMassSummation(), promotes=['*']) diff --git a/aviary/subsystems/mass/simple_mass/mass_summation.py b/aviary/subsystems/mass/simple_mass/mass_summation.py index 44d86290d..ada5f98de 100644 --- a/aviary/subsystems/mass/simple_mass/mass_summation.py +++ b/aviary/subsystems/mass/simple_mass/mass_summation.py @@ -1,8 +1,5 @@ import openmdao.api as om -from aviary.subsystems.mass.simple_mass.fuselage import FuselageMass -from aviary.subsystems.mass.simple_mass.tail import TailMass -from aviary.subsystems.mass.simple_mass.wing import WingMass from aviary.variable_info.functions import add_aviary_input from aviary.variable_info.variables import Aircraft @@ -17,38 +14,12 @@ class SimpleMassSummation(om.Group): """ def setup(self): - self.add_subsystem( - 'fuse_mass', - FuselageMass(), - promotes_inputs=['*'], - promotes_outputs=[Aircraft.Fuselage.MASS], - ) - - self.add_subsystem( - 'wing_mass', WingMass(), promotes_inputs=['*'], promotes_outputs=[Aircraft.Wing.MASS] - ) - - self.add_subsystem( - 'tail_mass', - TailMass(), - promotes_inputs=['*'], - promotes_outputs=[Aircraft.HorizontalTail.MASS], - ) - self.add_subsystem( 'structure_mass', StructureMass(), promotes_inputs=['*'], promotes_outputs=['*'] ) -class StructureMass(om.JaxExplicitComponent): - def initialize(self): - self.options.declare( - 'tail_type', - default='horizontal', - values=['horizontal', 'vertical'], - desc='Tail type used for the tail mass from tail.py file', - ) - +class StructureMass(om.ExplicitComponent): def setup(self): add_aviary_input(self, Aircraft.Wing.MASS, val=0.0, units='kg') add_aviary_input(self, Aircraft.Fuselage.MASS, val=0.0, units='kg') @@ -57,24 +28,17 @@ def setup(self): # More masses can be added, i.e., tail, spars, flaps, etc. as needed - self.add_output('structure_mass', val=0.0, units='kg') + self.add_output(Aircraft.Design.STRUCTURE_MASS, val=0.0, units='kg') + + def setup_partials(self): + self.declare_partials(Aircraft.Design.STRUCTURE_MASS, '*', val=1) - def compute_primal( - self, - aircraft__wing__mass, - aircraft__fuselage__mass, - aircraft__horizontal_tail__mass, - aircraft__vertical_tail__mass, - ): - tail_type = self.options['tail_type'] + def compute(self, inputs, outputs): + wing_mass = inputs[Aircraft.Wing.MASS] + fuselage_mass = inputs[Aircraft.Fuselage.MASS] + htail_mass = inputs[Aircraft.HorizontalTail.MASS] + vtail_mass = inputs[Aircraft.VerticalTail.MASS] - if tail_type == 'horizontal': - structure_mass = ( - aircraft__wing__mass + aircraft__fuselage__mass + aircraft__horizontal_tail__mass - ) - else: - structure_mass = ( - aircraft__wing__mass + aircraft__fuselage__mass + aircraft__vertical_tail__mass - ) + structure_mass = wing_mass + fuselage_mass + htail_mass + vtail_mass - return structure_mass + outputs[Aircraft.Design.STRUCTURE_MASS] = structure_mass diff --git a/aviary/subsystems/mass/simple_mass/materials_database.py b/aviary/subsystems/mass/simple_mass/materials_database.py index d61249593..c63247f29 100644 --- a/aviary/subsystems/mass/simple_mass/materials_database.py +++ b/aviary/subsystems/mass/simple_mass/materials_database.py @@ -6,7 +6,6 @@ """ from aviary.utils.named_values import NamedValues -from aviary.utils.named_values import get_keys, get_values, get_items materials = NamedValues() diff --git a/aviary/subsystems/mass/simple_mass/tail.py b/aviary/subsystems/mass/simple_mass/tail.py index 8ccbde990..076e4de0e 100644 --- a/aviary/subsystems/mass/simple_mass/tail.py +++ b/aviary/subsystems/mass/simple_mass/tail.py @@ -7,7 +7,7 @@ from aviary.subsystems.mass.simple_mass.materials_database import materials from aviary.utils.functions import get_path from aviary.utils.named_values import get_keys -from aviary.variable_info.functions import add_aviary_input, add_aviary_output +from aviary.variable_info.functions import add_aviary_output from aviary.variable_info.variables import Aircraft try: diff --git a/aviary/subsystems/mass/simple_mass/test/test_fuselage.py b/aviary/subsystems/mass/simple_mass/test/test_fuselage.py index bcfecd803..270c1cc0f 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_fuselage.py +++ b/aviary/subsystems/mass/simple_mass/test/test_fuselage.py @@ -31,8 +31,6 @@ def setUp(self): self.prob.model.set_input_defaults('z_offset', val=0.0, units='m') - self.prob.model.set_input_defaults('is_hollow', val=True) - self.prob.setup(check=False, force_alloc_complex=True) def test_case(self): diff --git a/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py b/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py index 9b7a9a371..b5245e0cb 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py +++ b/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py @@ -1,80 +1,26 @@ import unittest -import numpy as np -import jax.numpy as jnp import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal -from aviary.subsystems.mass.simple_mass.mass_summation import MassSummation, StructureMass +from aviary.subsystems.mass.simple_mass.mass_summation import SimpleMassSummation, StructureMass from aviary.variable_info.variables import Aircraft -# Horizontal Tail Only class MassSummationTest(unittest.TestCase): - """ - Total mass summation test case. - - """ + """Total mass summation test case.""" def test_case(self): self.prob = om.Problem() self.prob.model.add_subsystem('tot', SimpleMassSummation(), promotes=['*']) - self.prob.model.set_input_defaults(Aircraft.Wing.SPAN, val=1.0, units='m') - - self.prob.model.set_input_defaults(Aircraft.Wing.ROOT_CHORD, val=1.0, units='m') - - self.prob.model.set_input_defaults(Aircraft.HorizontalTail.SPAN, val=1, units='m') - - self.prob.model.set_input_defaults(Aircraft.HorizontalTail.ROOT_CHORD, val=1, units='m') - - self.prob.model.set_input_defaults(Aircraft.VerticalTail.SPAN, val=1, units='m') - - self.prob.model.set_input_defaults(Aircraft.VerticalTail.ROOT_CHORD, val=1, units='m') - - self.prob.model.set_input_defaults('tip_chord', val=0.5, units='m') - - self.prob.model.set_input_defaults('tip_chord_tail', val=0.5, units='m') - - self.prob.model.set_input_defaults('thickness_ratio', val=0.12) - - self.prob.model.set_input_defaults('skin_thickness', val=0.002, units='m') - - self.prob.model.set_input_defaults('twist', val=jnp.zeros(10), units='deg') - - self.prob.model.set_input_defaults('twist_tail', val=jnp.zeros(10), units='deg') - - self.prob.model.set_input_defaults(Aircraft.Fuselage.LENGTH, val=2.5, units='m') - - self.prob.model.set_input_defaults('base_diameter', val=0.4, units='m') - - self.prob.model.set_input_defaults('tip_diameter', val=0.2) - - self.prob.model.set_input_defaults('curvature', val=0.0, units='m') - - self.prob.model.set_input_defaults('y_offset', val=0.0, units='m') + self.prob.setup() - self.prob.model.set_input_defaults('z_offset', val=0.0, units='m') - - self.prob.model.set_input_defaults('thickness', val=0.05, units='m') - - self.prob.model.set_input_defaults('is_hollow', val=True) - - n_points = 10 # = num_sections - x = jnp.linspace(0, 1, n_points) - max_thickness_chord_ratio = 0.12 - thickness_dist = ( - 5 - * max_thickness_chord_ratio - * (0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) - ) - - self.prob.model.set_input_defaults('thickness_dist', val=thickness_dist, units='m') - - self.prob.setup(check=False, force_alloc_complex=True) - - self.prob.model.tot.tail_mass.options['tail_type'] = 'horizontal' + self.prob.set_val(Aircraft.Fuselage.MASS, val=100.0) + self.prob.set_val(Aircraft.Wing.MASS, val=4.2) + self.prob.set_val(Aircraft.HorizontalTail.MASS, val=4.25) + self.prob.set_val(Aircraft.VerticalTail.MASS, val=4.5) self.prob.run_model() @@ -82,10 +28,7 @@ def test_case(self): tol = 1e-10 - if self.prob.model.tot.tail_mass.options['tail_type'] == 'horizontal': - assert_near_equal(self.prob['structure_mass'], 355.18828485, tol) - else: - assert_near_equal(self.prob['structure_mass'], 355.18828485, tol) + assert_near_equal(self.prob[Aircraft.Design.STRUCTURE_MASS], 112.95, tol) partial_data = self.prob.check_partials(out_stream=None, method='cs') @@ -93,10 +36,7 @@ def test_case(self): class StructureMassTest(unittest.TestCase): - """ - Total structure summation mass test case. - - """ + """Total structure summation mass test case.""" def setUp(self): self.prob = om.Problem() @@ -111,23 +51,16 @@ def setUp(self): self.prob.setup(check=False, force_alloc_complex=True) self.prob.set_val(Aircraft.Fuselage.MASS, val=100.0) - self.prob.set_val(Aircraft.Wing.MASS, val=4.2) - self.prob.set_val(Aircraft.HorizontalTail.MASS, val=4.25) - self.prob.set_val(Aircraft.VerticalTail.MASS, val=4.5) def test_case(self): self.prob.run_model() tol = 1e-10 - self.prob.model.tot.options['tail_type'] = 'horizontal' - if self.prob.model.tot.options['tail_type'] == 'horizontal': - assert_near_equal(self.prob['structure_mass'], 108.45, tol) - else: - assert_near_equal(self.prob['structure_mass'], 108.45, tol) + assert_near_equal(self.prob[Aircraft.Design.STRUCTURE_MASS], 112.95, tol) partial_data = self.prob.check_partials(out_stream=None, method='cs') diff --git a/aviary/subsystems/mass/simple_mass/test/test_tail.py b/aviary/subsystems/mass/simple_mass/test/test_tail.py index c76da8e42..c72734c8f 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_tail.py +++ b/aviary/subsystems/mass/simple_mass/test/test_tail.py @@ -1,6 +1,5 @@ import unittest -import numpy as np import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal diff --git a/aviary/subsystems/mass/simple_mass/test/test_wing.py b/aviary/subsystems/mass/simple_mass/test/test_wing.py index cbc5c3c74..4dc215343 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_wing.py +++ b/aviary/subsystems/mass/simple_mass/test/test_wing.py @@ -1,22 +1,16 @@ import unittest +import jax.numpy as jnp +import numpy as np import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal -import aviary.api as av - -import numpy as np -import jax.numpy as jnp -from aviary.subsystems.mass.simple_mass.wing import WingMassAndCOG from aviary.variable_info.variables import Aircraft # @av.skipIfMissingDependencies(WingMassAndCOG) class WingMassTestCase(unittest.TestCase): - """ - Wing mass test case. - - """ + """Wing mass test case.""" def setUp(self): self.prob = om.Problem() diff --git a/aviary/subsystems/mass/simple_mass/wing.py b/aviary/subsystems/mass/simple_mass/wing.py index c85c06467..db4ba85cf 100644 --- a/aviary/subsystems/mass/simple_mass/wing.py +++ b/aviary/subsystems/mass/simple_mass/wing.py @@ -72,13 +72,13 @@ def setup(self): self.thickness, self.camber_line, ) = self.extract_airfoil_features(x_coords, y_coords) - num_sections = len(x_coords) + len(x_coords) else: # Parse the NACA airfoil type (4-digit) self.camber = int(airfoil_type[0]) / 100.0 # Maximum camber self.camber_location = int(airfoil_type[1]) / 10.0 # Location of max camber self.max_thickness = int(airfoil_type[2:4]) / 100.0 # Max thickness - num_sections = self.options['num_sections'] + self.options['num_sections'] def get_self_statics(self): return ( @@ -118,11 +118,11 @@ def compute_primal( num_sections = self.options['num_sections'] # Wing spanwise distribution - span_locations = jnp.linspace(0, aircraft__wing__span, num_sections) + jnp.linspace(0, aircraft__wing__span, num_sections) n_points = num_sections - x_points = jnp.linspace(0, 1, n_points) - dx = 1 / (n_points - 1) + jnp.linspace(0, 1, n_points) + 1 / (n_points - 1) if airfoil_type: aircraft__wing__mass_first_part, _ = quadgk( From 3ccaf6b1245fc5e7511375256fbb027b1292aa0d Mon Sep 17 00:00:00 2001 From: jkirk5 Date: Fri, 18 Jul 2025 16:07:51 -0400 Subject: [PATCH 144/147] docs fixes --- .../docs/examples/coupled_aircraft_mission_optimization.ipynb | 3 --- aviary/docs/examples/more_advanced_example.ipynb | 3 --- 2 files changed, 6 deletions(-) diff --git a/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb b/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb index ac8c37e7d..99ea34f62 100644 --- a/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb +++ b/aviary/docs/examples/coupled_aircraft_mission_optimization.ipynb @@ -66,7 +66,6 @@ " 'time_duration_bounds': ((35.0, 105.0), 'min'),\n", " },\n", " 'initial_guesses': {'time': ([0, 70], 'min')},\n", - " 'initial_guesses': {'times': ([0, 70], 'min')},\n", " },\n", " 'cruise': {\n", " 'subsystem_options': {'core_aerodynamics': {'method': 'computed'}},\n", @@ -88,7 +87,6 @@ " 'time_duration_bounds': ((91.5, 274.5), 'min'),\n", " },\n", " 'initial_guesses': {'time': ([70, 183], 'min')},\n", - " 'initial_guesses': {'times': ([70, 183], 'min')},\n", " },\n", " 'descent_1': {\n", " 'subsystem_options': {'core_aerodynamics': {'method': 'computed'}},\n", @@ -110,7 +108,6 @@ " 'time_duration_bounds': ((25.0, 75.0), 'min'),\n", " },\n", " 'initial_guesses': {'time': ([253, 50], 'min')},\n", - " 'initial_guesses': {'times': ([253, 50], 'min')},\n", " },\n", " 'post_mission': {\n", " 'include_landing': False,\n", diff --git a/aviary/docs/examples/more_advanced_example.ipynb b/aviary/docs/examples/more_advanced_example.ipynb index c2ccfaed8..4f6eec29e 100644 --- a/aviary/docs/examples/more_advanced_example.ipynb +++ b/aviary/docs/examples/more_advanced_example.ipynb @@ -66,7 +66,6 @@ " 'time_duration_bounds': ((27.0, 81.0), 'min'),\n", " },\n", " 'initial_guesses': {'time': ([0, 54], 'min')},\n", - " 'initial_guesses': {'times': ([0, 54], 'min')},\n", " },\n", " 'cruise': {\n", " 'subsystem_options': {'core_aerodynamics': {'method': 'computed'}},\n", @@ -87,7 +86,6 @@ " 'time_duration_bounds': ((85.5, 256.5), 'min'),\n", " },\n", " 'initial_guesses': {'time': ([54, 171], 'min')},\n", - " 'initial_guesses': {'times': ([54, 171], 'min')},\n", " },\n", " 'descent_1': {\n", " 'subsystem_options': {'core_aerodynamics': {'method': 'computed'}},\n", @@ -108,7 +106,6 @@ " 'time_duration_bounds': ((26.5, 79.5), 'min'),\n", " },\n", " 'initial_guesses': {'time': ([225, 53], 'min')},\n", - " 'initial_guesses': {'times': ([225, 53], 'min')},\n", " },\n", " 'post_mission': {\n", " 'include_landing': False,\n", From dc61d1dacc95e890f536b5bdd81113cb3abe1399 Mon Sep 17 00:00:00 2001 From: jkirk5 Date: Fri, 18 Jul 2025 16:08:36 -0400 Subject: [PATCH 145/147] additional docs fix --- aviary/docs/examples/simple_mission_example.ipynb | 3 --- 1 file changed, 3 deletions(-) diff --git a/aviary/docs/examples/simple_mission_example.ipynb b/aviary/docs/examples/simple_mission_example.ipynb index 518dd8ea8..255b920c8 100644 --- a/aviary/docs/examples/simple_mission_example.ipynb +++ b/aviary/docs/examples/simple_mission_example.ipynb @@ -188,7 +188,6 @@ " 'time_duration_bounds': ((27.0, 81.0), 'min'),\n", " },\n", " 'initial_guesses': {'time': ([0, 54], 'min')},\n", - " 'initial_guesses': {'times': ([0, 54], 'min')},\n", " },\n", " 'cruise': {\n", " 'subsystem_options': {'core_aerodynamics': {'method': 'computed'}},\n", @@ -210,7 +209,6 @@ " 'time_duration_bounds': ((85.5, 256.5), 'min'),\n", " },\n", " 'initial_guesses': {'time': ([54, 171], 'min')},\n", - " 'initial_guesses': {'times': ([54, 171], 'min')},\n", " },\n", " 'descent_1': {\n", " 'subsystem_options': {'core_aerodynamics': {'method': 'computed'}},\n", @@ -230,7 +228,6 @@ " 'time_duration_bounds': ((26.5, 79.5), 'min'),\n", " },\n", " 'initial_guesses': {'time': ([225, 53], 'min')},\n", - " 'initial_guesses': {'times': ([225, 53], 'min')},\n", " },\n", " 'post_mission': {\n", " 'include_landing': False,\n", From 0c2be8a911863df175809c75160bd3edc61c8ce8 Mon Sep 17 00:00:00 2001 From: jkirk5 Date: Mon, 21 Jul 2025 10:53:00 -0400 Subject: [PATCH 146/147] more updates to simple_mass components --- aviary/subsystems/mass/simple_mass/tail.py | 182 ++++++------------ .../mass/simple_mass/test/test_fuselage.py | 5 +- .../mass/simple_mass/test/test_tail.py | 21 +- .../mass/simple_mass/test/test_wing.py | 3 +- aviary/subsystems/mass/simple_mass/utils.py | 58 ++++++ aviary/subsystems/mass/simple_mass/wing.py | 156 ++++++--------- 6 files changed, 189 insertions(+), 236 deletions(-) create mode 100644 aviary/subsystems/mass/simple_mass/utils.py diff --git a/aviary/subsystems/mass/simple_mass/tail.py b/aviary/subsystems/mass/simple_mass/tail.py index 076e4de0e..70f6b07b6 100644 --- a/aviary/subsystems/mass/simple_mass/tail.py +++ b/aviary/subsystems/mass/simple_mass/tail.py @@ -1,13 +1,19 @@ +from pathlib import Path + import jax.numpy as jnp import numpy as np import openmdao.api as om -import openmdao.jax as omj -from scipy.interpolate import CubicSpline from aviary.subsystems.mass.simple_mass.materials_database import materials +from aviary.subsystems.mass.simple_mass.utils import ( + airfoil_camber_line, + airfoil_thickness, + extract_airfoil_features, + precompute_airfoil_geometry, +) from aviary.utils.functions import get_path from aviary.utils.named_values import get_keys -from aviary.variable_info.functions import add_aviary_output +from aviary.variable_info.functions import add_aviary_input, add_aviary_output from aviary.variable_info.variables import Aircraft try: @@ -29,8 +35,9 @@ def initialize(self): ) self.options.declare( - 'airfoil_file', + 'airfoil_data_file', default=None, + types=(str, Path), desc='File path for airfoil coordinates (overrides NACA digits)', ) @@ -48,23 +55,23 @@ def initialize(self): def setup(self): # Inputs - # TODO unused?!? - # add_aviary_input(self, Aircraft.HorizontalTail.SPAN, units='m', desc='Tail span') - # add_aviary_input( - # self, Aircraft.HorizontalTail.ROOT_CHORD, units='m', desc='Root chord length' - # ) + # TODO most of these are unused?!? + add_aviary_input(self, Aircraft.HorizontalTail.SPAN, units='m', desc='Tail span') + add_aviary_input( + self, Aircraft.HorizontalTail.ROOT_CHORD, units='m', desc='Root chord length' + ) - # self.add_input('tip_chord_tail', val=0.8, units='m', desc='Tip chord length') + self.add_input('tip_chord_tail', val=0.8, units='m', desc='Tip chord length') self.add_input( 'thickness_ratio', val=0.12, desc='Max thickness to chord ratio for NACA airfoil' ) - # self.add_input('skin_thickness', val=0.002, units='m', desc='Skin panel thickness') - # self.add_input( - # 'twist_tail', - # val=jnp.zeros(self.options['num_sections']), - # units='deg', - # desc='Twist distribution', - # ) + self.add_input('skin_thickness', val=0.002, units='m', desc='Skin panel thickness') + self.add_input( + 'twist_tail', + val=jnp.zeros(self.options['num_sections']), + units='deg', + desc='Twist distribution', + ) # Outputs add_aviary_output( @@ -72,13 +79,11 @@ def setup(self): ) # File check - airfoil_file = self.options['airfoil_file'] + airfoil_file = self.options['airfoil_data_file'] if airfoil_file is not None: airfoil_file = get_path(airfoil_file) - # try: airfoil_data = np.loadtxt(airfoil_file, skiprows=1) # Assume a header - # except Exception as e: - # raise ValueError(f'Error reading airfoil file: {e}') + x_coords, y_coords = airfoil_data[:, 0], airfoil_data[:, 1] ( @@ -110,19 +115,17 @@ def get_self_statics(self): def compute_primal( self, - # aircraft__horizontal_tail__span, - # aircraft__horizontal_tail__root_chord, - # aircraft__vertical_tail__span, - # aircraft__vertical_tail__root_chord, - # tip_chord_tail, + aircraft__horizontal_tail__span, + aircraft__horizontal_tail__root_chord, + tip_chord_tail, thickness_ratio, - # skin_thickness, - # twist_tail, + skin_thickness, + twist_tail, ): material = self.options['material'] density = materials.get_val(material, 'kg/m**3') - airfoil_file = self.options['airfoil_file'] - # num_sections = self.options['num_sections'] + airfoil_file = self.options['airfoil_data_file'] + num_sections = self.options['num_sections'] camber = self.camber camber_location = self.camber_location max_thickness = self.max_thickness @@ -133,13 +136,13 @@ def compute_primal( aircraft__horizontal_tail__mass = 0.0 * thickness_ratio # TODO unused?? - # span_locations = jnp.linspace(0, aircraft__horizontal_tail__span, num_sections) + span_locations = jnp.linspace(0, aircraft__horizontal_tail__span, num_sections) # Get x_points and dx for later - # x_points, dx = precompute_airfoil_geometry() + x_points, dx = precompute_airfoil_geometry(num_sections) # Thickness distribution - # thickness_dist = airfoil_thickness(x_points, max_thickness) + thickness_dist = airfoil_thickness(x_points, max_thickness) if airfoil_file is not None: aircraft__horizontal_tail__mass, _ = quadgk( @@ -187,8 +190,9 @@ def initialize(self): ) self.options.declare( - 'airfoil_file', + 'airfoil_data_file', default=None, + types=(str, Path), desc='File path for airfoil coordinates (overrides NACA digits)', ) @@ -206,23 +210,23 @@ def initialize(self): def setup(self): # Inputs - # TODO unused?!? - # add_aviary_input(self, Aircraft.VerticalTail.SPAN, units='m', desc='Tail span') - # add_aviary_input( - # self, Aircraft.VerticalTail.ROOT_CHORD, units='m', desc='Root chord length' - # ) + # TODO most of these are unused?!? + add_aviary_input(self, Aircraft.VerticalTail.SPAN, units='m', desc='Tail span') + add_aviary_input( + self, Aircraft.VerticalTail.ROOT_CHORD, units='m', desc='Root chord length' + ) - # self.add_input('tip_chord_tail', val=0.8, units='m', desc='Tip chord length') + self.add_input('tip_chord_tail', val=0.8, units='m', desc='Tip chord length') self.add_input( 'thickness_ratio', val=0.12, desc='Max thickness to chord ratio for NACA airfoil' ) - # self.add_input('skin_thickness', val=0.002, units='m', desc='Skin panel thickness') - # self.add_input( - # 'twist_tail', - # val=jnp.zeros(self.options['num_sections']), - # units='deg', - # desc='Twist distribution', - # ) + self.add_input('skin_thickness', val=0.002, units='m', desc='Skin panel thickness') + self.add_input( + 'twist_tail', + val=jnp.zeros(self.options['num_sections']), + units='deg', + desc='Twist distribution', + ) # Outputs add_aviary_output( @@ -230,13 +234,11 @@ def setup(self): ) # File check - airfoil_file = self.options['airfoil_file'] + airfoil_file = self.options['airfoil_data_file'] if airfoil_file is not None: airfoil_file = get_path(airfoil_file) - # try: airfoil_data = np.loadtxt(airfoil_file, skiprows=1) # Assume a header - # except Exception as e: - # raise ValueError(f'Error reading airfoil file: {e}') + x_coords, y_coords = airfoil_data[:, 0], airfoil_data[:, 1] ( @@ -268,19 +270,17 @@ def get_self_statics(self): def compute_primal( self, - # aircraft__vertical_tail__span, - # aircraft__vertical_tail__root_chord, - # aircraft__vertical_tail__span, - # aircraft__vertical_tail__root_chord, - # tip_chord_tail, + aircraft__vertical_tail__span, + aircraft__vertical_tail__root_chord, + tip_chord_tail, thickness_ratio, - # skin_thickness, - # twist_tail, + skin_thickness, + twist_tail, ): material = self.options['material'] density = materials.get_val(material, 'kg/m**3') - airfoil_file = self.options['airfoil_file'] - # num_sections = self.options['num_sections'] + airfoil_file = self.options['airfoil_data_file'] + num_sections = self.options['num_sections'] camber = self.camber camber_location = self.camber_location max_thickness = self.max_thickness @@ -291,13 +291,13 @@ def compute_primal( aircraft__vertical_tail__mass = 0.0 * thickness_ratio # TODO unused?? - # span_locations = jnp.linspace(0, aircraft__vertical_tail__span, num_sections) + span_locations = jnp.linspace(0, aircraft__vertical_tail__span, num_sections) # Get x_points and dx for later - # x_points, dx = precompute_airfoil_geometry() + x_points, dx = precompute_airfoil_geometry(num_sections) # Thickness distribution - # thickness_dist = airfoil_thickness(x_points, max_thickness) + thickness_dist = airfoil_thickness(x_points, max_thickness) if airfoil_file is not None: aircraft__vertical_tail__mass, _ = quadgk( @@ -333,59 +333,3 @@ def compute_primal( aircraft__vertical_tail__mass = total_mass_first_part + total_mass_second_part return aircraft__vertical_tail__mass - - -# def precompute_airfoil_geometry(self): -# n_points = self.options['num_sections'] -# x_points = jnp.linspace(0, 1, n_points) -# dx = 1 / (n_points - 1) -# return x_points, dx - - -def airfoil_thickness(x, max_thickness): - return ( - 5 - * max_thickness - * (0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) - ) - - -# def airfoil_camber_line(self, x, camber, camber_location): -# camber_location = omj.ks_max(camber_location, 1e-9) # Divide by zero check -# return jnp.where( -# x < camber_location, -# (camber / camber_location**2) * (2 * camber_location * x - x**2), -# (camber / (1 - camber_location) ** 2) -# * ((1 - 2 * camber_location) + 2 * camber_location * x - x**2), -# ) - - -def extract_airfoil_features(x_coords, y_coords): - """ - Extract camber, camber location, and max thickness from the given airfoil data. - This method assumes x_coords are normalized (ranging from 0 to 1). - """ - # Approximate the camber line and max thickness from the data - # Assume the camber line is the line of symmetry between the upper and lower surfaces - upper_surface = y_coords[: int(len(x_coords) // 2)] - lower_surface = y_coords[int(len(x_coords) // 2) :] - x_upper = x_coords[: int(len(x_coords) // 2)] - x_lower = x_coords[int(len(x_coords) // 2) :] - - upper_spline = CubicSpline(x_upper, upper_surface, bc_type='natural') - lower_spline = CubicSpline(x_lower, lower_surface, bc_type='natural') - - camber_line = (upper_spline(x_coords) + lower_spline(x_coords)) / 2.0 - - thickness = upper_spline(x_coords) - lower_spline(x_coords) - - max_thickness_index = omj.ks_max(thickness) - max_thickness_value = thickness[max_thickness_index] - - camber_slope = jnp.gradient(camber_line, x_coords) - camber_location_index = omj.ks_max(omj.smooth_abs(camber_slope)) - camber_location = x_coords[camber_location_index] - - camber = camber_line[camber_location_index] - - return camber, camber_location, max_thickness_value, camber_line, thickness diff --git a/aviary/subsystems/mass/simple_mass/test/test_fuselage.py b/aviary/subsystems/mass/simple_mass/test/test_fuselage.py index 270c1cc0f..c27d4dacb 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_fuselage.py +++ b/aviary/subsystems/mass/simple_mass/test/test_fuselage.py @@ -46,7 +46,4 @@ def test_case(self): if __name__ == '__main__': - # unittest.main() - test = FuselageMassTestCase() - test.setUp() - test.test_case() + unittest.main() diff --git a/aviary/subsystems/mass/simple_mass/test/test_tail.py b/aviary/subsystems/mass/simple_mass/test/test_tail.py index c72734c8f..66272de98 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_tail.py +++ b/aviary/subsystems/mass/simple_mass/test/test_tail.py @@ -1,5 +1,6 @@ import unittest +import numpy as np import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal @@ -19,12 +20,12 @@ def test_horizontal_tail(self): promotes_outputs=['*'], ) - # self.prob.model.set_input_defaults(Aircraft.HorizontalTail.SPAN, val=1, units='m') - # self.prob.model.set_input_defaults(Aircraft.HorizontalTail.ROOT_CHORD, val=1, units='m') - # self.prob.model.set_input_defaults('tip_chord_tail', val=0.5, units='m') + prob.model.set_input_defaults(Aircraft.HorizontalTail.SPAN, val=1, units='m') + prob.model.set_input_defaults(Aircraft.HorizontalTail.ROOT_CHORD, val=1, units='m') + prob.model.set_input_defaults('tip_chord_tail', val=0.5, units='m') prob.model.set_input_defaults('thickness_ratio', val=0.12) - # self.prob.model.set_input_defaults('skin_thickness', val=0.002, units='m') - # self.prob.model.set_input_defaults('twist_tail', val=np.zeros(10), units='deg') + prob.model.set_input_defaults('skin_thickness', val=0.002, units='m') + prob.model.set_input_defaults('twist_tail', val=np.zeros(10), units='deg') prob.setup(check=False, force_alloc_complex=True) @@ -47,12 +48,12 @@ def test_vertical_tail(self): promotes_outputs=['*'], ) - # self.prob.model.set_input_defaults(Aircraft.VerticalTail.SPAN, val=1, units='m') - # self.prob.model.set_input_defaults(Aircraft.VerticalTail.ROOT_CHORD, val=1, units='m') - # self.prob.model.set_input_defaults('tip_chord_tail', val=0.5, units='m') + prob.model.set_input_defaults(Aircraft.VerticalTail.SPAN, val=1, units='m') + prob.model.set_input_defaults(Aircraft.VerticalTail.ROOT_CHORD, val=1, units='m') + prob.model.set_input_defaults('tip_chord_tail', val=0.5, units='m') prob.model.set_input_defaults('thickness_ratio', val=0.12) - # self.prob.model.set_input_defaults('skin_thickness', val=0.002, units='m') - # self.prob.model.set_input_defaults('twist_tail', val=np.zeros(10), units='deg') + prob.model.set_input_defaults('skin_thickness', val=0.002, units='m') + prob.model.set_input_defaults('twist_tail', val=np.zeros(10), units='deg') prob.setup(check=False, force_alloc_complex=True) diff --git a/aviary/subsystems/mass/simple_mass/test/test_wing.py b/aviary/subsystems/mass/simple_mass/test/test_wing.py index 4dc215343..45036ad83 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_wing.py +++ b/aviary/subsystems/mass/simple_mass/test/test_wing.py @@ -5,6 +5,7 @@ import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal +from aviary.subsystems.mass.simple_mass.wing import WingMass from aviary.variable_info.variables import Aircraft @@ -45,7 +46,7 @@ def setUp(self): def test_case(self): self.prob.run_model() - tol = 1e-10 + tol = 1e-9 assert_near_equal(self.prob[Aircraft.Wing.MASS], 10.6966719, tol) partial_data = self.prob.check_partials(out_stream=None, method='cs') diff --git a/aviary/subsystems/mass/simple_mass/utils.py b/aviary/subsystems/mass/simple_mass/utils.py new file mode 100644 index 000000000..85ad74524 --- /dev/null +++ b/aviary/subsystems/mass/simple_mass/utils.py @@ -0,0 +1,58 @@ +import jax.numpy as jnp +import openmdao.jax as omj +from scipy.interpolate import CubicSpline + + +def precompute_airfoil_geometry(num_sections): + x_points = jnp.linspace(0, 1, num_sections) + dx = 1 / (num_sections - 1) + return x_points, dx + + +def airfoil_thickness(x, max_thickness): + return ( + 5 + * max_thickness + * (0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) + ) + + +def airfoil_camber_line(x, camber, camber_location): + camber_location = omj.ks_max(camber_location, 1e-9) # Divide by zero check + return jnp.where( + x < camber_location, + (camber / camber_location**2) * (2 * camber_location * x - x**2), + (camber / (1 - camber_location) ** 2) + * ((1 - 2 * camber_location) + 2 * camber_location * x - x**2), + ) + + +def extract_airfoil_features(x_coords, y_coords): + """ + Extract camber, camber location, and max thickness from the given airfoil data. + This method assumes x_coords are normalized (ranging from 0 to 1). + """ + # Approximate the camber line and max thickness from the data + # Assume the camber line is the line of symmetry between the upper and lower surfaces + upper_surface = y_coords[: int(len(x_coords) // 2)] + lower_surface = y_coords[int(len(x_coords) // 2) :] + x_upper = x_coords[: int(len(x_coords) // 2)] + x_lower = x_coords[int(len(x_coords) // 2) :] + + upper_spline = CubicSpline(x_upper, upper_surface, bc_type='natural') + lower_spline = CubicSpline(x_lower, lower_surface, bc_type='natural') + + camber_line = (upper_spline(x_coords) + lower_spline(x_coords)) / 2.0 + + thickness = upper_spline(x_coords) - lower_spline(x_coords) + + max_thickness_index = omj.ks_max(thickness) + max_thickness_value = thickness[max_thickness_index] + + camber_slope = jnp.gradient(camber_line, x_coords) + camber_location_index = omj.ks_max(omj.smooth_abs(camber_slope)) + camber_location = x_coords[camber_location_index] + + camber = camber_line[camber_location_index] + + return camber, camber_location, max_thickness_value, camber_line, thickness diff --git a/aviary/subsystems/mass/simple_mass/wing.py b/aviary/subsystems/mass/simple_mass/wing.py index db4ba85cf..8ddfcf0bd 100644 --- a/aviary/subsystems/mass/simple_mass/wing.py +++ b/aviary/subsystems/mass/simple_mass/wing.py @@ -1,13 +1,17 @@ -import os +from pathlib import Path import jax.numpy as jnp import numpy as np import openmdao.api as om -import openmdao.jax as omj -from scipy.interpolate import CubicSpline from aviary.subsystems.mass.simple_mass.materials_database import materials -from aviary.utils.functions import add_aviary_input, add_aviary_output +from aviary.subsystems.mass.simple_mass.utils import ( + airfoil_camber_line, + airfoil_thickness, + extract_airfoil_features, + precompute_airfoil_geometry, +) +from aviary.utils.functions import add_aviary_input, add_aviary_output, get_path from aviary.utils.named_values import get_keys from aviary.variable_info.variables import Aircraft @@ -19,26 +23,35 @@ ) -Debug = False - - class WingMass(om.JaxExplicitComponent): def initialize(self): self.options.declare('num_sections', types=int, default=10) self.options.declare( - 'airfoil_type', types=str, default='2412' - ) # use 2412 as example for default + 'NACA_digits', + default='2412', + types=(str, int), + desc='4 digit code for NACA airfoil of tail', + ) + + self.options.declare( + 'airfoil_data_file', + default=None, + types=(str, Path), + desc='File path for airfoil coordinates (overrides NACA digits)', + ) + + self.options.declare('num_sections', default=10, desc='Number of sections for enumeration') self.options.declare('material', default='Balsa', values=list(get_keys(materials))) - self.options.declare( - 'airfoil_data_file', default=None, types=str - ) # For user-provided airfoil data file + self.camber = 0 + self.camber_location = 0 + self.max_thickness = 0 + self.camber_line = 0 + self.thickness = 0 def setup(self): - self.options['use_jit'] = not (Debug) - # Inputs add_aviary_input(self, Aircraft.Wing.SPAN, units='m') # Full wingspan (adjustable) @@ -60,7 +73,10 @@ def setup(self): # Outputs add_aviary_output(self, Aircraft.Wing.MASS, units='kg') - if airfoil_data_file and os.path.exists(airfoil_data_file): + airfoil_data_file = self.options['airfoil_data_file'] + if airfoil_data_file is not None: + airfoil_data_file = get_path(airfoil_data_file) + # try: airfoil_data = np.loadtxt(airfoil_data_file) x_coords = airfoil_data[:, 0] y_coords = airfoil_data[:, 1] @@ -71,13 +87,14 @@ def setup(self): self.max_thickness, self.thickness, self.camber_line, - ) = self.extract_airfoil_features(x_coords, y_coords) + ) = extract_airfoil_features(x_coords, y_coords) len(x_coords) else: + NACA_digits = str(self.options['NACA_digits']) # Parse the NACA airfoil type (4-digit) - self.camber = int(airfoil_type[0]) / 100.0 # Maximum camber - self.camber_location = int(airfoil_type[1]) / 10.0 # Location of max camber - self.max_thickness = int(airfoil_type[2:4]) / 100.0 # Max thickness + self.camber = int(NACA_digits[0]) / 100.0 # Maximum camber + self.camber_location = int(NACA_digits[1]) / 10.0 # Location of max camber + self.max_thickness = int(NACA_digits[2:4]) / 100.0 # Max thickness self.options['num_sections'] def get_self_statics(self): @@ -93,30 +110,19 @@ def get_self_statics(self): def compute_primal( self, aircraft__wing__span, aircraft__wing__root_chord, tip_chord, twist, thickness_dist ): - material = self.options['material'] # Material is taken from options - airfoil_type = self.options['airfoil_type'] # NACA airfoil type + material = self.options['material'] + density = materials.get_val(material, 'kg/m**3') airfoil_data_file = self.options['airfoil_data_file'] + num_sections = self.options['num_sections'] + camber = self.camber + camber_location = self.camber_location + max_thickness = self.max_thickness + camber_line = self.camber_line + thickness = self.thickness # Get material density density = materials.get_val(material, 'kg/m**3') - if airfoil_data_file and os.path.exists(airfoil_data_file): - airfoil_data = np.loadtxt(airfoil_data_file) - x_coords = airfoil_data[:, 0] - y_coords = airfoil_data[:, 1] - - camber, camber_location, max_thickness, thickness, camber_line = ( - self.extract_airfoil_features(x_coords, y_coords) - ) - thickness_dist = thickness - num_sections = len(x_coords) - else: - # Parse the NACA airfoil type (4-digit) - camber = int(airfoil_type[0]) / 100.0 # Maximum camber - camber_location = int(airfoil_type[1]) / 10.0 # Location of max camber - max_thickness = int(airfoil_type[2:4]) / 100.0 # Max thickness - num_sections = self.options['num_sections'] - # Wing spanwise distribution jnp.linspace(0, aircraft__wing__span, num_sections) @@ -124,11 +130,18 @@ def compute_primal( jnp.linspace(0, 1, n_points) 1 / (n_points - 1) - if airfoil_type: + if airfoil_data_file is not None: + aircraft__wing__mass, _ = quadgk( + density * 2 * thickness_dist * jnp.sqrt(1 + jnp.gradient(camber_line) ** 2), + [0, 1], + epsabs=1e-9, + epsrel=1e-9, + ) + else: aircraft__wing__mass_first_part, _ = quadgk( lambda x: density * 2 - * jnp.atleast_1d(self.airfoil_thickness(x, max_thickness)) + * jnp.atleast_1d(airfoil_thickness(x, max_thickness)) * jnp.sqrt( 1 + ((camber / camber_location**2) * (2 * camber_location - 2 * x)) ** 2 ), @@ -139,7 +152,7 @@ def compute_primal( aircraft__wing__mass_second_part, _ = quadgk( lambda x: density * 2 - * jnp.atleast_1d(self.airfoil_thickness(x, max_thickness)) + * jnp.atleast_1d(airfoil_thickness(x, max_thickness)) * jnp.sqrt( 1 + (camber / (1 - camber_location) ** 2 * (2 * camber_location - 2 * x)) ** 2 ), @@ -152,65 +165,4 @@ def compute_primal( aircraft__wing__mass_first_part + aircraft__wing__mass_second_part ) - elif airfoil_data_file is not None: - aircraft__wing__mass, _ = quadgk( - density * 2 * thickness_dist * jnp.sqrt(1 + jnp.gradient(camber_line) ** 2), - [0, 1], - epsabs=1e-9, - epsrel=1e-9, - ) - return aircraft__wing__mass - - def precompute_airfoil_geometry(self): - num_sections = self.options['num_sections'] - n_points = num_sections - x_points = jnp.linspace(0, 1, n_points) - dx = 1 / (n_points - 1) - return x_points, dx - - def airfoil_thickness(self, x, max_thickness): - return ( - 5 - * max_thickness - * (0.2969 * jnp.sqrt(x) - 0.1260 * x - 0.3516 * x**2 + 0.2843 * x**3 - 0.1015 * x**4) - ) - - def airfoil_camber_line(self, x, camber, camber_location): - camber_location = omj.smooth_max(camber_location, 1e-9) # Divide by zero check - return jnp.where( - x < camber_location, - (camber / camber_location**2) * (2 * camber_location * x - x**2), - (camber / (1 - camber_location) ** 2) - * ((1 - 2 * camber_location) + 2 * camber_location * x - x**2), - ) - - def extract_airfoil_features(self, x_coords, y_coords): - """ - Extract camber, camber location, and max thickness from the given airfoil data. - This method assumes x_coords are normalized (ranging from 0 to 1). - """ - # Approximate the camber line and max thickness from the data - # Assume the camber line is the line of symmetry between the upper and lower surfaces - upper_surface = y_coords[: int(len(x_coords) // 2)] - lower_surface = y_coords[int(len(x_coords) // 2) :] - x_upper = x_coords[: int(len(x_coords) // 2)] - x_lower = x_coords[int(len(x_coords) // 2) :] - - upper_spline = CubicSpline(x_upper, upper_surface, bc_type='natural') - lower_spline = CubicSpline(x_lower, lower_surface, bc_type='natural') - - camber_line = (upper_spline(x_coords) + lower_spline(x_coords)) / 2.0 - - thickness = upper_spline(x_coords) - lower_spline(x_coords) - - max_thickness_index = jnp.argmax(thickness) - max_thickness_value = thickness[max_thickness_index] - - camber_slope = jnp.gradient(camber_line, x_coords) - camber_location_index = jnp.argmax(omj.smooth_abs(camber_slope)) - camber_location = x_coords[camber_location_index] - - camber = camber_line[camber_location_index] - - return camber, camber_location, max_thickness_value, thickness, camber_line From 187410a69fe7abf3b65fc70e981803e01238e4e1 Mon Sep 17 00:00:00 2001 From: jkirk5 Date: Mon, 21 Jul 2025 10:58:32 -0400 Subject: [PATCH 147/147] wing cleanup --- aviary/subsystems/mass/simple_mass/wing.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/aviary/subsystems/mass/simple_mass/wing.py b/aviary/subsystems/mass/simple_mass/wing.py index 8ddfcf0bd..ee44774e6 100644 --- a/aviary/subsystems/mass/simple_mass/wing.py +++ b/aviary/subsystems/mass/simple_mass/wing.py @@ -76,10 +76,9 @@ def setup(self): airfoil_data_file = self.options['airfoil_data_file'] if airfoil_data_file is not None: airfoil_data_file = get_path(airfoil_data_file) - # try: airfoil_data = np.loadtxt(airfoil_data_file) - x_coords = airfoil_data[:, 0] - y_coords = airfoil_data[:, 1] + + x_coords, y_coords = airfoil_data[:, 0], airfoil_data[:, 1] ( self.camber, @@ -88,23 +87,24 @@ def setup(self): self.thickness, self.camber_line, ) = extract_airfoil_features(x_coords, y_coords) - len(x_coords) + else: NACA_digits = str(self.options['NACA_digits']) # Parse the NACA airfoil type (4-digit) self.camber = int(NACA_digits[0]) / 100.0 # Maximum camber self.camber_location = int(NACA_digits[1]) / 10.0 # Location of max camber self.max_thickness = int(NACA_digits[2:4]) / 100.0 # Max thickness - self.options['num_sections'] def get_self_statics(self): return ( self.camber, self.camber_location, self.max_thickness, - self.thickness, self.camber_line, + self.thickness, self.options['material'], + self.options['num_sections'], + self.options['NACA_digits'], ) def compute_primal(