Mission Optimization with Many Phases for a Commercial Aircraft

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:

multiple_phases_gui

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:

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 or optimize_altitude flags

  • increase the polynomial_control_order so there’s more flexibility in the optimized mission

  • try different target_range values for the full mission range

  • add 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.