diff --git a/aviary/docs/user_guide/aerodynamics.ipynb b/aviary/docs/user_guide/aerodynamics.ipynb index e8504ef81..336258a67 100644 --- a/aviary/docs/user_guide/aerodynamics.ipynb +++ b/aviary/docs/user_guide/aerodynamics.ipynb @@ -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'])" ] }, { diff --git a/aviary/docs/user_guide/mass.ipynb b/aviary/docs/user_guide/mass.ipynb index 912484e2e..07230f4b6 100644 --- a/aviary/docs/user_guide/mass.ipynb +++ b/aviary/docs/user_guide/mass.ipynb @@ -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." ] }, { diff --git a/aviary/subsystems/aerodynamics/aerodynamics_builder.py b/aviary/subsystems/aerodynamics/aerodynamics_builder.py index 52a82d710..b38e62400 100644 --- a/aviary/subsystems/aerodynamics/aerodynamics_builder.py +++ b/aviary/subsystems/aerodynamics/aerodynamics_builder.py @@ -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': + 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 @@ -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 diff --git a/aviary/subsystems/geometry/geometry_builder.py b/aviary/subsystems/geometry/geometry_builder.py index 37c3b7358..3187f4c70 100644 --- a/aviary/subsystems/geometry/geometry_builder.py +++ b/aviary/subsystems/geometry/geometry_builder.py @@ -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)) diff --git a/aviary/subsystems/mass/mass_builder.py b/aviary/subsystems/mass/mass_builder.py index 772a9b838..9ef1a178c 100644 --- a/aviary/subsystems/mass/mass_builder.py +++ b/aviary/subsystems/mass/mass_builder.py @@ -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): """