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 01/23] 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 02/23] 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 03/23] 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 04/23] 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 05/23] 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 06/23] 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 07/23] 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 08/23] 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 09/23] 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 10/23] 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 11/23] 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 12/23] 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 13/23] 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 14/23] 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 15/23] 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 16/23] 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 17/23] 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 18/23] 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 19/23] 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 20/23] 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 21/23] 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 22/23] 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 23/23] 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