Examples of the same mission at different UI levels

Examples of the same mission at different UI levels#

Here we present a sort of Rosetta Stone for the same mission at different UI levels. This is to show the code used to make and solve similar mission optimization problems at different UI levels.

In each of these cases we’ll set the maximum iterations to 0 to save execution time. If you wanted to actually solve these problems, you’d need to set the maximum iterations to a larger number, like 50.

Note

Because we’re setting the max iter to 0, we see an “Optimization FAILED” output, but do not be concerned, this is expected as we’re simply showing the different levels here, not actually solving the problems.

Level 1#

This is the most basic level of the UI. There’s a command-line interface (CLI) for Level 1, or you can use the Python API shown below. If you want to make minor modifications to phase_info, you can do so here, but Level 1 largely assumes you’re using the default setup.

import aviary.api as av

prob = av.run_aviary('models/test_aircraft/aircraft_for_bench_FwFm.csv',
                     av.default_height_energy_phase_info,
                     max_iter=0, optimizer="SLSQP", make_plots=False)
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/pyoptsparse/pyOpt_MPI.py:68: UserWarning: mpi4py could not be imported. mpi4py is required to use the parallel gradient analysis and parallel objective analysis for non-gradient based optimizers. Continuing using a dummy MPI module from pyOptSparse.
  warnings.warn(warn)
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/dymos/phase/phase.py:902: 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:2328: RuntimeWarning: Invalid options for non-optimal control 'mach' in phase 'climb': 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:2328: RuntimeWarning: Invalid options for non-optimal control 'altitude' in phase 'climb': 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:2328: RuntimeWarning: Invalid options for non-optimal control 'mach' 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:2328: 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:2328: RuntimeWarning: Invalid options for non-optimal control 'mach' in phase 'descent': 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:2328: RuntimeWarning: Invalid options for non-optimal control 'altitude' in phase 'descent': 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
  'aircraft:engine:mass
  'aircraft:fins:mass
  'aircraft:fuel:auxiliary_fuel_capacity
  'aircraft:fuel:fuselage_fuel_capacity
  'aircraft:fuel:total_capacity
  'aircraft:fuselage:planform_area
  'aircraft:fuselage:wetted_area
  'aircraft:horizontal_tail:wetted_area
  'aircraft:landing_gear:main_gear_oleo_length
  'aircraft:landing_gear:nose_gear_oleo_length
  'aircraft:vertical_tail:wetted_area
  'aircraft:wing:aspect_ratio
  'aircraft:wing:control_surface_area
  'aircraft:wing:wetted_area

--- Constraint Report [traj] ---
    --- climb ---
        [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 ---
        [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:178: 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:178: 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.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/recorders/sqlite_recorder.py:226: UserWarning:The existing case recorder file, problem_history.db, is being overwritten.
Model viewer data has already been recorded for Driver.
Full total jacobian for problem 'aircraft_for_bench_FwFm' was computed 3 times, taking 0.6521291650000194 seconds.
Total jacobian shape: (136, 95) 


Jacobian shape: (136, 95)  (8.37% nonzero)
FWD solves: 13   REV solves: 0
Total colors vs. total size: 13 vs 95  (86.32% improvement)

Sparsity computed using tolerance: 1e-25
Time to compute sparsity:   0.6521 sec
Time to compute coloring:   0.0539 sec
Memory to compute coloring:   0.0000 MB
Coloring created on: 2024-09-16 15:57:17
Iteration limit reached    (Exit mode 9)
            Current function value: 0.3
            Iterations: 1
            Function evaluations: 1
            Gradient evaluations: 1
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.

Level 2#

This level grants more flexibility both in defining the phase_info object but also in calling the individual methods of AviaryProblem when setting up and running your model. You can modify the methods you call, what they do, and what info they’re given here. This is much more verbose than Level 1. In the absence of additional arguments to the methods, much of the default behavior here is the same as Level 1.

import aviary.api as av

phase_info = {
    "pre_mission": {"include_takeoff": False, "optimize_mass": True},
    "climb": {
        "subsystem_options": {"core_aerodynamics": {"method": "computed"}},
        "user_options": {
            "optimize_mach": False,
            "optimize_altitude": False,
            "polynomial_control_order": 1,
            "num_segments": 5,
            "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": (32000.0, "ft"),
            "altitude_bounds": ((0.0, 34000.0), "ft"),
            "throttle_enforcement": "path_constraint",
            "fix_initial": True,
            "constrain_final": False,
            "fix_duration": False,
            "initial_bounds": ((0.0, 0.0), "min"),
            "duration_bounds": ((64.0, 192.0), "min"),
            "add_initial_mass_constraint": False,
        },
        "initial_guesses": {"time": ([0, 128], "min")},
    },
    "cruise": {
        "subsystem_options": {"core_aerodynamics": {"method": "computed"}},
        "user_options": {
            "optimize_mach": False,
            "optimize_altitude": False,
            "polynomial_control_order": 1,
            "num_segments": 5,
            "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": (32000.0, "ft"),
            "final_altitude": (34000.0, "ft"),
            "altitude_bounds": ((23000.0, 38000.0), "ft"),
            "throttle_enforcement": "boundary_constraint",
            "fix_initial": False,
            "constrain_final": False,
            "fix_duration": False,
            "initial_bounds": ((64.0, 192.0), "min"),
            "duration_bounds": ((56.5, 169.5), "min"),
        },
        "initial_guesses": {"time": ([128, 113], "min")},
    },
    "descent": {
        "subsystem_options": {"core_aerodynamics": {"method": "computed"}},
        "user_options": {
            "optimize_mach": False,
            "optimize_altitude": False,
            "polynomial_control_order": 1,
            "num_segments": 5,
            "order": 3,
            "solve_for_distance": False,
            "initial_mach": (0.72, "unitless"),
            "final_mach": (0.36, "unitless"),
            "mach_bounds": ((0.34, 0.74), "unitless"),
            "initial_altitude": (34000.0, "ft"),
            "final_altitude": (500.0, "ft"),
            "altitude_bounds": ((0.0, 38000.0), "ft"),
            "throttle_enforcement": "path_constraint",
            "fix_initial": False,
            "constrain_final": True,
            "fix_duration": False,
            "initial_bounds": ((120.5, 361.5), "min"),
            "duration_bounds": ((29.0, 87.0), "min"),
        },
        "initial_guesses": {"time": ([241, 58], "min")},
    },
    "post_mission": {
        "include_landing": False,
        "constrain_range": True,
        "target_range": (1906, "nmi"),
    },
}

csv_path = "models/test_aircraft/aircraft_for_bench_FwFm.csv"

prob = av.AviaryProblem()

# Load aircraft and options data from user
# Allow for user overrides here
prob.load_inputs(csv_path, phase_info)

prob.check_and_preprocess_inputs()

prob.add_pre_mission_systems()

prob.add_phases()

prob.add_post_mission_systems()

# Link phases and variables
prob.link_phases()

prob.add_driver("SLSQP", max_iter=0)

prob.add_design_variables()

prob.add_objective(objective_type="mass", ref=-1e5)

prob.setup()

prob.set_initial_guesses()

prob.run_aviary_problem(record_filename='level2_example.db', suppress_solver_print=True, make_plots=False)
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/dymos/phase/phase.py:902: 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:2328: RuntimeWarning: Invalid options for non-optimal control 'mach' in phase 'climb': 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:2328: RuntimeWarning: Invalid options for non-optimal control 'altitude' in phase 'climb': 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:2328: RuntimeWarning: Invalid options for non-optimal control 'mach' 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:2328: 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:2328: RuntimeWarning: Invalid options for non-optimal control 'mach' in phase 'descent': 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:2328: RuntimeWarning: Invalid options for non-optimal control 'altitude' in phase 'descent': 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
  'aircraft:engine:mass
  'aircraft:fins:mass
  'aircraft:fuel:auxiliary_fuel_capacity
  'aircraft:fuel:fuselage_fuel_capacity
  'aircraft:fuel:total_capacity
  'aircraft:fuselage:planform_area
  'aircraft:fuselage:wetted_area
  'aircraft:horizontal_tail:wetted_area
  'aircraft:landing_gear:main_gear_oleo_length
  'aircraft:landing_gear:nose_gear_oleo_length
  'aircraft:vertical_tail:wetted_area
  'aircraft:wing:aspect_ratio
  'aircraft:wing:control_surface_area
  'aircraft:wing:wetted_area

--- Constraint Report [traj] ---
    --- climb ---
        [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 ---
        [path]    0.0000e+00 <= throttle <= 1.0000e+00  [unitless]
Model viewer data has already been recorded for Driver.
Full total jacobian for problem 'problem2' was computed 3 times, taking 0.64874535499996 seconds.
Total jacobian shape: (136, 95) 


Jacobian shape: (136, 95)  (7.79% nonzero)
FWD solves: 12   REV solves: 0
Total colors vs. total size: 12 vs 95  (87.37% improvement)

Sparsity computed using tolerance: 1e-25
Time to compute sparsity:   0.6487 sec
Time to compute coloring:   0.0522 sec
Memory to compute coloring:   0.0000 MB
Coloring created on: 2024-09-16 15:57:22
Iteration limit reached    (Exit mode 9)
            Current function value: -0.7956010169800001
            Iterations: 1
            Function evaluations: 1
            Gradient evaluations: 1
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.

Level 3#

This level is the most flexible and the code will be the most verbose. This directly calls the OpenMDAO and Dymos methods used to set up and run the model. You have supreme control over every part of the model and mission definition, but that flexibility results in much more code.

import scipy.constants as _units

import openmdao.api as om
import dymos as dm

import aviary.api as av
from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems


prob = om.Problem(model=om.Group())
driver = prob.driver = om.ScipyOptimizeDriver()
driver.options["optimizer"] = "SLSQP"
driver.options["maxiter"] = 1

########################################
# Aircraft Input Variables and Options #
########################################

csv_path = "models/test_aircraft/aircraft_for_bench_FwFm.csv"

aviary_inputs, _ = av.create_vehicle('models/test_aircraft/aircraft_for_bench_FwFm.csv')

engine = av.build_engine_deck(aviary_inputs)
av.preprocess_options(aviary_inputs, engine_models=engine)

alt_airport = 0  # ft

alt_i_climb = 0*_units.foot  # m
alt_f_climb = 32000.0*_units.foot  # m
mass_i_climb = 131000*_units.lb  # kg
mass_f_climb = 126000*_units.lb  # kg
mach_i_climb = 0.2
mach_f_climb = 0.72
distance_i_climb = 0*_units.nautical_mile  # m
distance_f_climb = 160.3*_units.nautical_mile  # m
t_i_climb = 0. * _units.minute  # sec
t_f_climb = 128 * _units.minute  # sec
t_duration_climb = t_f_climb - t_i_climb

alt_i_cruise = 32000*_units.foot  # m
alt_f_cruise = 34000*_units.foot  # m
alt_min_cruise = 32000*_units.foot  # m
alt_max_cruise = 34000*_units.foot  # m
mass_i_cruise = 126000*_units.lb  # kg
mass_f_cruise = 102000*_units.lb  # kg
cruise_mach = 0.79
distance_i_cruise = 160.3*_units.nautical_mile  # m
distance_f_cruise = 3243.9*_units.nautical_mile  # m
t_i_cruise = 128. * _units.minute  # sec
t_f_cruise = 241. * _units.minute  # sec
t_duration_cruise = t_f_cruise - t_i_cruise

alt_i_descent = 34000*_units.foot
alt_f_descent = 500*_units.foot
mach_i_descent = 0.72
mach_f_descent = 0.3
mass_i_descent = 102000*_units.pound
mass_f_descent = 101000*_units.pound
distance_i_descent = 3243.9*_units.nautical_mile
distance_f_descent = 3378.7*_units.nautical_mile
t_i_descent = 241. * _units.minute
t_f_descent = 299. * _units.minute
t_duration_descent = t_f_descent - t_i_descent

####################
# Build Subsystems #
####################
aero = av.CoreAerodynamicsBuilder(code_origin=av.LegacyCode('FLOPS'))
geom = av.CoreGeometryBuilder(code_origin=av.LegacyCode('FLOPS'))
mass = av.CoreMassBuilder(code_origin=av.LegacyCode('FLOPS'))
prop = av.CorePropulsionBuilder(engine_models=engine)

premission_subsystems = [prop, geom, aero, mass]
mission_subsystems = [aero, prop]

####################
# Design Variables #
####################

# Nudge it a bit off the correct answer to verify that the optimize takes us there.
aviary_inputs.set_val(av.Mission.Design.GROSS_MASS, 135000.0, units='lbm')

prob.model.add_design_var(av.Mission.Design.GROSS_MASS, units='lbm',
                            lower=100000.0, upper=200000.0, ref=135000)

# default subsystems
default_mission_subsystems = get_default_mission_subsystems('FLOPS', engine)

#################
# Define Phases #
#################
num_segments_climb = 6
num_segments_cruise = 1
num_segments_descent = 5

climb_seg_ends, _ = dm.utils.lgl.lgl(num_segments_climb + 1)
descent_seg_ends, _ = dm.utils.lgl.lgl(num_segments_descent + 1)

transcription_climb = dm.Radau(
    num_segments=num_segments_climb, order=3, compressed=True,
    segment_ends=climb_seg_ends)
transcription_cruise = dm.Radau(
    num_segments=num_segments_cruise, order=3, compressed=True)
transcription_descent = dm.Radau(
    num_segments=num_segments_descent, order=3, compressed=True,
    segment_ends=descent_seg_ends)

climb_options = av.HeightEnergyPhaseBuilder(
    'test_climb',
    user_options=av.AviaryValues({
        'initial_altitude': (alt_i_climb, 'm'),
        'final_altitude': (alt_f_climb, 'm'),
        'initial_mach': (mach_i_climb, 'unitless'),
        'final_mach': (mach_f_climb, 'unitless'),
        'fix_initial': (True, 'unitless'),
        'use_polynomial_control': (False, 'unitless'),
    }),
    core_subsystems=default_mission_subsystems,
    subsystem_options={'core_aerodynamics': {'method': 'computed'}},
    transcription=transcription_climb,
)

cruise_options = av.HeightEnergyPhaseBuilder(
    'test_cruise',
    user_options=av.AviaryValues({
        'initial_altitude': (alt_min_cruise, 'm'),
        'final_altitude': (alt_max_cruise, 'm'),
        'initial_mach': (cruise_mach, 'unitless'),
        'final_mach': (cruise_mach, 'unitless'),
        'required_available_climb_rate': (300, 'ft/min'),
        'fix_initial': (False, 'unitless'),
    }),
    core_subsystems=default_mission_subsystems,
    subsystem_options={'core_aerodynamics': {'method': 'computed'}},
    transcription=transcription_cruise,
)

descent_options = av.HeightEnergyPhaseBuilder(
    'test_descent',
    user_options=av.AviaryValues({
        'final_altitude': (alt_f_descent, 'm'),
        'initial_altitude': (alt_i_descent, 'm'),
        'initial_mach': (mach_i_descent, 'unitless'),
        'final_mach': (mach_f_descent, 'unitless'),
        'fix_initial': (False, 'unitless'),
        'use_polynomial_control': (False, 'unitless'),
    }),
    core_subsystems=default_mission_subsystems,
    subsystem_options={'core_aerodynamics': {'method': 'computed'}},
    transcription=transcription_descent,
)

av.preprocess_crewpayload(aviary_inputs)

# Upstream pre-mission analysis for aero
prob.model.add_subsystem(
    'pre_mission',
    av.CorePreMission(aviary_options=aviary_inputs,
                    subsystems=premission_subsystems),
    promotes_inputs=['aircraft:*', 'mission:*'],
    promotes_outputs=['aircraft:*', 'mission:*'])

# directly connect phases (strong_couple = True), or use linkage constraints (weak
# coupling / strong_couple=False)
strong_couple = False

climb = climb_options.build_phase(aviary_options=aviary_inputs)

cruise = cruise_options.build_phase(aviary_options=aviary_inputs)

descent = descent_options.build_phase(aviary_options=aviary_inputs)

traj = prob.model.add_subsystem('traj', dm.Trajectory())

# if fix_initial is false, can we always set input_initial to be true for
# necessary states, and then ignore if we use a linkage?
climb.set_time_options(fix_initial=True, fix_duration=False, units='s',
                        duration_bounds=(t_duration_climb*0.5, t_duration_climb*2),
                        duration_ref=t_duration_climb)
cruise.set_time_options(fix_initial=False, fix_duration=False, units='s',
                        duration_bounds=(t_duration_cruise*0.5, t_duration_cruise*2),
                        duration_ref=t_duration_cruise,
                        initial_bounds=(t_duration_climb*0.5, t_duration_climb*2))
descent.set_time_options(
    fix_initial=False, fix_duration=False, units='s',
    duration_bounds=(t_duration_descent*0.5, t_duration_descent*2),
    duration_ref=t_duration_descent,
    initial_bounds=(
        (t_duration_cruise + t_duration_climb)*0.5,
        (t_duration_cruise + t_duration_climb)*2))

traj.add_phase('climb', climb)

traj.add_phase('cruise', cruise)

traj.add_phase('descent', descent)

traj.link_phases(["climb", "cruise", "descent"], [
                    "time", "mass", "distance"], connected=strong_couple)

# Need to declare dymos parameters for every input that is promoted out of the missions.
external_parameters = {'climb': {}, 'cruise': {}, 'descent': {}}
for default_subsys in default_mission_subsystems:
    params = default_subsys.get_parameters(aviary_inputs=aviary_inputs,
                                           phase_info={})
    for key, val in params.items():
        for phname in external_parameters:
            external_parameters[phname][key] = val
                
traj = av.setup_trajectory_params(prob.model, traj, aviary_inputs, 
                                  external_parameters=external_parameters)

###############
# Constraints #
###############

ecomp = om.ExecComp('fuel_burned = initial_mass - descent_mass_final',
                    initial_mass={'units': 'lbm', 'shape': 1},
                    descent_mass_final={'units': 'lbm', 'shape': 1},
                    fuel_burned={'units': 'lbm', 'shape': 1})

prob.model.add_subsystem('fuel_burn', ecomp,
                            promotes_inputs=[
                                ('initial_mass', av.Mission.Design.GROSS_MASS)],
                            promotes_outputs=['fuel_burned'])

prob.model.connect("traj.descent.states:mass",
                    "fuel_burn.descent_mass_final", src_indices=[-1])

##########################
# Add Objective Function #
##########################

prob.model.add_objective("fuel_burned", ref=1e4)

# Set initial default values for any variables that have
# different defaults in premission and mission.
varnames = [
    av.Aircraft.Wing.AREA,
    av.Aircraft.Wing.MAX_CAMBER_AT_70_SEMISPAN,
    av.Aircraft.Wing.SWEEP,
    av.Aircraft.Wing.TAPER_RATIO,
    av.Aircraft.Wing.THICKNESS_TO_CHORD,
    av.Mission.Design.GROSS_MASS,
]
av.set_aviary_input_defaults(prob.model, varnames, aviary_inputs)

prob.setup(force_alloc_complex=True)

av.set_aviary_initial_values(prob, aviary_inputs)

############################################
# Initial Settings for States and Controls #
############################################

prob.set_val('traj.climb.t_initial', t_i_climb, units='s')
prob.set_val('traj.climb.t_duration', t_duration_climb, units='s')

prob.set_val('traj.climb.controls:altitude', climb.interp(
    av.Dynamic.Mission.ALTITUDE, ys=[alt_i_climb, alt_f_climb]), units='m')
prob.set_val(
    'traj.climb.controls:mach', climb.interp(
        av.Dynamic.Mission.MACH, ys=[mach_i_climb, mach_f_climb]), units='unitless')
prob.set_val('traj.climb.states:mass', climb.interp(
    av.Dynamic.Mission.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg')
prob.set_val('traj.climb.states:distance', climb.interp(
    av.Dynamic.Mission.DISTANCE, ys=[distance_i_climb, distance_f_climb]), units='m')

prob.set_val('traj.cruise.t_initial', t_i_cruise, units='s')
prob.set_val('traj.cruise.t_duration', t_duration_cruise, units='s')

prob.set_val('traj.cruise.controls:altitude', cruise.interp(
    av.Dynamic.Mission.ALTITUDE, ys=[alt_i_cruise, alt_f_cruise]), units='m')
prob.set_val(
    'traj.cruise.controls:mach', cruise.interp(
        av.Dynamic.Mission.MACH, ys=[cruise_mach, cruise_mach]), units='unitless')
prob.set_val('traj.cruise.states:mass', cruise.interp(
    av.Dynamic.Mission.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg')
prob.set_val('traj.cruise.states:distance', cruise.interp(
    av.Dynamic.Mission.DISTANCE, ys=[distance_i_cruise, distance_f_cruise]), units='m')

prob.set_val('traj.descent.t_initial', t_i_descent, units='s')
prob.set_val('traj.descent.t_duration', t_duration_descent, units='s')

prob.set_val('traj.descent.controls:altitude', descent.interp(
    av.Dynamic.Mission.ALTITUDE, ys=[alt_i_descent, alt_f_descent]), units='m')
prob.set_val(
    'traj.descent.controls:mach', descent.interp(
        av.Dynamic.Mission.MACH, ys=[mach_i_descent, mach_f_descent]), units='unitless')
prob.set_val('traj.descent.states:mass', descent.interp(
    av.Dynamic.Mission.MASS, ys=[mass_i_descent, mass_f_descent]), units='kg')
prob.set_val('traj.descent.states:distance', descent.interp(
    av.Dynamic.Mission.DISTANCE, ys=[distance_i_descent, distance_f_descent]), units='m')

# Turn off solver printing so that the SNOPT output is readable.
prob.set_solver_print(level=0)

dm.run_problem(prob, simulate=False, make_plots=False, simulate_kwargs={
                'times_per_seg': 100, 'atol': 1e-9, 'rtol': 1e-9})
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/dymos/phase/phase.py:902: 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:2328: RuntimeWarning: Invalid options for non-optimal control 'mach' in phase 'climb': 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:2328: RuntimeWarning: Invalid options for non-optimal control 'altitude' in phase 'climb': 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:2328: RuntimeWarning: Invalid options for non-optimal control 'mach' 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:2328: 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:2328: RuntimeWarning: Invalid options for non-optimal control 'mach' in phase 'descent': 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:2328: RuntimeWarning: Invalid options for non-optimal control 'altitude' in phase 'descent': 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/openmdao/core/system.py:4284: OpenMDAOWarning:Calling `list_inputs` before `final_setup` will only display the default values of variables and will not show the result of any `set_val` calls.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_propulsion.turbofan_28k' <class SizeEngine>: input variable 'aircraft:engine:scaled_sls_thrust', promoted using 'aircraft:engine:scaled_sls_thrust', was already promoted using 'aircraft:engine:scaled_sls_thrust'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.canard' <class Canard>: input variable 'aircraft:canard:area', promoted using 'aircraft:canard:area', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.canard' <class Canard>: input variable 'aircraft:canard:thickness_to_chord', promoted using 'aircraft:canard:thickness_to_chord', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.canard' <class Canard>: input variable 'aircraft:canard:wetted_area_scaler', promoted using 'aircraft:canard:wetted_area_scaler', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' <class CharacteristicLengths>: input variable 'aircraft:canard:area', promoted using 'aircraft:canard:area', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' <class CharacteristicLengths>: input variable 'aircraft:canard:aspect_ratio', promoted using 'aircraft:canard:aspect_ratio', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' <class CharacteristicLengths>: input variable 'aircraft:canard:thickness_to_chord', promoted using 'aircraft:canard:thickness_to_chord', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' <class CharacteristicLengths>: input variable 'aircraft:fuselage:avg_diameter', promoted using 'aircraft:fuselage:avg_diameter', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' <class CharacteristicLengths>: input variable 'aircraft:fuselage:length', promoted using 'aircraft:fuselage:length', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' <class CharacteristicLengths>: input variable 'aircraft:horizontal_tail:area', promoted using 'aircraft:horizontal_tail:area', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' <class CharacteristicLengths>: input variable 'aircraft:horizontal_tail:aspect_ratio', promoted using 'aircraft:horizontal_tail:aspect_ratio', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' <class CharacteristicLengths>: input variable 'aircraft:horizontal_tail:thickness_to_chord', promoted using 'aircraft:horizontal_tail:thickness_to_chord', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' <class CharacteristicLengths>: input variable 'aircraft:nacelle:avg_diameter', promoted using 'aircraft:nacelle:avg_diameter', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' <class CharacteristicLengths>: input variable 'aircraft:nacelle:avg_length', promoted using 'aircraft:nacelle:avg_length', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' <class CharacteristicLengths>: input variable 'aircraft:vertical_tail:area', promoted using 'aircraft:vertical_tail:area', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' <class CharacteristicLengths>: input variable 'aircraft:vertical_tail:aspect_ratio', promoted using 'aircraft:vertical_tail:aspect_ratio', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' <class CharacteristicLengths>: input variable 'aircraft:vertical_tail:thickness_to_chord', promoted using 'aircraft:vertical_tail:thickness_to_chord', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' <class CharacteristicLengths>: input variable 'aircraft:wing:area', promoted using 'aircraft:wing:area', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' <class CharacteristicLengths>: input variable 'aircraft:wing:aspect_ratio', promoted using 'aircraft:wing:aspect_ratio', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' <class CharacteristicLengths>: input variable 'aircraft:wing:glove_and_bat', promoted using 'aircraft:wing:glove_and_bat', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' <class CharacteristicLengths>: input variable 'aircraft:wing:taper_ratio', promoted using 'aircraft:wing:taper_ratio', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.characteristic_lengths' <class CharacteristicLengths>: input variable 'aircraft:wing:thickness_to_chord', promoted using 'aircraft:wing:thickness_to_chord', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.fuselage' <class _Fuselage>: input variable 'aircraft:fuselage:avg_diameter', promoted using 'aircraft:fuselage:avg_diameter', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.fuselage' <class _Fuselage>: input variable 'aircraft:fuselage:length', promoted using 'aircraft:fuselage:length', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.fuselage' <class _Fuselage>: input variable 'aircraft:fuselage:wetted_area_scaler', promoted using 'aircraft:fuselage:wetted_area_scaler', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.fuselage' <class _Fuselage>: input variable 'aircraft:horizontal_tail:thickness_to_chord', promoted using 'aircraft:horizontal_tail:thickness_to_chord', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.fuselage' <class _Fuselage>: input variable 'aircraft:horizontal_tail:vertical_tail_fraction', promoted using 'aircraft:horizontal_tail:vertical_tail_fraction', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.fuselage' <class _Fuselage>: input variable 'aircraft:vertical_tail:thickness_to_chord', promoted using 'aircraft:vertical_tail:thickness_to_chord', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.fuselage' <class _Fuselage>: input variable 'aircraft:wing:area', promoted using 'aircraft:wing:area', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.fuselage' <class _Fuselage>: input variable 'aircraft:wing:aspect_ratio', promoted using 'aircraft:wing:aspect_ratio', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.fuselage' <class _Fuselage>: input variable 'aircraft:wing:glove_and_bat', promoted using 'aircraft:wing:glove_and_bat', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.fuselage' <class _Fuselage>: input variable 'aircraft:wing:thickness_to_chord', promoted using 'aircraft:wing:thickness_to_chord', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.nacelles' <class Nacelles>: input variable 'aircraft:nacelle:avg_diameter', promoted using 'aircraft:nacelle:avg_diameter', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.nacelles' <class Nacelles>: input variable 'aircraft:nacelle:avg_length', promoted using 'aircraft:nacelle:avg_length', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.nacelles' <class Nacelles>: input variable 'aircraft:nacelle:wetted_area_scaler', promoted using 'aircraft:nacelle:wetted_area_scaler', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.tail' <class _Tail>: input variable 'aircraft:horizontal_tail:area', promoted using 'aircraft:horizontal_tail:area', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.tail' <class _Tail>: input variable 'aircraft:horizontal_tail:vertical_tail_fraction', promoted using 'aircraft:horizontal_tail:vertical_tail_fraction', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.tail' <class _Tail>: input variable 'aircraft:horizontal_tail:wetted_area_scaler', promoted using 'aircraft:horizontal_tail:wetted_area_scaler', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.tail' <class _Tail>: input variable 'aircraft:vertical_tail:area', promoted using 'aircraft:vertical_tail:area', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.tail' <class _Tail>: input variable 'aircraft:vertical_tail:wetted_area_scaler', promoted using 'aircraft:vertical_tail:wetted_area_scaler', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.wing' <class _Wing>: input variable 'aircraft:wing:area', promoted using 'aircraft:wing:area', was already promoted using 'aircraft*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2422: PromotionWarning:'pre_mission.core_geometry.wing' <class _Wing>: input variable 'aircraft:wing:wetted_area_scaler', promoted using 'aircraft:wing:wetted_area_scaler', was already promoted using 'aircraft*'.
The following variables have been overridden:
  'aircraft:design:touchdown_mass
  'aircraft:engine:mass
  'aircraft:fins:mass
  'aircraft:fuel:auxiliary_fuel_capacity
  'aircraft:fuel:fuselage_fuel_capacity
  'aircraft:fuel:total_capacity
  'aircraft:fuselage:planform_area
  'aircraft:fuselage:wetted_area
  'aircraft:horizontal_tail:wetted_area
  'aircraft:landing_gear:main_gear_oleo_length
  'aircraft:landing_gear:nose_gear_oleo_length
  'aircraft:vertical_tail:wetted_area
  'aircraft:wing:aspect_ratio
  'aircraft:wing:control_surface_area
  'aircraft:wing:wetted_area

--- Constraint Report [traj] ---
    --- climb ---
        None
    --- cruise ---
        [path]    3.0000e+02 <= altitude_rate_max  [ft/min]
    --- descent ---
        None
Model viewer data has already been recorded for Driver.
Iteration limit reached    (Exit mode 9)
            Current function value: 3.4000000000000017
            Iterations: 1
            Function evaluations: 1
            Gradient evaluations: 1
Optimization FAILED.
Iteration limit reached
-----------------------------------
Problem: problem3
Driver:  ScipyOptimizeDriver
  success     : False
  iterations  : 2
  runtime     : 6.8756E-01 s
  model_evals : 2
  model_time  : 5.7782E-01 s
  deriv_evals : 1
  deriv_time  : 9.3582E-02 s
  exit_status : FAIL