Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor level2 to eliminate the input_sink and set all input defaults in the top group's configure method. #132

Merged
merged 7 commits into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions aviary/docs/getting_started/onboarding_level2.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -550,8 +550,6 @@
"metadata": {},
"outputs": [],
"source": [
"print(\"Zero Fuel Mass (lbm)\",\n",
" prob.get_val(Aircraft.Design.ZERO_FUEL_MASS, units='lbm'))\n",
"print(\"Mission.Objectives.FUEL\",\n",
" prob.get_val(Mission.Objectives.FUEL, units='unitless'))\n",
"print(\"Mission.Design.FUEL_MASS\",\n",
Expand Down Expand Up @@ -889,7 +887,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
Expand All @@ -903,7 +901,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.17"
"version": "3.8.10"
}
},
"nbformat": 4,
Expand Down
83 changes: 67 additions & 16 deletions aviary/interface/methods_for_level2.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from dymos.utils.misc import _unspecified

import openmdao.api as om
from openmdao.core.component import Component
from openmdao.utils.units import convert_units

from aviary.constants import GRAV_ENGLISH_LBM, RHO_SEA_LEVEL_ENGLISH
Expand All @@ -36,7 +37,7 @@
from aviary.mission.gasp_based.phases.v_rotate_comp import VRotateComp
from aviary.mission.gasp_based.polynomial_fit import PolynomialFit
from aviary.subsystems.premission import CorePreMission
from aviary.utils.functions import set_aviary_initial_values, create_opts2vals, add_opts2vals, promote_aircraft_and_mission_vars
from aviary.utils.functions import create_opts2vals, add_opts2vals, promote_aircraft_and_mission_vars
from aviary.utils.process_input_decks import create_vehicle, update_GASP_options, initial_guessing
from aviary.utils.preprocessors import preprocess_crewpayload
from aviary.interface.utils.check_phase_info import check_phase_info
Expand All @@ -46,7 +47,6 @@
from aviary.variable_info.variables import Aircraft, Mission, Dynamic, Settings
from aviary.variable_info.enums import AnalysisScheme, ProblemType, SpeedType, AlphaModes, EquationsOfMotion, LegacyCode
from aviary.variable_info.variable_meta_data import _MetaData as BaseMetaData
from aviary.variable_info.variables_in import VariablesIn

from aviary.subsystems.propulsion.engine_deck import EngineDeck
from aviary.subsystems.propulsion.propulsion_builder import CorePropulsionBuilder
Expand All @@ -58,7 +58,6 @@

from aviary.interface.default_phase_info.two_dof_fiti import create_2dof_based_ascent_phases, create_2dof_based_descent_phases
from aviary.mission.gasp_based.idle_descent_estimation import descent_range_and_fuel
from aviary.mission.flops_based.phases.phase_utils import get_initial
from aviary.mission.phase_builder_base import PhaseBuilderBase


Expand Down Expand Up @@ -114,6 +113,68 @@ def configure(self):
promote_aircraft_and_mission_vars(self)


class AviaryGroup(om.Group):
"""
A standard OpenMDAO group that handles Aviary's promotions in the configure
method. This assures that we only call set_input_defaults on variables
that are present in the model.
"""

def initialize(self):
self.options.declare(
'aviary_options', types=AviaryValues,
desc='collection of Aircraft/Mission specific options')
self.options.declare(
'aviary_metadata', types=dict,
desc='metadata dictionary of the full aviary problem.')

def configure(self):
aviary_options = self.options['aviary_options']
aviary_metadata = self.options['aviary_metadata']

# Find promoted name of every input in the model.
all_prom_inputs = []

# We can call list_inputs on the groups.
for system in self.system_iter(recurse=False, typ=om.Group):
var_abs = system.list_inputs(out_stream=None)
var_prom = [v['prom_name'] for k, v in var_abs]
all_prom_inputs.extend(var_prom)

# Component promotes aren't handled until this group resolves.
# Here, we address anything promoted in AviaryProblem.
for system in self.system_iter(recurse=False, typ=Component):
input_meta = system._var_promotes['input']
var_prom = [v[0][1] for v in input_meta if isinstance(v[0], tuple)]
all_prom_inputs.extend(var_prom)
var_prom = [v[0] for v in input_meta if not isinstance(v[0], tuple)]
all_prom_inputs.extend(var_prom)

for key in aviary_metadata:

if ':' not in key or key.startswith('dynamic:'):
continue

if aviary_metadata[key]['option']:
continue

# Skip anything that is not presently an input.
if key not in all_prom_inputs:
continue

if key in aviary_options:
val, units = aviary_options.get_item(key)
else:
val = aviary_metadata[key]['default_value']
units = aviary_metadata[key]['units']

if val is None:
# optional, but no default value
continue

self.set_input_defaults(key, val=val, units=units)


class AviaryProblem(om.Problem):
"""
Main class for instantiating, formulating, and solving Aviary problems.
Expand All @@ -135,7 +196,7 @@ def __init__(self, analysis_scheme=AnalysisScheme.COLLOCATION, **kwargs):

self.timestamp = datetime.now()

self.model = om.Group()
self.model = AviaryGroup()
self.pre_mission = PreMissionGroup()
self.post_mission = PostMissionGroup()

Expand Down Expand Up @@ -1772,22 +1833,12 @@ def setup(self, **kwargs):
calls to `set_input_defaults` and do some simple `set_vals`
if needed.
"""
# Adding a trailing component that contains all inputs so that set_input_defaults
# doesn't raise any errors.
self.model.add_subsystem(
'input_sink',
VariablesIn(aviary_options=self.aviary_inputs,
meta_data=self.meta_data),
promotes_inputs=['*'],
promotes_outputs=['*'])

# suppress warnings:
# "input variable '...' promoted using '*' was already promoted using 'aircraft:*'
with warnings.catch_warnings():

# Set initial default values for all LEAPS aircraft variables.
set_aviary_initial_values(
self.model, self.aviary_inputs, meta_data=self.meta_data)
self.model.options['aviary_options'] = self.aviary_inputs
self.model.options['aviary_metadata'] = self.meta_data

warnings.simplefilter("ignore", om.OpenMDAOWarning)
warnings.simplefilter("ignore", om.PromotionWarning)
Expand Down
2 changes: 1 addition & 1 deletion aviary/validation_cases/benchmark_tests/test_bench_FwGm.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
class ProblemPhaseTestCase(unittest.TestCase):

@require_pyoptsparse(optimizer="IPOPT")
def bench_test_swap_3_FwGm(self):
def bench_test_swap_3_FwGm_IPOPT(self):
local_phase_info = deepcopy(phase_info)
prob = run_aviary('models/test_aircraft/aircraft_for_bench_FwGm.csv',
local_phase_info, optimizer='IPOPT')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def test_subsystems_in_a_mission(self):

prob.add_design_variables()

prob.add_objective('fuel')
prob.add_objective('fuel_burned')

prob.setup()

Expand Down
Loading