Skip to content

Commit

Permalink
Merge branch 'OpenMDAO:main' into test_flops_aero_builder
Browse files Browse the repository at this point in the history
  • Loading branch information
xjjiang authored Feb 21, 2025
2 parents 9759948 + 562e5ae commit 4182af7
Show file tree
Hide file tree
Showing 37 changed files with 614 additions and 668 deletions.
12 changes: 8 additions & 4 deletions aviary/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,14 @@

# ODEs
# TODO: check and see if this works with both sides, or just GASP
from aviary.mission.gasp_based.ode.base_ode import BaseODE
from aviary.mission.base_ode import BaseODE
from aviary.mission.flops_based.ode.energy_ODE import EnergyODE
from aviary.mission.flops_based.ode.landing_ode import LandingODE as DetailedLandingODE
from aviary.mission.flops_based.ode.landing_ode import FlareODE as DetailedFlareODE
from aviary.mission.flops_based.ode.takeoff_ode import TakeoffODE as DetailedTakeoffODE
from aviary.mission.flops_based.phases.simplified_takeoff import TakeoffGroup as HeightEnergySimplifiedTakeoff
from aviary.mission.flops_based.phases.simplified_landing import LandingGroup as HeightEnergySimplifiedLanding
from aviary.mission.gasp_based.ode.two_dof_ode import TwoDOFODE
from aviary.mission.gasp_based.ode.accel_ode import AccelODE as TwoDOFAccelerationODE
from aviary.mission.gasp_based.ode.ascent_ode import AscentODE as TwoDOFAscentODE
from aviary.mission.gasp_based.ode.breguet_cruise_ode import BreguetCruiseODESolution
Expand All @@ -76,14 +80,14 @@
from aviary.mission.gasp_based.ode.rotation_ode import RotationODE as TwoDOFRotationODE
from aviary.mission.gasp_based.ode.landing_ode import LandingSegment as TwoDOFSimplifiedLanding
from aviary.mission.gasp_based.ode.taxi_ode import TaxiSegment as AnalyticTaxi
from aviary.mission.flops_based.phases.simplified_takeoff import TakeoffGroup as HeightEnergySimplifiedTakeoff
from aviary.mission.flops_based.phases.simplified_landing import LandingGroup as HeightEnergySimplifiedLanding


# Phase builders
from aviary.mission.phase_builder_base import PhaseBuilderBase
# note that this is only for simplified right now
from aviary.mission.energy_phase import EnergyPhase as HeightEnergyPhaseBuilder
from aviary.mission.flops_based.phases.energy_phase import (
EnergyPhase as HeightEnergyPhaseBuilder,
)
from aviary.mission.flops_based.phases.build_landing import Landing as HeightEnergyLandingPhaseBuilder
# note that this is only for simplified right now
from aviary.mission.flops_based.phases.build_takeoff import Takeoff as HeightEnergyTakeoffPhaseBuilder
Expand Down
8 changes: 4 additions & 4 deletions aviary/docs/user_guide/SGM_capabilities.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
},
"outputs": [],
"source": [
"from aviary.mission.gasp_based.ode.base_ode import BaseODE\n",
"from aviary.mission.gasp_based.ode.two_dof_ode import TwoDOFODE\n",
"from aviary.variable_info.variables import Dynamic, Mission, Aircraft\n",
"from aviary.variable_info.enums import AnalysisScheme, LegacyCode\n",
"from aviary.mission.gasp_based.ode.time_integration_base_classes import SimuPyProblem\n",
Expand Down Expand Up @@ -62,7 +62,7 @@
"source": [
"from aviary.mission.gasp_based.ode.time_integration_base_classes import add_SGM_required_inputs, add_SGM_required_outputs\n",
"\n",
"class ClimbODE(BaseODE):\n",
"class ClimbODE(TwoDOFODE):\n",
" # ## ... ## #\n",
" def setup(self):\n",
" # ## ... ## #\n",
Expand Down Expand Up @@ -284,7 +284,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "latest_env",
"display_name": "aviary",
"language": "python",
"name": "python3"
},
Expand All @@ -298,7 +298,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.3"
"version": "3.12.8"
}
},
"nbformat": 4,
Expand Down
8 changes: 4 additions & 4 deletions aviary/docs/user_guide/reserve_missions.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"files = os.listdir(gasp_phase_path)\n",
"phases = [FlightPhaseBase]\n",
"for file in files:\n",
" if '_phase.py' in file:\n",
" if '_phase.py' in file and 'twodof' not in file:\n",
" file_path = os.path.join(str(gasp_phase_path),file)\n",
" phase_name = file.split('_phase.py')[0].capitalize()\n",
" module = SourceFileLoader(phase_name, file_path).load_module()\n",
Expand Down Expand Up @@ -193,7 +193,7 @@
"\n",
"gasp_phase_path = av.get_path(os.path.join('mission','gasp_based','phases'))\n",
"for file in os.listdir(gasp_phase_path):\n",
" if '_phase.py' in file:\n",
" if '_phase.py' in file and 'twodof' not in file:\n",
" phase_name = file.split('_phase.py')[0].capitalize()\n",
" file_path = os.path.join(str(gasp_phase_path),file)\n",
" module = SourceFileLoader(phase_name, file_path).load_module()\n",
Expand Down Expand Up @@ -297,7 +297,7 @@
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"display_name": "aviary",
"language": "python",
"name": "python3"
},
Expand All @@ -311,7 +311,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.0"
"version": "3.12.8"
}
},
"nbformat": 4,
Expand Down
1 change: 0 additions & 1 deletion aviary/examples/test/test_all_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ class RunScriptTest(unittest.TestCase):
"""
A test case class that uses unittest to run and test scripts with a timeout.
...
Attributes
----------
Expand Down
3 changes: 2 additions & 1 deletion aviary/interface/default_phase_info/height_energy_fiti.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@
}


def phase_info_parameterization(phase_info, post_mission_info, aviary_inputs: AviaryValues):
def phase_info_parameterization(phase_info, post_mission_info,
aviary_inputs: AviaryValues):
"""
Modify the values in the phase_info dictionary to accomodate different values
for the following mission design inputs: cruise altitude, cruise mach number,
Expand Down
6 changes: 3 additions & 3 deletions aviary/interface/methods_for_level2.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@
from aviary.constants import GRAV_ENGLISH_LBM, RHO_SEA_LEVEL_ENGLISH
from aviary.interface.default_phase_info.two_dof_fiti import add_default_sgm_args
from aviary.interface.utils.check_phase_info import check_phase_info
from aviary.mission.energy_phase import EnergyPhase
from aviary.mission.flops_based.phases.energy_phase import EnergyPhase
from aviary.mission.flops_based.phases.build_landing import Landing
from aviary.mission.flops_based.phases.build_takeoff import Takeoff
from aviary.mission.twodof_phase import TwoDOFPhase
from aviary.mission.gasp_based.phases.twodof_phase import TwoDOFPhase
from aviary.mission.gasp_based.idle_descent_estimation import add_descent_estimation_as_submodel
from aviary.mission.gasp_based.ode.params import ParamPort
from aviary.mission.gasp_based.phases.time_integration_traj import FlexibleTraj
Expand All @@ -40,7 +40,7 @@
from aviary.mission.gasp_based.phases.descent_phase import DescentPhase
from aviary.mission.gasp_based.ode.landing_ode import LandingSegment
from aviary.mission.gasp_based.ode.taxi_ode import TaxiSegment
from aviary.mission.gasp_based.phases.v_rotate_comp import VRotateComp
from aviary.mission.gasp_based.ode.v_rotate_comp import VRotateComp
from aviary.mission.gasp_based.polynomial_fit import PolynomialFit
from aviary.mission.phase_builder_base import PhaseBuilderBase

Expand Down
2 changes: 1 addition & 1 deletion aviary/interface/test/test_height_energy_mission.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from aviary.interface.methods_for_level1 import run_aviary
from aviary.interface.methods_for_level2 import AviaryProblem
from aviary.subsystems.test.test_dummy_subsystem import ArrayGuessSubsystemBuilder
from aviary.mission.energy_phase import EnergyPhase
from aviary.mission.flops_based.phases.energy_phase import EnergyPhase
from aviary.variable_info.variables import Dynamic


Expand Down
175 changes: 175 additions & 0 deletions aviary/mission/base_ode.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import openmdao.api as om

from aviary.subsystems.atmosphere.atmosphere import Atmosphere
from aviary.utils.aviary_values import AviaryValues
from aviary.utils.functions import promote_aircraft_and_mission_vars
from aviary.variable_info.enums import AnalysisScheme
from aviary.variable_info.variable_meta_data import _MetaData


#
class ExternalSubsystemGroup(om.Group):
"""
Create a lightly modified version of an OM group to add external subsystems to the
ODE with a special configure() method that promotes all 'aircraft:*' and 'mission:*'
variables to the ODE.
"""

def configure(self):
promote_aircraft_and_mission_vars(self)


class BaseODE(om.Group):
"""
The base class for all ODE components.
"""

def initialize(self):
self.options.declare('num_nodes', default=1, types=int)
self.options.declare(
'subsystem_options',
types=dict,
default={},
desc='dictionary of parameters to be passed to the subsystem builders',
)
self.options.declare(
'aviary_options',
types=AviaryValues,
desc='collection of Aircraft/Mission specific options',
)
self.options.declare(
'core_subsystems',
desc='list of core subsystem builder instances to be added to the ODE',
)
self.options.declare(
'external_subsystems',
default=[],
desc='list of external subsystem builder instances to be added to the ODE',
)
self.options.declare(
'meta_data',
default=_MetaData,
desc='metadata associated with the variables to be passed into the ODE',
)
self.options.declare(
"analysis_scheme",
default=AnalysisScheme.COLLOCATION,
types=AnalysisScheme,
desc="The analysis method that will be used to close the trajectory; for example collocation or time integration",
)

def add_atmosphere(self, **kwargs):
"""
Adds Atmosphere component to ODE
"""
nn = self.options['num_nodes']
self.add_subsystem(
name='atmosphere',
subsys=Atmosphere(num_nodes=nn, **kwargs), # Atmosphere defaults to TAS
promotes=['*'],
)

def add_core_subsystems(self, solver_group=None):
"""
Adds all specified external subsystems to ODE in their own group
Parameters
----------
solver_group : om.Group
If not None, core subsystems that require a solver
(subsystem.needs_mission_solver() == True) are placed inside solver_group.
If None, all core subsystems are added to BaseODE regardless of if they
request a solver. TODO add solver compatibility to all ODEs
"""
nn = self.options['num_nodes']
aviary_options = self.options['aviary_options']
core_subsystems = self.options['core_subsystems']
subsystem_options = self.options['subsystem_options']

for subsystem in core_subsystems:
# check if subsystem_options has entry for a subsystem of this name
if subsystem.name in subsystem_options:
kwargs = subsystem_options[subsystem.name]
else:
kwargs = {}

subsystem_mission = subsystem.build_mission(
num_nodes=nn, aviary_inputs=aviary_options, **kwargs
)

if subsystem_mission is not None:
if solver_group is not None:
target = solver_group
else:
target = self

target.add_subsystem(
subsystem.name,
subsystem_mission,
promotes_inputs=subsystem.mission_inputs(**kwargs),
promotes_outputs=subsystem.mission_outputs(**kwargs),
)

def add_external_subsystems(self, solver_group=None):
"""
Adds all specified external subsystems to ODE in their own group
Parameters
----------
solver_group : om.Group
If not None, external subsystems that require a solver
(subsystem.needs_mission_solver() == True) are placed inside solver_group.
If None, all external subsystems are added to BaseODE regardless of if they
request a solver. TODO add solver compatibility to all ODEs
"""
nn = self.options['num_nodes']
aviary_options = self.options['aviary_options']
external_subsystems = self.options['external_subsystems']
subsystem_options = self.options['subsystem_options']

external_subsystem_group = ExternalSubsystemGroup()
external_subsystem_group_solver = ExternalSubsystemGroup()
add_subsystem_group = False
add_subsystem_group_solver = False

for subsystem in external_subsystems:
if subsystem.name in subsystem_options:
kwargs = subsystem_options[subsystem.name]
else:
kwargs = {}

subsystem_mission = subsystem.build_mission(
num_nodes=nn, aviary_inputs=aviary_options, **kwargs)

if subsystem_mission is not None:
target = external_subsystem_group
if subsystem.needs_mission_solver(
aviary_options) and solver_group is not None:
add_subsystem_group_solver = True
target = external_subsystem_group_solver
else:
add_subsystem_group = True

target.add_subsystem(
subsystem.name,
subsystem_mission,
promotes_inputs=subsystem.mission_inputs(**kwargs),
promotes_outputs=subsystem.mission_outputs(**kwargs),
)

# Only add the external subsystem group if it has at least one subsystem.
# Without this logic there'd be an empty OM group added to the ODE.
if add_subsystem_group:
self.add_subsystem(
name='external_subsystems',
subsys=external_subsystem_group,
promotes_inputs=['*'],
promotes_outputs=['*'],
)
if add_subsystem_group_solver:
solver_group.add_subsystem(
name='external_subsystems',
subsys=external_subsystem_group_solver,
promotes_inputs=['*'],
promotes_outputs=['*'],
)
29 changes: 2 additions & 27 deletions aviary/mission/flight_phase_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import dymos as dm

from aviary.mission.initial_guess_builders import InitialGuessState
from aviary.mission.flops_based.ode.mission_ODE import MissionODE
from aviary.mission.flops_based.ode.energy_ODE import EnergyODE
from aviary.mission.flops_based.phases.phase_utils import add_subsystem_variables_to_phase, get_initial
from aviary.mission.phase_builder_base import PhaseBuilderBase, register

Expand All @@ -26,36 +26,11 @@ class FlightPhaseBase(PhaseBuilderBase):

__slots__ = ('external_subsystems', 'meta_data')

# region : derived type customization points
_meta_data_ = {}

_initial_guesses_meta_data_ = {}

default_name = 'cruise'

default_ode_class = MissionODE

default_ode_class = EnergyODE
default_meta_data = _MetaData
# endregion : derived type customization points

def __init__(
self, name=None, subsystem_options=None, user_options=None, initial_guesses=None,
ode_class=None, transcription=None, core_subsystems=None,
external_subsystems=None, meta_data=None
):
super().__init__(
name=name, core_subsystems=core_subsystems, subsystem_options=subsystem_options, user_options=user_options, initial_guesses=initial_guesses, ode_class=ode_class, transcription=transcription)

# TODO: support external_subsystems and meta_data in the base class
if external_subsystems is None:
external_subsystems = []

self.external_subsystems = external_subsystems

if meta_data is None:
meta_data = self.default_meta_data

self.meta_data = meta_data

def build_phase(self, aviary_options: AviaryValues = None, phase_type=EquationsOfMotion.HEIGHT_ENERGY):
'''
Expand Down
Loading

0 comments on commit 4182af7

Please sign in to comment.