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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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/103] 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 d6bda8405a50b0f36b720d1366aa7a20f66e8f09 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:08:50 -0400 Subject: [PATCH 081/103] 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 1a61320d1216152ddefd32d83e5a08284f1aef3e Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:09:10 -0400 Subject: [PATCH 082/103] 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 4f28b37b74ae2e5493878eb67fbe20b7c81b1f07 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:09:23 -0400 Subject: [PATCH 083/103] 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 2dba3a3d58ca803a7dee0107f27e68de53b3abb2 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:09:29 -0400 Subject: [PATCH 084/103] 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 96c8dea920f4d0f0376134c5cf8cf5f30cd0badc Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:09:38 -0400 Subject: [PATCH 085/103] 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 ee64116d48122bd7dcb8336c892e5baa3802fbe7 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:09:45 -0400 Subject: [PATCH 086/103] 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 677df372ae2807a85502ff2ed7a8e8bb7d614236 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:09:52 -0400 Subject: [PATCH 087/103] 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 6a7c59d648261ce4ae98da824fbd0a87c34db0eb Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:09:58 -0400 Subject: [PATCH 088/103] 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 6956666228472d4e14438466e35456c4cbe79ac6 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:10:04 -0400 Subject: [PATCH 089/103] 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 065f0927a0d6c22168617f972ed918c5058ae3eb Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:10:13 -0400 Subject: [PATCH 090/103] 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 da45dab049b597c6820541206fba092977d6c648 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:10:21 -0400 Subject: [PATCH 091/103] 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 21c4a558d772feb4d9db8dfa37eb2a11a9508be3 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 3 Jul 2025 11:10:30 -0400 Subject: [PATCH 092/103] 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 6efef1013de8ede33e23e448a1eac0dd99dc6705 Mon Sep 17 00:00:00 2001 From: Seth Zoppelt Date: Tue, 8 Jul 2025 15:17:30 +0000 Subject: [PATCH 093/103] Updates. --- aviary/mission/sixdof/force_component_calc.py | 121 +++++--- aviary/mission/sixdof/six_dof_EOM.py | 260 +++++++++--------- aviary/mission/sixdof/six_dof_ODE.py | 40 +-- 3 files changed, 237 insertions(+), 184 deletions(-) diff --git a/aviary/mission/sixdof/force_component_calc.py b/aviary/mission/sixdof/force_component_calc.py index 8b43dee3f..78a955b53 100644 --- a/aviary/mission/sixdof/force_component_calc.py +++ b/aviary/mission/sixdof/force_component_calc.py @@ -1,5 +1,7 @@ import numpy as np import openmdao.api as om +from aviary.variable_info.variables import Dynamic +from aviary.utils.functions import add_aviary_input class ForceComponentResolver(om.ExplicitComponent): @@ -10,6 +12,12 @@ class ForceComponentResolver(om.ExplicitComponent): This class assumes that the total force is given and needs to be resolved into the separate components. + Assumptions: + - Thrust is entirely in -z direction (T = (0,0,-T_z)^T) w.r.t. body CS + - Assuming F_i is in body CS, and D, S, and L are in wind CS. Wind -> body rotation matrix + was applied for coordinate transformations + - Thrust is initially in NED CS. So, two rotations (NED -> wind and wind -> body) are applied + """ def initialize(self): @@ -69,6 +77,17 @@ def setup(self): desc="Side vector (unresolved)" ) + self.add_input( + 'heading_angle', + val=np.zeros(nn), + units='rad', + desc='Heading angle' + ) + + add_aviary_input(self, + Dynamic.Mission.FLIGHT_PATH_ANGLE, + units='rad') + # self.add_input( # 'true_air_speed', # val=np.zeros(nn), @@ -107,6 +126,9 @@ def setup(self): 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='Fx', wrt='thrust', rows=ar, cols=ar) + self.declare_partials(of='Fx', wrt='heading_angle', rows=ar, cols=ar) + self.declare_partials(of='Fx', wrt=Dynamic.Mission.FLIGHT_PATH_ANGLE, 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) @@ -114,6 +136,9 @@ def setup(self): 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='Fy', wrt='thrust', rows=ar, cols=ar) + self.declare_partials(of='Fy', wrt='heading_angle', rows=ar, cols=ar) + self.declare_partials(of='Fy', wrt=Dynamic.Mission.FLIGHT_PATH_ANGLE, 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) @@ -121,6 +146,9 @@ def setup(self): 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) + self.declare_partials(of='Fz', wrt='thrust', rows=ar, cols=ar) + self.declare_partials(of='Fz', wrt='heading_angle', rows=ar, cols=ar) + self.declare_partials(of='Fz', wrt=Dynamic.Mission.FLIGHT_PATH_ANGLE, rows=ar, cols=ar) def compute(self, inputs, outputs): @@ -131,6 +159,8 @@ def compute(self, inputs, outputs): T = inputs['thrust'] L = inputs['lift'] S = inputs['side'] # side force -- assume 0 for now + chi = inputs['heading_angle'] + gamma = inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] nn = self.options['num_nodes'] @@ -138,14 +168,14 @@ def compute(self, inputs, outputs): V = np.sqrt(u**2 + v**2 + w**2) - # flight path angle + # angle of attack # divide by zero checks if np.any(u == 0): u[u == 0] = 1e-4 - gamma = np.arctan(w / u) + alpha = np.arctan(w / u) else: - gamma = np.arctan(w / u) + alpha = np.arctan(w / u) # side slip angle @@ -161,14 +191,14 @@ def compute(self, inputs, outputs): # some trig needed - cos_a = np.cos(gamma) + cos_a = np.cos(alpha) cos_b = np.cos(beta) - sin_a = np.sin(gamma) + sin_a = np.sin(alpha) 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) + outputs['Fx'] = -(cos_a * cos_b * D - cos_a * sin_b * S - sin_a * L) - T * cos_b * np.sin(alpha - gamma) + outputs['Fy'] = -(sin_b * D + cos_b * S) - T * sin_b * np.sin(alpha - gamma) + outputs['Fz'] = -(sin_a * cos_b * D + sin_a * sin_b * S + cos_a * L) - T * np.cos(alpha - gamma) def compute_partials(self, inputs, J): @@ -179,15 +209,17 @@ def compute_partials(self, inputs, J): T = inputs['thrust'] L = inputs['lift'] S = inputs['side'] # side force -- assume 0 for now + gamma = inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] + chi = inputs['heading_angle'] V = np.sqrt(u**2 + v**2 + w**2) # divide by zero checks if u == 0: u = 1e-4 - gamma = np.arctan(w / u) + alpha = np.arctan(w / u) else: - gamma = np.arctan(w / u) + alpha = np.arctan(w / u) # side slip angle @@ -203,34 +235,51 @@ 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(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['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) + np.sin(beta) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * T * np.sin(alpha - gamma) - \ + np.cos(alpha - gamma) * (-w / (w**2 + u**2)) * np.cos(beta) * T + 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 + \ + np.sin(beta) * (np.sqrt(w**2 + u**2) / V**2) * T * np.sin(alpha - gamma) + 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 + np.sin(beta) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) * T * np.sin(alpha - gamma) - \ + np.cos(alpha - gamma) * (u / (w**2 + u**2)) * T * np.cos(beta) + 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', 'thrust'] = -np.cos(beta) * np.sin(alpha - gamma) + J['Fx', Dynamic.Mission.FLIGHT_PATH_ANGLE] = T * np.cos(beta) * np.cos(alpha - gamma) + J['Fx', 'heading_angle'] = 0 + + 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 - \ + np.cos(beta) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * T * np.sin(alpha - gamma) - \ + np.cos(alpha - gamma) * (-w / (w**2 + u**2)) * T * np.sin(beta) + 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 - \ + np.cos(beta) * (np.sqrt(w**2 + u**2) / V**2) * T * np.sin(alpha - gamma) + 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 - \ + np.cos(beta) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) * T * np.sin(alpha - gamma) - \ + np.cos(alpha - gamma) * (u / (w**2 + u**2)) * T * np.sin(beta) 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) + J['Fy', 'thrust'] = -np.sin(beta) * np.sin(alpha - gamma) + J['Fy', Dynamic.Mission.FLIGHT_PATH_ANGLE] = T * np.sin(beta) * np.cos(alpha - gamma) + J['Fy', 'heading_angle'] = 0 + + 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 + np.sin(alpha - gamma) * (-w / (w**2 + u**2)) * T + 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 + np.sin(alpha - gamma) * (u / (w**2 + u**2)) * T + 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', 'thrust'] = -np.cos(alpha - gamma) + J['Fz', Dynamic.Mission.FLIGHT_PATH_ANGLE] = -T * np.sin(alpha - gamma) + J['Fz', 'heading_angle'] = 0 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 4b6040ce6..b725b65cf 100644 --- a/aviary/mission/sixdof/six_dof_EOM.py +++ b/aviary/mission/sixdof/six_dof_EOM.py @@ -30,21 +30,21 @@ def setup(self): ) self.add_input( - 'axial_vel', + 'u', 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', + 'v', 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', + 'w', val=np.zeros(nn), units='m/s', desc="vertical velocity of CM wrt inertial CS resolved in aircraft body fixed CS" @@ -142,21 +142,21 @@ def setup(self): ) self.add_input( - 'lx_ext', + 'lx', 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', + 'ly', val=np.zeros(nn), units='kg*m**2/s**2', desc="external moments in the y direction" ) self.add_input( - 'lz_ext', + 'lz', val=np.zeros(nn), units='kg*m**2/s**2', desc="external moments in the z direction" @@ -203,8 +203,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", - tags=['dymos.state_rate_source:axial_vel', 'dymos.state_units:m/s'] + "state: u", + tags=['dymos.state_rate_source:u', 'dymos.state_units:m/s'] ) self.add_output( @@ -212,8 +212,8 @@ def setup(self): 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'] + "state: v", + tags=['dymos.state_rate_source:v', 'dymos.state_units:m/s'] ) self.add_output( @@ -221,8 +221,8 @@ def setup(self): 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'] + "state: w", + tags=['dymos.state_rate_source:w', 'dymos.state_units:m/s'] ) self.add_output( @@ -303,8 +303,8 @@ 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', 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='v', rows=ar, cols=ar) + self.declare_partials(of='dx_accel', wrt='w', 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') @@ -312,8 +312,8 @@ def setup(self): 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='u', rows=ar, cols=ar) + self.declare_partials(of='dy_accel', wrt='w', 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') @@ -322,8 +322,8 @@ def setup(self): 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='v', rows=ar, cols=ar) + self.declare_partials(of='dz_accel', wrt='u', 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') @@ -337,8 +337,8 @@ def setup(self): 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='roll_accel', wrt='lx', rows=ar, cols=ar) + self.declare_partials(of='roll_accel', wrt='lz', rows=ar, cols=ar) self.declare_partials(of='pitch_accel', wrt='J_xz') self.declare_partials(of='pitch_accel', wrt='J_xx') @@ -346,7 +346,7 @@ def setup(self): 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='pitch_accel', wrt='ly', rows=ar, cols=ar) self.declare_partials(of='yaw_accel', wrt='J_xz') self.declare_partials(of='yaw_accel', wrt='J_xx') @@ -355,8 +355,8 @@ def setup(self): 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='yaw_accel', wrt='lx', rows=ar, cols=ar) + self.declare_partials(of='yaw_accel', wrt='lz', 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) @@ -373,23 +373,23 @@ def setup(self): 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='u', rows=ar, cols=ar) + self.declare_partials(of='dx_dt', wrt='v', rows=ar, cols=ar) + self.declare_partials(of='dx_dt', wrt='w', 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='u', rows=ar, cols=ar) + self.declare_partials(of='dy_dt', wrt='v', rows=ar, cols=ar) + self.declare_partials(of='dy_dt', wrt='w', 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='u', rows=ar, cols=ar) + self.declare_partials(of='dz_dt', wrt='v', rows=ar, cols=ar) + self.declare_partials(of='dz_dt', wrt='w', 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) @@ -406,9 +406,9 @@ def compute(self, inputs, outputs): # inputs mass = inputs['mass'] - axial_vel = inputs['axial_vel'] # u - lat_vel = inputs['lat_vel'] # v - vert_vel = inputs['vert_vel'] # w + u = inputs['u'] # u + v = inputs['v'] # v + w = inputs['w'] # 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 @@ -423,9 +423,9 @@ def compute(self, inputs, outputs): 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 + lx = inputs['lx'] # l + ly = inputs['ly'] # m + lz = inputs['lz'] # n J_xz = inputs['J_xz'] J_xx = inputs['J_xx'] J_yy = inputs['J_yy'] @@ -443,34 +443,34 @@ def compute(self, inputs, outputs): # roll-axis velocity equation - dx_accel = 1 / mass * Fx + gx_b - vert_vel * pitch_ang_vel + lat_vel * yaw_ang_vel + dx_accel = 1 / mass * Fx + gx_b - w * pitch_ang_vel + v * yaw_ang_vel # pitch-axis velocity equation - dy_accel = 1 / mass * Fy + gy_b - axial_vel * yaw_ang_vel + vert_vel * roll_ang_vel + dy_accel = 1 / mass * Fy + gy_b - u * yaw_ang_vel + w * roll_ang_vel # yaw-axis velocity equation - dz_accel = 1 / mass * Fz + gz_b - lat_vel * roll_ang_vel + axial_vel * pitch_ang_vel + dz_accel = 1 / mass * Fz + gz_b - v * roll_ang_vel + u * 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 + J_zz * lx + + J_xz * lz) / 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 + J_xz * (roll_ang_vel**2 - yaw_ang_vel**2) + ly) / 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 + J_xz * lx + + J_xz * lz) / Den # Kinematic equations @@ -484,17 +484,17 @@ def compute(self, inputs, outputs): # 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 + dx_dt = np.cos(pitch) * np.cos(yaw) * u + \ + (-np.cos(roll) * np.sin(yaw) + np.sin(roll) * np.sin(pitch) * np.cos(yaw)) * v + \ + (np.sin(roll) * np.sin(yaw) + np.cos(roll) * np.sin(pitch) * np.cos(yaw)) * w - 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 + dy_dt = np.cos(pitch) * np.sin(yaw) * u + \ + (np.cos(roll) * np.cos(yaw) + np.sin(roll) * np.sin(pitch) * np.sin(yaw)) * v + \ + (-np.sin(roll) * np.cos(yaw) + np.cos(roll) * np.sin(pitch) * np.sin(yaw)) * w - dz_dt = -np.sin(pitch) * axial_vel + \ - np.sin(roll) * np.cos(pitch) * lat_vel + \ - np.cos(roll) * np.cos(pitch) * vert_vel + dz_dt = -np.sin(pitch) * u + \ + np.sin(roll) * np.cos(pitch) * v + \ + np.cos(roll) * np.cos(pitch) * w outputs['dx_accel'] = dx_accel outputs['dy_accel'] = dy_accel @@ -512,9 +512,9 @@ def compute(self, inputs, outputs): 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 + u = inputs['u'] # u + v = inputs['v'] # v + w = inputs['w'] # 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 @@ -529,9 +529,9 @@ def compute_partials(self, inputs, J): 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 + lx = inputs['lx'] # l + ly = inputs['ly'] # m + lz = inputs['lz'] # n J_xz = inputs['J_xz'] J_xx = inputs['J_xx'] J_yy = inputs['J_yy'] @@ -542,91 +542,91 @@ def compute_partials(self, inputs, J): 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', 'v'] = yaw_ang_vel + J['dx_accel', 'w'] = -pitch_ang_vel + J['dx_accel', 'yaw_ang_vel'] = v + J['dx_accel', 'pitch_ang_vel'] = -w 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', 'u'] = -yaw_ang_vel + J['dy_accel', 'w'] = roll_ang_vel + J['dy_accel', 'yaw_ang_vel'] = -u + J['dy_accel', 'roll_ang_vel'] = w 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', 'v'] = -roll_ang_vel + J['dz_accel', 'u'] = pitch_ang_vel + J['dz_accel', 'roll_ang_vel'] = -v + J['dz_accel', 'pitch_ang_vel'] = u 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_xx - J_yy + J_zz) * roll_ang_vel * pitch_ang_vel - 2 * J_xz * pitch_ang_vel * yaw_ang_vel + lz) - ( 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_zz * lx + + J_xz * lz) * -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_zz * lx + + J_xz * lz) * 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 * roll_ang_vel * pitch_ang_vel - 2 * J_zz * pitch_ang_vel * yaw_ang_vel + J_yy * pitch_ang_vel * yaw_ang_vel + lx ) - (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_zz * lx + + J_xz * lz) * 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['roll_accel', 'lx'] = J_zz / Den + J['roll_accel', 'lz'] = 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_xz * (roll_ang_vel**2 - yaw_ang_vel**2) + ly) / 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['pitch_accel', 'ly'] = 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 + 2 * J_xz * roll_ang_vel * pitch_ang_vel + (J_xx - J_yy + J_zz) * pitch_ang_vel * yaw_ang_vel + lx + lz ) - ((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_xz * lx + + J_xz * lz) * -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_xz * lx + + J_xz * lz) * 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_xz * lx + + J_xz * lz) * 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['yaw_accel', 'lx'] = J_xz / Den + J['yaw_accel', 'lz'] = 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) @@ -646,38 +646,38 @@ def compute_partials(self, inputs, J): # 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['dx_dt', 'u'] = np.cos(pitch) * np.cos(yaw) + J['dx_dt', 'v'] = -np.cos(roll) * np.sin(yaw) + np.sin(roll) * np.sin(pitch) * np.cos(yaw) + J['dx_dt', 'w'] = 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)) * v + \ + (np.cos(roll) * np.sin(yaw) - np.sin(roll) * np.sin(pitch) * np.cos(yaw)) * w + J['dx_dt', 'pitch'] = -np.sin(pitch) * np.cos(yaw) * u + \ + np.sin(roll) * np.cos(pitch) * np.cos(yaw) * v + \ + np.cos(roll) * np.cos(pitch) * np.cos(yaw) * w + J['dx_dt', 'yaw'] = -np.cos(pitch) * np.sin(yaw) * u + \ + (-np.cos(roll) * np.cos(yaw) - np.sin(roll) * np.sin(pitch) * np.sin(yaw)) * v + \ + (np.sin(roll) * np.cos(yaw) - np.cos(roll) * np.sin(pitch) * np.sin(yaw)) * w - 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['dy_dt', 'u'] = np.cos(pitch) * np.sin(yaw) + J['dy_dt', 'v'] = np.cos(roll) * np.cos(yaw) + np.sin(roll) * np.sin(pitch) * np.sin(yaw) + J['dy_dt', 'w'] = -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)) * v + \ + (-np.cos(roll) * np.cos(yaw) - np.sin(roll) * np.sin(pitch) * np.sin(yaw)) * w + J['dy_dt', 'pitch'] = -np.sin(pitch) * np.sin(yaw) * u + \ + np.sin(roll) * np.cos(pitch) * np.sin(yaw) * v + \ + np.cos(roll) * np.cos(pitch) * np.sin(yaw) * w + J['dy_dt', 'yaw'] = np.cos(pitch) * np.cos(yaw) * u + \ + (-np.cos(roll) * np.sin(yaw) + np.sin(roll) * np.sin(pitch) * np.cos(yaw)) * v + \ + (np.sin(roll) * np.sin(yaw) + np.cos(roll) * np.sin(pitch) * np.cos(yaw)) * w - 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 + J['dz_dt', 'u'] = -np.sin(pitch) + J['dz_dt', 'v'] = np.sin(roll) * np.cos(pitch) + J['dz_dt', 'w'] = np.cos(roll) * np.cos(pitch) + J['dz_dt', 'roll'] = np.cos(roll) * np.cos(pitch) * v - \ + np.sin(roll) * np.cos(pitch) * w + J['dz_dt', 'pitch'] = -np.cos(pitch) * u - \ + np.sin(roll) * np.sin(pitch) * v - \ + np.cos(roll) * np.sin(pitch) * w @@ -690,9 +690,9 @@ def compute_partials(self, inputs, J): 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('u', 0.1, units='m/s') + des_vars.add_output('v', 0.7, units='m/s') + des_vars.add_output('w', 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') @@ -703,9 +703,9 @@ def compute_partials(self, inputs, J): 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('lx', 3.0, units='N*m') + des_vars.add_output('ly', 4.0, units='N*m') + des_vars.add_output('lz', 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') diff --git a/aviary/mission/sixdof/six_dof_ODE.py b/aviary/mission/sixdof/six_dof_ODE.py index 4658dd12f..a3e12f60e 100644 --- a/aviary/mission/sixdof/six_dof_ODE.py +++ b/aviary/mission/sixdof/six_dof_ODE.py @@ -23,17 +23,17 @@ def setup(self): self.add_subsystem( 'true_airspeed_comp', subsys=om.ExecComp( - 'true_airspeed = (axial_vel**2 + lat_vel**2 + vert_vel**2)**0.5', + 'true_airspeed = (u**2 + v**2 + w**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,)}, + u = {'units': 'm/s', 'shape': (nn,)}, + v = {'units': 'm/s', 'shape': (nn,)}, + w = {'units': 'm/s', 'shape': (nn,)}, has_diag_partials=True ), promotes_inputs=[ - 'axial_vel', - 'lat_vel', - 'vert_vel', + 'u', + 'v', + 'w', ], promotes_outputs=[ 'true_airspeed' @@ -48,7 +48,9 @@ def setup(self): promotes=['*'] ) - T_vert_comp = om.ExecComp( + self.add_subsystem( + 'thrust_comp', + subsys=om.ExecComp( 'T_z = cos(roll) * cos(pitch) * mass * g', roll = {'units': 'rad', 'shape': (nn,)}, pitch = {'units': 'rad', 'shape': (nn,)}, @@ -62,7 +64,7 @@ def setup(self): promotes_outputs=[ ('T_z', 'T_z'), ] - ) # body-relative CS + )) # body-relative CS comp = om.BalanceComp( name=Dynamic.Vehicle.Propulsion.THROTTLE, @@ -96,6 +98,8 @@ def setup(self): 'lift', 'side', 'thrust', + 'heading_angle', + Dynamic.Mission.FLIGHT_PATH_ANGLE, ], promotes_outputs=[ 'Fx', @@ -109,9 +113,9 @@ def setup(self): SixDOF_EOM(num_nodes=nn), promotes_inputs=[ 'mass', - 'axial_vel', - 'lat_vel', - 'vert_vel', + 'u', + 'v', + 'w', 'roll_ang_vel', 'pitch_ang_vel', 'yaw_ang_vel', @@ -119,12 +123,12 @@ def setup(self): 'pitch', 'yaw', 'g', - 'Fx_ext', - 'Fy_ext', - 'Fz_ext', - 'lx_ext', - 'ly_ext', - 'lz_ext', + 'Fx', + 'Fy', + 'Fz', + 'lx', + 'ly', + 'lz', 'J_xz', 'J_xx', 'J_yy', From 6fbe7307bc358e209ed88318113fd3eb5c723e4f Mon Sep 17 00:00:00 2001 From: Seth Zoppelt Date: Fri, 11 Jul 2025 16:11:53 +0000 Subject: [PATCH 094/103] Updates and unittest draft added. --- aviary/mission/sixdof/six_dof_EOM.py | 2 - .../mission/sixdof/test/test_six_dof_ODE.py | 24 +++++++++++ aviary/subsystems/mass/simple_mass/tail.py | 41 ++++++++++++------- .../simple_mass/test/test_mass_summation.py | 4 +- .../mass/simple_mass/test/test_tail.py | 4 +- .../mass/simple_mass/test/test_wing.py | 4 +- aviary/subsystems/mass/simple_mass/wing.py | 25 ++++++----- 7 files changed, 71 insertions(+), 33 deletions(-) create mode 100644 aviary/mission/sixdof/test/test_six_dof_ODE.py diff --git a/aviary/mission/sixdof/six_dof_EOM.py b/aviary/mission/sixdof/six_dof_EOM.py index b725b65cf..55e8adc25 100644 --- a/aviary/mission/sixdof/six_dof_EOM.py +++ b/aviary/mission/sixdof/six_dof_EOM.py @@ -11,8 +11,6 @@ class SixDOF_EOM(om.ExplicitComponent): - (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 """ diff --git a/aviary/mission/sixdof/test/test_six_dof_ODE.py b/aviary/mission/sixdof/test/test_six_dof_ODE.py new file mode 100644 index 000000000..c0eecf290 --- /dev/null +++ b/aviary/mission/sixdof/test/test_six_dof_ODE.py @@ -0,0 +1,24 @@ +import unittest +import openmdao.api as om +import numpy as np + +from openmdao.utils.assert_utils import assert_check_partials, assert_near_equal + +from aviary.mission.sixdof.six_dof_ODE import SixDOF_ODE +from aviary.variable_info.variables import Aircraft, Dynamic + + +class SixDOFODETestCase(unittest.TestCase): + """ + Test 6-degree of freedom ODE. + + """ + + def setUp(self): + self.prob = om.Problem() + + self.sys = self.prob.model = SixDOF_ODE( + num_nodes=1, + + ) + diff --git a/aviary/subsystems/mass/simple_mass/tail.py b/aviary/subsystems/mass/simple_mass/tail.py index f9bac747e..e60bf676f 100644 --- a/aviary/subsystems/mass/simple_mass/tail.py +++ b/aviary/subsystems/mass/simple_mass/tail.py @@ -107,6 +107,12 @@ def setup(self): Aircraft.VerticalTail.MASS, units='kg', desc="Total mass of the tail") + + def get_self_statics(self): + return (self.options['tail_type'], + self.options['material'], + self.options['num_sections'], + self.options['NACA_digits']) def compute_primal(self, aircraft__horizontal_tail__span, @@ -146,7 +152,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 @@ -169,22 +175,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_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 = 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 - ) - - 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 @@ -246,7 +257,7 @@ 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 if __name__ == "__main__": prob = om.Problem() 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..2e0972244 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 ) diff --git a/aviary/subsystems/mass/simple_mass/test/test_tail.py b/aviary/subsystems/mass/simple_mass/test/test_tail.py index 2b8eb3bd9..cc6219e27 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( diff --git a/aviary/subsystems/mass/simple_mass/test/test_wing.py b/aviary/subsystems/mass/simple_mass/test/test_wing.py index 79c5d5870..af8894ae1 100644 --- a/aviary/subsystems/mass/simple_mass/test/test_wing.py +++ b/aviary/subsystems/mass/simple_mass/test/test_wing.py @@ -73,9 +73,9 @@ def test_case(self): self.prob.run_model() - tol = 1e-10 + tol = 1e-8 assert_near_equal(self.prob[Aircraft.Wing.MASS], - 4.22032, + 10.6966719, tol) partial_data = self.prob.check_partials( diff --git a/aviary/subsystems/mass/simple_mass/wing.py b/aviary/subsystems/mass/simple_mass/wing.py index 8057c995e..02e5b481b 100644 --- a/aviary/subsystems/mass/simple_mass/wing.py +++ b/aviary/subsystems/mass/simple_mass/wing.py @@ -68,7 +68,7 @@ def setup(self): # Outputs add_aviary_output(self, - Aircraft.Wing.MASS, + Aircraft.Wing.MASS, units='kg') def compute_primal(self, aircraft__wing__span, aircraft__wing__root_chord, tip_chord, twist, thickness_dist): @@ -100,14 +100,19 @@ def compute_primal(self, aircraft__wing__span, aircraft__wing__root_chord, tip_c 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) * (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 def precompute_airfoil_geometry(self): @@ -193,6 +198,6 @@ def extract_airfoil_features(self, x_coords, y_coords): # Get the results total_weight = prob.get_val(Aircraft.Wing.MASS) - print(f"Total mass of the wing: {total_weight} kg") + print(f"Total mass of the wing: {total_weight} kg, shape = {jnp.shape(total_weight)}") From 07d7877559d38fe42afd2f34fee473cdb25cdcde Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 21 Aug 2025 12:14:51 -0500 Subject: [PATCH 095/103] Delete aviary/subsystems/mass/simple_mass directory --- .../subsystems/mass/simple_mass/Clark_Y.dat | 122 ------ .../mass/simple_mass/Custom_Fuselage.dat | 179 -------- .../subsystems/mass/simple_mass/__init__.py | 1 - .../mass/simple_mass/airfoil_data_test.dat | 124 ------ .../subsystems/mass/simple_mass/fuselage.py | 193 --------- .../mass/simple_mass/mass_builder.py | 34 -- .../mass/simple_mass/mass_premission.py | 31 -- .../mass/simple_mass/mass_summation.py | 97 ----- .../mass/simple_mass/materials_database.py | 68 --- .../mass/simple_mass/six_dof_EOM.py | 405 ------------------ aviary/subsystems/mass/simple_mass/tail.py | 292 ------------- .../mass/simple_mass/test/__init__.py | 0 .../subsystems/mass/simple_mass/test/test.py | 3 - .../mass/simple_mass/test/test_fuselage.py | 89 ---- .../simple_mass/test/test_mass_subsystem.py | 77 ---- .../simple_mass/test/test_mass_summation.py | 254 ----------- .../mass/simple_mass/test/test_tail.py | 106 ----- .../mass/simple_mass/test/test_wing.py | 90 ---- aviary/subsystems/mass/simple_mass/wing.py | 203 --------- 19 files changed, 2368 deletions(-) delete mode 100644 aviary/subsystems/mass/simple_mass/Clark_Y.dat delete mode 100644 aviary/subsystems/mass/simple_mass/Custom_Fuselage.dat delete mode 100644 aviary/subsystems/mass/simple_mass/__init__.py delete mode 100644 aviary/subsystems/mass/simple_mass/airfoil_data_test.dat delete mode 100644 aviary/subsystems/mass/simple_mass/fuselage.py delete mode 100644 aviary/subsystems/mass/simple_mass/mass_builder.py delete mode 100644 aviary/subsystems/mass/simple_mass/mass_premission.py delete mode 100644 aviary/subsystems/mass/simple_mass/mass_summation.py delete mode 100644 aviary/subsystems/mass/simple_mass/materials_database.py delete mode 100644 aviary/subsystems/mass/simple_mass/six_dof_EOM.py delete mode 100644 aviary/subsystems/mass/simple_mass/tail.py delete mode 100644 aviary/subsystems/mass/simple_mass/test/__init__.py delete mode 100644 aviary/subsystems/mass/simple_mass/test/test.py delete mode 100644 aviary/subsystems/mass/simple_mass/test/test_fuselage.py delete mode 100644 aviary/subsystems/mass/simple_mass/test/test_mass_subsystem.py delete mode 100644 aviary/subsystems/mass/simple_mass/test/test_mass_summation.py delete mode 100644 aviary/subsystems/mass/simple_mass/test/test_tail.py delete mode 100644 aviary/subsystems/mass/simple_mass/test/test_wing.py delete mode 100644 aviary/subsystems/mass/simple_mass/wing.py 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 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 - diff --git a/aviary/subsystems/mass/simple_mass/__init__.py b/aviary/subsystems/mass/simple_mass/__init__.py deleted file mode 100644 index 8b1378917..000000000 --- a/aviary/subsystems/mass/simple_mass/__init__.py +++ /dev/null @@ -1 +0,0 @@ - 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 diff --git a/aviary/subsystems/mass/simple_mass/fuselage.py b/aviary/subsystems/mass/simple_mass/fuselage.py deleted file mode 100644 index 94fad1c5f..000000000 --- a/aviary/subsystems/mass/simple_mass/fuselage.py +++ /dev/null @@ -1,193 +0,0 @@ -import openmdao.api as om -import numpy as np -from scipy.interpolate import interp1d - -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'." - ) - -from aviary.subsystems.mass.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=10) - - self.options.declare('material', - default='Aluminum Oxide', - values=list(get_keys(materials))) - - self.options.declare('custom_fuselage_data_file', - types=(str, type(None)), - default=None, - allow_none=True) - - self.custom_fuselage_function = None - - 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 - - # 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') - - 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.") - - 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 - - custom_fuselage_data_file = self.options['custom_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_item(material) - - 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 ValueError("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.") - - 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 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 - - 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 - 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 - - -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") - diff --git a/aviary/subsystems/mass/simple_mass/mass_builder.py b/aviary/subsystems/mass/simple_mass/mass_builder.py deleted file mode 100644 index 9231bada3..000000000 --- a/aviary/subsystems/mass/simple_mass/mass_builder.py +++ /dev/null @@ -1,34 +0,0 @@ -from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase -from aviary.subsystems.mass.simple_mass.mass_premission import MassPremission - - -""" - -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. - -""" - -_default_name = 'simple_mass' - -class MassBuilderBase(SubsystemBuilderBase): - """ - Base mass builder - - """ - - def __init__(self, name=None): - 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 deleted file mode 100644 index fa29c81a4..000000000 --- a/aviary/subsystems/mass/simple_mass/mass_premission.py +++ /dev/null @@ -1,31 +0,0 @@ -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 - -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(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 deleted file mode 100644 index 67a499ec5..000000000 --- a/aviary/subsystems/mass/simple_mass/mass_summation.py +++ /dev/null @@ -1,97 +0,0 @@ -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.variable_info.functions import add_aviary_input - - -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=[Aircraft.Fuselage.MASS] - ) - - self.add_subsystem( - 'wing_mass', - WingMassAndCOG(), - promotes_inputs=['*'], - promotes_outputs=[Aircraft.Wing.MASS] - ) - - self.add_subsystem( - 'tail_mass', - TailMassAndCOG(), - 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") - - 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') - - # 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): - - 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/materials_database.py b/aviary/subsystems/mass/simple_mass/materials_database.py deleted file mode 100644 index fc8bba94c..000000000 --- a/aviary/subsystems/mass/simple_mass/materials_database.py +++ /dev/null @@ -1,68 +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 -from aviary.utils.named_values import get_keys, get_values, get_items - -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('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. - -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/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 diff --git a/aviary/subsystems/mass/simple_mass/tail.py b/aviary/subsystems/mass/simple_mass/tail.py deleted file mode 100644 index e60bf676f..000000000 --- a/aviary/subsystems/mass/simple_mass/tail.py +++ /dev/null @@ -1,292 +0,0 @@ -import openmdao.api as om -import openmdao.jax as omj -import jax.numpy as jnp -import numpy as np -from scipy.interpolate import CubicSpline -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 -except ImportError: - raise ImportError( - "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 TailMassAndCOG(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") - - 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) - - # 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") - - # 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") - - # 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") - - def get_self_statics(self): - return (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_item(material) - airfoil_file = self.options['airfoil_file'] - 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. - # 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 - - # 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': - 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() - - # 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): - 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 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) - - 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):] - - 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 - -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") \ No newline at end of file diff --git a/aviary/subsystems/mass/simple_mass/test/__init__.py b/aviary/subsystems/mass/simple_mass/test/__init__.py deleted file mode 100644 index e69de29bb..000000000 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())) - diff --git a/aviary/subsystems/mass/simple_mass/test/test_fuselage.py b/aviary/subsystems/mass/simple_mass/test/test_fuselage.py deleted file mode 100644 index 145e1f679..000000000 --- a/aviary/subsystems/mass/simple_mass/test/test_fuselage.py +++ /dev/null @@ -1,89 +0,0 @@ -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 -from aviary.variable_info.variables import Aircraft - -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( - 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( - "tip_diameter", - val=0.3 - ) - - 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, - 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() \ 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 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') diff --git a/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py b/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py deleted file mode 100644 index 2e0972244..000000000 --- a/aviary/subsystems/mass/simple_mass/test/test_mass_summation.py +++ /dev/null @@ -1,254 +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 - -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. - - """ - - def test_case(self): - self.prob = om.Problem() - - self.prob.model.add_subsystem( - 'tot', - MassSummation(), - 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.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.run_model() - - #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 - ) - else: - assert_near_equal( - self.prob['structure_mass'], - 355.18828485, - 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(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() - - 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 - ) - - 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 deleted file mode 100644 index cc6219e27..000000000 --- a/aviary/subsystems/mass/simple_mass/test/test_tail.py +++ /dev/null @@ -1,106 +0,0 @@ -import unittest - -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.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( - "Tail", - TailMassAndCOG(), - 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.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", - 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_tail", - val=np.zeros(10), - units="deg" - ) - - 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) - 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__": - unittest.main() \ No newline at end of file diff --git a/aviary/subsystems/mass/simple_mass/test/test_wing.py b/aviary/subsystems/mass/simple_mass/test/test_wing.py deleted file mode 100644 index af8894ae1..000000000 --- a/aviary/subsystems/mass/simple_mass/test/test_wing.py +++ /dev/null @@ -1,90 +0,0 @@ -import unittest - -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. - - """ - - def setUp(self): - - self.prob = om.Problem() - self.prob.model.add_subsystem( - "wing_mass", - WingMassAndCOG(), - 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.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( - check=False, - force_alloc_complex=True - ) - - def test_case(self): - - self.prob.run_model() - - tol = 1e-8 - 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() \ No newline at end of file diff --git a/aviary/subsystems/mass/simple_mass/wing.py b/aviary/subsystems/mass/simple_mass/wing.py deleted file mode 100644 index 02e5b481b..000000000 --- a/aviary/subsystems/mass/simple_mass/wing.py +++ /dev/null @@ -1,203 +0,0 @@ -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.utils.functions import add_aviary_input, add_aviary_output - -try: - from quadax import quadgk -except ImportError: - raise ImportError( - "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 WingMassAndCOG(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 - - def setup(self): - 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 - - - # Outputs - add_aviary_output(self, - Aircraft.Wing.MASS, - units='kg') - - 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_item(material) # in 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 - 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 = 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 - -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, shape = {jnp.shape(total_weight)}") - - From e38f3a81afed250470ac32a94c3968d2e585e00c Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 21 Aug 2025 12:15:37 -0500 Subject: [PATCH 096/103] Delete aviary/mission/sixdof/plottest.py --- aviary/mission/sixdof/plottest.py | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 aviary/mission/sixdof/plottest.py 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 From 235fc708fc713dafeb77230241ecd0d6367b2fce Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 21 Aug 2025 12:16:01 -0500 Subject: [PATCH 097/103] Delete aviary/mission/sixdof/test_mission_6dof.py --- aviary/mission/sixdof/test_mission_6dof.py | 186 --------------------- 1 file changed, 186 deletions(-) delete mode 100644 aviary/mission/sixdof/test_mission_6dof.py 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 5d0a06954503dc8a2d51f639223e95749267134d Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 21 Aug 2025 12:17:41 -0500 Subject: [PATCH 098/103] 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 fcdc5751832682f8bea73f760c37b9e60a5af335 Mon Sep 17 00:00:00 2001 From: szoppelt <145373267+szoppelt@users.noreply.github.com> Date: Thu, 21 Aug 2025 12:17:54 -0500 Subject: [PATCH 099/103] 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 9c405ff3842e3c0186fc427c5bb9ef2d62ac7cd9 Mon Sep 17 00:00:00 2001 From: Seth Zoppelt Date: Wed, 27 Aug 2025 19:06:15 +0000 Subject: [PATCH 100/103] Updating thrust to allow for all x,y,z directions. Still updating. --- aviary/mission/sixdof/force_component_calc.py | 139 ++++++++++++++++-- 1 file changed, 123 insertions(+), 16 deletions(-) diff --git a/aviary/mission/sixdof/force_component_calc.py b/aviary/mission/sixdof/force_component_calc.py index 78a955b53..115889f70 100644 --- a/aviary/mission/sixdof/force_component_calc.py +++ b/aviary/mission/sixdof/force_component_calc.py @@ -81,12 +81,27 @@ def setup(self): 'heading_angle', val=np.zeros(nn), units='rad', - desc='Heading angle' + desc='Heading angle in body' ) add_aviary_input(self, Dynamic.Mission.FLIGHT_PATH_ANGLE, - units='rad') + units='rad', + desc="Flight path angle in body") + + self.add_input( + 'heading_angle_NED', + val=np.zeros(nn), + units='rad', + desc="Thrust heading angle in NED" + ) + + self.add_input( + 'fpa_NED', + val=np.zeros(nn), + units='rad', + desc="Thrust flight path angle in NED" + ) # self.add_input( # 'true_air_speed', @@ -129,6 +144,8 @@ def setup(self): self.declare_partials(of='Fx', wrt='thrust', rows=ar, cols=ar) self.declare_partials(of='Fx', wrt='heading_angle', rows=ar, cols=ar) self.declare_partials(of='Fx', wrt=Dynamic.Mission.FLIGHT_PATH_ANGLE, rows=ar, cols=ar) + self.declare_partials(of='Fx', wrt='heading_angle_NED', rows=ar, cols=ar) + self.declare_partials(of='Fx', wrt='fpa_NED', 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) @@ -139,6 +156,8 @@ def setup(self): self.declare_partials(of='Fy', wrt='thrust', rows=ar, cols=ar) self.declare_partials(of='Fy', wrt='heading_angle', rows=ar, cols=ar) self.declare_partials(of='Fy', wrt=Dynamic.Mission.FLIGHT_PATH_ANGLE, rows=ar, cols=ar) + self.declare_partials(of='Fy', wrt='heading_angle_NED', rows=ar, cols=ar) + self.declare_partials(of='Fy', wrt='fpa_NED', 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) @@ -149,6 +168,8 @@ def setup(self): self.declare_partials(of='Fz', wrt='thrust', rows=ar, cols=ar) self.declare_partials(of='Fz', wrt='heading_angle', rows=ar, cols=ar) self.declare_partials(of='Fz', wrt=Dynamic.Mission.FLIGHT_PATH_ANGLE, rows=ar, cols=ar) + self.declare_partials(of='Fz', wrt='heading_angle_NED', rows=ar, cols=ar) + self.declare_partials(of='Fz', wrt='fpa_NED', rows=ar, cols=ar) def compute(self, inputs, outputs): @@ -161,6 +182,8 @@ def compute(self, inputs, outputs): S = inputs['side'] # side force -- assume 0 for now chi = inputs['heading_angle'] gamma = inputs[Dynamic.Mission.FLIGHT_PATH_ANGLE] + chi_T = inputs['heading_angle_NED'] + gamma_T = inputs['fpa_NED'] nn = self.options['num_nodes'] @@ -195,13 +218,49 @@ def compute(self, inputs, outputs): cos_b = np.cos(beta) sin_a = np.sin(alpha) sin_b = np.sin(beta) + cos_g = np.cos(gamma) + sin_g = np.sin(gamma) + cos_c = np.cos(chi) + sin_c = np.sin(chi) + + # Thrust direction in NED -- as \hat{t}_n + + t_hat_n = np.array([ + np.cos(gamma_T) * np.cos(chi_T), + np.cos(gamma_T) * np.sin(chi_T), + -np.sin(gamma_T) + ]) + + # C_{b- Date: Thu, 28 Aug 2025 17:06:56 +0000 Subject: [PATCH 101/103] More updates to force_component_calc --- aviary/mission/sixdof/force_component_calc.py | 44 +++++++++++-------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/aviary/mission/sixdof/force_component_calc.py b/aviary/mission/sixdof/force_component_calc.py index 115889f70..8599d2d85 100644 --- a/aviary/mission/sixdof/force_component_calc.py +++ b/aviary/mission/sixdof/force_component_calc.py @@ -226,9 +226,9 @@ def compute(self, inputs, outputs): # Thrust direction in NED -- as \hat{t}_n t_hat_n = np.array([ - np.cos(gamma_T) * np.cos(chi_T), - np.cos(gamma_T) * np.sin(chi_T), - -np.sin(gamma_T) + [np.cos(gamma_T) * np.cos(chi_T)], + [np.cos(gamma_T) * np.sin(chi_T)], + [-np.sin(gamma_T)] ]) # C_{b- Date: Thu, 4 Sep 2025 17:32:08 +0000 Subject: [PATCH 102/103] Updates to derivatives for force_component_calc. --- aviary/mission/sixdof/force_component_calc.py | 123 ++++++++++++------ 1 file changed, 83 insertions(+), 40 deletions(-) diff --git a/aviary/mission/sixdof/force_component_calc.py b/aviary/mission/sixdof/force_component_calc.py index 8599d2d85..e2ec623ec 100644 --- a/aviary/mission/sixdof/force_component_calc.py +++ b/aviary/mission/sixdof/force_component_calc.py @@ -225,25 +225,39 @@ def compute(self, inputs, outputs): # Thrust direction in NED -- as \hat{t}_n - t_hat_n = np.array([ - [np.cos(gamma_T) * np.cos(chi_T)], - [np.cos(gamma_T) * np.sin(chi_T)], - [-np.sin(gamma_T)] - ]) + t_hat_n = [ + np.cos(gamma_T) * np.cos(chi_T), + np.cos(gamma_T) * np.sin(chi_T), + -np.sin(gamma_T) + ] + + t_hat_n = np.array(t_hat_n) + t_hat_n = t_hat_n.reshape((3, 1)) # C_{b- Date: Thu, 11 Sep 2025 18:45:36 +0000 Subject: [PATCH 103/103] Updating force_component_calc derivatives. --- aviary/mission/sixdof/force_component_calc.py | 48 ++++++++++++++----- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/aviary/mission/sixdof/force_component_calc.py b/aviary/mission/sixdof/force_component_calc.py index e2ec623ec..9fe759467 100644 --- a/aviary/mission/sixdof/force_component_calc.py +++ b/aviary/mission/sixdof/force_component_calc.py @@ -379,16 +379,18 @@ def compute_partials(self, inputs, J): (np.sin(gamma_T) * sin_b * np.sin(alpha - gamma) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) - np.sin(gamma_T) * cos_b * np.cos(alpha - gamma) * (-w / (w**2 + u**2)))) 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 + T * ( - (-np.cos(gamma_T) * np.cos(chi_T) * sin_b * sin_c * (np.sqrt(w**2 + u**2) / V**2) - np.cos(gamma_T) * np.cos(chi_T) * cos_b * cos_c * np.cos(alpha - gamma) * (np.sqrt(w**2 + u**2) / V**2)) + - (np.cos(gamma_T) * np.sin(chi_T) * sin_b * cos_c * (np.sqrt(w**2 + u**2) / V**2) - np.cos(gamma_T) * np.sin(chi_T) * cos_b * sin_c * np.cos(alpha - gamma) * (np.sqrt(w**2 + u**2) / V**2)) - - (np.sin(gamma_T) * cos_b * np.sin(alpha - gamma) * (np.sqrt(w**2 + u**2) / V**2)) + (-np.cos(gamma_T) * np.cos(chi_T) * cos_b * sin_c * (np.sqrt(w**2 + u**2) / V**2) + np.cos(gamma_T) * np.cos(chi_T) * sin_b * cos_c * np.cos(alpha - gamma) * (np.sqrt(w**2 + u**2) / V**2)) + + (np.cos(gamma_T) * np.sin(chi_T) * cos_b * cos_c * (np.sqrt(w**2 + u**2) / V**2) + np.cos(gamma_T) * np.sin(chi_T) * sin_b * sin_c * np.cos(alpha - gamma) * (np.sqrt(w**2 + u**2) / V**2)) + + (np.sin(gamma_T) * sin_b * np.sin(alpha - gamma) * (np.sqrt(w**2 + u**2) / V**2)) ) 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 + T * ( - (np.cos(gamma_T) * np.cos(chi_T) * cos_c * np.cos(alpha - gamma) * (u / (w**2 + u**2))) + - (np.cos(gamma_T) * np.sin(chi_T) * sin_c * np.cos(alpha - gamma) * (u / (w**2 + u**2))) + - (np.sin(gamma_T) * np.sin(alpha - gamma) * (u / (w**2 + u**2))) + (-np.cos(gamma_T) * np.cos(chi_T) * cos_b * sin_c * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) + np.cos(gamma_T) * np.cos(chi_T) * cos_b * cos_c * np.sin(alpha - gamma) * (u / (w**2 + u**2)) + + np.cos(gamma_T) * np.cos(chi_T) * sin_b * cos_c * np.cos(alpha - gamma) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2))))) + + (np.cos(gamma_T) * np.sin(chi_T) * cos_b * cos_c * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) + np.cos(gamma_T) * np.sin(chi_T) * cos_b * sin_c * np.sin(alpha - gamma) * (u / (w**2 + u**2)) + + np.cos(gamma_T) * np.sin(chi_T) * sin_b * sin_c * np.cos(alpha - gamma) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2))))) + + (-np.sin(gamma_T) * cos_b * np.cos(alpha - gamma) * (u / (w**2 + u**2)) + np.sin(gamma_T) * sin_b * np.sin(alpha - gamma) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2))))) ) J['Fx', 'drag'] = -np.cos(alpha) * np.cos(beta) J['Fx', 'lift'] = np.sin(alpha) @@ -402,13 +404,29 @@ def compute_partials(self, inputs, J): J['Fx', 'fpa_NED'] = T * dt_b_dgamma[0] 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 - \ - np.cos(beta) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * T * np.sin(alpha - gamma) - \ - np.cos(alpha - gamma) * (-w / (w**2 + u**2)) * T * np.sin(beta) + T * np.cos(gamma_T) * np.cos(chi_T) * sin_b * sin_c * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) - \ + np.cos(gamma_T) * np.cos(chi_T) * np.cos(beta) * cos_c * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * T * np.cos(alpha - gamma) + \ + np.sin(alpha - gamma) * cos_c * (-w / (w**2 + u**2)) * T * np.sin(beta) * np.cos(gamma_T) * np.cos(chi_T) + \ + sin_b * cos_c * np.cos(gamma_T) * np.sin(chi_T) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * T - \ + np.cos(gamma_T) * np.sin(chi_T) * cos_b * sin_c * np.cos(alpha - gamma) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * T + \ + np.cos(gamma_T) * np.sin(chi_T) * sin_b * sin_c * np.sin(alpha - gamma) * (-w / (w**2 + u**2)) * T - \ + np.sin(gamma_T) * cos_b * np.sin(alpha - gamma) * ((-v * u) / ((V**2 * np.sqrt(w**2 + u**2)))) * T - \ + np.sin(gamma_T) * sin_b * np.cos(alpha - gamma) * (-w / (w**2 + u**2)) * T 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 - \ - np.cos(beta) * (np.sqrt(w**2 + u**2) / V**2) * T * np.sin(alpha - gamma) + np.cos(gamma_T) * np.cos(chi_T) * sin_b * sin_c * (np.sqrt(w**2 + u**2) / V**2) * T - \ + np.cos(gamma_T) * np.cos(chi_T) * cos_b * cos_c * np.cos(alpha - gamma) * (np.sqrt(w**2 + u**2) / V**2) * T + \ + np.cos(gamma_T) * np.sin(chi_T) * sin_b * cos_c * (np.sqrt(w**2 + u**2) / V**2) * T - \ + np.cos(gamma_T) * np.sin(chi_T) * np.cos(beta) * sin_c * (np.sqrt(w**2 + u**2) / V**2) * T * np.cos(alpha - gamma) - \ + np.sin(gamma_T) * cos_b * np.sin(alpha - gamma) * (np.sqrt(w**2 + u**2) / V**2) * T 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 - \ - np.cos(beta) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) * T * np.sin(alpha - gamma) - \ - np.cos(alpha - gamma) * (u / (w**2 + u**2)) * T * np.sin(beta) + np.cos(gamma_T) * np.cos(chi_T) * sin_b * sin_c * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) * T - \ + np.cos(gamma_T) * np.cos(chi_T) * cos_b * cos_c * np.cos(alpha - gamma) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) * T + \ + np.cos(gamma_T) * np.cos(chi_T) * sin_b * cos_c * np.sin(alpha - gamma) * (u / (w**2 + u**2)) * T + \ + np.cos(gamma_T) * np.sin(chi_T) * sin_b * cos_c * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) * T - \ + np.cos(gamma_T) * np.sin(chi_T) * cos_b * sin_c * np.cos(alpha - gamma) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) * T + \ + np.cos(gamma_T) * np.sin(chi_T) * sin_b * sin_c * np.sin(alpha - gamma) * (u / (w**2 + u**2)) * T - \ + np.sin(gamma_T) * np.cos(beta) * ((-w * v) / ((V**2 * np.sqrt(w**2 + u**2)))) * T * np.sin(alpha - gamma) - \ + np.sin(gamma_T) * np.cos(alpha - gamma) * (u / (w**2 + u**2)) * T * np.sin(beta) J['Fy', 'drag'] = -np.sin(beta) J['Fy', 'side'] = -np.cos(beta) J['Fy', 'thrust'] = t_b[1] @@ -420,11 +438,15 @@ def compute_partials(self, inputs, J): 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 + np.sin(alpha - gamma) * (-w / (w**2 + u**2)) * T + np.sin(alpha) * (-w / (w**2 + u**2)) * L + np.cos(gamma_T) * np.cos(chi_T) * cos_c * np.cos(alpha - gamma) * (-w / (w**2 + u**2)) * T + \ + np.cos(gamma_T) * np.sin(chi_T) * sin_c * np.cos(alpha - gamma) * (-w / (w**2 + u**2)) * T + \ + np.sin(gamma_T) * np.sin(alpha - gamma) * (-w / (w**2 + u**2)) * T 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 + np.sin(alpha - gamma) * (u / (w**2 + u**2)) * T + np.sin(alpha) * (u / (w**2 + u**2)) * L + np.cos(gamma_T) * np.cos(chi_T) * cos_c * np.cos(alpha - gamma) * (u / (w**2 + u**2)) * T + \ + np.cos(gamma_T) * np.sin(chi_T) * sin_c * np.cos(alpha - gamma) * (u / (w**2 + u**2)) * T + \ + np.sin(gamma_T) * np.sin(alpha - gamma) * (u / (w**2 + u**2)) * T J['Fz', 'drag'] = -np.sin(alpha) * np.cos(beta) J['Fz', 'lift'] = -np.cos(alpha) J['Fz', 'side'] = -np.sin(alpha) * np.sin(beta)