Off-Design Missions#

Overview#

Off-design missions are missions that take an already designed and sized aircraft and attempt to run different mission trajectories, different payload quantities, or both.

Off-design missions are enabled for the following mission types:

  • HEIGHT_ENERGY

  • TWO_DEGREES_OF_FREEDOM

There are currently two types of off-design missions supported in Aviary:

  • Alternate Missions: the mission’s target range and aircraft payload mass are inputs and the fuel mass required is solved for.

  • Fallout Missions: the aircraft payload and gross mass as inputs and the range of the aircraft is solved for.

The off-design missions correspond to the different problem types that can have differing objectives which are discussed in detail in Level 2. The problem type determines what the optimizer can control to find a valid solution.

  • Sizing Missions allow the optimizer to control both the mission:summary:gross_mass and mission:design:gross_mass for the given mission and objective.

  • Alternate Missions allow the optimizer to only control the mission:summary:gross_mass for the mission.

  • Fallout Missions don’t allow the optimizer to control either mission:summary:gross_mass or mission:design:gross_mass but allows the optimizer to extend the range until the summary matches the design.

There are currently 3 different methods for running an off-design mission within Aviary.

The first method is to take the input deck of an already sized aircraft and change its problem type to either fallout or alternate.

Note

The user may need to revise some of the values in their input deck for the off-design mission. Since the aircraft is not re-designed, it is assumed that provided inputs constitute a valid aircraft.

The second method is to run off-design missions in the same script used to solve the design mission. An example of this is shown in aviary/examples/run_off_design_example.py.

The third method is to run a sizing mission to design the aircraft, save the sizing information to a JSON file, then load the off-design mission in another script.

Note

If the sizing mission did not converge to a valid aircraft design, any off-design analysis will be invalid even if the off-design missions themselves converged. Therefore the validity of off-design analysis depends entirely on the validity of its source sizing mission.

Off-Design from an already sized aircraft.#

The first method of running an off-design mission requires that the user has an input deck of a fully sized and valid aircraft. ex: aircraft_for_bench_FwFm.csv. This is done by adding one of the following lines to its csv file:

settings:problem_type, fallout

or

settings:problem_type, alternate

Once the problem type is specified, run Aviary as you would any other mission.

Note

Off-design missions are run with the assumption that the sizing mission’s mission:design:gross_mass is the maximum structural mass the aircraft can support. However, Aviary is capable of running a converging off-design missions with mission:summary:gross_mass that exceed that structural constraint. Therefore the user should check the mission:summary:gross_mass of the off-design to ensure the optimization is valid.

Sizing & off-design in the same script.#

Firstly, we highly recommend users first read through and understand the Level 2 onboarding guide before attempting an off-design mission.

This is the Aviary Team’s preferred method for running off-design missions as it allows the user to interrogate both the sizing and off-design missions together in the same script. Off-design functionality within the script involves first running a sizing mission then transferring the sizing parameters via JSON file into a new AviaryProblem() object. User input payload, phase_info, and mission_mass or mission_range is parsed to the new problem object and the problem is executed within the level 2 method.

Running an off-design mission first requires a sizing mission setup similar to aviary/examples/run_level2_example.py then the addition of save_sizing_to_json() to the AviaryProblem.

  • prob.save_sizing_to_json(json_filename = 'sizing_problem.json')

The save_sizing_to_json() argument saves the sizing mission’s parameters to a JSON filename of the user’s choosing where sizing_problem.json is the default filename.

To run a fallout or alternate mission these level 2 functions can be added to the end of the script.

  • prob.fallout_mission(json_filename = 'sizing_problem.json')

  • prob.alternate_mission(json_filename = 'sizing_problem.json')

If an argument is left empty Aviary will assume it is the same as that of the sizing mission. Both off-design mission types take payload as an input parameter. The mission’s payload is split up into the 3 passenger classes and the 2 cargo loadings. The respective Aviary variables are then updated with the user’s off-design passenger and cargo quantities.

Note

As of v0.9.10 Aviary’s off-design capabilities do not allow missions to be run with 0 passengers, so a minimum of 1 passenger must be specified. This is a known bug and is currently being investigated.

Inputs

Aviary Variable Name

Description

num_first

aircraft:crew_and_payload:num_first_class

The number of first class passengers

num_business

aircraft:crew_and_payload:num_business_class

The number of business class passengers

num_tourist

aircraft:crew_and_payload:num_tourist_class

The number of tourist class passengers

num_pax

aircraft:crew_and_payload:num_passengers

Total number of passengers

wing_cargo

aircraft:crew_and_payload:wing_cargo

Cargo carried in wing

misc_cargo

aircraft:crew_and_payload:misc_cargo

Additional cargo carried in fuselage

cargo_mass

aircraft:crew_and_payload:cargo_mass

Total mass of as-flown cargo

phase_info

phase_info

The mission trajectory for the aircraft

mission_range

target_range

The target range for alternate missions

mission_mass

mission:summary:gross_mass

The mission mass for fallout missions

Note

Off-design missions cannot be run with more passengers than the original sizing mission. For example, if aircraft:crew_and_payload:num_first_class within the Aviary inputs csv was set to 3, an off-design mission cannot be run where num_first = 8 as the cabin for first class was sized for precisely 3 passengers.

The phase_info argument allows the user to specify a different phase information for an off-design mission trajectory, more information can be found in The phase_info Format. This can be due to the off-design mission requiring a different trajectory shape or phase durations than the sizing mission. For example, an aircraft sized for long-range cruise might need its climb and descent profiles modified to operate on shorter routes.

Note

In cases where passengers or cargo are changed and the user has not specified a aircraft:crew_and_payload:cargo_container_mass in the Aviary input deck, off-design missions recalculates it in the off-design mission. It is the only parameter within the operating mass that gets recalculated between off-design and sizing.

%%capture

"""
This is an example of a sizing mission and alternate mission being run in the same script. 
This is done with 
"""
import aviary.api as av

# inputs that run_aviary() requires
aircraft_data = 'models/aircraft/test_aircraft/aircraft_for_bench_FwFm.csv'
optimizer = 'SLSQP'
phase_info = av.default_height_energy_phase_info
max_iter = 15

# Set up and run avairy problem.
prob = av.AviaryProblem(verbosity=0)

# This is the default FwFm (Flops weights Flops mission) aircraft.
prob.load_inputs(aircraft_data, phase_info)

prob.check_and_preprocess_inputs()

prob.add_pre_mission_systems()

prob.add_phases()

prob.add_post_mission_systems()

prob.link_phases()

prob.add_driver(optimizer, max_iter=max_iter)

prob.add_design_variables()

prob.add_objective()

prob.setup()

prob.set_initial_guesses()

prob.run_aviary_problem()

# save the sizing mission to a JSON file
prob.save_sizing_to_json(json_filename='off_design_documentation_example.json')

# initialize alternate mission flying a much shorter distance.
# if payload values are unspecified, off-design will uses the values from the sizing mission.
# the mission_range argument is much shorter than the sizing mission's 1906 NM range.
prob.alternate_mission(
    json_filename='off_design_documentation_example.json',
    num_first=0,
    num_business=0,
    num_tourist=50,
    num_pax=50,
    wing_cargo=0,
    misc_cargo=0,
    cargo_mass=0,
    mission_range=1000,
    phase_info=phase_info,
    verbosity=0,
)

Off-design missions separately#

The third method in running an off-design mission requires saving the sizing information as a JSON file using save_sizing_to_json() then calls the JSON file into an off-design mission in another script. This method allows for off-design missions to be run without re-executing the sizing mission every time. Once saved, the third method works identically to the second method except that the user must manually run the _load_off_design() function to create a new Aviary problem.

The _load_off_design() function then requires the json_filename input along with 3 additional problem definition parameters problem_type, equations_of_motion, and mass_method. Once defined, the _load_off_design() function essentially replaces the load_inputs() step of a standard level 2 problem. The user can then adjust payload quantities and mission_range/mission_gross_mass then complete the level 2 script as shown below.

  • problem_type: Determines which type of off-design analysis the user would like to run. (alternate or fallout)

  • equations_of_motion: Determines the type of trajectory calculations the user is running. (HEIGHT_ENERGY or TWO_DEGREES_OF_FREEDOM)

  • mass_method: Specifies how mass calculations are handled (FLOPS or GASP)

%%capture

"""
This is an example of running off-design mission directly form a saved sized aircraft JSON file
Note: If there were external subsystems in the original sized aircraft model 
these will NOT be transferred (since these are not saved in the JSON file).
"""

from aviary.interface.methods_for_level2 import _load_off_design
from aviary.variable_info.enums import LegacyCode
import aviary.api as av

optimizer = 'SLSQP'
phase_info = av.default_height_energy_phase_info
max_iter = 15
# Load aircraft and options data from provided sources

# To run an alternate mission, we need the sized aircraft JSON file from the sizing mission.
# Set ProblemType to ALTERNATE, and specify the mission range and payload mass.
# mission_gross_mass does nothing).

# Use specific _load_off_design function to define the off-design mission.
prob_alternate = _load_off_design(
    json_filename='off_design_documentation_example.json',
    problem_type=av.ProblemType.ALTERNATE,
    equations_of_motion=av.EquationsOfMotion.HEIGHT_ENERGY,
    mass_method=LegacyCode.FLOPS,
    phase_info=phase_info,
    num_first=0,
    num_business=0,
    num_tourist=50,
    num_pax=50,
    wing_cargo=0,
    misc_cargo=0,
    cargo_mass=0,
    mission_range=1000,
    verbosity=0,
)

# Run off-design mission the same way as any Level 2 aviary problem.
prob_alternate.check_and_preprocess_inputs()

prob_alternate.add_pre_mission_systems()

prob_alternate.add_phases()

prob_alternate.add_post_mission_systems()

prob_alternate.link_phases()

prob_alternate.add_driver(optimizer=optimizer, max_iter=max_iter)

prob_alternate.add_design_variables()

prob_alternate.add_objective()

prob_alternate.setup()

prob_alternate.set_initial_guesses()

prob_alternate.run_aviary_problem()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[3], line 21
     13 max_iter = 15
     14 # Load aircraft and options data from provided sources
     15 
     16 # To run an alternate mission, we need the sized aircraft JSON file from the sizing mission.
   (...)     19 
     20 # Use specific _load_off_design function to define the off-design mission.
---> 21 prob_alternate = _load_off_design(
     22     json_filename='off_design_documentation_example.json',
     23     problem_type=av.ProblemType.ALTERNATE,
     24     equations_of_motion=av.EquationsOfMotion.HEIGHT_ENERGY,
     25     mass_method=LegacyCode.FLOPS,
     26     phase_info=phase_info,
     27     num_first=0,
     28     num_business=0,
     29     num_tourist=50,
     30     num_pax=50,
     31     wing_cargo=0,
     32     misc_cargo=0,
     33     cargo_mass=0,
     34     mission_range=1000,
     35     verbosity=0,
     36 )
     38 # Run off-design mission the same way as any Level 2 aviary problem.
     39 prob_alternate.check_and_preprocess_inputs()

File ~/work/Aviary/Aviary/aviary/interface/methods_for_level2.py:2014, in _load_off_design(json_filename, problem_type, equations_of_motion, mass_method, phase_info, num_first, num_business, num_tourist, num_pax, wing_cargo, misc_cargo, cargo_mass, mission_range, mission_gross_mass, verbosity)
   2011         phase_info['post_mission']['target_range'] = (mission_range, 'nmi')
   2012     # set initial guess for Mission.Summary.GROSS_MASS to help optimizer with new design variable bounds.
   2013     prob.aviary_inputs.set_val(
-> 2014         Mission.Summary.GROSS_MASS, mission_gross_mass * 0.9, units='lbm'
   2015     )
   2017 elif problem_type == ProblemType.FALLOUT:
   2018     # Set mission fuel and calculate gross weight, aviary will calculate range
   2019     if mission_gross_mass is None:

TypeError: unsupported operand type(s) for *: 'NoneType' and 'float'

#