Level 3#

Level 3 represents the highest level of user control and customization in Aviary’s user interface. At this level, users have full access to Python and OpenMDAO methods that Aviary calls. They can use the complete set of Aviary’s methods, functionalities, and classes to construct and fine-tune their aircraft models. Level 3 enables users to have supreme control over every aspect of the model, including subsystems, connections, and advanced optimization techniques.

Level 3 is the most complex but specific methods defined at this level are used in levels 1 and 2, hopefully reducing user activation energy when learning more about Aviary. This progressive approach helps users gradually enhance their analysis capabilities and adapt to more complex modeling requirements as they gain proficiency and experience.

We will show two approaches of level 3 development using two examples: The first one will implement all methods differently from what are available in aviary/interface/methods_for_level2.py but will follow the same steps. It will show that you don’t have to have a .csv input file and you don’t have to have a phase_info dictionary. The second is a solved mission approach that is embedded into all the methods of aviary/interface/methods_for_level2.py.

Note

For each of these examples we have set max_iter = 0, which means that the optimization will not run. This is done to reduce the computational time for the examples. If you want to run the optimization, you can set max_iter = 100 or some similar value.

A level 3 example: N3CC#

In level 2, we have shown how to follow the standard steps to build an Aviary model, but sometimes you may find that the model you have in mind does not match that predefined structure. If you start a new model that cannot been embedded in those methods, we can write special methods ourselves. This example will show you how to do that.

In aviary/validation_cases/benchmark_tests folder, there is an N3CC aircraft full mission benchmark test test_FLOPS_based_sizing_N3CC.py. Now, we will show how to create an N3CC example in level3. The key is that we follow the same steps:

  • init

  • load_inputs

  • check_and_preprocess_inputs (optional)

  • add_pre_mission_systems

  • add_phases

  • add_post_mission_systems

  • link_phases

  • add_driver

  • add_design_variables (optional)

  • add_objective

  • setup

  • set_initial_guesses

  • run_aviary_problem

Examining an N3CC design case#

'''
NOTES:
Includes:
Takeoff, Climb, Cruise, Descent, Landing
Computed Aero
N3CC data
'''

import dymos as dm
import openmdao.api as om
import scipy.constants as _units

import aviary.api as av
from aviary.validation_cases.validation_tests import get_flops_inputs


prob = om.Problem(model=om.Group())
driver = prob.driver = om.pyOptSparseDriver()
driver.options["optimizer"] = "IPOPT"
driver.opt_settings["max_iter"] = 100
driver.opt_settings["tol"] = 1e-3
driver.opt_settings['print_level'] = 4

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

aviary_inputs = get_flops_inputs('N3CC')

aviary_inputs.set_val(av.Mission.Landing.LIFT_COEFFICIENT_MAX,
                        2.4, units="unitless")
aviary_inputs.set_val(av.Mission.Takeoff.LIFT_COEFFICIENT_MAX,
                        2.0, units="unitless")
aviary_inputs.set_val(
    av.Mission.Takeoff.ROLLING_FRICTION_COEFFICIENT,
    val=.0175, units="unitless")

takeoff_fuel_burned = 577  # lbm
takeoff_thrust_per_eng = 24555.5  # lbf
takeoff_L_over_D = 17.35

aviary_inputs.set_val(av.Mission.Takeoff.FUEL_SIMPLE,
                        takeoff_fuel_burned, units='lbm')
aviary_inputs.set_val(av.Mission.Takeoff.LIFT_OVER_DRAG,
                        takeoff_L_over_D, units="unitless")
aviary_inputs.set_val(av.Mission.Design.THRUST_TAKEOFF_PER_ENG,
                        takeoff_thrust_per_eng, units='lbf')

alt_airport = 0  # ft
cruise_mach = 0.79

alt_i_climb = 0*_units.foot  # m
alt_f_climb = 35000.0*_units.foot  # m
mass_i_climb = 131000*_units.lb  # kg
mass_f_climb = 126000*_units.lb  # kg
# initial mach set to lower value so it can intersect with takeoff end mach
# mach_i_climb = 0.3
mach_i_climb = 0.2
mach_f_climb = cruise_mach
range_i_climb = 0*_units.nautical_mile  # m
range_f_climb = 160.3*_units.nautical_mile  # m
t_i_climb = 2 * _units.minute  # sec
t_f_climb = 26.20*_units.minute  # sec
t_duration_climb = t_f_climb - t_i_climb

alt_i_cruise = 35000*_units.foot  # m
alt_f_cruise = 35000*_units.foot  # m
alt_min_cruise = 35000*_units.foot  # m
alt_max_cruise = 35000*_units.foot  # m
mass_i_cruise = 126000*_units.lb  # kg
mass_f_cruise = 102000*_units.lb  # kg
cruise_mach = cruise_mach
range_i_cruise = 160.3*_units.nautical_mile  # m
range_f_cruise = 3243.9*_units.nautical_mile  # m
t_i_cruise = 26.20*_units.minute  # sec
t_f_cruise = 432.38*_units.minute  # sec
t_duration_cruise = t_f_cruise - t_i_cruise

alt_i_descent = 35000*_units.foot
# final altitude set to 35 to ensure landing is feasible point
# alt_f_descent = 0*_units.foot
alt_f_descent = 35*_units.foot
mach_i_descent = 0.79
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 = 432.38*_units.minute
t_f_descent = 461.62*_units.minute
t_duration_descent = t_f_descent - t_i_descent

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

# define 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')
aviary_inputs.set_val(av.Mission.Summary.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)
prob.model.add_design_var(av.Mission.Summary.GROSS_MASS, units='lbm',
                            lower=100000.0, upper=200000.0, ref=135000)

takeoff_options = av.HeightEnergyTakeoffPhaseBuilder(
    airport_altitude=alt_airport,  # ft
    # no units
    num_engines=aviary_inputs.get_val(av.Aircraft.Engine.NUM_ENGINES)
)

#################
# 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': (False, 'unitless'),
        'input_initial': (True, 'unitless'),
        'use_polynomial_control': (False, 'unitless'),
    }),
    core_subsystems=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=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=mission_subsystems,
    subsystem_options={'core_aerodynamics': {'method': 'computed'}},
    transcription=transcription_descent,
)

landing_options = av.HeightEnergyLandingPhaseBuilder(
    ref_wing_area=aviary_inputs.get_val(av.Aircraft.Wing.AREA, units='ft**2'),
    Cl_max_ldg=aviary_inputs.get_val(
        av.Mission.Landing.LIFT_COEFFICIENT_MAX)  # no units
)

# 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

takeoff = takeoff_options.build_phase(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)

landing = landing_options.build_phase(False)

prob.model.add_subsystem(
    'takeoff', takeoff, promotes_inputs=['aircraft:*', 'mission:*'],
    promotes_outputs=['mission:*'])

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)

prob.model.add_subsystem(
    'landing', landing, promotes_inputs=['aircraft:*', 'mission:*'],
    promotes_outputs=['mission:*'])

###############
# link phases #
###############

traj.link_phases(["climb", "cruise", "descent"], ["time", av.Dynamic.Vehicle.MASS, av.Dynamic.Mission.DISTANCE], connected=strong_couple)

param_vars = [av.Aircraft.Nacelle.CHARACTERISTIC_LENGTH,
              av.Aircraft.Nacelle.FINENESS,
              av.Aircraft.Nacelle.LAMINAR_FLOW_LOWER,
              av.Aircraft.Nacelle.LAMINAR_FLOW_UPPER,
              av.Aircraft.Nacelle.WETTED_AREA]

params = {}
for var in param_vars:
    params[var] = {'shape': (1, ), 'static_target': True}

external_parameters = {}
external_parameters['climb'] = params
external_parameters['cruise'] = params
external_parameters['descent'] = params

traj = av.setup_trajectory_params(prob.model, traj, aviary_inputs,
                                  external_parameters=external_parameters)

##################################
# Connect in Takeoff and Landing #
##################################
prob.model.connect(av.Mission.Takeoff.FINAL_MASS,
                    'traj.climb.initial_states:mass')
prob.model.connect(av.Mission.Takeoff.GROUND_DISTANCE,
                    'traj.climb.initial_states:distance')

prob.model.connect('traj.descent.states:mass',
                    av.Mission.Landing.TOUCHDOWN_MASS, src_indices=[-1])
prob.model.connect('traj.descent.control_values:altitude', av.Mission.Landing.INITIAL_ALTITUDE,
                    src_indices=[-1])

###############
# 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])

ecomp = om.ExecComp('overall_fuel = fuel_burned + fuel_reserve',
                    fuel_burned={'units': 'lbm', 'shape': 1},
                    fuel_reserve={'units': 'lbm', 'val': 2173.},
                    overall_fuel={'units': 'lbm'})
prob.model.add_subsystem('fuel_calc', ecomp,
                            promotes_inputs=['fuel_burned'],
                            promotes_outputs=['overall_fuel'])

ecomp = om.ExecComp(
    'mass_resid = operating_empty_mass + overall_fuel + payload_mass '
    '- initial_mass',
    operating_empty_mass={'units': 'lbm'},
    overall_fuel={'units': 'lbm'},
    payload_mass={'units': 'lbm'},
    initial_mass={'units': 'lbm'},
    mass_resid={'units': 'lbm'})

prob.model.add_subsystem(
    'mass_constraint', ecomp,
    promotes_inputs=[
        ('operating_empty_mass', av.Aircraft.Design.OPERATING_MASS),
        'overall_fuel',
        ('payload_mass', av.Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS),
        ('initial_mass', av.Mission.Design.GROSS_MASS)],
    promotes_outputs=['mass_resid'])

prob.model.add_constraint('mass_resid', equals=0.0, ref=1.0)

prob.model.add_subsystem(
    'gtow_constraint',
    om.EQConstraintComp(
        'GTOW',
        eq_units='lbm',
        normalize=True,
        add_constraint=True,
    ),
    promotes_inputs=[
        ('lhs:GTOW', av.Mission.Design.GROSS_MASS),
        ('rhs:GTOW', av.Mission.Summary.GROSS_MASS),
    ],
)

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

# This is an example of a overall mission objective
# create a compound objective that minimizes climb time and maximizes final mass
# we are maxing final mass b/c we don't have an independent value for fuel_mass yet
# we are going to normalize these (making each of the sub-objectives approx = 1 )
prob.model.add_subsystem(
    "regularization",
    om.ExecComp(
        "reg_objective = fuel_mass/1500",
        reg_objective=0.0,
        fuel_mass={"units": "lbm", "shape": 1},
    ),
    promotes_outputs=['reg_objective']
)
# connect the final mass from cruise into the objective
prob.model.connect(av.Mission.Design.FUEL_MASS, "regularization.fuel_mass")

prob.model.add_objective('reg_objective', ref=1)

# Set initial default values for all LEAPS aircraft variables.
varnames = [
    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.Mission.Summary.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.Atmosphere.MACH, ys=[mach_i_climb, mach_f_climb]), units='unitless')
prob.set_val('traj.climb.states:mass', climb.interp(
    av.Dynamic.Vehicle.MASS, ys=[mass_i_climb, mass_f_climb]), units='kg')
prob.set_val('traj.climb.states:distance', climb.interp(
    av.Dynamic.Mission.DISTANCE, ys=[range_i_climb, range_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.Atmosphere.MACH, ys=[cruise_mach, cruise_mach]), units='unitless')
prob.set_val('traj.cruise.states:mass', cruise.interp(
    av.Dynamic.Vehicle.MASS, ys=[mass_i_cruise, mass_f_cruise]), units='kg')
prob.set_val('traj.cruise.states:distance', cruise.interp(
    av.Dynamic.Mission.DISTANCE, ys=[range_i_cruise, range_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.Atmosphere.MACH, ys=[mach_i_descent, mach_f_descent]), units='unitless')
prob.set_val('traj.descent.states:mass', descent.interp(
    av.Dynamic.Vehicle.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},
                solution_record_file='N3CC_sizing.db')
prob.record("final")
prob.cleanup()

times_climb = prob.get_val('traj.climb.timeseries.time', units='s')
altitudes_climb = prob.get_val(
    'traj.climb.timeseries.altitude', units='m')
masses_climb = prob.get_val('traj.climb.timeseries.mass', units='kg')
ranges_climb = prob.get_val('traj.climb.timeseries.distance', units='m')
velocities_climb = prob.get_val(
    'traj.climb.timeseries.velocity', units='m/s')
thrusts_climb = prob.get_val('traj.climb.timeseries.thrust_net_total', units='N')
times_cruise = prob.get_val('traj.cruise.timeseries.time', units='s')
altitudes_cruise = prob.get_val(
    'traj.cruise.timeseries.altitude', units='m')
masses_cruise = prob.get_val('traj.cruise.timeseries.mass', units='kg')
ranges_cruise = prob.get_val('traj.cruise.timeseries.distance', units='m')
velocities_cruise = prob.get_val(
    'traj.cruise.timeseries.velocity', units='m/s')
thrusts_cruise = prob.get_val(
    'traj.cruise.timeseries.thrust_net_total', units='N')
times_descent = prob.get_val('traj.descent.timeseries.time', units='s')
altitudes_descent = prob.get_val(
    'traj.descent.timeseries.altitude', units='m')
masses_descent = prob.get_val('traj.descent.timeseries.mass', units='kg')
ranges_descent = prob.get_val('traj.descent.timeseries.distance', units='m')
velocities_descent = prob.get_val(
    'traj.descent.timeseries.velocity', units='m/s')
thrusts_descent = prob.get_val(
    'traj.descent.timeseries.thrust_net_total', units='N')


print("-------------------------------")
print(f"times_climb: {times_climb[-1]} (s)")
print(f"altitudes_climb: {altitudes_climb[-1]} (m)")
print(f"masses_climb: {masses_climb[-1]} (kg)")
print(f"ranges_climb: {ranges_climb[-1]} (m)")
print(f"velocities_climb: {velocities_climb[-1]} (m/s)")
print(f"thrusts_climb: {thrusts_climb[-1]} (N)")
print(f"times_cruise: {times_cruise[-1]} (s)")
print(f"altitudes_cruise: {altitudes_cruise[-1]} (m)")
print(f"masses_cruise: {masses_cruise[-1]} (kg)")
print(f"ranges_cruise: {ranges_cruise[-1]} (m)")
print(f"velocities_cruise: {velocities_cruise[-1]} (m/s)")
print(f"thrusts_cruise: {thrusts_cruise[-1]} (N)")
print(f"times_descent: {times_descent[-1]} (s)")
print(f"altitudes_descent: {altitudes_descent[-1]} (m)")
print(f"masses_descent: {masses_descent[-1]} (kg)")
print(f"ranges_descent: {ranges_descent[-1]} (m)")
print(f"velocities_descent: {velocities_descent[-1]} (m/s)")
print(f"thrusts_descent: {thrusts_descent[-1]} (N)")
print("-------------------------------")
/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 '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:2323: 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:2323: 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: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 '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:2323: 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:4431: 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:2548: PromotionWarning:'pre_mission.core_propulsion.turbofan_22k' <class SizeEngine>: input variable 'aircraft:engine:scale_factor', promoted using 'aircraft:engine:scale_factor', was already promoted using 'aircraft:engine:scale_factor'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/core/system.py:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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:2548: 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*'.
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/dymos/transcriptions/transcription_base.py:390: OpenMDAOWarning:'traj.phases.climb' <class Phase>
  Non-default solvers are required
    implicit duration: False
    solved segments: False
    input initial: True
  Setting `traj.phases.climb.nonlinear_solver = om.NewtonSolver(iprint=0, solve_subsystems=True, maxiter=1000, stall_limit=3)`
  Explicitly set traj.phases.climb.nonlinear_solver to override.
  Setting `traj.phases.climb.linear_solver = om.DirectSolver(iprint=2)`
  Explicitly set traj.phases.climb.linear_solver to override.
  Set `traj.phases.climb.options["auto_solvers"] = False` to disable this behavior.
--- Constraint Report [traj] ---
    --- climb ---
        None
    --- cruise ---
        [path]    3.0000e+02 <= altitude_rate_max  [ft/min]
    --- descent ---
        None
+  NL: NewtonSolver 'NL: Newton' on system 'traj.phases.climb.rhs_all.solver_sub': residuals contain 'inf' or 'NaN' after 0 iterations.
NL: NewtonSolver 'NL: Newton' on system 'traj.phases.climb': residuals contain 'inf' or 'NaN' after 0 iterations.
NL: NewtonSolver 'NL: Newton' on system 'traj.phases.cruise.rhs_all.solver_sub': residuals contain 'inf' or 'NaN' after 0 iterations.
List of user-set options:

                                    Name   Value                used
                        file_print_level = 5                     yes
                   hessian_approximation = limited-memory        yes
                           linear_solver = mumps                 yes
                                max_iter = 100                   yes
                      nlp_scaling_method = user-scaling          yes
                             output_file = /home/runner/work/Aviary/Aviary/aviary/docs/getting_started/problem_out/IPOPT.out  yes
                             print_level = 4                     yes
                      print_user_options = yes                   yes
                                      sb = yes                   yes
                                     tol = 0.001                 yes

Number of Iterations....: 0

Number of objective function evaluations             = 0
Number of objective gradient evaluations             = 0
Number of equality constraint evaluations            = 0
Number of inequality constraint evaluations          = 1
Number of equality constraint Jacobian evaluations   = 0
Number of inequality constraint Jacobian evaluations = 0
Number of Lagrangian Hessian evaluations             = 0
Total seconds in IPOPT                               = 0.070

EXIT: Invalid number in NLP function or derivative detected.


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

    Solution: 
--------------------------------------------------------------------------------
    Total Time:                    0.0711
       User Objective Time :       0.0693
       User Sensitivity Time :     0.0000
       Interface Time :            0.0005
       Opt Solver Time:            0.0013
    Calls to Objective Function :       1
    Calls to Sens Function :            0


   Objectives
      Index  Name                     Value
          0  reg_objective              NAN

   Variables (c - continuous, i - integer, d - discrete)
      Index  Name                              Type      Lower Bound            Value      Upper Bound     Status
          0  mission:design:gross_mass_0          c     7.407407E-01     1.000000E+00     1.481481E+00           
          1  mission:summary:gross_mass_0         c     7.407407E-01     1.000000E+00     1.481481E+00           
          2  traj.climb.t_duration_0              c     5.000000E-01     1.000000E+00     2.000000E+00           
          3  traj.climb.states:mass_0             c     0.000000E+00     5.935225E+00     1.000000E+17           
          4  traj.climb.states:mass_1             c     0.000000E+00     5.925793E+00     1.000000E+17           
          5  traj.climb.states:mass_2             c     0.000000E+00     5.922808E+00     1.000000E+17           
          6  traj.climb.states:mass_3             c     0.000000E+00     5.908258E+00     1.000000E+17           
          7  traj.climb.states:mass_4             c     0.000000E+00     5.888182E+00     1.000000E+17           
          8  traj.climb.states:mass_5             c     0.000000E+00     5.881829E+00     1.000000E+17           
          9  traj.climb.states:mass_6             c     0.000000E+00     5.862952E+00     1.000000E+17           
         10  traj.climb.states:mass_7             c     0.000000E+00     5.836905E+00     1.000000E+17           
         11  traj.climb.states:mass_8             c     0.000000E+00     5.828662E+00     1.000000E+17           
         12  traj.climb.states:mass_9             c     0.000000E+00     5.809785E+00     1.000000E+17           
         13  traj.climb.states:mass_10            c     0.000000E+00     5.783739E+00     1.000000E+17           
         14  traj.climb.states:mass_11            c     0.000000E+00     5.775495E+00     1.000000E+17           
         15  traj.climb.states:mass_12            c     0.000000E+00     5.760946E+00     1.000000E+17           
         16  traj.climb.states:mass_13            c     0.000000E+00     5.740870E+00     1.000000E+17           
         17  traj.climb.states:mass_14            c     0.000000E+00     5.734516E+00     1.000000E+17           
         18  traj.climb.states:mass_15            c     0.000000E+00     5.727681E+00     1.000000E+17           
         19  traj.climb.states:mass_16            c     0.000000E+00     5.718249E+00     1.000000E+17           
         20  traj.climb.states:mass_17            c     0.000000E+00     5.715264E+00     1.000000E+17           
         21  traj.climb.states:distance_0         c     0.000000E+00     8.947709E-03     1.000000E+15           
         22  traj.climb.states:distance_1         c     0.000000E+00     2.129372E-02     1.000000E+15           
         23  traj.climb.states:distance_2         c     0.000000E+00     2.520119E-02     1.000000E+15           
         24  traj.climb.states:distance_3         c     0.000000E+00     4.424674E-02     1.000000E+15           
         25  traj.climb.states:distance_4         c     0.000000E+00     7.052571E-02     1.000000E+15           
         26  traj.climb.states:distance_5         c     0.000000E+00     7.884292E-02     1.000000E+15           
         27  traj.climb.states:distance_6         c     0.000000E+00     1.035527E-01     1.000000E+15           
         28  traj.climb.states:distance_7         c     0.000000E+00     1.376470E-01     1.000000E+15           
         29  traj.climb.states:distance_8         c     0.000000E+00     1.484378E-01     1.000000E+15           
         30  traj.climb.states:distance_9         c     0.000000E+00     1.731475E-01     1.000000E+15           
         31  traj.climb.states:distance_10        c     0.000000E+00     2.072419E-01     1.000000E+15           
         32  traj.climb.states:distance_11        c     0.000000E+00     2.180327E-01     1.000000E+15           
         33  traj.climb.states:distance_12        c     0.000000E+00     2.370782E-01     1.000000E+15           
         34  traj.climb.states:distance_13        c     0.000000E+00     2.633572E-01     1.000000E+15           
         35  traj.climb.states:distance_14        c     0.000000E+00     2.716744E-01     1.000000E+15           
         36  traj.climb.states:distance_15        c     0.000000E+00     2.806221E-01     1.000000E+15           
         37  traj.climb.states:distance_16        c     0.000000E+00     2.929681E-01     1.000000E+15           
         38  traj.climb.states:distance_17        c     0.000000E+00     2.968756E-01     1.000000E+15           
         39  traj.cruise.t_initial_0              c     7.260000E+02     1.572000E+03     2.904000E+03           
         40  traj.cruise.t_duration_0             c     5.000000E-01     1.000000E+00     2.000000E+00           
         41  traj.cruise.states:mass_0            c     0.000000E+00     5.715264E+00     1.000000E+17           
         42  traj.cruise.states:mass_1            c     0.000000E+00     5.328748E+00     1.000000E+17           
         43  traj.cruise.states:mass_2            c     0.000000E+00     4.795434E+00     1.000000E+17           
         44  traj.cruise.states:mass_3            c     0.000000E+00     4.626642E+00     1.000000E+17           
         45  traj.cruise.states:distance_0        c     0.000000E+00     2.968756E-01     1.000000E+15           
         46  traj.cruise.states:distance_1        c     0.000000E+00     2.324511E+00     1.000000E+15           
         47  traj.cruise.states:distance_2        c     0.000000E+00     5.122233E+00     1.000000E+15           
         48  traj.cruise.states:distance_3        c     0.000000E+00     6.007703E+00     1.000000E+15           
         49  traj.descent.t_initial_0             c     1.291140E+04     2.594280E+04     5.164560E+04           
         50  traj.descent.t_duration_0            c     5.000000E-01     1.000000E+00     2.000000E+00           
         51  traj.descent.states:mass_0           c     0.000000E+00     4.626642E+00     1.000000E+17           
         52  traj.descent.states:mass_1           c     0.000000E+00     4.624750E+00     1.000000E+17           
         53  traj.descent.states:mass_2           c     0.000000E+00     4.622140E+00     1.000000E+17           
         54  traj.descent.states:mass_3           c     0.000000E+00     4.621314E+00     1.000000E+17           
         55  traj.descent.states:mass_4           c     0.000000E+00     4.617450E+00     1.000000E+17           
         56  traj.descent.states:mass_5           c     0.000000E+00     4.612119E+00     1.000000E+17           
         57  traj.descent.states:mass_6           c     0.000000E+00     4.610431E+00     1.000000E+17           
         58  traj.descent.states:mass_7           c     0.000000E+00     4.605838E+00     1.000000E+17           
         59  traj.descent.states:mass_8           c     0.000000E+00     4.599500E+00     1.000000E+17           
         60  traj.descent.states:mass_9           c     0.000000E+00     4.597494E+00     1.000000E+17           
         61  traj.descent.states:mass_10          c     0.000000E+00     4.593630E+00     1.000000E+17           
         62  traj.descent.states:mass_11          c     0.000000E+00     4.588299E+00     1.000000E+17           
         63  traj.descent.states:mass_12          c     0.000000E+00     4.586611E+00     1.000000E+17           
         64  traj.descent.states:mass_13          c     0.000000E+00     4.584720E+00     1.000000E+17           
         65  traj.descent.states:mass_14          c     0.000000E+00     4.582109E+00     1.000000E+17           
         66  traj.descent.states:mass_15          c     0.000000E+00     4.581283E+00     1.000000E+17           
         67  traj.descent.states:distance_0       c     0.000000E+00     6.007703E+00     1.000000E+15           
         68  traj.descent.states:distance_1       c     0.000000E+00     6.018115E+00     1.000000E+15           
         69  traj.descent.states:distance_2       c     0.000000E+00     6.032483E+00     1.000000E+15           
         70  traj.descent.states:distance_3       c     0.000000E+00     6.037030E+00     1.000000E+15           
         71  traj.descent.states:distance_4       c     0.000000E+00     6.058295E+00     1.000000E+15           
         72  traj.descent.states:distance_5       c     0.000000E+00     6.087637E+00     1.000000E+15           
         73  traj.descent.states:distance_6       c     0.000000E+00     6.096924E+00     1.000000E+15           
         74  traj.descent.states:distance_7       c     0.000000E+00     6.122206E+00     1.000000E+15           
         75  traj.descent.states:distance_8       c     0.000000E+00     6.157091E+00     1.000000E+15           
         76  traj.descent.states:distance_9       c     0.000000E+00     6.168132E+00     1.000000E+15           
         77  traj.descent.states:distance_10      c     0.000000E+00     6.189397E+00     1.000000E+15           
         78  traj.descent.states:distance_11      c     0.000000E+00     6.218739E+00     1.000000E+15           
         79  traj.descent.states:distance_12      c     0.000000E+00     6.228025E+00     1.000000E+15           
         80  traj.descent.states:distance_13      c     0.000000E+00     6.238438E+00     1.000000E+15           
         81  traj.descent.states:distance_14      c     0.000000E+00     6.252805E+00     1.000000E+15           
         82  traj.descent.states:distance_15      c     0.000000E+00     6.257352E+00     1.000000E+15           

   Constraints (i - inequality, e - equality)
      Index  Name                                                         Type          Lower           Value           Upper    Status  Lagrange Multiplier (N/A)
          0  mass_resid                                                      e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
          1  gtow_constraint.GTOW                                            e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
          2  traj.linkages.climb:time_final|cruise:time_initial              e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
          3  traj.linkages.climb:mass_final|cruise:mass_initial              e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
          4  traj.linkages.climb:distance_final|cruise:distance_initial      e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
          5  traj.linkages.cruise:time_final|descent:time_initial            e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
          6  traj.linkages.cruise:mass_final|descent:mass_initial            e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
          7  traj.linkages.cruise:distance_final|descent:distance_initial    e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
          8  traj.climb.collocation_constraint.defects:mass                  e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
          9  traj.climb.collocation_constraint.defects:mass                  e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         10  traj.climb.collocation_constraint.defects:mass                  e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         11  traj.climb.collocation_constraint.defects:mass                  e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         12  traj.climb.collocation_constraint.defects:mass                  e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         13  traj.climb.collocation_constraint.defects:mass                  e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         14  traj.climb.collocation_constraint.defects:mass                  e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         15  traj.climb.collocation_constraint.defects:mass                  e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         16  traj.climb.collocation_constraint.defects:mass                  e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         17  traj.climb.collocation_constraint.defects:mass                  e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         18  traj.climb.collocation_constraint.defects:mass                  e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         19  traj.climb.collocation_constraint.defects:mass                  e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         20  traj.climb.collocation_constraint.defects:mass                  e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         21  traj.climb.collocation_constraint.defects:mass                  e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         22  traj.climb.collocation_constraint.defects:mass                  e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         23  traj.climb.collocation_constraint.defects:mass                  e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         24  traj.climb.collocation_constraint.defects:mass                  e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         25  traj.climb.collocation_constraint.defects:mass                  e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         26  traj.climb.collocation_constraint.defects:distance              e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         27  traj.climb.collocation_constraint.defects:distance              e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         28  traj.climb.collocation_constraint.defects:distance              e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         29  traj.climb.collocation_constraint.defects:distance              e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         30  traj.climb.collocation_constraint.defects:distance              e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         31  traj.climb.collocation_constraint.defects:distance              e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         32  traj.climb.collocation_constraint.defects:distance              e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         33  traj.climb.collocation_constraint.defects:distance              e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         34  traj.climb.collocation_constraint.defects:distance              e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         35  traj.climb.collocation_constraint.defects:distance              e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         36  traj.climb.collocation_constraint.defects:distance              e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         37  traj.climb.collocation_constraint.defects:distance              e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         38  traj.climb.collocation_constraint.defects:distance              e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         39  traj.climb.collocation_constraint.defects:distance              e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         40  traj.climb.collocation_constraint.defects:distance              e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         41  traj.climb.collocation_constraint.defects:distance              e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         42  traj.climb.collocation_constraint.defects:distance              e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         43  traj.climb.collocation_constraint.defects:distance              e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         44  traj.cruise.collocation_constraint.defects:mass                 e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         45  traj.cruise.collocation_constraint.defects:mass                 e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         46  traj.cruise.collocation_constraint.defects:mass                 e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         47  traj.cruise.collocation_constraint.defects:distance             e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         48  traj.cruise.collocation_constraint.defects:distance             e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         49  traj.cruise.collocation_constraint.defects:distance             e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         50  traj.descent.collocation_constraint.defects:mass                e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         51  traj.descent.collocation_constraint.defects:mass                e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         52  traj.descent.collocation_constraint.defects:mass                e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         53  traj.descent.collocation_constraint.defects:mass                e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         54  traj.descent.collocation_constraint.defects:mass                e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         55  traj.descent.collocation_constraint.defects:mass                e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         56  traj.descent.collocation_constraint.defects:mass                e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         57  traj.descent.collocation_constraint.defects:mass                e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         58  traj.descent.collocation_constraint.defects:mass                e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         59  traj.descent.collocation_constraint.defects:mass                e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         60  traj.descent.collocation_constraint.defects:mass                e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         61  traj.descent.collocation_constraint.defects:mass                e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         62  traj.descent.collocation_constraint.defects:mass                e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         63  traj.descent.collocation_constraint.defects:mass                e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         64  traj.descent.collocation_constraint.defects:mass                e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         65  traj.descent.collocation_constraint.defects:distance            e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         66  traj.descent.collocation_constraint.defects:distance            e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         67  traj.descent.collocation_constraint.defects:distance            e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         68  traj.descent.collocation_constraint.defects:distance            e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         69  traj.descent.collocation_constraint.defects:distance            e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         70  traj.descent.collocation_constraint.defects:distance            e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         71  traj.descent.collocation_constraint.defects:distance            e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         72  traj.descent.collocation_constraint.defects:distance            e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         73  traj.descent.collocation_constraint.defects:distance            e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         74  traj.descent.collocation_constraint.defects:distance            e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         75  traj.descent.collocation_constraint.defects:distance            e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         76  traj.descent.collocation_constraint.defects:distance            e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         77  traj.descent.collocation_constraint.defects:distance            e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         78  traj.descent.collocation_constraint.defects:distance            e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         79  traj.descent.collocation_constraint.defects:distance            e   0.000000E+00             NAN    0.000000E+00              9.00000E+100
         80  traj.phases.cruise->path_constraint->altitude_rate_max          i   3.000000E+02             NAN    1.000000E+30        lu    9.00000E+100
         81  traj.phases.cruise->path_constraint->altitude_rate_max          i   3.000000E+02             NAN    1.000000E+30        lu    9.00000E+100
         82  traj.phases.cruise->path_constraint->altitude_rate_max          i   3.000000E+02             NAN    1.000000E+30        lu    9.00000E+100
         83  traj.phases.cruise->path_constraint->altitude_rate_max          i   3.000000E+02             NAN    1.000000E+30        lu    9.00000E+100

--------------------------------------------------------------------------------

+  NL: NewtonSolver 'NL: Newton' on system 'traj.phases.climb.rhs_all.solver_sub': residuals contain 'inf' or 'NaN' after 0 iterations.
NL: NewtonSolver 'NL: Newton' on system 'traj.phases.climb': residuals contain 'inf' or 'NaN' after 0 iterations.
NL: NewtonSolver 'NL: Newton' on system 'traj.phases.cruise.rhs_all.solver_sub': residuals contain 'inf' or 'NaN' after 0 iterations.
/home/runner/work/Aviary/Aviary/aviary/subsystems/aerodynamics/flops_based/lift_dependent_drag.py:235: RuntimeWarning: invalid value encountered in divide
  DCDP = FCDP * (1.0 + CAM/10.0) * A/AR
/home/runner/work/Aviary/Aviary/aviary/subsystems/aerodynamics/flops_based/induced_drag.py:106: RuntimeWarning: divide by zero encountered in divide
  CDi = CL ** 2 / (np.pi * AR * span_efficiency)
/usr/share/miniconda/envs/test/lib/python3.12/site-packages/openmdao/vectors/default_vector.py:491: RuntimeWarning: invalid value encountered in add
  data[idxs] += val
-------------------------------
times_climb: [1572.] (s)
altitudes_climb: [10668.] (m)
masses_climb: [57152.63862] (kg)
ranges_climb: [296875.6] (m)
velocities_climb: [234.32014809] (m/s)
thrusts_climb: [35286.14075168] (N)
times_cruise: [1.] (s)
altitudes_cruise: [0.3048] (m)
masses_cruise: [1.] (kg)
ranges_cruise: [1.] (m)
velocities_cruise: [1.] (m/s)
thrusts_cruise: [4.44822162] (N)
times_descent: [1.] (s)
altitudes_descent: [0.3048] (m)
masses_descent: [1.] (kg)
ranges_descent: [1.] (m)
velocities_descent: [1.] (m/s)
thrusts_descent: [4.44822162] (N)
-------------------------------

This model demonstrates the flexibility of level 3. For example, we do not load the aircraft model from a .csv file but from a Python file using the get_flops_inputs() method.

This function not only reads Aviary and mission variables but also builds the engine. More information can be found in aviary/models/N3CC/N3CC_data.py.

Note that we can read large single aisle aircraft inputs this way as well:

aviary_inputs = get_flops_inputs('LargeSingleAisle1FLOPS')
aviary_inputs = get_flops_inputs('LargeSingleAisle2FLOPS')
aviary_inputs = get_flops_inputs('LargeSingleAisle2FLOPSdw')
aviary_inputs = get_flops_inputs('LargeSingleAisle2FLOPSalt')

The data files are at:

aviary/models/large_single_aisle_1/large_single_aisle_1_FLOPS_data.py
aviary/models/large_single_aisle_2/large_single_aisle_2_FLOPS_data.py
aviary/models/large_single_aisle_2/large_single_aisle_2_detailwing_FLOPS_data.py
aviary/models/large_single_aisle_2/large_single_aisle_2_altwt_FLOPS_data.py

respectively.

Discussing this example in more detail#

We move all the code blocks on taxi to add_pre_mission_system function because it is how it is done in methods_for_level2.py. Similarly, all the code blocks on landing are moved to add_post_mission_systems function. Be careful! Generally speaking, not all components can be moved around due to the expected order of execution.

In aviary/validation_cases/benchmark_tests folder, there is another N3CC model test_FLOPS_based_sizing_N3CC.py. If we had started from that model, you would need to have an add_design_variables function.

Summary#

We have shown in an example that users have total control over every aspect of the model in level 3. There is one big feature that hasn’t been covered: adding external subsystems. We will move on to discuss how to run Aviary External Subsystem next.