Mission Optimization with Many Phases for a Commercial Aircraft#
So far within these example docs we have been building up the complexity of our coupled aircraft-mission design problem. In the simple mission example, we flew the aircraft in straight line phases. In the more advanced mission example, we allowed the optimizer to find the optimal Mach profiles for phases.
In this example, we will build on the prior examples by adding more phases to the mission. 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.
Problem Formulation#
We use the aviary draw_mission
GUI as shown below:
This results in the following phase_info
dictionary:
phase_info = {
"pre_mission": {"include_takeoff": False, "optimize_mass": True},
"climb_1": {
"subsystem_options": {"core_aerodynamics": {"method": "computed"}},
"user_options": {
"optimize_mach": False,
"optimize_altitude": False,
"polynomial_control_order": 1,
"num_segments": 3,
"order": 3,
"solve_for_distance": False,
"initial_mach": (0.2, "unitless"),
"final_mach": (0.72, "unitless"),
"mach_bounds": ((0.18, 0.74), "unitless"),
"initial_altitude": (0.0, "ft"),
"final_altitude": (31000.0, "ft"),
"altitude_bounds": ((0.0, 31500.0), "ft"),
"throttle_enforcement": "path_constraint",
"fix_initial": True,
"constrain_final": False,
"fix_duration": False,
"initial_bounds": ((0.0, 0.0), "min"),
"duration_bounds": ((25.5, 76.5), "min"),
},
"initial_guesses": {"time": ([0, 51], "min")},
},
"cruise_1": {
"subsystem_options": {"core_aerodynamics": {"method": "computed"}},
"user_options": {
"optimize_mach": False,
"optimize_altitude": False,
"polynomial_control_order": 1,
"num_segments": 3,
"order": 3,
"solve_for_distance": False,
"initial_mach": (0.72, "unitless"),
"final_mach": (0.72, "unitless"),
"mach_bounds": ((0.7, 0.74), "unitless"),
"initial_altitude": (31000.0, "ft"),
"final_altitude": (31000.0, "ft"),
"altitude_bounds": ((30500.0, 31500.0), "ft"),
"throttle_enforcement": "boundary_constraint",
"fix_initial": False,
"constrain_final": False,
"fix_duration": False,
"initial_bounds": ((25.5, 76.5), "min"),
"duration_bounds": ((23.5, 70.5), "min"),
},
"initial_guesses": {"time": ([51, 47], "min")},
},
"climb_2": {
"subsystem_options": {"core_aerodynamics": {"method": "computed"}},
"user_options": {
"optimize_mach": False,
"optimize_altitude": False,
"polynomial_control_order": 1,
"num_segments": 3,
"order": 3,
"solve_for_distance": False,
"initial_mach": (0.72, "unitless"),
"final_mach": (0.74, "unitless"),
"mach_bounds": ((0.7, 0.76), "unitless"),
"initial_altitude": (31000.0, "ft"),
"final_altitude": (33000.0, "ft"),
"altitude_bounds": ((30500.0, 33500.0), "ft"),
"throttle_enforcement": "boundary_constraint",
"fix_initial": False,
"constrain_final": False,
"fix_duration": False,
"initial_bounds": ((49.0, 147.0), "min"),
"duration_bounds": ((5.0, 15.0), "min"),
},
"initial_guesses": {"time": ([98, 10], "min")},
},
"cruise_2": {
"subsystem_options": {"core_aerodynamics": {"method": "computed"}},
"user_options": {
"optimize_mach": False,
"optimize_altitude": False,
"polynomial_control_order": 1,
"num_segments": 3,
"order": 3,
"solve_for_distance": False,
"initial_mach": (0.74, "unitless"),
"final_mach": (0.74, "unitless"),
"mach_bounds": ((0.72, 0.76), "unitless"),
"initial_altitude": (33000.0, "ft"),
"final_altitude": (33000.0, "ft"),
"altitude_bounds": ((32500.0, 33500.0), "ft"),
"throttle_enforcement": "boundary_constraint",
"fix_initial": False,
"constrain_final": False,
"fix_duration": False,
"initial_bounds": ((54.0, 162.0), "min"),
"duration_bounds": ((24.0, 72.0), "min"),
},
"initial_guesses": {"time": ([108, 48], "min")},
},
"climb_3": {
"subsystem_options": {"core_aerodynamics": {"method": "computed"}},
"user_options": {
"optimize_mach": False,
"optimize_altitude": False,
"polynomial_control_order": 1,
"num_segments": 3,
"order": 3,
"solve_for_distance": False,
"initial_mach": (0.74, "unitless"),
"final_mach": (0.76, "unitless"),
"mach_bounds": ((0.72, 0.78), "unitless"),
"initial_altitude": (33000.0, "ft"),
"final_altitude": (34500.0, "ft"),
"altitude_bounds": ((32500.0, 35000.0), "ft"),
"throttle_enforcement": "boundary_constraint",
"fix_initial": False,
"constrain_final": False,
"fix_duration": False,
"initial_bounds": ((78.0, 234.0), "min"),
"duration_bounds": ((7.0, 21.0), "min"),
},
"initial_guesses": {"time": ([156, 14], "min")},
},
"climb_4": {
"subsystem_options": {"core_aerodynamics": {"method": "computed"}},
"user_options": {
"optimize_mach": False,
"optimize_altitude": False,
"polynomial_control_order": 1,
"num_segments": 3,
"order": 3,
"solve_for_distance": False,
"initial_mach": (0.76, "unitless"),
"final_mach": (0.76, "unitless"),
"mach_bounds": ((0.74, 0.78), "unitless"),
"initial_altitude": (34500.0, "ft"),
"final_altitude": (36000.0, "ft"),
"altitude_bounds": ((34000.0, 36500.0), "ft"),
"throttle_enforcement": "boundary_constraint",
"fix_initial": False,
"constrain_final": False,
"fix_duration": False,
"initial_bounds": ((85.0, 255.0), "min"),
"duration_bounds": ((43.0, 129.0), "min"),
},
"initial_guesses": {"time": ([170, 86], "min")},
},
"descent_1": {
"subsystem_options": {"core_aerodynamics": {"method": "computed"}},
"user_options": {
"optimize_mach": False,
"optimize_altitude": False,
"polynomial_control_order": 1,
"num_segments": 3,
"order": 3,
"solve_for_distance": False,
"initial_mach": (0.76, "unitless"),
"final_mach": (0.2, "unitless"),
"mach_bounds": ((0.18, 0.78), "unitless"),
"initial_altitude": (36000.0, "ft"),
"final_altitude": (500.0, "ft"),
"altitude_bounds": ((0.0, 36500.0), "ft"),
"throttle_enforcement": "path_constraint",
"fix_initial": False,
"constrain_final": True,
"fix_duration": False,
"initial_bounds": ((128.0, 384.0), "min"),
"duration_bounds": ((41.0, 123.0), "min"),
},
"initial_guesses": {"time": ([256, 82], "min")},
},
"post_mission": {
"include_landing": False,
"constrain_range": True,
"target_range": (2393, "nmi"),
},
}
Running Aviary with Updated Parameters#
Let’s now run Aviary with this multiphase mission and view the results.
import aviary.api as av
prob = av.run_aviary('models/test_aircraft/aircraft_for_bench_FwFm.csv',
phase_info, optimizer="SLSQP", make_plots=True)
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/solvers/linear/linear_rhs_checker.py:177: SolverWarning:DirectSolver in 'traj.phases.cruise_1.indep_states' <class StateIndependentsComp>: 'rhs_checking' is active but no redundant adjoint dependencies were found, so caching has been disabled.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/solvers/linear/linear_rhs_checker.py:177: SolverWarning:DirectSolver in 'traj.phases.climb_2.indep_states' <class StateIndependentsComp>: 'rhs_checking' is active but no redundant adjoint dependencies were found, so caching has been disabled.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/solvers/linear/linear_rhs_checker.py:177: SolverWarning:DirectSolver in 'traj.phases.cruise_2.indep_states' <class StateIndependentsComp>: 'rhs_checking' is active but no redundant adjoint dependencies were found, so caching has been disabled.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/solvers/linear/linear_rhs_checker.py:177: SolverWarning:DirectSolver in 'traj.phases.climb_3.indep_states' <class StateIndependentsComp>: 'rhs_checking' is active but no redundant adjoint dependencies were found, so caching has been disabled.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/solvers/linear/linear_rhs_checker.py:177: SolverWarning:DirectSolver in 'traj.phases.climb_4.indep_states' <class StateIndependentsComp>: 'rhs_checking' is active but no redundant adjoint dependencies were found, so caching has been disabled.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/solvers/linear/linear_rhs_checker.py:177: SolverWarning:DirectSolver in 'traj.phases.descent_1.indep_states' <class StateIndependentsComp>: 'rhs_checking' is active but no redundant adjoint dependencies were found, so caching has been disabled.
Optimization terminated successfully (Exit mode 0)
Current function value: 2.9526252835180378
Iterations: 17
Function evaluations: 17
Gradient evaluations: 17
Optimization Complete
-----------------------------------
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/driver.py:143: OMDeprecationWarning:boolean evaluation of DriverResult is temporarily implemented to mimick the previous `failed` return behavior of run_driver.
Use the `success` attribute of the returned DriverResult object to test for successful driver completion.
Now that we’ve run Aviary, we can look at the results.
Open up the automatically generated traj_results_report.html
and scroll through it to visualize the results.
Here are the altitude and Mach profiles:
Note
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.
What Next?#
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. If you want multiple climb, cruise, descent phases, that’s absolutely something Aviary can handle.
There are a lot of options for how you could modify this example. You could:
enable the
optimize_mach
oroptimize_altitude
flagsincrease the
polynomial_control_order
so there’s more flexibility in the optimized missiontry different
target_range
values for the full mission rangeadd an external subsystem to the phases
Playing around with a model and seeing how different settings affect the optimization and resulting aircraft design is always an enlightening experience.