Optimizing the Mission Profile of a Conventional Aircraft#

Building upon our previous example, this notebook introduces more complexity into the Aviary optimization process. Please see the simple mission example if you haven’t already.

Increasing Complexity in Phase Information#

We will now modify the phase_info object from our prior example by increasing num_segments to 3 and setting optimize_mach to True in each of the three phases. This means that we’ll query the aircraft performance at more points along the mission and also give the optimizer the freedom to choose an optimal Mach profile.

Note

We are still using a polynomial_control_order of 1, which means that the optimal Mach profiles for each phase will be linear (straight lines). Later in this example, we increase this order which will allow the optimizer to choose a more complex Mach profile.

phase_info = {
    "pre_mission": {"include_takeoff": False, "optimize_mass": True},
    "climb_1": {
        "subsystem_options": {"core_aerodynamics": {"method": "computed"}},
        "user_options": {
            "optimize_mach": True,
            "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": (30500.0, "ft"),
            "altitude_bounds": ((0.0, 31000.0), "ft"),
            "throttle_enforcement": "path_constraint",
            "fix_initial": True,
            "constrain_final": False,
            "fix_duration": False,
            "initial_bounds": ((0.0, 0.0), "min"),
            "duration_bounds": ((27.0, 81.0), "min"),
        },
        "initial_guesses": {"time": ([0, 54], "min")},
    },
    "cruise": {
        "subsystem_options": {"core_aerodynamics": {"method": "computed"}},
        "user_options": {
            "optimize_mach": True,
            "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": (30500.0, "ft"),
            "final_altitude": (31000.0, "ft"),
            "altitude_bounds": ((30000.0, 31500.0), "ft"),
            "throttle_enforcement": "boundary_constraint",
            "fix_initial": False,
            "constrain_final": False,
            "fix_duration": False,
            "initial_bounds": ((27.0, 81.0), "min"),
            "duration_bounds": ((85.5, 256.5), "min"),
        },
        "initial_guesses": {"time": ([54, 171], "min")},
    },
    "descent_1": {
        "subsystem_options": {"core_aerodynamics": {"method": "computed"}},
        "user_options": {
            "optimize_mach": True,
            "optimize_altitude": False,
            "polynomial_control_order": 1,
            "num_segments": 3,
            "order": 3,
            "solve_for_distance": False,
            "initial_mach": (0.72, "unitless"),
            "final_mach": (0.2, "unitless"),
            "mach_bounds": ((0.18, 0.74), "unitless"),
            "initial_altitude": (31000.0, "ft"),
            "final_altitude": (500.0, "ft"),
            "altitude_bounds": ((0.0, 31500.0), "ft"),
            "throttle_enforcement": "path_constraint",
            "fix_initial": False,
            "constrain_final": True,
            "fix_duration": False,
            "initial_bounds": ((112.5, 337.5), "min"),
            "duration_bounds": ((26.5, 79.5), "min"),
        },
        "initial_guesses": {"time": ([225, 53], "min")},
    },
    "post_mission": {
        "include_landing": False,
        "constrain_range": True,
        "target_range": (1915, "nmi"),
    },
}

Running Aviary with Updated Parameters#

Let’s run the Aviary optimization with our updated phase_info object in the same way as before.

import aviary.api as av

prob = av.run_aviary('models/test_aircraft/aircraft_for_bench_FwFm.csv',
                     phase_info, optimizer="SLSQP", make_plots=True)
User has specified Design.NUM_* passenger values but CrewPyaload.NUM_* has been left blank or set to zero.
Assuming they are equal to maintain backwards compatibility with GASP and FLOPS output files.
If you intended to have no passengers on this flight, please set Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS to zero in aviary_values.

The following variables have been overridden:
  'aircraft:design:touchdown_mass  152800  lbm
  'aircraft:engine:mass  [7400.]  lbm
  'aircraft:fins:mass  0  lbm
  'aircraft:fuel:auxiliary_fuel_capacity  0  lbm
  'aircraft:fuel:fuselage_fuel_capacity  0  lbm
  'aircraft:fuel:total_capacity  45694  lbm
  'aircraft:fuselage:planform_area  1578.24  ft**2
  'aircraft:fuselage:wetted_area  4158.62  ft**2
  'aircraft:horizontal_tail:wetted_area  592.65  ft**2
  'aircraft:landing_gear:main_gear_oleo_length  102  inch
  'aircraft:landing_gear:nose_gear_oleo_length  67  inch
  'aircraft:vertical_tail:wetted_area  581.13  ft**2
  'aircraft:wing:aspect_ratio  11.22091  unitless
  'aircraft:wing:control_surface_area  137  ft**2
  'aircraft:wing:wetted_area  2396.56  ft**2
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/dymos/phase/phase.py:897: OMDeprecationWarning:None: The method `add_polynomial_control` is deprecated and will be removed in Dymos 2.1. Please use `add_control` with the appropriate options to define a polynomial control.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/dymos/phase/phase.py:2323: RuntimeWarning: Invalid options for non-optimal control 'altitude' in phase 'climb_1': lower, upper, ref
  warnings.warn(f"Invalid options for non-optimal control '{name}' in phase "
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/dymos/phase/phase.py:2323: RuntimeWarning: Invalid options for non-optimal control 'altitude' in phase 'cruise': lower, upper, ref
  warnings.warn(f"Invalid options for non-optimal control '{name}' in phase "
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/dymos/phase/phase.py:2323: RuntimeWarning: Invalid options for non-optimal control 'altitude' in phase 'descent_1': lower, upper, ref
  warnings.warn(f"Invalid options for non-optimal control '{name}' in phase "
--- Constraint Report [traj] ---
    --- climb_1 ---
        [initial] 2.0000e-01 == mach [unitless]
        [path]    0.0000e+00 <= throttle <= 1.0000e+00  [unitless]
    --- cruise ---
        [initial] 0.0000e+00 <= throttle <= 1.0000e+00  [unitless]
        [final]   0.0000e+00 <= throttle <= 1.0000e+00  [unitless]
    --- descent_1 ---
        [final]   2.0000e-01 == mach [unitless]
        [path]    0.0000e+00 <= throttle <= 1.0000e+00  [unitless]
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/solvers/linear/linear_rhs_checker.py:177: SolverWarning:DirectSolver in 'traj.phases.cruise.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.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/recorders/sqlite_recorder.py:230: UserWarning:The existing case recorder file, /home/runner/work/Aviary/Aviary/aviary/docs/examples/aircraft_for_bench_FwFm_out/problem_history.db, is being overwritten.
Full total jacobian for problem 'aircraft_for_bench_FwFm' was computed 3 times, taking 0.42315359000008357 seconds.
Total jacobian shape: (89, 66) 


Jacobian shape: (89, 66)  (8.39% nonzero)
FWD solves: 7   REV solves: 0
Total colors vs. total size: 7 vs 66  (89.39% improvement)

Sparsity computed using tolerance: 1e-25
Time to compute sparsity:   0.4232 sec
Time to compute coloring:   0.0648 sec
Memory to compute coloring:   0.1250 MB
Coloring created on: 2024-12-17 21:03:12
Optimization terminated successfully    (Exit mode 0)
            Current function value: 2.4776520445788486
            Iterations: 10
            Function evaluations: 10
            Gradient evaluations: 10
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

We note two major changes compared to our first example.

The first is that we have many more points where the flight dynamics were evaluated because we increased num_segments to 3. This means that we have more points shown on the resulting plots.

The second is that the optimizer chose the optimal Mach profile. Again, each phase’s Mach profile is constrained to be linear because we set polynomial_control_order to 1. However, we see that the optimizer chose to decrease the Mach number during the cruise-climb segment to minimize fuel burn.

Note

Remember, we did not allow the optimizer to control the altitude profile, so that remains fixed.

Let’s take a look at the optimization objective, mission:summary:fuel_burned:

print(prob.get_val(av.Mission.Summary.FUEL_BURNED, units='kg')[0])
9877.663519358655

We can print fuel_burned in pounds easily, thanks to OpenMDAO’s automatic unit conversion feature:

print(prob.get_val(av.Mission.Summary.FUEL_BURNED, units='lb')[0])
21776.520445788483

Modifying the Aircraft Configuration#

Next, we’ll modify the aircraft configuration by decreasing the wing aspect ratio by 0.2. This results in a less slender wing, which will increase the induced drag. We’ve made this change and have a modified aircraft data file called modified_aircraft.csv.

Hide code cell source
import csv

filename = 'models/test_aircraft/aircraft_for_bench_FwFm.csv'
filename = av.get_path(filename)

# Read the file
with open(filename, 'r') as file:
    reader = csv.reader(file)
    lines = list(reader)

# Find the index of the line containing 'aircraft:wing:span'
index = None
for i, line in enumerate(lines):
    if 'aircraft:wing:aspect_ratio' in line:
        index = i
        break

# Modify the value in the line
if index is not None:
    aspect_ratio = float(lines[index][1]) - 0.2
    lines[index][1] = str(aspect_ratio)

# Write the modified content to a new CSV file
with open(new_filename, 'w', newline='') as file:
    writer = csv.writer(file)
    writer.writerows(lines)

Re-running the Optimization with Modified Aircraft#

Now, let’s re-run the optimization with the modified aircraft configuration. We’ll use the same phase_info object as before, but we’ll change the input deck to point to our new aircraft file.

prob = av.run_aviary('modified_aircraft.csv', phase_info,
                     optimizer="SLSQP", make_plots=True)
User has specified Design.NUM_* passenger values but CrewPyaload.NUM_* has been left blank or set to zero.
Assuming they are equal to maintain backwards compatibility with GASP and FLOPS output files.
If you intended to have no passengers on this flight, please set Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS to zero in aviary_values.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/dymos/phase/phase.py:897: OMDeprecationWarning:None: The method `add_polynomial_control` is deprecated and will be removed in Dymos 2.1. Please use `add_control` with the appropriate options to define a polynomial control.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/dymos/phase/phase.py:2323: RuntimeWarning: Invalid options for non-optimal control 'altitude' in phase 'climb_1': lower, upper, ref
  warnings.warn(f"Invalid options for non-optimal control '{name}' in phase "
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/dymos/phase/phase.py:2323: RuntimeWarning: Invalid options for non-optimal control 'altitude' in phase 'cruise': lower, upper, ref
  warnings.warn(f"Invalid options for non-optimal control '{name}' in phase "
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/dymos/phase/phase.py:2323: RuntimeWarning: Invalid options for non-optimal control 'altitude' in phase 'descent_1': lower, upper, ref
  warnings.warn(f"Invalid options for non-optimal control '{name}' in phase "
The following variables have been overridden:
  'aircraft:design:touchdown_mass  152800  lbm
  'aircraft:engine:mass  [7400.]  lbm
  'aircraft:fins:mass  0  lbm
  'aircraft:fuel:auxiliary_fuel_capacity  0  lbm
  'aircraft:fuel:fuselage_fuel_capacity  0  lbm
  'aircraft:fuel:total_capacity  45694  lbm
  'aircraft:fuselage:planform_area  1578.24  ft**2
  'aircraft:fuselage:wetted_area  4158.62  ft**2
  'aircraft:horizontal_tail:wetted_area  592.65  ft**2
  'aircraft:landing_gear:main_gear_oleo_length  102  inch
  'aircraft:landing_gear:nose_gear_oleo_length  67  inch
  'aircraft:vertical_tail:wetted_area  581.13  ft**2
  'aircraft:wing:aspect_ratio  11.02091  unitless
  'aircraft:wing:control_surface_area  137  ft**2
  'aircraft:wing:wetted_area  2396.56  ft**2

--- Constraint Report [traj] ---
    --- climb_1 ---
        [initial] 2.0000e-01 == mach [unitless]
        [path]    0.0000e+00 <= throttle <= 1.0000e+00  [unitless]
    --- cruise ---
        [initial] 0.0000e+00 <= throttle <= 1.0000e+00  [unitless]
        [final]   0.0000e+00 <= throttle <= 1.0000e+00  [unitless]
    --- descent_1 ---
        [final]   2.0000e-01 == mach [unitless]
        [path]    0.0000e+00 <= throttle <= 1.0000e+00  [unitless]
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/solvers/linear/linear_rhs_checker.py:177: SolverWarning:DirectSolver in 'traj.phases.cruise.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.
Full total jacobian for problem 'modified_aircraft' was computed 3 times, taking 0.4242635870000413 seconds.
Total jacobian shape: (89, 66) 


Jacobian shape: (89, 66)  (8.39% nonzero)
FWD solves: 7   REV solves: 0
Total colors vs. total size: 7 vs 66  (89.39% improvement)

Sparsity computed using tolerance: 1e-25
Time to compute sparsity:   0.4243 sec
Time to compute coloring:   0.0658 sec
Memory to compute coloring:   0.0000 MB
Coloring created on: 2024-12-17 21:03:19
Iteration limit reached    (Exit mode 9)
            Current function value: 2.4932837760586555
            Iterations: 50
            Function evaluations: 232
            Gradient evaluations: 50
Optimization FAILED.
Iteration limit reached
-----------------------------------
/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.

The case again converged in relatively few iterations. Let’s take a look at the fuel burn value:

print(prob.get_val(av.Mission.Summary.FUEL_BURNED, units='kg')[0])
9948.567860649948

As expected, it’s a bit higher than our prior run that had a larger aspect ratio.

Increasing the Polynomial Control Order#

Next, we’ll increase the polynomial_control_order to 3 for the climb and descent phases. This means that the optimizer will be able to choose a cubic Mach profile per phase instead of a line. We’ll use the original aircraft configuration for this run.

Note

We’ll use the IPOPT optimizer for this problem as it will handle the increased complexity better than SLSQP.

phase_info['climb_1']['user_options']['polynomial_control_order'] = 3
phase_info['cruise']['user_options']['polynomial_control_order'] = 1
phase_info['descent_1']['user_options']['polynomial_control_order'] = 3

prob = av.run_aviary('models/test_aircraft/aircraft_for_bench_FwFm.csv',
                     phase_info, optimizer="IPOPT", make_plots=True)
User has specified Design.NUM_* passenger values but CrewPyaload.NUM_* has been left blank or set to zero.
Assuming they are equal to maintain backwards compatibility with GASP and FLOPS output files.
If you intended to have no passengers on this flight, please set Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS to zero in aviary_values.
The following variables have been overridden:
  'aircraft:design:touchdown_mass  152800  lbm
  'aircraft:engine:mass  [7400.]  lbm
  'aircraft:fins:mass  0  lbm
  'aircraft:fuel:auxiliary_fuel_capacity  0  lbm
  'aircraft:fuel:fuselage_fuel_capacity  0  lbm
  'aircraft:fuel:total_capacity  45694  lbm
  'aircraft:fuselage:planform_area  1578.24  ft**2
  'aircraft:fuselage:wetted_area  4158.62  ft**2
  'aircraft:horizontal_tail:wetted_area  592.65  ft**2
  'aircraft:landing_gear:main_gear_oleo_length  102  inch
  'aircraft:landing_gear:nose_gear_oleo_length  67  inch
  'aircraft:vertical_tail:wetted_area  581.13  ft**2
  'aircraft:wing:aspect_ratio  11.22091  unitless
  'aircraft:wing:control_surface_area  137  ft**2
  'aircraft:wing:wetted_area  2396.56  ft**2
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/dymos/phase/phase.py:897: OMDeprecationWarning:None: The method `add_polynomial_control` is deprecated and will be removed in Dymos 2.1. Please use `add_control` with the appropriate options to define a polynomial control.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/dymos/phase/phase.py:2323: RuntimeWarning: Invalid options for non-optimal control 'altitude' in phase 'climb_1': lower, upper, ref
  warnings.warn(f"Invalid options for non-optimal control '{name}' in phase "
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/dymos/phase/phase.py:2323: RuntimeWarning: Invalid options for non-optimal control 'altitude' in phase 'cruise': lower, upper, ref
  warnings.warn(f"Invalid options for non-optimal control '{name}' in phase "
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/dymos/phase/phase.py:2323: RuntimeWarning: Invalid options for non-optimal control 'altitude' in phase 'descent_1': lower, upper, ref
  warnings.warn(f"Invalid options for non-optimal control '{name}' in phase "
--- Constraint Report [traj] ---
    --- climb_1 ---
        [initial] 2.0000e-01 == mach [unitless]
        [path]    0.0000e+00 <= throttle <= 1.0000e+00  [unitless]
    --- cruise ---
        [initial] 0.0000e+00 <= throttle <= 1.0000e+00  [unitless]
        [final]   0.0000e+00 <= throttle <= 1.0000e+00  [unitless]
    --- descent_1 ---
        [final]   2.0000e-01 == mach [unitless]
        [path]    0.0000e+00 <= throttle <= 1.0000e+00  [unitless]
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/solvers/linear/linear_rhs_checker.py:177: SolverWarning:DirectSolver in 'traj.phases.cruise.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.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/recorders/sqlite_recorder.py:230: UserWarning:The existing case recorder file, /home/runner/work/Aviary/Aviary/aviary/docs/examples/aircraft_for_bench_FwFm_out/problem_history.db, is being overwritten.
Full total jacobian for problem 'aircraft_for_bench_FwFm' was computed 3 times, taking 0.44067835400005606 seconds.
Total jacobian shape: (89, 70) 


Jacobian shape: (89, 70)  (9.78% nonzero)
FWD solves: 9   REV solves: 0
Total colors vs. total size: 9 vs 70  (87.14% improvement)

Sparsity computed using tolerance: 1e-25
Time to compute sparsity:   0.4407 sec
Time to compute coloring:   0.0683 sec
Memory to compute coloring:   0.0000 MB
Coloring created on: 2024-12-17 21:03:58
This is Ipopt version 3.14.17, running with linear solver MUMPS 5.7.3.

Number of nonzeros in equality constraint Jacobian...:     1323
Number of nonzeros in inequality constraint Jacobian.:      620
Number of nonzeros in Lagrangian Hessian.............:        0

Total number of variables............................:       70
                     variables with only lower bounds:        2
                variables with lower and upper bounds:       68
                     variables with only upper bounds:        0
Total number of equality constraints.................:       62
Total number of inequality constraints...............:       26
        inequality constraints with only lower bounds:        0
   inequality constraints with lower and upper bounds:       26
        inequality constraints with only upper bounds:        0

iter    objective    inf_pr   inf_du lg(mu)  ||d||  lg(rg) alpha_du alpha_pr  ls
   0  3.0000000e-01 1.91e+02 1.45e-01  -5.0 0.00e+00    -  0.00e+00 0.00e+00   0
  10  1.6525679e+00 8.90e+01 1.06e+00  -5.0 2.06e+00    -  3.75e-02 1.99e-01h  1
  20  2.4521890e+00 8.70e-05 1.97e-01  -5.0 3.59e-01    -  1.21e-01 1.00e+00f  1
  30  2.4399606e+00 1.48e-09 7.09e-06  -7.0 2.55e-05    -  1.00e+00 5.00e-01h  2
Number of Iterations....: 31

                                   (scaled)                 (unscaled)
Objective...............:   2.4399625347506313e+00    2.4399625347506313e+00
Dual infeasibility......:   5.3272101239391944e-08    5.3272101239391944e-08
Constraint violation....:   3.1409164545075208e-11    3.1409164545075208e-11
Variable bound violation:   0.0000000000000000e+00    0.0000000000000000e+00
Complementarity.........:   9.0916068280315482e-08    9.0916068280315482e-08
Overall NLP error.......:   9.0916068280315482e-08    9.0916068280315482e-08


Number of objective function evaluations             = 34
Number of objective gradient evaluations             = 32
Number of equality constraint evaluations            = 34
Number of inequality constraint evaluations          = 34
Number of equality constraint Jacobian evaluations   = 32
Number of inequality constraint Jacobian evaluations = 32
Number of Lagrangian Hessian evaluations             = 0
Total seconds in IPOPT                               = 11.372

EXIT: Optimal Solution Found.
minimal_print is not available for this solution


Optimization Problem -- Optimization using pyOpt_sparse
================================================================================
    Objective Function: _objfunc

    Solution: 
--------------------------------------------------------------------------------
    Total Time:                   11.3728
       User Objective Time :       8.9470
       User Sensitivity Time :     2.2515
       Interface Time :            0.0780
       Opt Solver Time:            0.0963
    Calls to Objective Function :      35
    Calls to Sens Function :           33


   Objectives
      Index  Name                               Value
          0  mission:objectives:fuel     2.439963E+00

   Variables (c - continuous, i - integer, d - discrete)
      Index  Name                               Type      Lower Bound            Value      Upper Bound     Status
          0  mission:design:gross_mass_0           c     5.714286E-05     9.060298E-01     1.000000E+30           
          1  mission:summary:gross_mass_0          c     5.714286E-05     9.060298E-01     1.000000E+30           
          2  traj.climb_1.t_duration_0             c     5.000000E-01     5.000015E-01     1.500000E+00           
          3  traj.climb_1.states:mass_0            c     0.000000E+00     7.191943E+00     1.000000E+17           
          4  traj.climb_1.states:mass_1            c     0.000000E+00     7.170816E+00     1.000000E+17           
          5  traj.climb_1.states:mass_2            c     0.000000E+00     7.148940E+00     1.000000E+17           
          6  traj.climb_1.states:mass_3            c     0.000000E+00     7.141411E+00     1.000000E+17           
          7  traj.climb_1.states:mass_4            c     0.000000E+00     7.115129E+00     1.000000E+17           
          8  traj.climb_1.states:mass_5            c     0.000000E+00     7.080061E+00     1.000000E+17           
          9  traj.climb_1.states:mass_6            c     0.000000E+00     7.069525E+00     1.000000E+17           
         10  traj.climb_1.states:mass_7            c     0.000000E+00     7.055025E+00     1.000000E+17           
         11  traj.climb_1.states:mass_8            c     0.000000E+00     7.035676E+00     1.000000E+17           
         12  traj.climb_1.states:mass_9            c     0.000000E+00     7.029647E+00     1.000000E+17           
         13  traj.climb_1.states:distance_0        c     0.000000E+00     1.401625E-02     1.000000E+15           
         14  traj.climb_1.states:distance_1        c     0.000000E+00     4.220495E-02     1.000000E+15           
         15  traj.climb_1.states:distance_2        c     0.000000E+00     5.275879E-02     1.000000E+15           
         16  traj.climb_1.states:distance_3        c     0.000000E+00     9.678232E-02     1.000000E+15           
         17  traj.climb_1.states:distance_4        c     0.000000E+00     1.656637E-01     1.000000E+15           
         18  traj.climb_1.states:distance_5        c     0.000000E+00     1.883451E-01     1.000000E+15           
         19  traj.climb_1.states:distance_6        c     0.000000E+00     2.210148E-01     1.000000E+15           
         20  traj.climb_1.states:distance_7        c     0.000000E+00     2.667981E-01     1.000000E+15           
         21  traj.climb_1.states:distance_8        c     0.000000E+00     2.814396E-01     1.000000E+15           
         22  traj.climb_1.controls:mach_0          c     3.600000E-01     4.000000E-01     1.480000E+00           
         23  traj.climb_1.controls:mach_1          c     3.600000E-01     9.514307E-01     1.480000E+00           
         24  traj.climb_1.controls:mach_2          c     3.600000E-01     1.302329E+00     1.480000E+00           
         25  traj.climb_1.controls:mach_3          c     3.600000E-01     1.400001E+00     1.480000E+00           
         26  traj.cruise.t_duration_0              c     5.000000E-01     1.378671E+00     1.500000E+00           
         27  traj.cruise.states:mass_0             c     0.000000E+00     6.951271E+00     1.000000E+17           
         28  traj.cruise.states:mass_1             c     0.000000E+00     6.844162E+00     1.000000E+17           
         29  traj.cruise.states:mass_2             c     0.000000E+00     6.810508E+00     1.000000E+17           
         30  traj.cruise.states:mass_3             c     0.000000E+00     6.686817E+00     1.000000E+17           
         31  traj.cruise.states:mass_4             c     0.000000E+00     6.518608E+00     1.000000E+17           
         32  traj.cruise.states:mass_5             c     0.000000E+00     6.465932E+00     1.000000E+17           
         33  traj.cruise.states:mass_6             c     0.000000E+00     6.391836E+00     1.000000E+17           
         34  traj.cruise.states:mass_7             c     0.000000E+00     6.290438E+00     1.000000E+17           
         35  traj.cruise.states:mass_8             c     0.000000E+00     6.258544E+00     1.000000E+17           
         36  traj.cruise.states:distance_0         c     0.000000E+00     5.754088E-01     1.000000E+15           
         37  traj.cruise.states:distance_1         c     0.000000E+00     9.809237E-01     1.000000E+15           
         38  traj.cruise.states:distance_2         c     0.000000E+00     1.109243E+00     1.000000E+15           
         39  traj.cruise.states:distance_3         c     0.000000E+00     1.584579E+00     1.000000E+15           
         40  traj.cruise.states:distance_4         c     0.000000E+00     2.240176E+00     1.000000E+15           
         41  traj.cruise.states:distance_5         c     0.000000E+00     2.447605E+00     1.000000E+15           
         42  traj.cruise.states:distance_6         c     0.000000E+00     2.741113E+00     1.000000E+15           
         43  traj.cruise.states:distance_7         c     0.000000E+00     3.145991E+00     1.000000E+15           
         44  traj.cruise.states:distance_8         c     0.000000E+00     3.274108E+00     1.000000E+15           
         45  traj.cruise.controls:mach_0           c     1.400000E+00     1.400001E+00     1.480000E+00          l
         46  traj.cruise.controls:mach_1           c     1.400000E+00     1.400000E+00     1.480000E+00          l
         47  traj.descent_1.t_duration_0           c     5.000000E-01     6.179850E-01     1.500000E+00           
         48  traj.descent_1.states:mass_0          c     0.000000E+00     6.254338E+00     1.000000E+17           
         49  traj.descent_1.states:mass_1          c     0.000000E+00     6.248928E+00     1.000000E+17           
         50  traj.descent_1.states:mass_2          c     0.000000E+00     6.247230E+00     1.000000E+17           
         51  traj.descent_1.states:mass_3          c     0.000000E+00     6.241101E+00     1.000000E+17           
         52  traj.descent_1.states:mass_4          c     0.000000E+00     6.233194E+00     1.000000E+17           
         53  traj.descent_1.states:mass_5          c     0.000000E+00     6.230893E+00     1.000000E+17           
         54  traj.descent_1.states:mass_6          c     0.000000E+00     6.227680E+00     1.000000E+17           
         55  traj.descent_1.states:mass_7          c     0.000000E+00     6.222957E+00     1.000000E+17           
         56  traj.descent_1.states:mass_8          c     0.000000E+00     6.221273E+00     1.000000E+17           
         57  traj.descent_1.states:distance_0      c     0.000000E+00     3.312484E+00     1.000000E+15           
         58  traj.descent_1.states:distance_1      c     0.000000E+00     3.359070E+00     1.000000E+15           
         59  traj.descent_1.states:distance_2      c     0.000000E+00     3.372684E+00     1.000000E+15           
         60  traj.descent_1.states:distance_3      c     0.000000E+00     3.419684E+00     1.000000E+15           
         61  traj.descent_1.states:distance_4      c     0.000000E+00     3.477251E+00     1.000000E+15           
         62  traj.descent_1.states:distance_5      c     0.000000E+00     3.493998E+00     1.000000E+15           
         63  traj.descent_1.states:distance_6      c     0.000000E+00     3.515639E+00     1.000000E+15           
         64  traj.descent_1.states:distance_7      c     0.000000E+00     3.540369E+00     1.000000E+15           
         65  traj.descent_1.states:distance_8      c     0.000000E+00     3.546580E+00     1.000000E+15           
         66  traj.descent_1.controls:mach_0        c     3.600000E-01     1.400000E+00     1.480000E+00           
         67  traj.descent_1.controls:mach_1        c     3.600000E-01     1.015228E+00     1.480000E+00           
         68  traj.descent_1.controls:mach_2        c     3.600000E-01     7.178231E-01     1.480000E+00           
         69  traj.descent_1.controls:mach_3        c     3.600000E-01     4.000000E-01     1.480000E+00           

   Constraints (i - inequality, e - equality)
      Index  Name                                                      Type          Lower           Value           Upper    Status  Lagrange Multiplier (N/A)
          0  mission:constraints:range_residual                           e   0.000000E+00   -2.273737E-14    0.000000E+00              9.00000E+100
          1  gtow_constraint.GTOW                                         e   0.000000E+00    0.000000E+00    0.000000E+00              9.00000E+100
          2  link_climb_1_mass.mass                                       e   0.000000E+00    0.000000E+00    0.000000E+00              9.00000E+100
          3  mission:constraints:mass_residual                            e   0.000000E+00    0.000000E+00    0.000000E+00              9.00000E+100
          4  traj.linkages.climb_1:mach_final|cruise:mach_initial         e   0.000000E+00    0.000000E+00    0.000000E+00              9.00000E+100
          5  traj.linkages.cruise:mach_final|descent_1:mach_initial       e   0.000000E+00    0.000000E+00    0.000000E+00              9.00000E+100
          6  traj.phases.climb_1->initial_boundary_constraint->mach       e   2.000000E-01    2.000000E-01    2.000000E-01              9.00000E+100
          7  traj.climb_1.collocation_constraint.defects:mass             e   0.000000E+00   -1.477416E-16    0.000000E+00              9.00000E+100
          8  traj.climb_1.collocation_constraint.defects:mass             e   0.000000E+00    2.054157E-12    0.000000E+00              9.00000E+100
          9  traj.climb_1.collocation_constraint.defects:mass             e   0.000000E+00    8.752449E-12    0.000000E+00              9.00000E+100
         10  traj.climb_1.collocation_constraint.defects:mass             e   0.000000E+00    1.772565E-11    0.000000E+00              9.00000E+100
         11  traj.climb_1.collocation_constraint.defects:mass             e   0.000000E+00    2.484852E-11    0.000000E+00              9.00000E+100
         12  traj.climb_1.collocation_constraint.defects:mass             e   0.000000E+00    1.706487E-11    0.000000E+00              9.00000E+100
         13  traj.climb_1.collocation_constraint.defects:mass             e   0.000000E+00    7.882804E-12    0.000000E+00              9.00000E+100
         14  traj.climb_1.collocation_constraint.defects:mass             e   0.000000E+00    4.764313E-12    0.000000E+00              9.00000E+100
         15  traj.climb_1.collocation_constraint.defects:mass             e   0.000000E+00    2.277959E-12    0.000000E+00              9.00000E+100
         16  traj.climb_1.collocation_constraint.defects:distance         e   0.000000E+00    1.686202E-18    0.000000E+00              9.00000E+100
         17  traj.climb_1.collocation_constraint.defects:distance         e   0.000000E+00   -1.825362E-15    0.000000E+00              9.00000E+100
         18  traj.climb_1.collocation_constraint.defects:distance         e   0.000000E+00   -3.127746E-15    0.000000E+00              9.00000E+100
         19  traj.climb_1.collocation_constraint.defects:distance         e   0.000000E+00   -5.335795E-15    0.000000E+00              9.00000E+100
         20  traj.climb_1.collocation_constraint.defects:distance         e   0.000000E+00   -5.151607E-15    0.000000E+00              9.00000E+100
         21  traj.climb_1.collocation_constraint.defects:distance         e   0.000000E+00   -3.105049E-15    0.000000E+00              9.00000E+100
         22  traj.climb_1.collocation_constraint.defects:distance         e   0.000000E+00   -1.451216E-15    0.000000E+00              9.00000E+100
         23  traj.climb_1.collocation_constraint.defects:distance         e   0.000000E+00   -8.725620E-16    0.000000E+00              9.00000E+100
         24  traj.climb_1.collocation_constraint.defects:distance         e   0.000000E+00   -4.126424E-16    0.000000E+00              9.00000E+100
         25  traj.cruise.collocation_constraint.defects:mass              e   0.000000E+00    1.642874E-11    0.000000E+00              9.00000E+100
         26  traj.cruise.collocation_constraint.defects:mass              e   0.000000E+00    1.563784E-11    0.000000E+00              9.00000E+100
         27  traj.cruise.collocation_constraint.defects:mass              e   0.000000E+00    1.455234E-11    0.000000E+00              9.00000E+100
         28  traj.cruise.collocation_constraint.defects:mass              e   0.000000E+00    2.299245E-11    0.000000E+00              9.00000E+100
         29  traj.cruise.collocation_constraint.defects:mass              e   0.000000E+00    2.095089E-11    0.000000E+00              9.00000E+100
         30  traj.cruise.collocation_constraint.defects:mass              e   0.000000E+00    1.815736E-11    0.000000E+00              9.00000E+100
         31  traj.cruise.collocation_constraint.defects:mass              e   0.000000E+00    1.067901E-11    0.000000E+00              9.00000E+100
         32  traj.cruise.collocation_constraint.defects:mass              e   0.000000E+00    9.846079E-12    0.000000E+00              9.00000E+100
         33  traj.cruise.collocation_constraint.defects:mass              e   0.000000E+00    8.802876E-12    0.000000E+00              9.00000E+100
         34  traj.cruise.collocation_constraint.defects:distance          e   0.000000E+00   -1.884010E-15    0.000000E+00              9.00000E+100
         35  traj.cruise.collocation_constraint.defects:distance          e   0.000000E+00   -1.794005E-15    0.000000E+00              9.00000E+100
         36  traj.cruise.collocation_constraint.defects:distance          e   0.000000E+00   -1.672886E-15    0.000000E+00              9.00000E+100
         37  traj.cruise.collocation_constraint.defects:distance          e   0.000000E+00   -2.642060E-15    0.000000E+00              9.00000E+100
         38  traj.cruise.collocation_constraint.defects:distance          e   0.000000E+00   -2.417319E-15    0.000000E+00              9.00000E+100
         39  traj.cruise.collocation_constraint.defects:distance          e   0.000000E+00   -2.118862E-15    0.000000E+00              9.00000E+100
         40  traj.cruise.collocation_constraint.defects:distance          e   0.000000E+00   -1.252303E-15    0.000000E+00              9.00000E+100
         41  traj.cruise.collocation_constraint.defects:distance          e   0.000000E+00   -1.143963E-15    0.000000E+00              9.00000E+100
         42  traj.cruise.collocation_constraint.defects:distance          e   0.000000E+00   -1.026733E-15    0.000000E+00              9.00000E+100
         43  traj.phases.descent_1->final_boundary_constraint->mach       e   2.000000E-01    2.000000E-01    2.000000E-01              9.00000E+100
         44  traj.descent_1.collocation_constraint.defects:mass           e   0.000000E+00    1.054153E-12    0.000000E+00              9.00000E+100
         45  traj.descent_1.collocation_constraint.defects:mass           e   0.000000E+00   -1.143530E-11    0.000000E+00              9.00000E+100
         46  traj.descent_1.collocation_constraint.defects:mass           e   0.000000E+00   -1.743211E-11    0.000000E+00              9.00000E+100
         47  traj.descent_1.collocation_constraint.defects:mass           e   0.000000E+00   -2.963973E-11    0.000000E+00              9.00000E+100
         48  traj.descent_1.collocation_constraint.defects:mass           e   0.000000E+00   -3.140916E-11    0.000000E+00              9.00000E+100
         49  traj.descent_1.collocation_constraint.defects:mass           e   0.000000E+00   -1.389077E-11    0.000000E+00              9.00000E+100
         50  traj.descent_1.collocation_constraint.defects:mass           e   0.000000E+00   -5.726969E-12    0.000000E+00              9.00000E+100
         51  traj.descent_1.collocation_constraint.defects:mass           e   0.000000E+00   -2.391097E-12    0.000000E+00              9.00000E+100
         52  traj.descent_1.collocation_constraint.defects:mass           e   0.000000E+00   -1.788369E-13    0.000000E+00              9.00000E+100
         53  traj.descent_1.collocation_constraint.defects:distance       e   0.000000E+00    1.222743E-15    0.000000E+00              9.00000E+100
         54  traj.descent_1.collocation_constraint.defects:distance       e   0.000000E+00   -1.748096E-14    0.000000E+00              9.00000E+100
         55  traj.descent_1.collocation_constraint.defects:distance       e   0.000000E+00   -3.599840E-14    0.000000E+00              9.00000E+100
         56  traj.descent_1.collocation_constraint.defects:distance       e   0.000000E+00   -6.501762E-14    0.000000E+00              9.00000E+100
         57  traj.descent_1.collocation_constraint.defects:distance       e   0.000000E+00   -7.873918E-14    0.000000E+00              9.00000E+100
         58  traj.descent_1.collocation_constraint.defects:distance       e   0.000000E+00   -7.034027E-14    0.000000E+00              9.00000E+100
         59  traj.descent_1.collocation_constraint.defects:distance       e   0.000000E+00   -3.803031E-14    0.000000E+00              9.00000E+100
         60  traj.descent_1.collocation_constraint.defects:distance       e   0.000000E+00   -2.738393E-14    0.000000E+00              9.00000E+100
         61  traj.descent_1.collocation_constraint.defects:distance       e   0.000000E+00   -7.468450E-15    0.000000E+00              9.00000E+100
         62  traj.phases.climb_1->path_constraint->throttle               i   0.000000E+00    6.815913E-01    1.000000E+00              9.00000E+100
         63  traj.phases.climb_1->path_constraint->throttle               i   0.000000E+00    5.030957E-01    1.000000E+00              9.00000E+100
         64  traj.phases.climb_1->path_constraint->throttle               i   0.000000E+00    5.085216E-01    1.000000E+00              9.00000E+100
         65  traj.phases.climb_1->path_constraint->throttle               i   0.000000E+00    5.268627E-01    1.000000E+00              9.00000E+100
         66  traj.phases.climb_1->path_constraint->throttle               i   0.000000E+00    5.268627E-01    1.000000E+00              9.00000E+100
         67  traj.phases.climb_1->path_constraint->throttle               i   0.000000E+00    5.928249E-01    1.000000E+00              9.00000E+100
         68  traj.phases.climb_1->path_constraint->throttle               i   0.000000E+00    7.070927E-01    1.000000E+00              9.00000E+100
         69  traj.phases.climb_1->path_constraint->throttle               i   0.000000E+00    7.478084E-01    1.000000E+00              9.00000E+100
         70  traj.phases.climb_1->path_constraint->throttle               i   0.000000E+00    7.478084E-01    1.000000E+00              9.00000E+100
         71  traj.phases.climb_1->path_constraint->throttle               i   0.000000E+00    8.220685E-01    1.000000E+00              9.00000E+100
         72  traj.phases.climb_1->path_constraint->throttle               i   0.000000E+00    9.472318E-01    1.000000E+00              9.00000E+100
         73  traj.phases.climb_1->path_constraint->throttle               i   0.000000E+00    9.999980E-01    1.000000E+00              9.00000E+100
         74  traj.phases.cruise->initial_boundary_constraint->throttle    i   0.000000E+00    6.532217E-01    1.000000E+00              9.00000E+100
         75  traj.phases.cruise->final_boundary_constraint->throttle      i   0.000000E+00    6.175645E-01    1.000000E+00              9.00000E+100
         76  traj.phases.descent_1->path_constraint->throttle             i   0.000000E+00    2.259456E-01    1.000000E+00              9.00000E+100
         77  traj.phases.descent_1->path_constraint->throttle             i   0.000000E+00    1.862015E-01    1.000000E+00              9.00000E+100
         78  traj.phases.descent_1->path_constraint->throttle             i   0.000000E+00    1.570243E-01    1.000000E+00              9.00000E+100
         79  traj.phases.descent_1->path_constraint->throttle             i   0.000000E+00    1.486994E-01    1.000000E+00              9.00000E+100
         80  traj.phases.descent_1->path_constraint->throttle             i   0.000000E+00    1.486994E-01    1.000000E+00              9.00000E+100
         81  traj.phases.descent_1->path_constraint->throttle             i   0.000000E+00    1.195121E-01    1.000000E+00              9.00000E+100
         82  traj.phases.descent_1->path_constraint->throttle             i   0.000000E+00    6.383234E-02    1.000000E+00              9.00000E+100
         83  traj.phases.descent_1->path_constraint->throttle             i   0.000000E+00    3.657651E-02    1.000000E+00              9.00000E+100
         84  traj.phases.descent_1->path_constraint->throttle             i   0.000000E+00    3.657651E-02    1.000000E+00              9.00000E+100
         85  traj.phases.descent_1->path_constraint->throttle             i   0.000000E+00    2.959326E-06    1.000000E+00              9.00000E+100
         86  traj.phases.descent_1->path_constraint->throttle             i   0.000000E+00    1.924565E-06    1.000000E+00              9.00000E+100
         87  traj.phases.descent_1->path_constraint->throttle             i   0.000000E+00    4.824172E-02    1.000000E+00              9.00000E+100

--------------------------------------------------------------------------------
/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.

And let’s print out the objective value, fuel burned:

print(prob.get_val(av.Mission.Summary.FUEL_BURNED, units='kg')[0])
9706.706778487463

The added flexibility in the mission allowed the optimizer to reduce the fuel burn compared to the linear Mach profile case.

Looking at the altitude and Mach profiles, we see that the optimizer chose a more subtly complex Mach profile:

Altitude and Mach Profiles

Conclusion#

This example demonstrated how to use Aviary to optimize a more complex mission. We increased the number of segments in the mission, allowed the optimizer to choose the optimal Mach profile, and increased the polynomial control order to allow for more complex Mach profiles. We also modified the aircraft configuration to demonstrate how Aviary can be used to quickly evaluate the impact of design changes on the mission performance.