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

Optional subsystems #648

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion aviary/docs/user_guide/aerodynamics.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"# Testing Cell\n",
"from aviary.api import CoreAerodynamicsBuilder\n",
"from aviary.utils.doctape import check_args\n",
"check_args(CoreAerodynamicsBuilder.build_pre_mission,['aviary_inputs'])"
"check_args(CoreAerodynamicsBuilder.build_pre_mission,['aviary_inputs', 'kwargs'])"
]
},
{
Expand Down
5 changes: 4 additions & 1 deletion aviary/docs/user_guide/mass.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@
"Which variables are used depends on which mass estimation subsystem you're using, such as `aircraft:crew_and_payload:mass_per_passenger`, `aircraft:engine:additional_mass_fraction`, etc.\n",
"\n",
"Aviary allows for extensive customization and extensions within the mass subsystem.\n",
"Users can develop alternative components and integrate them as subsystems with the existing platform."
"Users can develop alternative components and integrate them as subsystems with the existing platform.\n",
"\n",
"## External Mass\n",
"Specifying the `external` mass method disables Aviary's core mass group. This allows for external subsystems to completely replace these calculations."
Copy link
Member

@Kenneth-T-Moore Kenneth-T-Moore Jan 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should stress that, yeah, this replaces all mass calculations, so you don't want to use it for subsystem mass.

Also, it might be worth mentioning that, to replace the mass subsystem for the sizing problem, your new mass group needs to compute the Aircraft.Design.OPERATING_MASS and Aircraft.CrewPayload.TOTAL_PAYLOAD_MASS, which feed into the downstream constraints.

(Note: might need to check what the gasp mass feeds into the downstream components too.)

]
},
{
Expand Down
159 changes: 89 additions & 70 deletions aviary/subsystems/aerodynamics/aerodynamics_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,20 @@ def __init__(self, name=None, meta_data=None, code_origin=None):

super().__init__(name=name, meta_data=meta_data)

def build_pre_mission(self, aviary_inputs):
def build_pre_mission(self, aviary_inputs, **kwargs):
code_origin = self.code_origin
try:
method = kwargs.pop('method')
except KeyError:
method = None
aero_group = None

if code_origin is GASP:
aero_group = PreMissionAero()
if method != 'external':
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be cleaner to do:

if method is 'external':
    return None

That would remove the need to indent the entire rest of the method by 4 spaces. Just a thought.

if code_origin is GASP:
aero_group = PreMissionAero()

elif code_origin is FLOPS:
aero_group = Design()
elif code_origin is FLOPS:
aero_group = Design()

return aero_group

Expand All @@ -116,76 +122,89 @@ def build_mission(self, num_nodes, aviary_inputs, **kwargs):
method = kwargs.pop('method')
except KeyError:
method = None
if self.code_origin is FLOPS:
if method is None:
aero_group = ComputedAeroGroup(num_nodes=num_nodes)

elif method == 'computed':
aero_group = ComputedAeroGroup(num_nodes=num_nodes,
**kwargs)

elif method == 'low_speed':
aero_group = TakeoffAeroGroup(num_nodes=num_nodes,
aviary_options=aviary_inputs,
**kwargs)

# TODO solved alpha belongs in the GASP side, rolled into tabular aero
# It is currently only here because it is not possible to define
# per-subsystem code origins in AviaryProblem yet
elif method == 'solved_alpha':
aero_group = SolvedAlphaGroup(num_nodes=num_nodes,
aero_data=kwargs.pop('aero_data'),
**kwargs)

elif method == 'tabular':
aero_group = TabularAeroGroup(num_nodes=num_nodes,
CD0_data=kwargs.pop('CD0_data'),
CDI_data=kwargs.pop('CDI_data'),
**kwargs)

elif method == 'external':
# Aero completely replaced by external group.
aero_group = None
aero_group = None

if method != 'external':
if self.code_origin is FLOPS:
if method is None:
aero_group = ComputedAeroGroup(num_nodes=num_nodes)

elif method == 'computed':
aero_group = ComputedAeroGroup(num_nodes=num_nodes, **kwargs)

elif method == 'low_speed':
aero_group = TakeoffAeroGroup(
num_nodes=num_nodes, aviary_options=aviary_inputs, **kwargs
)

# TODO solved alpha belongs in the GASP side, rolled into tabular aero
# It is currently only here because it is not possible to define
# per-subsystem code origins in AviaryProblem yet
elif method == 'solved_alpha':
aero_group = SolvedAlphaGroup(
num_nodes=num_nodes, aero_data=kwargs.pop('aero_data'), **kwargs
)

elif method == 'tabular':
aero_group = TabularAeroGroup(
num_nodes=num_nodes,
CD0_data=kwargs.pop('CD0_data'),
CDI_data=kwargs.pop('CDI_data'),
**kwargs
)

else:
raise ValueError('FLOPS-based aero method is not one of the following: '
'(computed, low_speed, solved_alpha, tabular)')

elif self.code_origin is GASP:
if method is None:
aero_group = CruiseAero(num_nodes=num_nodes,
aviary_options=aviary_inputs)

elif method == 'cruise':
if 'aero_data' in kwargs:
aero_group = TabularCruiseAero(num_nodes=num_nodes,
aviary_options=aviary_inputs,
aero_data=kwargs.pop('aero_data'),
**kwargs)
else:
aero_group = CruiseAero(num_nodes=num_nodes,
**kwargs)

elif method == 'low_speed':
if any(key in kwargs for key in ['free_aero_data',
'free_flaps_data',
'free_ground_data']) in kwargs:
aero_group = TabularLowSpeedAero(num_nodes=num_nodes,
free_aero_data=kwargs.pop(
'free_aero_data'),
free_flaps_data=kwargs.pop(
'free_flaps_data'),
free_ground_data=kwargs.pop(
'free_ground_data'),
**kwargs)
raise ValueError(
'FLOPS-based aero method is not one of the following: '
'(computed, low_speed, solved_alpha, tabular)'
)

elif self.code_origin is GASP:
if method is None:
aero_group = CruiseAero(
num_nodes=num_nodes, aviary_options=aviary_inputs
)

elif method == 'cruise':
if 'aero_data' in kwargs:
aero_group = TabularCruiseAero(
num_nodes=num_nodes,
aviary_options=aviary_inputs,
aero_data=kwargs.pop('aero_data'),
**kwargs
)
else:
aero_group = CruiseAero(num_nodes=num_nodes, **kwargs)

elif method == 'low_speed':
if (
any(
key in kwargs
for key in [
'free_aero_data',
'free_flaps_data',
'free_ground_data',
]
)
in kwargs
):
aero_group = TabularLowSpeedAero(
num_nodes=num_nodes,
free_aero_data=kwargs.pop('free_aero_data'),
free_flaps_data=kwargs.pop('free_flaps_data'),
free_ground_data=kwargs.pop('free_ground_data'),
**kwargs
)

else:
aero_group = LowSpeedAero(num_nodes=num_nodes, **kwargs)

else:
aero_group = LowSpeedAero(num_nodes=num_nodes,
**kwargs)

else:
raise ValueError('GASP-based aero method is not one of the following: '
'(cruise, low_speed)')
raise ValueError(
'GASP-based aero method is not one of the following: '
'(cruise, low_speed)'
)

return aero_group

Expand Down
39 changes: 27 additions & 12 deletions aviary/subsystems/geometry/geometry_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,30 +82,45 @@ def __init__(self, name=None, meta_data=None, code_origin=None,

super().__init__(name=name, meta_data=meta_data)

def build_pre_mission(self, aviary_inputs):
def build_pre_mission(self, aviary_inputs, **kwargs):
code_origin = self.code_origin
both_geom = self.use_both_geometries
code_origin_to_prioritize = self.code_origin_to_prioritize
try:
method = kwargs.pop('method')
except KeyError:
method = None

geom_group = None

if both_geom:
geom_group = CombinedGeometry(
code_origin_to_prioritize=code_origin_to_prioritize
)
if method != 'external':
if both_geom:
geom_group = CombinedGeometry(
code_origin_to_prioritize=code_origin_to_prioritize
)

elif code_origin is GASP:
geom_group = SizeGroup()
geom_group.manual_overrides = None
elif code_origin is GASP:
geom_group = SizeGroup()
geom_group.manual_overrides = None

elif code_origin is FLOPS:
geom_group = PrepGeom()
geom_group.manual_overrides = None
elif code_origin is FLOPS:
geom_group = PrepGeom()
geom_group.manual_overrides = None

return geom_group

def build_mission(self, num_nodes, aviary_inputs, **kwargs):
super().build_mission(num_nodes, aviary_inputs)
# by default there is no geom mission, but call super for safety/future-proofing
try:
method = kwargs.pop('method')
except KeyError:
method = None
geom_group = None

if method != 'external':
geom_group = super().build_mission(num_nodes, aviary_inputs)

geom_group

def get_parameters(self, aviary_inputs=None, phase_info=None):
num_engine_type = len(aviary_inputs.get_val(Aircraft.Engine.NUM_ENGINES))
Expand Down
30 changes: 23 additions & 7 deletions aviary/subsystems/mass/mass_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,19 +55,35 @@ def __init__(self, name=None, meta_data=None, code_origin=None):

super().__init__(name=name, meta_data=meta_data)

def build_pre_mission(self, aviary_inputs):
def build_pre_mission(self, aviary_inputs, **kwargs):
code_origin = self.code_origin
try:
method = kwargs.pop('method')
except KeyError:
method = None
mass_group = None

if code_origin is GASP:
mass_premission = MassPremissionGASP()
if method != 'external':
if code_origin is GASP:
mass_group = MassPremissionGASP()

elif code_origin is FLOPS:
mass_premission = MassPremissionFLOPS()
elif code_origin is FLOPS:
mass_group = MassPremissionFLOPS()

return mass_premission
return mass_group

def build_mission(self, num_nodes, aviary_inputs, **kwargs):
super().build_mission(num_nodes, aviary_inputs)
# by default there is no mass mission, but call super for safety/future-proofing
try:
method = kwargs.pop('method')
except KeyError:
method = None
mass_group = None

if method != 'external':
mass_group = super().build_mission(num_nodes, aviary_inputs)

mass_group

def report(self, prob, reports_folder, **kwargs):
"""
Expand Down
Loading