# Testing Cell
from pathlib import Path
from aviary.api import get_path
from aviary.interface.cmd_entry_points import _command_map
from aviary.interface.run_aviary import run_aviary
from aviary.utils.doctape import glue_keys, glue_variable
Path.exists(get_path('advanced_single_aisle_FLOPS.csv'))
Path.exists(get_path('models/missions/energy_state_default.py'))
if 'run_mission' in _command_map:
glue_variable('run_mission', md_code=True)
glue_variable(run_aviary.__name__, md_code=True)
glue_variable(f'{run_aviary.__name__}()', md_code=True)
run_mission
run_aviary
run_aviary()
Running a Simple Mission#
This example will show how to run an already existing aircraft through a pre-defined mission in Aviary. We will demonstrate two ways to run this example: through the command line interface, and using the Python API.
Aircraft#
The aircraft model used in this example is Aviary’s “Advanced Single Aisle”. This is a model of a theoretical aircraft with technology predictions of what a next-generation air transport might look like. The advanced single aisle is a conventional “tube-and-wing” configuration that seats 154 passengers - essentially a Boeing 737 or Airbus A320 with slightly improved performance. This aircraft uses the FLOPS analysis for aerodyanmics, geometry, and mass estimation.
The aircraft model exists as a csv text file (which can be seen here).
Mission#
This example uses the “energy-state” equations of motion. This method highly simplifies the flight physics, representing the aircraft as a point mass. This makes it fairly robust and quick to calculate.
We will be flying this aircraft through Aviary’s default mission profile. It includes 3 segments (climb, cruise, descent) with the following properties:
Climb
Mach starting at 0.2 and ending at 0.72
Altitude starting at 0 ft. and ending at 32,000 ft.
Cruise
Fixed Mach of 0.72
Altitude starting at 32,000 ft. and ending at 34,000 ft.
Descent
Mach starting at 0.72 and ending at 0.36
Altitude starting at 34,000 ft. and ending at 500 ft.
Total range of 1,906 nautical miles
The full mission definition is stored in a “phase_info” dictionary in a Python file (which can be found here)
Running via the Command Line#
We can run this aircraft model through the default mission very simply from the command line using the run_mission command.
This command needs the name of the aircraft csv file and phase_info file. Because we are using an example model provided in the Aviary source code itself, we only have to specify the name of this known aircraft. If you want to run your own custom model, you will need to provide the filepath to where that csv file is located.
In addition, we are also using the default “phase_info”, so we do not need to specify our own file. Just like with the aircraft model, if you want to run a custom mission you must provide the path to where you have defined that Python script.
!aviary run_mission advanced_single_aisle
Traceback (most recent call last):
File "/usr/share/miniconda/envs/test/bin/aviary", line 6, in <module>
sys.exit(aviary_cmd())
~~~~~~~~~~^^
File "/home/runner/work/Aviary/Aviary/aviary/interface/cmd_entry_points.py", line 173, in aviary_cmd
options.executor(options, user_args)
~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^
File "/home/runner/work/Aviary/Aviary/aviary/interface/run_aviary.py", line 180, in _exec_run_aviary
run_aviary_cmd(
~~~~~~~~~~~~~~^
input_deck=args.input_deck,
^^^^^^^^^^^^^^^^^^^^^^^^^^^
...<3 lines>...
verbosity=args.verbosity,
^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "/home/runner/work/Aviary/Aviary/aviary/interface/run_aviary.py", line 141, in run_aviary_cmd
prob = run_aviary(input_deck, phase_info, **kwargs)
File "/home/runner/work/Aviary/Aviary/aviary/interface/run_aviary.py", line 84, in run_aviary
prob.load_inputs(aircraft_data, phase_info, verbosity=verbosity)
~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/runner/work/Aviary/Aviary/aviary/core/aviary_problem.py", line 124, in load_inputs
aviary_inputs, verbosity = self.model.load_inputs(
~~~~~~~~~~~~~~~~~~~~~~^
aircraft_data=aircraft_data,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...<2 lines>...
verbosity=verbosity,
^^^^^^^^^^^^^^^^^^^^
)
^
File "/home/runner/work/Aviary/Aviary/aviary/core/aviary_group.py", line 201, in load_inputs
aviary_inputs, self.initialization_guesses = create_vehicle(
~~~~~~~~~~~~~~^
aircraft_data, meta_data=self.meta_data, verbosity=verbosity
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "/home/runner/work/Aviary/Aviary/aviary/utils/process_input_decks.py", line 115, in create_vehicle
aircraft_values, initialization_guesses = parse_inputs(
~~~~~~~~~~~~^
vehicle_deck=vehicle_deck,
^^^^^^^^^^^^^^^^^^^^^^^^^^
...<2 lines>...
meta_data=meta_data,
^^^^^^^^^^^^^^^^^^^^
)
^
File "/home/runner/work/Aviary/Aviary/aviary/utils/process_input_decks.py", line 162, in parse_inputs
with open(vehicle_deck, newline='') as f_in:
~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^
IsADirectoryError: [Errno 21] Is a directory: '/home/runner/work/Aviary/Aviary/aviary/models/aircraft/advanced_single_aisle'
Running via Python API#
We can also run that exact same problem setup using the basic Python API. Here we call the run_aviary() function with a the same information. Just like with the command line, we are able to take the same shortcuts because we are using pre-provided models and the default mission. However, for completeness the below code shows how to provide a full filepath for the aircraft input file and phase info file. This is the template you will need to use when using custom input files.
import aviary.api as av
prob = av.run_aviary(
aircraft_data='models/aircraft/advanced_single_aisle/advanced_single_aisle_FLOPS.csv',
phase_info='models/missions/energy_state_default',
)
/usr/share/miniconda/envs/test/lib/python3.13/site-packages/openmdao/utils/relevance.py:1296: OpenMDAOWarning:The following groups have a nonlinear solver that computes gradients and will be treated as atomic for the purposes of determining which systems are included in the optimization iteration:
traj.phases.climb.rhs_all.solver_sub
traj.phases.cruise.rhs_all.solver_sub
traj.phases.descent.rhs_all.solver_sub
/usr/share/miniconda/envs/test/lib/python3.13/site-packages/openmdao/solvers/linear/linear_rhs_checker.py:175: SolverWarning:DirectSolver in 'traj.phases.climb.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.13/site-packages/openmdao/solvers/linear/linear_rhs_checker.py:175: 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.13/site-packages/openmdao/solvers/linear/linear_rhs_checker.py:175: SolverWarning:DirectSolver in 'traj.phases.descent.indep_states' <class StateIndependentsComp>: 'rhs_checking' is active but no redundant adjoint dependencies were found, so caching has been disabled.
Total number of variables............................: 96
variables with only lower bounds: 93
variables with lower and upper bounds: 3
variables with only upper bounds: 0
Total number of equality constraints.................: 94
Total number of inequality constraints...............: 61
inequality constraints with only lower bounds: 1
inequality constraints with lower and upper bounds: 60
inequality constraints with only upper bounds: 0
Number of Iterations....: 16
(scaled) (unscaled)
Objective...............: 1.3234433662344252e+00 1.3234433662344252e+00
Dual infeasibility......: 3.0829817942481745e-08 3.0829817942481745e-08
Constraint violation....: 4.5492079551478333e-15 4.5492079551478333e-15
Variable bound violation: 0.0000000000000000e+00 0.0000000000000000e+00
Complementarity.........: 9.0921400446732355e-08 9.0921400446732355e-08
Overall NLP error.......: 9.0921400446732355e-08 9.0921400446732355e-08
Number of objective function evaluations = 24
Number of objective gradient evaluations = 17
Number of equality constraint evaluations = 24
Number of inequality constraint evaluations = 24
Number of equality constraint Jacobian evaluations = 17
Number of inequality constraint Jacobian evaluations = 17
Number of Lagrangian Hessian evaluations = 0
Total seconds in IPOPT
Optimization Problem -- Optimization using pyOpt_sparse
================================================================================
Objective Function: _objfunc
Objectives
Index Name Value
0 mission:objectives:fuel 1.323443E+00
Variables (c - continuous, i - integer, d - discrete)
Index Name Type Lower Bound Value Upper Bound Status
2 traj.climb.t_duration_0 c 5.000000E-01 5.000006E-01 1.500000E+00 l
Constraints (i - inequality, e - equality)
Index Name Type Lower Value Upper Status Lagrange Multiplier (N/A)
154 traj.descent.throttle[path] i 0.000000E+00 5.221075E-07 1.000000E+00 l 9.00000E+100
= 8.459
EXIT: Optimal Solution Found.
What Just Happened?#
This example just sized an aircraft model to fly a specified mission. Specifically, Aviary performed an optimization to minimize fuel burned during the mission while satisfying the aircraft design loop (finding the aircraft’s gross mass). Only gross mass was a design variable here - the optimizer did not touch any other aircraft properties during the Aviary run. We can see a brief output that shows us the optimization was successful and some stats about the optimization run. All of the behaviors that Aviary decided by default, such as the default mission flown, the objective of minimal fuel, and even how much information was printed to the terminal as the model ran, can all be adjusted. Several of the more advanced examples showcase changing these options.
Viewing Results#
While very little was printed to the terminal after we ran Aviary, all of the results were still saved! If you try running this example for yourself, you should see a new folder named “advanced_single_aisle_FLOPS_out” appear. This reports folder contains a wealth of information about your Aviary run - the Aviary Dashboard walkthrough in the User’s Guide explains how you can view your results.