diff --git a/aviary/api.py b/aviary/api.py index 2d4291bc5..f43eb032b 100644 --- a/aviary/api.py +++ b/aviary/api.py @@ -45,7 +45,7 @@ from aviary.utils.options import list_options from aviary.constants import GRAV_METRIC_GASP, GRAV_ENGLISH_GASP, GRAV_METRIC_FLOPS, GRAV_ENGLISH_FLOPS, GRAV_ENGLISH_LBM, RHO_SEA_LEVEL_ENGLISH, RHO_SEA_LEVEL_METRIC, MU_TAKEOFF, MU_LANDING, PSLS_PSF, TSLS_DEGR, RADIUS_EARTH_METRIC from aviary.subsystems.test.subsystem_tester import TestSubsystemBuilderBase, skipIfMissingDependencies -from aviary.interface.default_phase_info.height_energy import default_premission_subsystems, default_mission_subsystems +from aviary.subsystems.propulsion.utils import build_engine_deck ################### # Level 3 Imports # diff --git a/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb b/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb index 3d6ead06d..52694774c 100644 --- a/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb +++ b/aviary/docs/getting_started/onboarding_ext_subsystem.ipynb @@ -758,7 +758,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.18" + "version": "3.10.8" } }, "nbformat": 4, diff --git a/aviary/docs/getting_started/onboarding_level2.ipynb b/aviary/docs/getting_started/onboarding_level2.ipynb index 2f93625e0..601951ef5 100644 --- a/aviary/docs/getting_started/onboarding_level2.ipynb +++ b/aviary/docs/getting_started/onboarding_level2.ipynb @@ -750,7 +750,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -764,7 +764,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.8" + "version": "3.10.8" } }, "nbformat": 4, diff --git a/aviary/docs/getting_started/onboarding_level3.ipynb b/aviary/docs/getting_started/onboarding_level3.ipynb index 0524c71ae..e697a5aff 100644 --- a/aviary/docs/getting_started/onboarding_level3.ipynb +++ b/aviary/docs/getting_started/onboarding_level3.ipynb @@ -85,9 +85,9 @@ "driver.opt_settings[\"tol\"] = 1e-3\n", "driver.opt_settings['print_level'] = 4\n", "\n", - "##########################################\n", - "# Aircraft Input Variables and Options #\n", - "##########################################\n", + "########################################\n", + "# Aircraft Input Variables and Options #\n", + "########################################\n", "\n", "aviary_inputs = get_flops_inputs('N3CC')\n", "\n", @@ -154,9 +154,21 @@ "t_f_descent = 461.62*_units.minute\n", "t_duration_descent = t_f_descent - t_i_descent\n", "\n", - "##########################\n", - "# Design Variables #\n", - "##########################\n", + "engine = av.build_engine_deck(aviary_inputs)\n", + "av.preprocess_options(aviary_inputs, engine_models=engine)\n", + "\n", + "# define subsystems\n", + "aero = av.CoreAerodynamicsBuilder(code_origin=av.LegacyCode('FLOPS'))\n", + "geom = av.CoreGeometryBuilder(code_origin=av.LegacyCode('FLOPS'))\n", + "mass = av.CoreMassBuilder(code_origin=av.LegacyCode('FLOPS'))\n", + "prop = av.CorePropulsionBuilder(engine_models=engine)\n", + "\n", + "premission_subsystems = [prop, geom, aero, mass]\n", + "mission_subsystems = [aero, prop]\n", + "\n", + "####################\n", + "# Design Variables #\n", + "####################\n", "\n", "# Nudge it a bit off the correct answer to verify that the optimize takes us there.\n", "aviary_inputs.set_val(av.Mission.Design.GROSS_MASS, 135000.0, units='lbm')\n", @@ -170,9 +182,9 @@ " num_engines=aviary_inputs.get_val(av.Aircraft.Engine.NUM_ENGINES)\n", ")\n", "\n", - "##################\n", - "# Define Phases #\n", - "##################\n", + "#################\n", + "# Define Phases #\n", + "#################\n", "num_segments_climb = 6\n", "num_segments_cruise = 1\n", "num_segments_descent = 5\n", @@ -200,7 +212,7 @@ " 'input_initial': (True, 'unitless'),\n", " 'use_polynomial_control': (False, 'unitless'),\n", " }),\n", - " core_subsystems=av.default_mission_subsystems,\n", + " core_subsystems=mission_subsystems,\n", " subsystem_options={'core_aerodynamics': {'method': 'computed'}},\n", " transcription=transcription_climb,\n", ")\n", @@ -215,7 +227,7 @@ " 'required_available_climb_rate': (300, 'ft/min'),\n", " 'fix_initial': (False, 'unitless'),\n", " }),\n", - " core_subsystems=av.default_mission_subsystems,\n", + " core_subsystems=mission_subsystems,\n", " subsystem_options={'core_aerodynamics': {'method': 'computed'}},\n", " transcription=transcription_cruise,\n", ")\n", @@ -230,7 +242,7 @@ " 'fix_initial': (False, 'unitless'),\n", " 'use_polynomial_control': (False, 'unitless'),\n", " }),\n", - " core_subsystems=av.default_mission_subsystems,\n", + " core_subsystems=mission_subsystems,\n", " subsystem_options={'core_aerodynamics': {'method': 'computed'}},\n", " transcription=transcription_descent,\n", ")\n", @@ -241,13 +253,11 @@ " av.Mission.Landing.LIFT_COEFFICIENT_MAX) # no units\n", ")\n", "\n", - "av.preprocess_crewpayload(aviary_inputs)\n", - "\n", "# Upstream static analysis for aero\n", "prob.model.add_subsystem(\n", " 'pre_mission',\n", " av.CorePreMission(aviary_options=aviary_inputs,\n", - " subsystems=av.default_premission_subsystems),\n", + " subsystems=premission_subsystems),\n", " promotes_inputs=['aircraft:*', 'mission:*'],\n", " promotes_outputs=['aircraft:*', 'mission:*'])\n", "\n", @@ -298,9 +308,9 @@ " 'landing', landing, promotes_inputs=['aircraft:*', 'mission:*'],\n", " promotes_outputs=['mission:*'])\n", "\n", - "##########################################\n", - "# link phases #\n", - "##########################################\n", + "###############\n", + "# link phases #\n", + "###############\n", "\n", "traj.link_phases([\"climb\", \"cruise\", \"descent\"], [\"time\", av.Dynamic.Mission.MASS, av.Dynamic.Mission.DISTANCE], connected=strong_couple)\n", "\n", @@ -336,9 +346,9 @@ "prob.model.connect('traj.descent.control_values:altitude', av.Mission.Landing.INITIAL_ALTITUDE,\n", " src_indices=[-1])\n", "\n", - "##########################\n", - "# Constraints #\n", - "##########################\n", + "###############\n", + "# Constraints #\n", + "###############\n", "\n", "ecomp = om.ExecComp('fuel_burned = initial_mass - descent_mass_final',\n", " initial_mass={'units': 'lbm', 'shape': 1},\n", diff --git a/aviary/docs/user_guide/FLOPS_based_detailed_takeoff_and_landing.ipynb b/aviary/docs/user_guide/FLOPS_based_detailed_takeoff_and_landing.ipynb index e652c3d48..7bc2eaa8a 100644 --- a/aviary/docs/user_guide/FLOPS_based_detailed_takeoff_and_landing.ipynb +++ b/aviary/docs/user_guide/FLOPS_based_detailed_takeoff_and_landing.ipynb @@ -46,6 +46,8 @@ "\n", "from aviary.models.N3CC.N3CC_data import inputs\n", "\n", + "aviary_options = inputs.deepcopy()\n", + "\n", "# This builder can be used for both takeoff and landing phases\n", "aero_builder = av.CoreAerodynamicsBuilder(\n", " name='low_speed_aero',\n", @@ -79,7 +81,8 @@ "\n", "# We also need propulsion analysis for takeoff and landing. No additional configuration\n", "# is needed for this builder\n", - "prop_builder = av.CorePropulsionBuilder()" + "engine = av.build_engine_deck(aviary_options)\n", + "prop_builder = av.CorePropulsionBuilder(engine_models=engine)" ] }, { @@ -254,10 +257,9 @@ " takeoff_mic_p2_builder, takeoff_mic_p2_to_engine_cutback_builder,\n", " takeoff_engine_cutback_builder, takeoff_engine_cutback_to_mic_p1_builder,\n", " takeoff_mic_p1_to_climb_builder, takeoff_liftoff_user_options)\n", + "from aviary.utils.test_utils.default_subsystems import get_default_premission_subsystems\n", "\n", "\n", - "aviary_options = inputs.deepcopy()\n", - "\n", "takeoff_trajectory_builder = av.DetailedTakeoffTrajectoryBuilder('detailed_takeoff')\n", "\n", "takeoff_trajectory_builder.set_brake_release_to_decision_speed(\n", @@ -283,12 +285,15 @@ "\n", "takeoff = om.Problem()\n", "\n", + "# default subsystems\n", + "default_premission_subsystems = get_default_premission_subsystems('FLOPS', engine)\n", + " \n", "# Upstream pre-mission analysis for aero\n", "takeoff.model.add_subsystem(\n", " 'core_subsystems',\n", " av.CorePreMission(\n", " aviary_options=aviary_options,\n", - " subsystems=av.default_premission_subsystems,\n", + " subsystems=default_premission_subsystems,\n", " ),\n", " promotes_inputs=['*'],\n", " promotes_outputs=['*'])\n", @@ -541,7 +546,7 @@ " 'core_subsystems',\n", " av.CorePreMission(\n", " aviary_options=aviary_options,\n", - " subsystems=av.default_premission_subsystems,\n", + " subsystems=default_premission_subsystems,\n", " ),\n", " promotes_inputs=['*'],\n", " promotes_outputs=['*'])\n", @@ -581,7 +586,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -595,7 +600,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.10.8" } }, "nbformat": 4, diff --git a/aviary/docs/user_guide/examples_of_the_same_mission_at_different_UI_levels.ipynb b/aviary/docs/user_guide/examples_of_the_same_mission_at_different_UI_levels.ipynb index 5a6341037..7d542227f 100644 --- a/aviary/docs/user_guide/examples_of_the_same_mission_at_different_UI_levels.ipynb +++ b/aviary/docs/user_guide/examples_of_the_same_mission_at_different_UI_levels.ipynb @@ -193,6 +193,7 @@ "import dymos as dm\n", "\n", "import aviary.api as av\n", + "from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems\n", "\n", "\n", "prob = om.Problem(model=om.Group())\n", @@ -200,16 +201,16 @@ "driver.options[\"optimizer\"] = \"SLSQP\"\n", "driver.options[\"maxiter\"] = 1\n", "\n", - "##########################################\n", - "# Aircraft Input Variables and Options #\n", - "##########################################\n", + "########################################\n", + "# Aircraft Input Variables and Options #\n", + "########################################\n", "\n", "csv_path = \"models/test_aircraft/aircraft_for_bench_FwFm.csv\"\n", "\n", "aviary_inputs, _ = av.create_vehicle('models/test_aircraft/aircraft_for_bench_FwFm.csv')\n", "\n", - "engine = av.EngineDeck(options=aviary_inputs)\n", - "av.preprocess_propulsion(aviary_inputs, [engine])\n", + "engine = av.build_engine_deck(aviary_inputs)\n", + "av.preprocess_options(aviary_inputs, engine_models=engine)\n", "\n", "alt_airport = 0 # ft\n", "\n", @@ -250,9 +251,20 @@ "t_f_descent = 299. * _units.minute\n", "t_duration_descent = t_f_descent - t_i_descent\n", "\n", - "##########################\n", - "# Design Variables #\n", - "##########################\n", + "####################\n", + "# Build Subsystems #\n", + "####################\n", + "aero = av.CoreAerodynamicsBuilder(code_origin=av.LegacyCode('FLOPS'))\n", + "geom = av.CoreGeometryBuilder(code_origin=av.LegacyCode('FLOPS'))\n", + "mass = av.CoreMassBuilder(code_origin=av.LegacyCode('FLOPS'))\n", + "prop = av.CorePropulsionBuilder(engine_models=engine)\n", + "\n", + "premission_subsystems = [prop, geom, aero, mass]\n", + "mission_subsystems = [aero, prop]\n", + "\n", + "####################\n", + "# Design Variables #\n", + "####################\n", "\n", "# Nudge it a bit off the correct answer to verify that the optimize takes us there.\n", "aviary_inputs.set_val(av.Mission.Design.GROSS_MASS, 135000.0, units='lbm')\n", @@ -260,9 +272,12 @@ "prob.model.add_design_var(av.Mission.Design.GROSS_MASS, units='lbm',\n", " lower=100000.0, upper=200000.0, ref=135000)\n", "\n", - "##################\n", - "# Define Phases #\n", - "##################\n", + "# default subsystems\n", + "default_mission_subsystems = get_default_mission_subsystems('FLOPS', engine)\n", + "\n", + "#################\n", + "# Define Phases #\n", + "#################\n", "num_segments_climb = 6\n", "num_segments_cruise = 1\n", "num_segments_descent = 5\n", @@ -289,7 +304,7 @@ " 'fix_initial': (True, 'unitless'),\n", " 'use_polynomial_control': (False, 'unitless'),\n", " }),\n", - " core_subsystems=av.default_mission_subsystems,\n", + " core_subsystems=default_mission_subsystems,\n", " subsystem_options={'core_aerodynamics': {'method': 'computed'}},\n", " transcription=transcription_climb,\n", ")\n", @@ -304,7 +319,7 @@ " 'required_available_climb_rate': (300, 'ft/min'),\n", " 'fix_initial': (False, 'unitless'),\n", " }),\n", - " core_subsystems=av.default_mission_subsystems,\n", + " core_subsystems=default_mission_subsystems,\n", " subsystem_options={'core_aerodynamics': {'method': 'computed'}},\n", " transcription=transcription_cruise,\n", ")\n", @@ -319,7 +334,7 @@ " 'fix_initial': (False, 'unitless'),\n", " 'use_polynomial_control': (False, 'unitless'),\n", " }),\n", - " core_subsystems=av.default_mission_subsystems,\n", + " core_subsystems=default_mission_subsystems,\n", " subsystem_options={'core_aerodynamics': {'method': 'computed'}},\n", " transcription=transcription_descent,\n", ")\n", @@ -330,7 +345,7 @@ "prob.model.add_subsystem(\n", " 'pre_mission',\n", " av.CorePreMission(aviary_options=aviary_inputs,\n", - " subsystems=av.default_premission_subsystems),\n", + " subsystems=premission_subsystems),\n", " promotes_inputs=['aircraft:*', 'mission:*'],\n", " promotes_outputs=['aircraft:*', 'mission:*'])\n", "\n", @@ -390,9 +405,9 @@ "traj = av.setup_trajectory_params(prob.model, traj, aviary_inputs, \n", " external_parameters=external_parameters)\n", "\n", - "##########################\n", - "# Constraints #\n", - "##########################\n", + "###############\n", + "# Constraints #\n", + "###############\n", "\n", "ecomp = om.ExecComp('fuel_burned = initial_mass - descent_mass_final',\n", " initial_mass={'units': 'lbm', 'shape': 1},\n", @@ -425,9 +440,9 @@ "\n", "prob.setup(force_alloc_complex=True)\n", "\n", - "###########################################\n", + "############################################\n", "# Initial Settings for States and Controls #\n", - "###########################################\n", + "############################################\n", "\n", "prob.set_val('traj.climb.t_initial', t_i_climb, units='s')\n", "prob.set_val('traj.climb.t_duration', t_duration_climb, units='s')\n", diff --git a/aviary/interface/default_phase_info/height_energy.py b/aviary/interface/default_phase_info/height_energy.py index 6f15be48e..0e7a91f56 100644 --- a/aviary/interface/default_phase_info/height_energy.py +++ b/aviary/interface/default_phase_info/height_energy.py @@ -1,20 +1,4 @@ -from aviary.subsystems.propulsion.propulsion_builder import CorePropulsionBuilder -from aviary.subsystems.geometry.geometry_builder import CoreGeometryBuilder -from aviary.subsystems.mass.mass_builder import CoreMassBuilder -from aviary.subsystems.aerodynamics.aerodynamics_builder import CoreAerodynamicsBuilder -from aviary.variable_info.variable_meta_data import _MetaData as BaseMetaData -from aviary.variable_info.variables import Dynamic, Mission -from aviary.variable_info.enums import LegacyCode - -FLOPS = LegacyCode.FLOPS - -prop = CorePropulsionBuilder('core_propulsion', BaseMetaData) -mass = CoreMassBuilder('core_mass', BaseMetaData, FLOPS) -aero = CoreAerodynamicsBuilder('core_aerodynamics', BaseMetaData, FLOPS) -geom = CoreGeometryBuilder('core_geometry', BaseMetaData, FLOPS) - -default_premission_subsystems = [prop, geom, mass, aero] -default_mission_subsystems = [aero, prop] +from aviary.variable_info.variables import Mission phase_info = { diff --git a/aviary/interface/default_phase_info/height_energy_fiti.py b/aviary/interface/default_phase_info/height_energy_fiti.py index 50922a517..082b87202 100644 --- a/aviary/interface/default_phase_info/height_energy_fiti.py +++ b/aviary/interface/default_phase_info/height_energy_fiti.py @@ -1,26 +1,12 @@ from aviary.mission.flops_based.phases.time_integration_phases import SGMDetailedTakeoff, \ SGMHeightEnergy, SGMDetailedLanding -from aviary.subsystems.propulsion.propulsion_builder import CorePropulsionBuilder -from aviary.subsystems.geometry.geometry_builder import CoreGeometryBuilder -from aviary.subsystems.mass.mass_builder import CoreMassBuilder -from aviary.subsystems.aerodynamics.aerodynamics_builder import CoreAerodynamicsBuilder from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variable_meta_data import _MetaData as BaseMetaData from aviary.variable_info.variables import Dynamic, Mission -from aviary.variable_info.enums import SpeedType, Verbosity, AlphaModes, LegacyCode +from aviary.variable_info.enums import SpeedType, AlphaModes from aviary.interface.default_phase_info.two_dof_fiti import add_default_sgm_args -FLOPS = LegacyCode.FLOPS - -prop = CorePropulsionBuilder('core_propulsion', BaseMetaData) -mass = CoreMassBuilder('core_mass', BaseMetaData, FLOPS) -aero = CoreAerodynamicsBuilder('core_aerodynamics', BaseMetaData, FLOPS) -geom = CoreGeometryBuilder('core_geometry', BaseMetaData, FLOPS) - -default_premission_subsystems = [prop, geom, mass, aero] -default_mission_subsystems = [aero, prop] - cruise_mach = .8, cruise_alt = 35e3, diff --git a/aviary/interface/default_phase_info/two_dof.py b/aviary/interface/default_phase_info/two_dof.py index 3bc8fbed3..9c6bca3da 100644 --- a/aviary/interface/default_phase_info/two_dof.py +++ b/aviary/interface/default_phase_info/two_dof.py @@ -1,21 +1,5 @@ from aviary.variable_info.enums import SpeedType -from aviary.subsystems.propulsion.propulsion_builder import CorePropulsionBuilder -from aviary.subsystems.geometry.geometry_builder import CoreGeometryBuilder -from aviary.subsystems.mass.mass_builder import CoreMassBuilder -from aviary.subsystems.aerodynamics.aerodynamics_builder import CoreAerodynamicsBuilder -from aviary.variable_info.variable_meta_data import _MetaData as BaseMetaData, Mission -from aviary.variable_info.enums import LegacyCode - - -GASP = LegacyCode.GASP - -prop = CorePropulsionBuilder('core_propulsion', BaseMetaData) -mass = CoreMassBuilder('core_mass', BaseMetaData, GASP) -aero = CoreAerodynamicsBuilder('core_aerodynamics', BaseMetaData, GASP) -geom = CoreGeometryBuilder('core_geometry', BaseMetaData, GASP) - -default_premission_subsystems = [prop, geom, aero, mass] -default_mission_subsystems = [aero, prop] +from aviary.variable_info.variables import Mission mission_distance = 3675 diff --git a/aviary/interface/default_phase_info/two_dof_fiti.py b/aviary/interface/default_phase_info/two_dof_fiti.py index 04e51c08f..8de3b0a82 100644 --- a/aviary/interface/default_phase_info/two_dof_fiti.py +++ b/aviary/interface/default_phase_info/two_dof_fiti.py @@ -1,26 +1,11 @@ -from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.enums import SpeedType, Verbosity, AlphaModes, LegacyCode +from aviary.variable_info.enums import SpeedType, AlphaModes from aviary.mission.gasp_based.phases.time_integration_phases import SGMGroundroll, \ SGMRotation, SGMAscentCombined, SGMAccel, SGMClimb, SGMCruise, SGMDescent +from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Aircraft, Mission, Dynamic, Settings -from aviary.subsystems.propulsion.propulsion_builder import CorePropulsionBuilder -from aviary.subsystems.geometry.geometry_builder import CoreGeometryBuilder -from aviary.subsystems.mass.mass_builder import CoreMassBuilder -from aviary.subsystems.aerodynamics.aerodynamics_builder import CoreAerodynamicsBuilder -from aviary.variable_info.variable_meta_data import _MetaData as BaseMetaData, Mission -from aviary.interface.default_phase_info.two_dof_fiti_deprecated import create_2dof_based_ascent_phases, create_2dof_based_descent_phases +from aviary.variable_info.enums import Verbosity # defaults for 2DOF based forward in time integeration phases - -GASP = LegacyCode.GASP - -prop = CorePropulsionBuilder('core_propulsion', BaseMetaData) -mass = CoreMassBuilder('core_mass', BaseMetaData, GASP) -aero = CoreAerodynamicsBuilder('core_aerodynamics', BaseMetaData, GASP) -geom = CoreGeometryBuilder('core_geometry', BaseMetaData, GASP) - -default_premission_subsystems = [prop, geom, aero, mass] - cruise_alt = 35e3, cruise_mach = .8, diff --git a/aviary/interface/methods_for_level2.py b/aviary/interface/methods_for_level2.py index 006b4eae5..a29b8838c 100644 --- a/aviary/interface/methods_for_level2.py +++ b/aviary/interface/methods_for_level2.py @@ -48,7 +48,7 @@ from aviary.variable_info.enums import AnalysisScheme, ProblemType, SpeedType, AlphaModes, EquationsOfMotion, LegacyCode, Verbosity from aviary.variable_info.variable_meta_data import _MetaData as BaseMetaData -from aviary.subsystems.propulsion.engine_deck import EngineDeck +from aviary.subsystems.propulsion.utils import build_engine_deck from aviary.subsystems.propulsion.propulsion_builder import CorePropulsionBuilder from aviary.subsystems.geometry.geometry_builder import CoreGeometryBuilder from aviary.subsystems.mass.mass_builder import CoreMassBuilder @@ -234,7 +234,7 @@ def __init__(self, analysis_scheme=AnalysisScheme.COLLOCATION, **kwargs): self.regular_phases = [] self.reserve_phases = [] - def load_inputs(self, aviary_inputs, phase_info=None, engine_builder=None, meta_data=BaseMetaData, verbosity=Verbosity.BRIEF): + def load_inputs(self, aviary_inputs, phase_info=None, engine_builders=None, meta_data=BaseMetaData, verbosity=None): """ This method loads the aviary_values inputs and options that the user specifies. They could specify files to load and values to @@ -249,7 +249,7 @@ def load_inputs(self, aviary_inputs, phase_info=None, engine_builder=None, meta_ # Create AviaryValues object from file (or process existing AviaryValues object # with default values from metadata) and generate initial guesses aviary_inputs, initial_guesses = create_vehicle( - aviary_inputs, verbosity=verbosity, meta_data=meta_data) + aviary_inputs, meta_data=meta_data, verbosity=verbosity) # pull which methods will be used for subsystems and mission self.mission_method = mission_method = aviary_inputs.get_val( @@ -335,68 +335,9 @@ def load_inputs(self, aviary_inputs, phase_info=None, engine_builder=None, meta_ self.post_mission_info = {'include_landing': True, 'external_subsystems': []} - ## PROCESSING ## - # set up core subsystems - if mission_method in (HEIGHT_ENERGY, SOLVED_2DOF): - everything_else_origin = FLOPS - elif mission_method is TWO_DEGREES_OF_FREEDOM: - everything_else_origin = GASP - else: - raise ValueError(f'Unknown mission method {self.mission_method}') - - prop = CorePropulsionBuilder('core_propulsion') - mass = CoreMassBuilder('core_mass', code_origin=self.mass_method) - aero = CoreAerodynamicsBuilder( - 'core_aerodynamics', code_origin=everything_else_origin) - - # TODO These values are currently hardcoded, in future should come from user - both_geom = False - code_origin_to_prioritize = None - - # which geometry methods should be used, or both? - geom_code_origin = None - if (everything_else_origin is FLOPS) and (mass_method is FLOPS): - geom_code_origin = FLOPS - elif (everything_else_origin is GASP) and (mass_method is GASP): - geom_code_origin = GASP - else: - both_geom = True - - # which geometry method gets prioritized in case of conflicting outputs - if not code_origin_to_prioritize: - if everything_else_origin is GASP: - code_origin_to_prioritize = GASP - elif everything_else_origin is FLOPS: - code_origin_to_prioritize = FLOPS - - geom = CoreGeometryBuilder('core_geometry', - code_origin=geom_code_origin, - use_both_geometries=both_geom, - code_origin_to_prioritize=code_origin_to_prioritize) - - self.core_subsystems = {'propulsion': prop, - 'geometry': geom, - 'mass': mass, - 'aerodynamics': aero} - - # TODO optionally accept which subsystems to load from phase_info - subsystems = self.core_subsystems - default_mission_subsystems = [ - subsystems['aerodynamics'], subsystems['propulsion']] - self.ode_args = dict(aviary_options=aviary_inputs, - core_subsystems=default_mission_subsystems) - - if 'engine_models' in aviary_inputs: - engine_models = aviary_inputs.get_val('engine_models') - else: - engine_models = [EngineDeck(options=aviary_inputs)] - - preprocess_propulsion(aviary_inputs, engine_models) - - self._update_metadata_from_subsystems() - - if Settings.VERBOSITY not in aviary_inputs: - aviary_inputs.set_val(Settings.VERBOSITY, verbosity) + if engine_builders is None: + engine_builders = build_engine_deck(aviary_inputs) + self.engine_builders = engine_builders self.aviary_inputs = aviary_inputs return aviary_inputs @@ -404,8 +345,6 @@ def load_inputs(self, aviary_inputs, phase_info=None, engine_builder=None, meta_ def _update_metadata_from_subsystems(self): self.meta_data = BaseMetaData.copy() - variables_to_pop = [] - # loop through phase_info and external subsystems for phase_name in self.phase_info: external_subsystems = self._get_all_subsystems( @@ -462,7 +401,7 @@ def check_and_preprocess_inputs(self): This method checks the user-supplied input values for any potential problems and preprocesses the inputs to prepare them for use in the Aviary problem. """ - + aviary_inputs = self.aviary_inputs # Target_distance verification for all phases # Checks to make sure target_distance is positive, for idx, phase_name in enumerate(self.phase_info): @@ -513,13 +452,68 @@ def check_and_preprocess_inputs(self): for phase_name in self.phase_info: for external_subsystem in self.phase_info[phase_name]['external_subsystems']: - self.aviary_inputs = external_subsystem.preprocess_inputs( - self.aviary_inputs) + aviary_inputs = external_subsystem.preprocess_inputs( + aviary_inputs) - # TODO find preprocessors a permanent home # PREPROCESSORS # # Fill in anything missing in the options with computed defaults. - preprocess_crewpayload(self.aviary_inputs) + preprocess_propulsion(aviary_inputs, self.engine_builders) + preprocess_crewpayload(aviary_inputs) + + mission_method = aviary_inputs.get_val(Settings.EQUATIONS_OF_MOTION) + mass_method = aviary_inputs.get_val(Settings.MASS_METHOD) + + ## Set Up Core Subsystems ## + if mission_method in (HEIGHT_ENERGY, SOLVED_2DOF): + everything_else_origin = FLOPS + elif mission_method is TWO_DEGREES_OF_FREEDOM: + everything_else_origin = GASP + else: + raise ValueError(f'Unknown mission method {self.mission_method}') + + prop = CorePropulsionBuilder( + 'core_propulsion', engine_models=self.engine_builders) + mass = CoreMassBuilder('core_mass', code_origin=self.mass_method) + aero = CoreAerodynamicsBuilder( + 'core_aerodynamics', code_origin=everything_else_origin) + + # TODO These values are currently hardcoded, in future should come from user + both_geom = False + code_origin_to_prioritize = None + + # which geometry methods should be used, or both? + geom_code_origin = None + if (everything_else_origin is FLOPS) and (mass_method is FLOPS): + geom_code_origin = FLOPS + elif (everything_else_origin is GASP) and (mass_method is GASP): + geom_code_origin = GASP + else: + both_geom = True + + # which geometry method gets prioritized in case of conflicting outputs + if not code_origin_to_prioritize: + if everything_else_origin is GASP: + code_origin_to_prioritize = GASP + elif everything_else_origin is FLOPS: + code_origin_to_prioritize = FLOPS + + geom = CoreGeometryBuilder('core_geometry', + code_origin=geom_code_origin, + use_both_geometries=both_geom, + code_origin_to_prioritize=code_origin_to_prioritize) + + subsystems = self.core_subsystems = {'propulsion': prop, + 'geometry': geom, + 'mass': mass, + 'aerodynamics': aero} + + # TODO optionally accept which subsystems to load from phase_info + default_mission_subsystems = [ + subsystems['aerodynamics'], subsystems['propulsion']] + self.ode_args = {'aviary_options': aviary_inputs, + 'core_subsystems': default_mission_subsystems} + + self._update_metadata_from_subsystems() if self.mission_method in (HEIGHT_ENERGY, SOLVED_2DOF, TWO_DEGREES_OF_FREEDOM): self.phase_separator() @@ -846,7 +840,8 @@ def _get_phase(self, phase_name, phase_idx): control_dicts = subsystem.get_controls( phase_name=phase_name) else: - control_dicts = subsystem.get_controls() + control_dicts = subsystem.get_controls( + phase_name=phase_name) for control_name, control_dict in control_dicts.items(): phase.add_control(control_name, **control_dict) @@ -2345,8 +2340,6 @@ def _save_to_csv_file(self, filename): writer = csv.DictWriter(csvfile, fieldnames=fieldnames) for name, value_units in sorted(self.aviary_inputs): - if 'engine_models' in name: - continue value, units = value_units writer.writerow({'name': name, 'value': value, 'units': units}) diff --git a/aviary/interface/test/test_phase_info.py b/aviary/interface/test/test_phase_info.py index 8e8ee46b9..dd3b8ac82 100644 --- a/aviary/interface/test/test_phase_info.py +++ b/aviary/interface/test/test_phase_info.py @@ -157,5 +157,5 @@ def test_phase_info_parameterization_height_energy(self): # To run the tests if __name__ == '__main__': unittest.main() - # test = TestPhaseInfo() - # test.test_default_phase_height_energy() + # test = TestParameterizePhaseInfo() + # test.test_phase_info_parameterization_two_dof() diff --git a/aviary/mission/flight_phase_builder.py b/aviary/mission/flight_phase_builder.py index d975cb7cf..8cc748274 100644 --- a/aviary/mission/flight_phase_builder.py +++ b/aviary/mission/flight_phase_builder.py @@ -11,6 +11,7 @@ from aviary.variable_info.variables import Aircraft, Dynamic from aviary.mission.flops_based.ode.mission_ODE import MissionODE from aviary.variable_info.enums import EquationsOfMotion, ThrottleAllocation +from aviary.variable_info.variables import Aircraft # TODO: support/handle the following in the base class diff --git a/aviary/mission/flops_based/ode/mission_ODE.py b/aviary/mission/flops_based/ode/mission_ODE.py index 6ea553729..0658d18c9 100644 --- a/aviary/mission/flops_based/ode/mission_ODE.py +++ b/aviary/mission/flops_based/ode/mission_ODE.py @@ -67,7 +67,7 @@ def setup(self): aviary_options = options['aviary_options'] core_subsystems = options['core_subsystems'] subsystem_options = options['subsystem_options'] - num_engine_type = len(aviary_options.get_val('engine_models')) + num_engine_type = len(aviary_options.get_val(Aircraft.Engine.NUM_ENGINES)) if analysis_scheme is AnalysisScheme.SHOOTING: SGM_required_inputs = { diff --git a/aviary/mission/flops_based/ode/test/test_landing_ode.py b/aviary/mission/flops_based/ode/test/test_landing_ode.py index 526fbc9cf..1b1845342 100644 --- a/aviary/mission/flops_based/ode/test/test_landing_ode.py +++ b/aviary/mission/flops_based/ode/test/test_landing_ode.py @@ -2,7 +2,8 @@ import openmdao.api as om -from aviary.interface.default_phase_info.height_energy import default_mission_subsystems +from aviary.subsystems.propulsion.utils import build_engine_deck +from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems from aviary.mission.flops_based.ode.landing_ode import FlareODE from aviary.models.N3CC.N3CC_data import ( detailed_landing_flare, inputs, landing_subsystem_options) @@ -13,11 +14,13 @@ class FlareODETest(unittest.TestCase): def test_case(self): prob = om.Problem() - time, _ = detailed_landing_flare.get_item('time') nn = len(time) aviary_options = inputs + default_mission_subsystems = get_default_mission_subsystems( + 'FLOPS', build_engine_deck(aviary_options)) + prob.model.add_subsystem( "landing_flare_ode", FlareODE( diff --git a/aviary/mission/flops_based/ode/test/test_takeoff_ode.py b/aviary/mission/flops_based/ode/test/test_takeoff_ode.py index 6ffbf6e20..a7c0c9cf7 100644 --- a/aviary/mission/flops_based/ode/test/test_takeoff_ode.py +++ b/aviary/mission/flops_based/ode/test/test_takeoff_ode.py @@ -3,7 +3,8 @@ import openmdao.api as om -from aviary.interface.default_phase_info.height_energy import default_mission_subsystems +from aviary.subsystems.propulsion.utils import build_engine_deck +from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems from aviary.mission.flops_based.ode.takeoff_ode import TakeoffODE from aviary.models.N3CC.N3CC_data import ( detailed_takeoff_climbing, detailed_takeoff_ground, takeoff_subsystem_options, inputs) @@ -70,6 +71,9 @@ def _make_prob(climbing): nn = len(time) aviary_options = inputs + default_mission_subsystems = get_default_mission_subsystems( + 'FLOPS', build_engine_deck(aviary_options)) + prob.model.add_subsystem( "takeoff_ode", TakeoffODE( diff --git a/aviary/mission/flops_based/phases/test/test_time_integration_phases.py b/aviary/mission/flops_based/phases/test/test_time_integration_phases.py index f8bb6f1c2..daec19787 100644 --- a/aviary/mission/flops_based/phases/test/test_time_integration_phases.py +++ b/aviary/mission/flops_based/phases/test/test_time_integration_phases.py @@ -7,12 +7,13 @@ SGMHeightEnergy, SGMDetailedTakeoff, SGMDetailedLanding from aviary.subsystems.premission import CorePreMission from aviary.utils.functions import set_aviary_initial_values -from aviary.variable_info.enums import Verbosity, EquationsOfMotion +from aviary.variable_info.enums import EquationsOfMotion from aviary.variable_info.variables import Aircraft, Dynamic, Mission, Settings from aviary.variable_info.variables_in import VariablesIn -from aviary.interface.default_phase_info.height_energy_fiti import aero, prop, geom, add_default_sgm_args -from aviary.subsystems.propulsion.engine_deck import EngineDeck +from aviary.interface.default_phase_info.height_energy_fiti import add_default_sgm_args +from aviary.utils.test_utils.default_subsystems import get_default_premission_subsystems +from aviary.subsystems.propulsion.utils import build_engine_deck from aviary.utils.process_input_decks import create_vehicle from aviary.utils.preprocessors import preprocess_propulsion from aviary.variable_info.variable_meta_data import _MetaData as BaseMetaData @@ -35,8 +36,12 @@ def setUp(self): val=0.35, units="unitless") aviary_inputs.set_val(Settings.EQUATIONS_OF_MOTION, val=EquationsOfMotion.SOLVED_2DOF) - ode_args = dict(aviary_options=aviary_inputs, core_subsystems=[prop, geom, aero]) - preprocess_propulsion(aviary_inputs, [EngineDeck(options=aviary_inputs)]) + + engines = build_engine_deck(aviary_inputs) + # don't need mass + core_subsystems = get_default_premission_subsystems('FLOPS', engines)[:-1] + ode_args = dict(aviary_options=aviary_inputs, core_subsystems=core_subsystems) + preprocess_propulsion(aviary_inputs, engines) ode_args['num_nodes'] = 1 ode_args['subsystem_options'] = {'core_aerodynamics': {'method': 'computed'}} diff --git a/aviary/mission/gasp_based/ode/test/test_accel_ode.py b/aviary/mission/gasp_based/ode/test/test_accel_ode.py index 3645de3a4..7781dd58a 100644 --- a/aviary/mission/gasp_based/ode/test/test_accel_ode.py +++ b/aviary/mission/gasp_based/ode/test/test_accel_ode.py @@ -8,14 +8,20 @@ from aviary.variable_info.options import get_option_defaults from aviary.utils.test_utils.IO_test_util import check_prob_outputs from aviary.variable_info.variables import Dynamic -from aviary.interface.default_phase_info.two_dof import default_mission_subsystems +from aviary.subsystems.propulsion.utils import build_engine_deck +from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems class AccelerationODETestCase(unittest.TestCase): def setUp(self): self.prob = om.Problem() + + aviary_options = get_option_defaults() + default_mission_subsystems = get_default_mission_subsystems( + 'GASP', build_engine_deck(aviary_options)) + self.sys = self.prob.model = AccelODE(num_nodes=2, - aviary_options=get_option_defaults(), + aviary_options=aviary_options, core_subsystems=default_mission_subsystems) def test_accel(self): diff --git a/aviary/mission/gasp_based/ode/test/test_ascent_ode.py b/aviary/mission/gasp_based/ode/test/test_ascent_ode.py index 1493ff78b..b17f051f1 100644 --- a/aviary/mission/gasp_based/ode/test/test_ascent_ode.py +++ b/aviary/mission/gasp_based/ode/test/test_ascent_ode.py @@ -4,7 +4,8 @@ from openmdao.utils.assert_utils import assert_check_partials from aviary.mission.gasp_based.ode.ascent_ode import AscentODE -from aviary.interface.default_phase_info.two_dof import default_mission_subsystems +from aviary.subsystems.propulsion.utils import build_engine_deck +from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Dynamic @@ -12,8 +13,13 @@ class AscentODETestCase(unittest.TestCase): def setUp(self): self.prob = om.Problem() + + aviary_options = get_option_defaults() + default_mission_subsystems = get_default_mission_subsystems( + 'GASP', build_engine_deck(aviary_options)) + self.prob.model = AscentODE(num_nodes=2, - aviary_options=get_option_defaults(), + aviary_options=aviary_options, core_subsystems=default_mission_subsystems) def test_ascent_partials(self): diff --git a/aviary/mission/gasp_based/ode/test/test_climb_ode.py b/aviary/mission/gasp_based/ode/test/test_climb_ode.py index 47eb53f5f..e11a0069d 100644 --- a/aviary/mission/gasp_based/ode/test/test_climb_ode.py +++ b/aviary/mission/gasp_based/ode/test/test_climb_ode.py @@ -9,12 +9,18 @@ from aviary.utils.test_utils.IO_test_util import check_prob_outputs from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft, Dynamic -from aviary.interface.default_phase_info.two_dof import default_mission_subsystems +from aviary.subsystems.propulsion.utils import build_engine_deck +from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems class ClimbODETestCase(unittest.TestCase): def setUp(self): self.prob = om.Problem() + + aviary_options = get_option_defaults() + default_mission_subsystems = get_default_mission_subsystems( + 'GASP', build_engine_deck(aviary_options)) + self.sys = self.prob.model = ClimbODE( num_nodes=1, EAS_target=250, diff --git a/aviary/mission/gasp_based/ode/test/test_descent_ode.py b/aviary/mission/gasp_based/ode/test/test_descent_ode.py index 7d642f6e8..5e2c70db3 100644 --- a/aviary/mission/gasp_based/ode/test/test_descent_ode.py +++ b/aviary/mission/gasp_based/ode/test/test_descent_ode.py @@ -12,12 +12,18 @@ from aviary.utils.test_utils.IO_test_util import check_prob_outputs from aviary.variable_info.enums import SpeedType from aviary.variable_info.variables import Dynamic -from aviary.interface.default_phase_info.two_dof import default_mission_subsystems +from aviary.subsystems.propulsion.utils import build_engine_deck +from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems class DescentODETestCase(unittest.TestCase): def setUp(self): self.prob = om.Problem() + + aviary_options = get_option_defaults() + default_mission_subsystems = get_default_mission_subsystems( + 'GASP', build_engine_deck(aviary_options)) + self.sys = self.prob.model = DescentODE(num_nodes=1, mach_cruise=0.8, aviary_options=get_option_defaults(), diff --git a/aviary/mission/gasp_based/ode/test/test_groundroll_ode.py b/aviary/mission/gasp_based/ode/test/test_groundroll_ode.py index 57d36fcac..18af08fe3 100644 --- a/aviary/mission/gasp_based/ode/test/test_groundroll_ode.py +++ b/aviary/mission/gasp_based/ode/test/test_groundroll_ode.py @@ -5,13 +5,19 @@ from aviary.mission.gasp_based.ode.groundroll_ode import GroundrollODE from aviary.variable_info.options import get_option_defaults -from aviary.interface.default_phase_info.two_dof import default_mission_subsystems +from aviary.subsystems.propulsion.utils import build_engine_deck +from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems from aviary.variable_info.variables import Dynamic class GroundrollODETestCase(unittest.TestCase): def setUp(self): self.prob = om.Problem() + + aviary_options = get_option_defaults() + default_mission_subsystems = get_default_mission_subsystems( + 'GASP', build_engine_deck(aviary_options)) + self.prob.model = GroundrollODE(num_nodes=2, aviary_options=get_option_defaults(), core_subsystems=default_mission_subsystems) diff --git a/aviary/mission/gasp_based/ode/test/test_rotation_ode.py b/aviary/mission/gasp_based/ode/test/test_rotation_ode.py index 34d39ac0b..f1c8b9d82 100644 --- a/aviary/mission/gasp_based/ode/test/test_rotation_ode.py +++ b/aviary/mission/gasp_based/ode/test/test_rotation_ode.py @@ -1,5 +1,4 @@ import unittest -import os import openmdao.api as om from openmdao.utils.assert_utils import assert_check_partials @@ -7,12 +6,18 @@ from aviary.mission.gasp_based.ode.rotation_ode import RotationODE from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft, Dynamic -from aviary.interface.default_phase_info.two_dof import default_mission_subsystems +from aviary.subsystems.propulsion.utils import build_engine_deck +from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems class RotationODETestCase(unittest.TestCase): def setUp(self): self.prob = om.Problem() + + aviary_options = get_option_defaults() + default_mission_subsystems = get_default_mission_subsystems( + 'GASP', build_engine_deck(aviary_options)) + self.prob.model = RotationODE(num_nodes=2, aviary_options=get_option_defaults(), core_subsystems=default_mission_subsystems) diff --git a/aviary/mission/gasp_based/ode/unsteady_solved/test/test_unsteady_alpha_thrust_iter_group.py b/aviary/mission/gasp_based/ode/unsteady_solved/test/test_unsteady_alpha_thrust_iter_group.py index 3029008bc..f9170c5ef 100644 --- a/aviary/mission/gasp_based/ode/unsteady_solved/test/test_unsteady_alpha_thrust_iter_group.py +++ b/aviary/mission/gasp_based/ode/unsteady_solved/test/test_unsteady_alpha_thrust_iter_group.py @@ -5,15 +5,16 @@ from openmdao.utils.assert_utils import assert_near_equal from aviary.constants import GRAV_ENGLISH_LBM -from aviary.interface.default_phase_info.two_dof import aero from aviary.mission.gasp_based.ode.params import ParamPort from aviary.mission.gasp_based.ode.unsteady_solved.unsteady_control_iter_group import \ UnsteadyControlIterGroup from aviary.mission.gasp_based.ode.unsteady_solved.unsteady_solved_flight_conditions import \ UnsteadySolvedFlightConditions from aviary.variable_info.enums import SpeedType +from aviary.variable_info.options import get_option_defaults from aviary.variable_info.variables import Aircraft, Dynamic -from variable_info.options import get_option_defaults +from aviary.subsystems.aerodynamics.aerodynamics_builder import CoreAerodynamicsBuilder +from aviary.variable_info.enums import LegacyCode class TestUnsteadyAlphaThrustIterGroup(unittest.TestCase): @@ -21,6 +22,9 @@ class TestUnsteadyAlphaThrustIterGroup(unittest.TestCase): def _test_unsteady_alpha_thrust_iter_group(self, ground_roll=False): nn = 5 + # just need aero subsystem + aero = CoreAerodynamicsBuilder(code_origin=LegacyCode.GASP) + p = om.Problem() # TODO: paramport diff --git a/aviary/mission/gasp_based/ode/unsteady_solved/test/test_unsteady_solved_ode.py b/aviary/mission/gasp_based/ode/unsteady_solved/test/test_unsteady_solved_ode.py index 80e3ebc68..26ee05a11 100644 --- a/aviary/mission/gasp_based/ode/unsteady_solved/test/test_unsteady_solved_ode.py +++ b/aviary/mission/gasp_based/ode/unsteady_solved/test/test_unsteady_solved_ode.py @@ -11,7 +11,8 @@ from aviary.variable_info.options import get_option_defaults from aviary.variable_info.enums import SpeedType from aviary.variable_info.variables import Aircraft, Dynamic, Mission -from aviary.interface.default_phase_info.two_dof import default_mission_subsystems +from aviary.subsystems.propulsion.utils import build_engine_deck +from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems class TestUnsteadySolvedODE(unittest.TestCase): @@ -22,11 +23,15 @@ def _test_unsteady_solved_ode(self, ground_roll=False, input_speed_type=SpeedTyp p = om.Problem() + aviary_options = get_option_defaults() + default_mission_subsystems = get_default_mission_subsystems( + 'GASP', build_engine_deck(aviary_options)) + ode = UnsteadySolvedODE(num_nodes=nn, input_speed_type=input_speed_type, clean=clean, ground_roll=ground_roll, - aviary_options=get_option_defaults(), + aviary_options=aviary_options, core_subsystems=default_mission_subsystems) p.model.add_subsystem("ode", ode, promotes=["*"]) diff --git a/aviary/mission/gasp_based/phases/landing_group.py b/aviary/mission/gasp_based/phases/landing_group.py index 0152721d8..51063df58 100644 --- a/aviary/mission/gasp_based/phases/landing_group.py +++ b/aviary/mission/gasp_based/phases/landing_group.py @@ -6,14 +6,17 @@ from aviary.mission.gasp_based.phases.landing_components import ( GlideConditionComponent, LandingAltitudeComponent, LandingGroundRollComponent) -from aviary.subsystems.aerodynamics.gasp_based.gaspaero import LowSpeedAero -from aviary.subsystems.propulsion.propulsion_mission import PropulsionMission from aviary.variable_info.enums import SpeedType from aviary.variable_info.variables import Aircraft, Dynamic, Mission +from aviary.subsystems.aerodynamics.aerodynamics_builder import AerodynamicsBuilderBase +from aviary.subsystems.propulsion.propulsion_builder import PropulsionBuilderBase class LandingSegment(BaseODE): def setup(self): + aviary_options = self.options['aviary_options'] + core_subsystems = self.options['core_subsystems'] + # TODO: paramport self.add_subsystem("params", ParamPort(), promotes=["*"]) @@ -51,44 +54,51 @@ def setup(self): promotes_outputs=[(Dynamic.Mission.DYNAMIC_PRESSURE, "q_app")], ) - propulsion_mission = self.add_subsystem( - name='propulsion', - subsys=PropulsionMission( - num_nodes=1, - aviary_options=self.options['aviary_options']), - promotes_inputs=["*", (Dynamic.Mission.ALTITUDE, Mission.Landing.INITIAL_ALTITUDE), - (Dynamic.Mission.MACH, Mission.Landing.INITIAL_MACH)], - promotes_outputs=[(Dynamic.Mission.THRUST_TOTAL, "thrust_idle")]) - propulsion_mission.set_input_defaults(Dynamic.Mission.THROTTLE, 0.0) - - # alpha input not needed, only used for CL_max - self.add_subsystem( - "aero_app", - LowSpeedAero(num_nodes=1, aviary_options=self.options['aviary_options']), - promotes_inputs=[ - "*", - (Dynamic.Mission.ALTITUDE, Mission.Landing.INITIAL_ALTITUDE), - ("rho", "rho_app"), - (Dynamic.Mission.SPEED_OF_SOUND, "sos_app"), - ("viscosity", "viscosity_app"), - ("airport_alt", Mission.Landing.AIRPORT_ALTITUDE), - (Dynamic.Mission.MACH, Mission.Landing.INITIAL_MACH), - (Dynamic.Mission.DYNAMIC_PRESSURE, "q_app"), - ("flap_defl", Aircraft.Wing.FLAP_DEFLECTION_LANDING), - ("t_init_flaps", "t_init_flaps_app"), - ("t_init_gear", "t_init_gear_app"), - ("CL_max_flaps", Mission.Landing.LIFT_COEFFICIENT_MAX), - ( - "dCL_flaps_model", - Mission.Landing.LIFT_COEFFICIENT_FLAP_INCREMENT, - ), - ( - "dCD_flaps_model", - Mission.Landing.DRAG_COEFFICIENT_FLAP_INCREMENT, - ), - ], - promotes_outputs=["CL_max"], - ) + # collect the propulsion group names for later use with + for subsystem in core_subsystems: + if isinstance(subsystem, AerodynamicsBuilderBase): + kwargs = {'method': 'low_speed'} + aero_builder = subsystem + aero_system = subsystem.build_mission(num_nodes=1, + aviary_inputs=aviary_options, + **kwargs) + self.add_subsystem(subsystem.name, + aero_system, + promotes_inputs=[ + "*", + (Dynamic.Mission.ALTITUDE, + Mission.Landing.INITIAL_ALTITUDE), + ("rho", "rho_app"), + (Dynamic.Mission.SPEED_OF_SOUND, "sos_app"), + ("viscosity", "viscosity_app"), + ("airport_alt", Mission.Landing.AIRPORT_ALTITUDE), + (Dynamic.Mission.MACH, Mission.Landing.INITIAL_MACH), + (Dynamic.Mission.DYNAMIC_PRESSURE, "q_app"), + ("flap_defl", Aircraft.Wing.FLAP_DEFLECTION_LANDING), + ("t_init_flaps", "t_init_flaps_app"), + ("t_init_gear", "t_init_gear_app"), + ("CL_max_flaps", Mission.Landing.LIFT_COEFFICIENT_MAX), + ( + "dCL_flaps_model", + Mission.Landing.LIFT_COEFFICIENT_FLAP_INCREMENT, + ), + ( + "dCD_flaps_model", + Mission.Landing.DRAG_COEFFICIENT_FLAP_INCREMENT, + ), + ], + promotes_outputs=["CL_max"], + ) + + if isinstance(subsystem, PropulsionBuilderBase): + propulsion_system = subsystem.build_mission( + num_nodes=1, aviary_inputs=aviary_options) + propulsion_mission = self.add_subsystem(subsystem.name, + propulsion_system, + promotes_inputs=[ + "*", (Dynamic.Mission.ALTITUDE, Mission.Landing.INITIAL_ALTITUDE), (Dynamic.Mission.MACH, Mission.Landing.INITIAL_MACH)], + promotes_outputs=[(Dynamic.Mission.THRUST_TOTAL, "thrust_idle")]) + propulsion_mission.set_input_defaults(Dynamic.Mission.THROTTLE, 0.0) self.add_subsystem( "glide", @@ -142,10 +152,14 @@ def setup(self): (Dynamic.Mission.MACH, "mach_td")], ) + kwargs = {'method': 'low_speed', + 'retract_flaps': True, + 'retract_gear': False} + self.add_subsystem( "aero_td", - LowSpeedAero(num_nodes=1, aviary_options=self.options['aviary_options'], - retract_flaps=True, retract_gear=False), + aero_builder.build_mission( + num_nodes=1, aviary_inputs=aviary_options, **kwargs), promotes_inputs=[ "*", (Dynamic.Mission.ALTITUDE, Mission.Landing.AIRPORT_ALTITUDE), diff --git a/aviary/mission/gasp_based/phases/taxi_group.py b/aviary/mission/gasp_based/phases/taxi_group.py index a5035ebd9..3094d20ac 100644 --- a/aviary/mission/gasp_based/phases/taxi_group.py +++ b/aviary/mission/gasp_based/phases/taxi_group.py @@ -5,14 +5,14 @@ from aviary.mission.gasp_based.ode.base_ode import BaseODE from aviary.mission.gasp_based.ode.params import ParamPort from aviary.mission.gasp_based.phases.taxi_component import TaxiFuelComponent -from aviary.subsystems.propulsion.propulsion_mission import \ - PropulsionMission +from aviary.subsystems.propulsion.propulsion_builder import PropulsionBuilderBase from aviary.variable_info.variables import Dynamic, Mission class TaxiSegment(BaseODE): def setup(self): options: AviaryValues = self.options['aviary_options'] + core_subsystems = self.options['core_subsystems'] self.add_subsystem("params", ParamPort(), promotes=["*"]) self.add_subsystem( "USatm", @@ -25,15 +25,15 @@ def setup(self): add_opts2vals(self, create_opts2vals( [Mission.Taxi.MACH]), options) - self.add_subsystem( - name='propulsion', - subsys=PropulsionMission( - num_nodes=1, - aviary_options=options, - ), - promotes_inputs=['*', (Dynamic.Mission.ALTITUDE, Mission.Takeoff.AIRPORT_ALTITUDE), - (Dynamic.Mission.MACH, Mission.Taxi.MACH)], - promotes_outputs=['*']) + for subsystem in core_subsystems: + if isinstance(subsystem, PropulsionBuilderBase): + system = subsystem.build_mission(num_nodes=1, aviary_inputs=options) + + self.add_subsystem(subsystem.name, + system, + promotes_inputs=['*', (Dynamic.Mission.ALTITUDE, Mission.Takeoff.AIRPORT_ALTITUDE), + (Dynamic.Mission.MACH, Mission.Taxi.MACH)], + promotes_outputs=['*']) self.add_subsystem("taxifuel", TaxiFuelComponent( aviary_options=options), promotes=["*"]) diff --git a/aviary/mission/gasp_based/phases/test/test_landing_group.py b/aviary/mission/gasp_based/phases/test/test_landing_group.py index 6ed7c3265..8f6efd371 100644 --- a/aviary/mission/gasp_based/phases/test/test_landing_group.py +++ b/aviary/mission/gasp_based/phases/test/test_landing_group.py @@ -11,13 +11,22 @@ from aviary.variable_info.options import get_option_defaults from aviary.utils.test_utils.IO_test_util import check_prob_outputs from aviary.variable_info.variables import Dynamic, Mission +from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems +from aviary.subsystems.aerodynamics.aerodynamics_builder import AerodynamicsBuilderBase +from aviary.subsystems.propulsion.utils import build_engine_deck class DLandTestCase(unittest.TestCase): def setUp(self): self.prob = om.Problem() - self.prob.model = LandingSegment(aviary_options=get_option_defaults()) + + options = get_option_defaults() + engine = build_engine_deck(options) + core_subsystems = get_default_mission_subsystems('GASP', engine) + + self.prob.model = LandingSegment( + aviary_options=options, core_subsystems=core_subsystems) @unittest.skipIf(version.parse(openmdao.__version__) < version.parse("3.26"), "Skipping due to OpenMDAO version being too low (<3.26)") def test_dland(self): @@ -56,3 +65,6 @@ def test_dland(self): if __name__ == "__main__": unittest.main() + # test = DLandTestCase() + # test.setUp() + # test.test_dland() diff --git a/aviary/mission/gasp_based/phases/test/test_taxi_group.py b/aviary/mission/gasp_based/phases/test/test_taxi_group.py index 6ed7c3265..c2f5daced 100644 --- a/aviary/mission/gasp_based/phases/test/test_taxi_group.py +++ b/aviary/mission/gasp_based/phases/test/test_taxi_group.py @@ -11,13 +11,21 @@ from aviary.variable_info.options import get_option_defaults from aviary.utils.test_utils.IO_test_util import check_prob_outputs from aviary.variable_info.variables import Dynamic, Mission +from aviary.subsystems.propulsion.utils import build_engine_deck +from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems class DLandTestCase(unittest.TestCase): def setUp(self): self.prob = om.Problem() - self.prob.model = LandingSegment(aviary_options=get_option_defaults()) + + options = get_option_defaults() + default_mission_subsystems = get_default_mission_subsystems( + 'GASP', build_engine_deck(options)) + + self.prob.model = LandingSegment( + aviary_options=options, core_subsystems=default_mission_subsystems) @unittest.skipIf(version.parse(openmdao.__version__) < version.parse("3.26"), "Skipping due to OpenMDAO version being too low (<3.26)") def test_dland(self): diff --git a/aviary/mission/gasp_based/test/test_idle_descent_estimation.py b/aviary/mission/gasp_based/test/test_idle_descent_estimation.py index a12ab67e1..4871a3e0a 100644 --- a/aviary/mission/gasp_based/test/test_idle_descent_estimation.py +++ b/aviary/mission/gasp_based/test/test_idle_descent_estimation.py @@ -8,9 +8,10 @@ from openmdao.utils.assert_utils import assert_near_equal -from aviary.interface.default_phase_info.two_dof import default_mission_subsystems +from aviary.subsystems.propulsion.utils import build_engine_deck +from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems from aviary.mission.gasp_based.idle_descent_estimation import descent_range_and_fuel, add_descent_estimation_as_submodel -from aviary.subsystems.propulsion.engine_deck import EngineDeck +from aviary.subsystems.propulsion.utils import build_engine_deck from aviary.variable_info.variables import Aircraft, Dynamic, Settings from aviary.variable_info.enums import Verbosity from aviary.utils.process_input_decks import create_vehicle @@ -25,10 +26,15 @@ def setUp(self): aviary_inputs.set_val(Settings.VERBOSITY, Verbosity.QUIET) aviary_inputs.set_val(Aircraft.Engine.SCALED_SLS_THRUST, val=28690, units="lbf") aviary_inputs.set_val(Dynamic.Mission.THROTTLE, val=0, units="unitless") + + engine = build_engine_deck(aviary_options=aviary_inputs) + preprocess_propulsion(aviary_inputs, engine) + + default_mission_subsystems = get_default_mission_subsystems( + 'GASP', build_engine_deck(aviary_inputs)) + ode_args = dict(aviary_options=aviary_inputs, core_subsystems=default_mission_subsystems) - engine = EngineDeck(options=aviary_inputs) - preprocess_propulsion(aviary_inputs, [engine]) self.ode_args = ode_args self.aviary_inputs = aviary_inputs @@ -63,7 +69,7 @@ def test_subproblem(self): ) prob.setup() - om.n2(prob, 'idle_descent_n2.html', show_browser=False) + warnings.filterwarnings('ignore', category=UserWarning) prob.run_model() warnings.filterwarnings('default', category=UserWarning) diff --git a/aviary/models/N3CC/N3CC_data.py b/aviary/models/N3CC/N3CC_data.py index 13d7c6629..151f723c7 100644 --- a/aviary/models/N3CC/N3CC_data.py +++ b/aviary/models/N3CC/N3CC_data.py @@ -17,14 +17,13 @@ TakeoffEngineCutback, TakeoffEngineCutbackToMicP1, TakeoffLiftoffToObstacle, TakeoffMicP1ToClimb, TakeoffMicP2ToEngineCutback, TakeoffObstacleToMicP2, TakeoffRotateToLiftoff, TakeoffTrajectory) -from aviary.subsystems.propulsion.engine_deck import EngineDeck +from aviary.subsystems.propulsion.utils import build_engine_deck from aviary.utils.aviary_values import AviaryValues -from aviary.utils.preprocessors import preprocess_propulsion +from aviary.utils.test_utils.default_subsystems import get_default_premission_subsystems, get_default_mission_subsystems +from aviary.utils.preprocessors import preprocess_options from aviary.utils.functions import get_path from aviary.variable_info.variables import Aircraft, Dynamic, Mission, Settings from aviary.variable_info.enums import EquationsOfMotion, LegacyCode -from aviary.interface.default_phase_info.height_energy import default_mission_subsystems - N3CC = {} inputs = N3CC['inputs'] = AviaryValues() @@ -443,10 +442,12 @@ outputs.set_val(Mission.Design.LIFT_COEFFICIENT, 0.583) # Create engine model -engine = EngineDeck(name='engine', - options=engine_inputs - ) -preprocess_propulsion(inputs, [engine]) +engine = build_engine_deck(aviary_options=engine_inputs) +preprocess_options(inputs, engine_models=engine) + +# build subsystems +default_premission_subsystems = get_default_premission_subsystems('FLOPS', engine) +default_mission_subsystems = get_default_mission_subsystems('FLOPS', engine) # region - detailed takeoff takeoff_trajectory_builder = TakeoffTrajectory('detailed_takeoff') diff --git a/aviary/models/large_single_aisle_1/large_single_aisle_1_FLOPS_data.py b/aviary/models/large_single_aisle_1/large_single_aisle_1_FLOPS_data.py index 1cd71cf2e..c5fd70877 100644 --- a/aviary/models/large_single_aisle_1/large_single_aisle_1_FLOPS_data.py +++ b/aviary/models/large_single_aisle_1/large_single_aisle_1_FLOPS_data.py @@ -1,8 +1,6 @@ import numpy as np -from aviary.subsystems.propulsion.engine_deck import EngineDeck from aviary.utils.aviary_values import AviaryValues -from aviary.utils.preprocessors import preprocess_propulsion from aviary.utils.functions import get_path from aviary.variable_info.enums import EquationsOfMotion, LegacyCode from aviary.variable_info.variables import Aircraft, Mission, Settings @@ -145,52 +143,34 @@ inputs.set_val(Aircraft.Propulsion.ENGINE_OIL_MASS_SCALER, 1.0) inputs.set_val(Aircraft.Propulsion.MISC_MASS_SCALER, 1.0) -filename = get_path( - 'models/engines/turbofan_28k.deck') - -engine_inputs = AviaryValues() -engine_inputs.set_val(Aircraft.Engine.DATA_FILE, filename) -engine_mass = 7400 -engine_mass_units = 'lbm' -engine_inputs.set_val(Aircraft.Engine.MASS, engine_mass, engine_mass_units) -engine_inputs.set_val( - Aircraft.Engine.REFERENCE_MASS, - engine_mass, - engine_mass_units) -scaled_sls_thrust = 28928.1 -scaled_sls_thrust_units = 'lbf' -engine_inputs.set_val( - Aircraft.Engine.SCALED_SLS_THRUST, scaled_sls_thrust, scaled_sls_thrust_units -) -engine_inputs.set_val( - Aircraft.Engine.REFERENCE_SLS_THRUST, scaled_sls_thrust, scaled_sls_thrust_units) -num_engines = 2 -engine_inputs.set_val(Aircraft.Engine.NUM_ENGINES, num_engines) -num_fuselage_engines = 0 -engine_inputs.set_val(Aircraft.Engine.NUM_FUSELAGE_ENGINES, 0) -num_wing_engines = num_engines -engine_inputs.set_val(Aircraft.Engine.NUM_WING_ENGINES, num_wing_engines) -engine_inputs.set_val(Aircraft.Engine.THRUST_REVERSERS_MASS_SCALER, 0.0) -engine_inputs.set_val( - Aircraft.Engine.WING_LOCATIONS, 15.8300 / (117.83 / 2)) -engine_inputs.set_val(Aircraft.Engine.SCALE_MASS, True) -engine_inputs.set_val(Aircraft.Engine.MASS_SCALER, 1.15) -engine_inputs.set_val(Aircraft.Engine.SCALE_PERFORMANCE, True) -engine_inputs.set_val(Aircraft.Engine.SUBSONIC_FUEL_FLOW_SCALER, 1.0) -engine_inputs.set_val(Aircraft.Engine.SUPERSONIC_FUEL_FLOW_SCALER, 1.0) -engine_inputs.set_val( - Aircraft.Engine.FUEL_FLOW_SCALER_CONSTANT_TERM, 0.0) -engine_inputs.set_val(Aircraft.Engine.FUEL_FLOW_SCALER_LINEAR_TERM, 0.0) -engine_inputs.set_val(Aircraft.Engine.CONSTANT_FUEL_CONSUMPTION, 0.0, units='lbm/h') -engine_inputs.set_val(Aircraft.Engine.ADDITIONAL_MASS_FRACTION, 0.0) -engine_inputs.set_val(Aircraft.Engine.GENERATE_FLIGHT_IDLE, True) -engine_inputs.set_val(Aircraft.Engine.IGNORE_NEGATIVE_THRUST, False) -engine_inputs.set_val(Aircraft.Engine.FLIGHT_IDLE_THRUST_FRACTION, 0.0) -engine_inputs.set_val(Aircraft.Engine.FLIGHT_IDLE_MAX_FRACTION, 1.0) -engine_inputs.set_val(Aircraft.Engine.FLIGHT_IDLE_MIN_FRACTION, 0.08) -engine_inputs.set_val(Aircraft.Engine.GEOPOTENTIAL_ALT, False) -engine_inputs.set_val(Aircraft.Engine.INTERPOLATION_METHOD, 'slinear') - +filename = get_path('models/engines/turbofan_28k.deck') + +inputs.set_val(Aircraft.Engine.DATA_FILE, filename) +inputs.set_val(Aircraft.Engine.MASS, 7400, 'lbm') +inputs.set_val(Aircraft.Engine.REFERENCE_MASS, 7400, 'lbm') +inputs.set_val(Aircraft.Engine.SCALED_SLS_THRUST, 28928.1, 'lbf') +inputs.set_val(Aircraft.Engine.REFERENCE_SLS_THRUST, 28928.1, 'lbf') +inputs.set_val(Aircraft.Engine.NUM_ENGINES, 2) +inputs.set_val(Aircraft.Engine.NUM_FUSELAGE_ENGINES, 0) +inputs.set_val(Aircraft.Engine.NUM_WING_ENGINES, 2) +inputs.set_val(Aircraft.Engine.THRUST_REVERSERS_MASS_SCALER, 0.0) +inputs.set_val(Aircraft.Engine.WING_LOCATIONS, 15.8300 / (117.83 / 2)) +inputs.set_val(Aircraft.Engine.SCALE_MASS, True) +inputs.set_val(Aircraft.Engine.MASS_SCALER, 1.15) +inputs.set_val(Aircraft.Engine.SCALE_PERFORMANCE, True) +inputs.set_val(Aircraft.Engine.SUBSONIC_FUEL_FLOW_SCALER, 1.0) +inputs.set_val(Aircraft.Engine.SUPERSONIC_FUEL_FLOW_SCALER, 1.0) +inputs.set_val(Aircraft.Engine.FUEL_FLOW_SCALER_CONSTANT_TERM, 0.0) +inputs.set_val(Aircraft.Engine.FUEL_FLOW_SCALER_LINEAR_TERM, 0.0) +inputs.set_val(Aircraft.Engine.CONSTANT_FUEL_CONSUMPTION, 0.0, units='lbm/h') +inputs.set_val(Aircraft.Engine.ADDITIONAL_MASS_FRACTION, 0.0) +inputs.set_val(Aircraft.Engine.GENERATE_FLIGHT_IDLE, True) +inputs.set_val(Aircraft.Engine.IGNORE_NEGATIVE_THRUST, False) +inputs.set_val(Aircraft.Engine.FLIGHT_IDLE_THRUST_FRACTION, 0.0) +inputs.set_val(Aircraft.Engine.FLIGHT_IDLE_MAX_FRACTION, 1.0) +inputs.set_val(Aircraft.Engine.FLIGHT_IDLE_MIN_FRACTION, 0.08) +inputs.set_val(Aircraft.Engine.GEOPOTENTIAL_ALT, False) +inputs.set_val(Aircraft.Engine.INTERPOLATION_METHOD, 'slinear') # Vertical Tail # --------------------------- @@ -350,11 +330,10 @@ outputs.set_val(Aircraft.Paint.MASS, 306.2, 'lbm') outputs.set_val( - Aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST, - scaled_sls_thrust * num_engines, scaled_sls_thrust_units) + Aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST, 28928.1*2, 'lbf') outputs.set_val( - Aircraft.Propulsion.TOTAL_NUM_ENGINES, num_engines) + Aircraft.Propulsion.TOTAL_NUM_ENGINES, 2) engine_ctrls_mass = 88.44 engine_ctrls_mass_units = 'lbm' @@ -365,9 +344,9 @@ engine_ctrls_mass, engine_ctrls_mass_units) outputs.set_val(Aircraft.Propulsion.TOTAL_ENGINE_OIL_MASS, 130.23, 'lbm') -outputs.set_val(Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES, num_wing_engines) +outputs.set_val(Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES, 2) -outputs.set_val(Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES, num_fuselage_engines) +outputs.set_val(Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES, 0) outputs.set_val(Aircraft.Engine.MASS, 14800/2, 'lbm') outputs.set_val(Aircraft.Engine.POD_MASS, 9000, 'lbm') @@ -379,9 +358,7 @@ outputs.set_val(Aircraft.Propulsion.TOTAL_THRUST_REVERSERS_MASS, 0, 'lbm') outputs.set_val(Aircraft.Engine.THRUST_REVERSERS_MASS, 0, 'lbm') -outputs.set_val( - Aircraft.Propulsion.TOTAL_ENGINE_MASS, - engine_mass * num_engines, engine_mass_units) +outputs.set_val(Aircraft.Propulsion.TOTAL_ENGINE_MASS, 7400 * 2, 'lbm') outputs.set_val(Aircraft.VerticalTail.CHARACTERISTIC_LENGTH, 12.74, 'ft') outputs.set_val(Aircraft.VerticalTail.FINENESS, 0.1195) @@ -402,10 +379,3 @@ outputs.set_val(Mission.Design.MACH, 0.800) outputs.set_val(Mission.Design.LIFT_COEFFICIENT, 0.568) - -# Create engine model -engine_inputs.set_val(Settings.VERBOSITY, 0) -engine = EngineDeck(name='engine', - options=engine_inputs - ) -preprocess_propulsion(inputs, [engine]) diff --git a/aviary/models/large_single_aisle_2/large_single_aisle_2_FLOPS_data.py b/aviary/models/large_single_aisle_2/large_single_aisle_2_FLOPS_data.py index dad959c83..c6c0f8e34 100644 --- a/aviary/models/large_single_aisle_2/large_single_aisle_2_FLOPS_data.py +++ b/aviary/models/large_single_aisle_2/large_single_aisle_2_FLOPS_data.py @@ -1,9 +1,7 @@ import numpy as np from numpy import pi -from aviary.subsystems.propulsion.engine_deck import EngineDeck from aviary.utils.aviary_values import AviaryValues -from aviary.utils.preprocessors import preprocess_propulsion from aviary.utils.functions import get_path from aviary.variable_info.enums import EquationsOfMotion, LegacyCode from aviary.variable_info.variables import Aircraft, Mission, Settings @@ -156,46 +154,45 @@ filename = get_path( 'models/engines/turbofan_24k_1.deck') -engine_inputs = AviaryValues() -engine_inputs.set_val(Aircraft.Engine.DATA_FILE, filename) +inputs.set_val(Aircraft.Engine.DATA_FILE, filename) engine_mass = 8071.35 engine_mass_units = 'lbm' -engine_inputs.set_val(Aircraft.Engine.MASS, engine_mass, engine_mass_units) -engine_inputs.set_val( +inputs.set_val(Aircraft.Engine.MASS, engine_mass, engine_mass_units) +inputs.set_val( Aircraft.Engine.REFERENCE_MASS, engine_mass, engine_mass_units) scaled_sls_thrust = 27301.0 scaled_sls_thrust_units = 'lbf' -engine_inputs.set_val(Aircraft.Engine.SCALED_SLS_THRUST, - scaled_sls_thrust, scaled_sls_thrust_units) -engine_inputs.set_val( +inputs.set_val(Aircraft.Engine.SCALED_SLS_THRUST, + scaled_sls_thrust, scaled_sls_thrust_units) +inputs.set_val( Aircraft.Engine.REFERENCE_SLS_THRUST, scaled_sls_thrust, scaled_sls_thrust_units) num_engines = 2 -engine_inputs.set_val(Aircraft.Engine.NUM_ENGINES, num_engines) +inputs.set_val(Aircraft.Engine.NUM_ENGINES, num_engines) num_fuselage_engines = 0 -engine_inputs.set_val(Aircraft.Engine.NUM_FUSELAGE_ENGINES, num_fuselage_engines) +inputs.set_val(Aircraft.Engine.NUM_FUSELAGE_ENGINES, num_fuselage_engines) num_wing_engines = 2 -engine_inputs.set_val(Aircraft.Engine.NUM_WING_ENGINES, num_wing_engines) -engine_inputs.set_val(Aircraft.Engine.THRUST_REVERSERS_MASS_SCALER, 1.0) -engine_inputs.set_val(Aircraft.Engine.SCALE_MASS, True) -engine_inputs.set_val(Aircraft.Engine.MASS_SCALER, 1.15) -engine_inputs.set_val(Aircraft.Engine.SCALE_PERFORMANCE, True) -engine_inputs.set_val(Aircraft.Engine.SCALE_FACTOR, 1.0) -engine_inputs.set_val(Aircraft.Engine.SUBSONIC_FUEL_FLOW_SCALER, 1.0) -engine_inputs.set_val(Aircraft.Engine.SUPERSONIC_FUEL_FLOW_SCALER, 1.0) -engine_inputs.set_val( +inputs.set_val(Aircraft.Engine.NUM_WING_ENGINES, num_wing_engines) +inputs.set_val(Aircraft.Engine.THRUST_REVERSERS_MASS_SCALER, 1.0) +inputs.set_val(Aircraft.Engine.SCALE_MASS, True) +inputs.set_val(Aircraft.Engine.MASS_SCALER, 1.15) +inputs.set_val(Aircraft.Engine.SCALE_PERFORMANCE, True) +inputs.set_val(Aircraft.Engine.SCALE_FACTOR, 1.0) +inputs.set_val(Aircraft.Engine.SUBSONIC_FUEL_FLOW_SCALER, 1.0) +inputs.set_val(Aircraft.Engine.SUPERSONIC_FUEL_FLOW_SCALER, 1.0) +inputs.set_val( Aircraft.Engine.FUEL_FLOW_SCALER_CONSTANT_TERM, 0.0) -engine_inputs.set_val(Aircraft.Engine.FUEL_FLOW_SCALER_LINEAR_TERM, 0.0) -engine_inputs.set_val(Aircraft.Engine.CONSTANT_FUEL_CONSUMPTION, 0.0, units='lbm/h') -engine_inputs.set_val(Aircraft.Engine.ADDITIONAL_MASS_FRACTION, 0.0) -engine_inputs.set_val(Aircraft.Engine.GENERATE_FLIGHT_IDLE, True) -engine_inputs.set_val(Aircraft.Engine.IGNORE_NEGATIVE_THRUST, False) -engine_inputs.set_val(Aircraft.Engine.FLIGHT_IDLE_THRUST_FRACTION, 0.0) -engine_inputs.set_val(Aircraft.Engine.FLIGHT_IDLE_MAX_FRACTION, 1.0) -engine_inputs.set_val(Aircraft.Engine.FLIGHT_IDLE_MIN_FRACTION, 0.08) -engine_inputs.set_val(Aircraft.Engine.GEOPOTENTIAL_ALT, False) -engine_inputs.set_val(Aircraft.Engine.INTERPOLATION_METHOD, 'slinear') +inputs.set_val(Aircraft.Engine.FUEL_FLOW_SCALER_LINEAR_TERM, 0.0) +inputs.set_val(Aircraft.Engine.CONSTANT_FUEL_CONSUMPTION, 0.0, units='lbm/h') +inputs.set_val(Aircraft.Engine.ADDITIONAL_MASS_FRACTION, 0.0) +inputs.set_val(Aircraft.Engine.GENERATE_FLIGHT_IDLE, True) +inputs.set_val(Aircraft.Engine.IGNORE_NEGATIVE_THRUST, False) +inputs.set_val(Aircraft.Engine.FLIGHT_IDLE_THRUST_FRACTION, 0.0) +inputs.set_val(Aircraft.Engine.FLIGHT_IDLE_MAX_FRACTION, 1.0) +inputs.set_val(Aircraft.Engine.FLIGHT_IDLE_MIN_FRACTION, 0.08) +inputs.set_val(Aircraft.Engine.GEOPOTENTIAL_ALT, False) +inputs.set_val(Aircraft.Engine.INTERPOLATION_METHOD, 'slinear') # Vertical Tail # --------------------------- @@ -408,10 +405,3 @@ outputs.set_val(Mission.Design.MACH, 0.799) outputs.set_val(Mission.Design.LIFT_COEFFICIENT, 0.523) - -# Create engine model -engine_inputs.set_val(Settings.VERBOSITY, 0) -engine = EngineDeck(name='engine', - options=engine_inputs - ) -preprocess_propulsion(inputs, [engine]) diff --git a/aviary/models/large_single_aisle_2/large_single_aisle_2_altwt_FLOPS_data.py b/aviary/models/large_single_aisle_2/large_single_aisle_2_altwt_FLOPS_data.py index 3654c53c9..56130af1b 100644 --- a/aviary/models/large_single_aisle_2/large_single_aisle_2_altwt_FLOPS_data.py +++ b/aviary/models/large_single_aisle_2/large_single_aisle_2_altwt_FLOPS_data.py @@ -1,9 +1,7 @@ import numpy as np from numpy import pi -from aviary.subsystems.propulsion.engine_deck import EngineDeck from aviary.utils.aviary_values import AviaryValues -from aviary.utils.preprocessors import preprocess_propulsion from aviary.utils.functions import get_path from aviary.variable_info.enums import EquationsOfMotion, LegacyCode from aviary.variable_info.variables import Aircraft, Mission, Settings @@ -153,47 +151,34 @@ inputs.set_val(Aircraft.Propulsion.ENGINE_OIL_MASS_SCALER, 1.0) inputs.set_val(Aircraft.Propulsion.MISC_MASS_SCALER, 1.0) -filename = get_path( - 'models/engines/turbofan_24k_1.deck') - -engine_inputs = AviaryValues() -engine_inputs.set_val(Aircraft.Engine.DATA_FILE, filename) -engine_mass = 8071.35 -engine_mass_units = 'lbm' -engine_inputs.set_val(Aircraft.Engine.MASS, engine_mass, engine_mass_units) -engine_inputs.set_val(Aircraft.Engine.REFERENCE_MASS, - engine_mass, engine_mass_units) -scaled_sls_thrust = 27301.0 -scaled_sls_thrust_units = 'lbf' -engine_inputs.set_val( - Aircraft.Engine.SCALED_SLS_THRUST, scaled_sls_thrust, scaled_sls_thrust_units) -engine_inputs.set_val( - Aircraft.Engine.REFERENCE_SLS_THRUST, scaled_sls_thrust, scaled_sls_thrust_units) -num_engines = 2 -engine_inputs.set_val(Aircraft.Engine.NUM_ENGINES, num_engines) -num_fuselage_engines = 0 -engine_inputs.set_val(Aircraft.Engine.NUM_FUSELAGE_ENGINES, num_fuselage_engines) -num_wing_engines = 2 -engine_inputs.set_val(Aircraft.Engine.NUM_WING_ENGINES, num_wing_engines) -engine_inputs.set_val(Aircraft.Engine.THRUST_REVERSERS_MASS_SCALER, 1.0) -engine_inputs.set_val(Aircraft.Engine.SCALE_MASS, True) -engine_inputs.set_val(Aircraft.Engine.MASS_SCALER, 1.15) -engine_inputs.set_val(Aircraft.Engine.SCALE_PERFORMANCE, True) - -engine_inputs.set_val(Aircraft.Engine.SUBSONIC_FUEL_FLOW_SCALER, 1.0) -engine_inputs.set_val(Aircraft.Engine.SUPERSONIC_FUEL_FLOW_SCALER, 1.0) -engine_inputs.set_val( - Aircraft.Engine.FUEL_FLOW_SCALER_CONSTANT_TERM, 0.0) -engine_inputs.set_val(Aircraft.Engine.FUEL_FLOW_SCALER_LINEAR_TERM, 0.0) -engine_inputs.set_val(Aircraft.Engine.CONSTANT_FUEL_CONSUMPTION, 0.0, units='lbm/h') -engine_inputs.set_val(Aircraft.Engine.ADDITIONAL_MASS_FRACTION, 0.0) -engine_inputs.set_val(Aircraft.Engine.GENERATE_FLIGHT_IDLE, True) -engine_inputs.set_val(Aircraft.Engine.IGNORE_NEGATIVE_THRUST, False) -engine_inputs.set_val(Aircraft.Engine.FLIGHT_IDLE_THRUST_FRACTION, 0.0) -engine_inputs.set_val(Aircraft.Engine.FLIGHT_IDLE_MAX_FRACTION, 1.0) -engine_inputs.set_val(Aircraft.Engine.FLIGHT_IDLE_MIN_FRACTION, 0.08) -engine_inputs.set_val(Aircraft.Engine.GEOPOTENTIAL_ALT, False) -engine_inputs.set_val(Aircraft.Engine.INTERPOLATION_METHOD, 'slinear') +filename = get_path('models/engines/turbofan_24k_1.deck') + +inputs.set_val(Aircraft.Engine.DATA_FILE, filename) +inputs.set_val(Aircraft.Engine.MASS, 8071.35, 'lbm') +inputs.set_val(Aircraft.Engine.REFERENCE_MASS, 8071.35, 'lbm') +inputs.set_val(Aircraft.Engine.SCALED_SLS_THRUST, 27301.0, 'lbf') +inputs.set_val(Aircraft.Engine.REFERENCE_SLS_THRUST, 27301.0, 'lbf') +inputs.set_val(Aircraft.Engine.NUM_ENGINES, 2) +inputs.set_val(Aircraft.Engine.NUM_FUSELAGE_ENGINES, 0) +inputs.set_val(Aircraft.Engine.NUM_WING_ENGINES, 2) +inputs.set_val(Aircraft.Engine.THRUST_REVERSERS_MASS_SCALER, 1.0) +inputs.set_val(Aircraft.Engine.SCALE_MASS, True) +inputs.set_val(Aircraft.Engine.MASS_SCALER, 1.15) +inputs.set_val(Aircraft.Engine.SCALE_PERFORMANCE, True) + +inputs.set_val(Aircraft.Engine.SUBSONIC_FUEL_FLOW_SCALER, 1.0) +inputs.set_val(Aircraft.Engine.SUPERSONIC_FUEL_FLOW_SCALER, 1.0) +inputs.set_val(Aircraft.Engine.FUEL_FLOW_SCALER_CONSTANT_TERM, 0.0) +inputs.set_val(Aircraft.Engine.FUEL_FLOW_SCALER_LINEAR_TERM, 0.0) +inputs.set_val(Aircraft.Engine.CONSTANT_FUEL_CONSUMPTION, 0.0, units='lbm/h') +inputs.set_val(Aircraft.Engine.ADDITIONAL_MASS_FRACTION, 0.0) +inputs.set_val(Aircraft.Engine.GENERATE_FLIGHT_IDLE, True) +inputs.set_val(Aircraft.Engine.IGNORE_NEGATIVE_THRUST, False) +inputs.set_val(Aircraft.Engine.FLIGHT_IDLE_THRUST_FRACTION, 0.0) +inputs.set_val(Aircraft.Engine.FLIGHT_IDLE_MAX_FRACTION, 1.0) +inputs.set_val(Aircraft.Engine.FLIGHT_IDLE_MIN_FRACTION, 0.08) +inputs.set_val(Aircraft.Engine.GEOPOTENTIAL_ALT, False) +inputs.set_val(Aircraft.Engine.INTERPOLATION_METHOD, 'slinear') # Vertical Tail @@ -355,10 +340,10 @@ outputs.set_val(Aircraft.Paint.MASS, 582.3, 'lbm') -outputs.set_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES, num_engines) +outputs.set_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES, 2) outputs.set_val( Aircraft.Propulsion.TOTAL_SCALED_SLS_THRUST, - scaled_sls_thrust * num_engines, scaled_sls_thrust_units) + 27301.0 * 2, 'lbf') outputs.set_val( Aircraft.Propulsion.TOTAL_ENGINE_CONTROLS_MASS, 0.26 * 2 * 27301.0**0.5, 'lbm') # 85.92 @@ -374,13 +359,12 @@ outputs.set_val( Aircraft.Engine.THRUST_REVERSERS_MASS, thrust_reversers_mass, thrust_reversers_mass_units) -outputs.set_val(Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES, num_fuselage_engines) -outputs.set_val(Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES, num_wing_engines) +outputs.set_val(Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES, 0) +outputs.set_val(Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES, 2) outputs.set_val(Aircraft.Engine.MASS, 16143./2.0, 'lbm') outputs.set_val(Aircraft.Engine.ADDITIONAL_MASS, 0.0, 'lbm') outputs.set_val(Aircraft.Engine.SCALE_FACTOR, 1.0) -outputs.set_val( - Aircraft.Propulsion.TOTAL_ENGINE_MASS, engine_mass * num_engines, engine_mass_units) +outputs.set_val(Aircraft.Propulsion.TOTAL_ENGINE_MASS, 8071.35 * 2, 'lbm') outputs.set_val(Aircraft.VerticalTail.CHARACTERISTIC_LENGTH, 11.30, 'ft') outputs.set_val(Aircraft.VerticalTail.FINENESS, 0.1375) @@ -422,10 +406,3 @@ # Aircraft.Design.SYSTEMS_EQUIP_MASS_BASE, # Aircraft.Propulsion.MASS]: # inputs.set_val(key, outputs[key] - -# Create engine model -engine_inputs.set_val(Settings.VERBOSITY, 0) -engine = EngineDeck(name='engine', - options=engine_inputs - ) -preprocess_propulsion(inputs, [engine]) diff --git a/aviary/models/large_single_aisle_2/large_single_aisle_2_detailwing_FLOPS_data.py b/aviary/models/large_single_aisle_2/large_single_aisle_2_detailwing_FLOPS_data.py index f001b7b2d..2aca006c4 100644 --- a/aviary/models/large_single_aisle_2/large_single_aisle_2_detailwing_FLOPS_data.py +++ b/aviary/models/large_single_aisle_2/large_single_aisle_2_detailwing_FLOPS_data.py @@ -1,8 +1,6 @@ import numpy as np -from aviary.subsystems.propulsion.engine_deck import EngineDeck from aviary.utils.aviary_values import AviaryValues -from aviary.utils.preprocessors import preprocess_propulsion from aviary.utils.functions import get_path from aviary.variable_info.enums import EquationsOfMotion, LegacyCode from aviary.variable_info.variables import Aircraft, Mission, Settings @@ -149,46 +147,45 @@ filename = get_path( 'models/engines/turbofan_24k_1.deck') -engine_inputs = AviaryValues() -engine_inputs.set_val(Aircraft.Engine.DATA_FILE, filename) +inputs.set_val(Aircraft.Engine.DATA_FILE, filename) engine_mass = 8071.35 engine_mass_units = 'lbm' -engine_inputs.set_val(Aircraft.Engine.MASS, engine_mass, engine_mass_units) -engine_inputs.set_val( +inputs.set_val(Aircraft.Engine.MASS, engine_mass, engine_mass_units) +inputs.set_val( Aircraft.Engine.REFERENCE_MASS, engine_mass, engine_mass_units) scaled_sls_thrust = 27301.0 scaled_sls_thrust_units = 'lbf' -engine_inputs.set_val( +inputs.set_val( Aircraft.Engine.SCALED_SLS_THRUST, scaled_sls_thrust, scaled_sls_thrust_units) -engine_inputs.set_val( +inputs.set_val( Aircraft.Engine.REFERENCE_SLS_THRUST, scaled_sls_thrust, scaled_sls_thrust_units) num_engines = 2 -engine_inputs.set_val(Aircraft.Engine.NUM_ENGINES, num_engines) +inputs.set_val(Aircraft.Engine.NUM_ENGINES, num_engines) num_fuselage_engines = 0 -engine_inputs.set_val(Aircraft.Engine.NUM_FUSELAGE_ENGINES, num_fuselage_engines) +inputs.set_val(Aircraft.Engine.NUM_FUSELAGE_ENGINES, num_fuselage_engines) num_wing_engines = num_engines -engine_inputs.set_val(Aircraft.Engine.NUM_WING_ENGINES, num_wing_engines) -engine_inputs.set_val(Aircraft.Engine.WING_LOCATIONS, 0.28131) -engine_inputs.set_val(Aircraft.Engine.THRUST_REVERSERS_MASS_SCALER, 1.0) -engine_inputs.set_val(Aircraft.Engine.SCALE_MASS, True) -engine_inputs.set_val(Aircraft.Engine.MASS_SCALER, 1.15) -engine_inputs.set_val(Aircraft.Engine.SCALE_PERFORMANCE, True) -engine_inputs.set_val(Aircraft.Engine.SUBSONIC_FUEL_FLOW_SCALER, 1.0) -engine_inputs.set_val(Aircraft.Engine.SUPERSONIC_FUEL_FLOW_SCALER, 1.0) -engine_inputs.set_val( +inputs.set_val(Aircraft.Engine.NUM_WING_ENGINES, num_wing_engines) +inputs.set_val(Aircraft.Engine.WING_LOCATIONS, 0.28131) +inputs.set_val(Aircraft.Engine.THRUST_REVERSERS_MASS_SCALER, 1.0) +inputs.set_val(Aircraft.Engine.SCALE_MASS, True) +inputs.set_val(Aircraft.Engine.MASS_SCALER, 1.15) +inputs.set_val(Aircraft.Engine.SCALE_PERFORMANCE, True) +inputs.set_val(Aircraft.Engine.SUBSONIC_FUEL_FLOW_SCALER, 1.0) +inputs.set_val(Aircraft.Engine.SUPERSONIC_FUEL_FLOW_SCALER, 1.0) +inputs.set_val( Aircraft.Engine.FUEL_FLOW_SCALER_CONSTANT_TERM, 0.0) -engine_inputs.set_val(Aircraft.Engine.FUEL_FLOW_SCALER_LINEAR_TERM, 0.0) -engine_inputs.set_val(Aircraft.Engine.CONSTANT_FUEL_CONSUMPTION, 0.0, units='lbm/h') -engine_inputs.set_val(Aircraft.Engine.ADDITIONAL_MASS_FRACTION, 0.0) -engine_inputs.set_val(Aircraft.Engine.GENERATE_FLIGHT_IDLE, True) -engine_inputs.set_val(Aircraft.Engine.IGNORE_NEGATIVE_THRUST, False) -engine_inputs.set_val(Aircraft.Engine.FLIGHT_IDLE_THRUST_FRACTION, 0.0) -engine_inputs.set_val(Aircraft.Engine.FLIGHT_IDLE_MAX_FRACTION, 1.0) -engine_inputs.set_val(Aircraft.Engine.FLIGHT_IDLE_MIN_FRACTION, 0.08) -engine_inputs.set_val(Aircraft.Engine.GEOPOTENTIAL_ALT, False) -engine_inputs.set_val(Aircraft.Engine.INTERPOLATION_METHOD, 'slinear') +inputs.set_val(Aircraft.Engine.FUEL_FLOW_SCALER_LINEAR_TERM, 0.0) +inputs.set_val(Aircraft.Engine.CONSTANT_FUEL_CONSUMPTION, 0.0, units='lbm/h') +inputs.set_val(Aircraft.Engine.ADDITIONAL_MASS_FRACTION, 0.0) +inputs.set_val(Aircraft.Engine.GENERATE_FLIGHT_IDLE, True) +inputs.set_val(Aircraft.Engine.IGNORE_NEGATIVE_THRUST, False) +inputs.set_val(Aircraft.Engine.FLIGHT_IDLE_THRUST_FRACTION, 0.0) +inputs.set_val(Aircraft.Engine.FLIGHT_IDLE_MAX_FRACTION, 1.0) +inputs.set_val(Aircraft.Engine.FLIGHT_IDLE_MIN_FRACTION, 0.08) +inputs.set_val(Aircraft.Engine.GEOPOTENTIAL_ALT, False) +inputs.set_val(Aircraft.Engine.INTERPOLATION_METHOD, 'slinear') # Vertical Tail @@ -410,10 +407,3 @@ outputs.set_val(Mission.Design.MACH, 0.799) outputs.set_val(Mission.Design.LIFT_COEFFICIENT, 0.523) - -# Create engine model -engine_inputs.set_val(Settings.VERBOSITY, 0) -engine = EngineDeck(name='engine', - options=engine_inputs - ) -preprocess_propulsion(inputs, [engine]) diff --git a/aviary/models/multi_engine_single_aisle/multi_engine_single_aisle_data.py b/aviary/models/multi_engine_single_aisle/multi_engine_single_aisle_data.py index fa1821612..d45060497 100644 --- a/aviary/models/multi_engine_single_aisle/multi_engine_single_aisle_data.py +++ b/aviary/models/multi_engine_single_aisle/multi_engine_single_aisle_data.py @@ -1,8 +1,6 @@ import numpy as np -from aviary.subsystems.propulsion.engine_deck import EngineDeck from aviary.utils.aviary_values import AviaryValues -from aviary.utils.preprocessors import preprocess_propulsion from aviary.utils.functions import get_path from aviary.variable_info.enums import EquationsOfMotion, LegacyCode, Verbosity from aviary.variable_info.variables import Aircraft, Mission, Settings @@ -419,15 +417,3 @@ outputs.set_val(Mission.Design.MACH, 0.800) outputs.set_val(Mission.Design.LIFT_COEFFICIENT, 0.568) - -# Create engine model -engine_1_inputs.set_val(Settings.VERBOSITY, 0) -engine1 = EngineDeck(name='engine_1', - options=engine_1_inputs - ) -# Create engine model -engine_2_inputs.set_val(Settings.VERBOSITY, 0) -engine2 = EngineDeck(name='engine_2', - options=engine_2_inputs - ) -preprocess_propulsion(inputs, [engine1, engine2]) diff --git a/aviary/subsystems/aerodynamics/flops_based/test/test_computed_aero_group.py b/aviary/subsystems/aerodynamics/flops_based/test/test_computed_aero_group.py index d74ca7f62..0ca6a40b3 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/test_computed_aero_group.py +++ b/aviary/subsystems/aerodynamics/flops_based/test/test_computed_aero_group.py @@ -5,12 +5,14 @@ from openmdao.utils.assert_utils import assert_near_equal from aviary.subsystems.premission import CorePreMission -from aviary.interface.default_phase_info.height_energy import aero, prop, geom from aviary.utils.aviary_values import get_items from aviary.utils.functions import set_aviary_initial_values from aviary.validation_cases.validation_tests import get_flops_inputs, get_flops_outputs from aviary.variable_info.variables import Aircraft, Dynamic, Settings from aviary.variable_info.variables_in import VariablesIn +from aviary.subsystems.propulsion.utils import build_engine_deck +from aviary.utils.test_utils.default_subsystems import get_default_premission_subsystems +from aviary.utils.preprocessors import preprocess_options class MissionDragTest(unittest.TestCase): @@ -29,6 +31,15 @@ def test_basic_large_single_aisle_1(self): flops_inputs.set_val(key, *(flops_outputs.get_item(key))) flops_inputs.set_val(Settings.VERBOSITY, 0) + engine = build_engine_deck(flops_inputs) + preprocess_options(flops_inputs, engine_models=engine) + + # don't need mass subsystem, so we skip it + default_premission_subsystems = get_default_premission_subsystems( + 'FLOPS', engine)[:-1] + # we just want aero for mission, make a copy by itself + aero = default_premission_subsystems[-1] + # Design conditions: alt = 41000 # mach = 0.79 @@ -56,13 +67,11 @@ def test_basic_large_single_aisle_1(self): prob = om.Problem() model = prob.model - core_subsystems = [prop, geom, aero] - # Upstream static analysis for aero prob.model.add_subsystem( 'pre_mission', CorePreMission(aviary_options=flops_inputs, - subsystems=core_subsystems), + subsystems=default_premission_subsystems), promotes_inputs=['aircraft:*', 'mission:*'], promotes_outputs=['aircraft:*', 'mission:*']) @@ -162,6 +171,15 @@ def test_n3cc_drag(self): flops_inputs.set_val(key, *(flops_outputs.get_item(key))) flops_inputs.set_val(Settings.VERBOSITY, 0) + engine = build_engine_deck(flops_inputs) + preprocess_options(flops_inputs, engine_models=engine) + + # don't need mass subsystem, so we skip it + default_premission_subsystems = get_default_premission_subsystems( + 'FLOPS', engine)[:-1] + # we just want aero for mission, make a copy by itself + aero = default_premission_subsystems[-1] + alt = 43000 Sref = 1220.0 @@ -185,13 +203,11 @@ def test_n3cc_drag(self): prob = om.Problem() model = prob.model - core_subsystems = [prop, geom, aero] - # Upstream static analysis for aero prob.model.add_subsystem( 'pre_mission', CorePreMission(aviary_options=flops_inputs, - subsystems=core_subsystems), + subsystems=default_premission_subsystems), promotes_inputs=['aircraft:*', 'mission:*'], promotes_outputs=['aircraft:*', 'mission:*']) @@ -277,6 +293,15 @@ def test_large_single_aisle_2_drag(self): flops_inputs.set_val(key, *(flops_outputs.get_item(key))) flops_inputs.set_val(Settings.VERBOSITY, 0) + engine = build_engine_deck(flops_inputs) + preprocess_options(flops_inputs, engine_models=engine) + + # don't need mass subsystem, so we skip it + default_premission_subsystems = get_default_premission_subsystems( + 'FLOPS', engine)[:-1] + # we just want aero for mission, make a copy by itself + aero = default_premission_subsystems[-1] + alt = 41000 Sref = 1341.0 @@ -302,13 +327,11 @@ def test_large_single_aisle_2_drag(self): prob = om.Problem() model = prob.model - core_subsystems = [prop, geom, aero] - # Upstream static analysis for aero prob.model.add_subsystem( 'pre_mission', CorePreMission(aviary_options=flops_inputs, - subsystems=core_subsystems), + subsystems=default_premission_subsystems), promotes_inputs=['aircraft:*', 'mission:*'], promotes_outputs=['aircraft:*', 'mission:*']) diff --git a/aviary/subsystems/aerodynamics/flops_based/test/test_tabular_aero_group.py b/aviary/subsystems/aerodynamics/flops_based/test/test_tabular_aero_group.py index ff631d241..d661f93da 100644 --- a/aviary/subsystems/aerodynamics/flops_based/test/test_tabular_aero_group.py +++ b/aviary/subsystems/aerodynamics/flops_based/test/test_tabular_aero_group.py @@ -8,7 +8,8 @@ from aviary.subsystems.aerodynamics.aerodynamics_builder import CoreAerodynamicsBuilder from aviary.subsystems.premission import CorePreMission -from aviary.interface.default_phase_info.height_energy import aero, prop, geom +from aviary.utils.test_utils.default_subsystems import get_default_premission_subsystems +from aviary.subsystems.propulsion.utils import build_engine_deck from aviary.utils.aviary_values import AviaryValues, get_items from aviary.utils.functions import set_aviary_initial_values from aviary.utils.named_values import NamedValues @@ -164,7 +165,7 @@ class ComputedVsTabularTest(unittest.TestCase): @parameterized.expand(data_sets, name_func=print_case) def test_case(self, case_name): - flops_inputs = get_flops_inputs(case_name) + flops_inputs = get_flops_inputs(case_name, preprocess=True) flops_outputs = get_flops_outputs(case_name) flops_inputs.set_val(Aircraft.Design.LIFT_DEPENDENT_DRAG_COEFF_FACTOR, 0.9) @@ -588,13 +589,16 @@ def setup(self): gamma = options['gamma'] aviary_options: AviaryValues = options['aviary_options'] - core_subsystems = [prop, geom, aero] + engine = build_engine_deck(aviary_options) + # don't need mass, skip it + default_premission_subsystems = get_default_premission_subsystems('FLOPS', engine)[ + :-1] # Upstream static analysis for aero pre_mission: om.Group = self.add_subsystem( 'pre_mission', CorePreMission(aviary_options=aviary_options, - subsystems=core_subsystems), + subsystems=default_premission_subsystems), promotes_inputs=['aircraft:*', 'mission:*'], promotes_outputs=['aircraft:*', 'mission:*']) diff --git a/aviary/subsystems/geometry/flops_based/test/test_prep_geom.py b/aviary/subsystems/geometry/flops_based/test/test_prep_geom.py index bca5ef42f..c20ae0433 100644 --- a/aviary/subsystems/geometry/flops_based/test/test_prep_geom.py +++ b/aviary/subsystems/geometry/flops_based/test/test_prep_geom.py @@ -26,6 +26,8 @@ print_case) from aviary.variable_info.functions import override_aviary_vars from aviary.variable_info.variables import Aircraft +from aviary.subsystems.propulsion.utils import build_engine_deck +from aviary.utils.preprocessors import preprocess_options unit_data_sets = get_flops_case_names( only=['LargeSingleAisle2FLOPS', 'LargeSingleAisle2FLOPSdw', 'LargeSingleAisle2FLOPSalt', 'LargeSingleAisle1FLOPS']) @@ -61,7 +63,7 @@ def configure(self): override_aviary_vars(self, aviary_options) - options = get_flops_data(case_name, + options = get_flops_data(case_name, preprocess=True, keys=[ Aircraft.Fuselage.NUM_FUSELAGES, Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES, @@ -300,7 +302,7 @@ def test_case(self, case_name): prob.model.add_subsystem( 'tails', - _Tail(aviary_options=get_flops_inputs(case_name, + _Tail(aviary_options=get_flops_inputs(case_name, preprocess=True, keys=[Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION, Aircraft.Propulsion.TOTAL_NUM_FUSELAGE_ENGINES])), promotes=['*']) @@ -396,10 +398,14 @@ def test_case(self, case_name): prob = self.prob + flops_inputs = get_flops_inputs(case_name, preprocess=True, + keys=[Aircraft.Engine.NUM_ENGINES, + Aircraft.Fuselage.NUM_FUSELAGES, + ]) + prob.model.add_subsystem( 'nacelles', - Nacelles(aviary_options=get_flops_inputs(case_name, - keys=[Aircraft.Engine.NUM_ENGINES])), + Nacelles(aviary_options=flops_inputs), promotes=['*']) prob.setup(check=False, force_alloc_complex=True) @@ -462,14 +468,16 @@ def test_case(self, case_name): prob = self.prob + flops_inputs = get_flops_inputs(case_name, preprocess=True, + keys=[Aircraft.Engine.NUM_ENGINES, + Aircraft.Fuselage.NUM_FUSELAGES, + Aircraft.VerticalTail.NUM_TAILS, + Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION, + ]) + prob.model.add_subsystem( 'characteristic_lengths', - CharacteristicLengths(aviary_options=get_flops_inputs(case_name, - keys=[Aircraft.Engine.NUM_ENGINES, - Aircraft.Fuselage.NUM_FUSELAGES, - Aircraft.VerticalTail.NUM_TAILS, - Aircraft.Wing.SPAN_EFFICIENCY_REDUCTION, - "engine_models"])), + CharacteristicLengths(aviary_options=flops_inputs), promotes=['*'] ) diff --git a/aviary/subsystems/mass/flops_based/landing_gear.py b/aviary/subsystems/mass/flops_based/landing_gear.py index 56c9e4879..a69319eb9 100644 --- a/aviary/subsystems/mass/flops_based/landing_gear.py +++ b/aviary/subsystems/mass/flops_based/landing_gear.py @@ -278,15 +278,16 @@ def initialize(self): desc='collection of Aircraft/Mission specific options') def setup(self): - count = len(self.options['aviary_options'].get_val('engine_models')) + engine_count = len(self.options['aviary_options'].get_val( + Aircraft.Engine.NUM_ENGINES)) num_wing_engines = self.options['aviary_options'].get_val( Aircraft.Engine.NUM_WING_ENGINES) add_aviary_input(self, Aircraft.Fuselage.LENGTH, val=0.0) add_aviary_input(self, Aircraft.Fuselage.MAX_WIDTH, val=0.0) - add_aviary_input(self, Aircraft.Nacelle.AVG_DIAMETER, val=np.zeros(count)) + add_aviary_input(self, Aircraft.Nacelle.AVG_DIAMETER, val=np.zeros(engine_count)) add_aviary_input(self, Aircraft.Engine.WING_LOCATIONS, - val=np.zeros((count, int(num_wing_engines[0]/2)))) + val=np.zeros((engine_count, int(num_wing_engines[0]/2)))) add_aviary_input(self, Aircraft.Wing.DIHEDRAL, val=0.0) add_aviary_input(self, Aircraft.Wing.SPAN, val=0.0) diff --git a/aviary/subsystems/mass/flops_based/starter.py b/aviary/subsystems/mass/flops_based/starter.py index 293ad5b5a..e7b06a4d9 100644 --- a/aviary/subsystems/mass/flops_based/starter.py +++ b/aviary/subsystems/mass/flops_based/starter.py @@ -22,7 +22,8 @@ def initialize(self): desc='collection of Aircraft/Mission specific options') def setup(self): - num_engine_type = len(self.options['aviary_options'].get_val('engine_models')) + num_engine_type = len(self.options['aviary_options'].get_val( + Aircraft.Engine.NUM_ENGINES)) add_aviary_input(self, Aircraft.Nacelle.AVG_DIAMETER, val=np.zeros(num_engine_type)) diff --git a/aviary/subsystems/mass/flops_based/test/test_anti_icing.py b/aviary/subsystems/mass/flops_based/test/test_anti_icing.py index 43a33a0d6..8f37f3985 100644 --- a/aviary/subsystems/mass/flops_based/test/test_anti_icing.py +++ b/aviary/subsystems/mass/flops_based/test/test_anti_icing.py @@ -28,7 +28,7 @@ def test_case(self, case_name): prob.model.add_subsystem( "anti_icing", - AntiIcingMass(aviary_options=get_flops_inputs(case_name)), + AntiIcingMass(aviary_options=get_flops_inputs(case_name, preprocess=True)), promotes_inputs=['*'], promotes_outputs=['*'], ) diff --git a/aviary/subsystems/mass/flops_based/test/test_engine.py b/aviary/subsystems/mass/flops_based/test/test_engine.py index 6675a1176..74cf0bdf2 100644 --- a/aviary/subsystems/mass/flops_based/test/test_engine.py +++ b/aviary/subsystems/mass/flops_based/test/test_engine.py @@ -31,7 +31,7 @@ def test_case(self, case_name): prob.model.add_subsystem( "engine_mass", - EngineMass(aviary_options=get_flops_inputs(case_name)), + EngineMass(aviary_options=get_flops_inputs(case_name, preprocess=True)), promotes_inputs=['*'], promotes_outputs=['*'], ) diff --git a/aviary/subsystems/mass/flops_based/test/test_engine_controls.py b/aviary/subsystems/mass/flops_based/test/test_engine_controls.py index 45822248c..cc863cdc1 100644 --- a/aviary/subsystems/mass/flops_based/test/test_engine_controls.py +++ b/aviary/subsystems/mass/flops_based/test/test_engine_controls.py @@ -24,7 +24,7 @@ def setUp(self): @parameterized.expand(get_flops_case_names(omit='N3CC'), name_func=print_case) def test_case(self, case_name): - flops_inputs = get_flops_inputs(case_name) + flops_inputs = get_flops_inputs(case_name, preprocess=True) prob = self.prob diff --git a/aviary/subsystems/mass/flops_based/test/test_engine_oil.py b/aviary/subsystems/mass/flops_based/test/test_engine_oil.py index 1f46699dc..c75c44c43 100644 --- a/aviary/subsystems/mass/flops_based/test/test_engine_oil.py +++ b/aviary/subsystems/mass/flops_based/test/test_engine_oil.py @@ -28,9 +28,12 @@ def test_case(self, case_name): prob = self.prob + options = get_flops_inputs(case_name) + options.set_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES, 2) + prob.model.add_subsystem( 'engine_oil', - TransportEngineOilMass(aviary_options=get_flops_inputs(case_name)), + TransportEngineOilMass(aviary_options=options), promotes_outputs=['*'], promotes_inputs=['*'] ) @@ -64,9 +67,12 @@ def test_case(self, case_name): prob = self.prob + options = get_flops_inputs(case_name) + options.set_val(Aircraft.Propulsion.TOTAL_NUM_ENGINES, 2) + prob.model.add_subsystem( 'engine_oil', - AltEngineOilMass(aviary_options=get_flops_inputs(case_name)), + AltEngineOilMass(aviary_options=options), promotes_outputs=['*'], promotes_inputs=['*'] ) @@ -76,7 +82,7 @@ def test_case(self, case_name): flops_validation_test( prob, case_name, - input_keys=[Aircraft.Propulsion.ENGINE_OIL_MASS_SCALER], + input_keys=[Aircraft.Propulsion.ENGINE_OIL_MASS_SCALER,], output_keys=[Aircraft.Propulsion.TOTAL_ENGINE_OIL_MASS], version=Version.ALTERNATE) diff --git a/aviary/subsystems/mass/flops_based/test/test_engine_pod.py b/aviary/subsystems/mass/flops_based/test/test_engine_pod.py index 840dea329..7882b7178 100644 --- a/aviary/subsystems/mass/flops_based/test/test_engine_pod.py +++ b/aviary/subsystems/mass/flops_based/test/test_engine_pod.py @@ -32,7 +32,7 @@ def test_case(self, case_name): prob.model.add_subsystem( 'engine_pod', - EnginePodMass(aviary_options=get_flops_inputs(case_name)), + EnginePodMass(aviary_options=get_flops_inputs(case_name, preprocess=True)), promotes_outputs=['*'], promotes_inputs=['*'] ) diff --git a/aviary/subsystems/mass/flops_based/test/test_fuel_system.py b/aviary/subsystems/mass/flops_based/test/test_fuel_system.py index 3016a7dbc..ef492ab6d 100644 --- a/aviary/subsystems/mass/flops_based/test/test_fuel_system.py +++ b/aviary/subsystems/mass/flops_based/test/test_fuel_system.py @@ -27,7 +27,8 @@ def test_case(self, case_name): prob.model.add_subsystem( "alt_fuel_sys_test", - AltFuelSystemMass(aviary_options=get_flops_inputs(case_name)), + AltFuelSystemMass(aviary_options=get_flops_inputs( + case_name, preprocess=True)), promotes_outputs=['*'], promotes_inputs=['*'] ) @@ -59,7 +60,8 @@ def test_case(self, case_name): prob.model.add_subsystem( "transport_fuel_sys_test", - TransportFuelSystemMass(aviary_options=get_flops_inputs(case_name)), + TransportFuelSystemMass( + aviary_options=get_flops_inputs(case_name, preprocess=True)), promotes_outputs=['*'], promotes_inputs=['*'] ) diff --git a/aviary/subsystems/mass/flops_based/test/test_fuselage.py b/aviary/subsystems/mass/flops_based/test/test_fuselage.py index fb3d6652a..7b965fd46 100644 --- a/aviary/subsystems/mass/flops_based/test/test_fuselage.py +++ b/aviary/subsystems/mass/flops_based/test/test_fuselage.py @@ -27,7 +27,8 @@ def test_case(self, case_name): prob.model.add_subsystem( "fuselage", - TransportFuselageMass(aviary_options=get_flops_inputs(case_name)), + TransportFuselageMass(aviary_options=get_flops_inputs( + case_name, preprocess=True)), promotes_inputs=['*'], promotes_outputs=['*'], ) diff --git a/aviary/subsystems/mass/flops_based/test/test_hydraulics.py b/aviary/subsystems/mass/flops_based/test/test_hydraulics.py index 783bd7b03..506cf87f8 100644 --- a/aviary/subsystems/mass/flops_based/test/test_hydraulics.py +++ b/aviary/subsystems/mass/flops_based/test/test_hydraulics.py @@ -42,7 +42,8 @@ def test_case(self, case_name): prob.model.add_subsystem( 'hydraulics', - TransportHydraulicsGroupMass(aviary_options=get_flops_inputs(case_name)), + TransportHydraulicsGroupMass( + aviary_options=get_flops_inputs(case_name, preprocess=True)), promotes_outputs=['*'], promotes_inputs=['*'] ) @@ -81,7 +82,8 @@ def test_case(self, case_name): prob.model.add_subsystem( 'hydraulics', - AltHydraulicsGroupMass(aviary_options=get_flops_inputs(case_name)), + AltHydraulicsGroupMass( + aviary_options=get_flops_inputs(case_name, preprocess=True)), promotes_outputs=['*'], promotes_inputs=['*'] ) diff --git a/aviary/subsystems/mass/flops_based/test/test_mass_summation.py b/aviary/subsystems/mass/flops_based/test/test_mass_summation.py index a09142881..ef5ebe344 100644 --- a/aviary/subsystems/mass/flops_based/test/test_mass_summation.py +++ b/aviary/subsystems/mass/flops_based/test/test_mass_summation.py @@ -30,7 +30,7 @@ def test_case(self, case_name): prob.model.add_subsystem( "tot", - MassSummation(aviary_options=get_flops_inputs(case_name)), + MassSummation(aviary_options=get_flops_inputs(case_name, preprocess=True)), promotes_inputs=['*'], promotes_outputs=['*'], ) @@ -101,7 +101,7 @@ def test_case(self, case_name): prob.model.add_subsystem( "tot", - MassSummation(aviary_options=get_flops_inputs(case_name)), + MassSummation(aviary_options=get_flops_inputs(case_name, preprocess=True)), promotes_inputs=['*'], promotes_outputs=['*'], ) diff --git a/aviary/subsystems/mass/flops_based/test/test_misc_engine.py b/aviary/subsystems/mass/flops_based/test/test_misc_engine.py index a0beeea3d..dc90b0b99 100644 --- a/aviary/subsystems/mass/flops_based/test/test_misc_engine.py +++ b/aviary/subsystems/mass/flops_based/test/test_misc_engine.py @@ -30,7 +30,7 @@ def test_case(self, case_name): prob.model.add_subsystem( "misc_mass", - EngineMiscMass(aviary_options=get_flops_inputs(case_name)), + EngineMiscMass(aviary_options=get_flops_inputs(case_name, preprocess=True)), promotes_inputs=['*'], promotes_outputs=['*'] ) diff --git a/aviary/subsystems/mass/flops_based/test/test_nacelle.py b/aviary/subsystems/mass/flops_based/test/test_nacelle.py index abaa948f9..4c101016f 100644 --- a/aviary/subsystems/mass/flops_based/test/test_nacelle.py +++ b/aviary/subsystems/mass/flops_based/test/test_nacelle.py @@ -30,7 +30,7 @@ def test_case(self, case_name): prob.model.add_subsystem( "nacelle", - NacelleMass(aviary_options=get_flops_inputs(case_name)), + NacelleMass(aviary_options=get_flops_inputs(case_name, preprocess=True)), promotes_inputs=['*'], promotes_outputs=['*'], ) diff --git a/aviary/subsystems/mass/flops_based/test/test_starter.py b/aviary/subsystems/mass/flops_based/test/test_starter.py index 2a9f5ad8c..e069767ed 100644 --- a/aviary/subsystems/mass/flops_based/test/test_starter.py +++ b/aviary/subsystems/mass/flops_based/test/test_starter.py @@ -27,7 +27,8 @@ def test_case_1(self, case_name): prob.model.add_subsystem( "starter_test", - TransportStarterMass(aviary_options=get_flops_inputs(case_name)), + TransportStarterMass(aviary_options=get_flops_inputs( + case_name, preprocess=True)), promotes_outputs=['*'], promotes_inputs=['*'] ) diff --git a/aviary/subsystems/mass/flops_based/test/test_thrust_reverser.py b/aviary/subsystems/mass/flops_based/test/test_thrust_reverser.py index a55e6f62f..02e9e290b 100644 --- a/aviary/subsystems/mass/flops_based/test/test_thrust_reverser.py +++ b/aviary/subsystems/mass/flops_based/test/test_thrust_reverser.py @@ -30,7 +30,8 @@ def test_case(self, case_name): prob.model.add_subsystem( "thrust_rev", - ThrustReverserMass(aviary_options=get_flops_inputs(case_name)), + ThrustReverserMass(aviary_options=get_flops_inputs( + case_name, preprocess=True)), promotes=['*'] ) diff --git a/aviary/subsystems/mass/flops_based/test/test_unusable_fuel.py b/aviary/subsystems/mass/flops_based/test/test_unusable_fuel.py index a9bfeee81..ba947524c 100644 --- a/aviary/subsystems/mass/flops_based/test/test_unusable_fuel.py +++ b/aviary/subsystems/mass/flops_based/test/test_unusable_fuel.py @@ -37,7 +37,7 @@ def setUp(self): def test_case(self, case_name): prob = self.prob - flops_inputs = get_flops_inputs(case_name) + flops_inputs = get_flops_inputs(case_name, preprocess=True) prob.model.add_subsystem( 'unusable_fuel', diff --git a/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py b/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py index d3386e4e6..9ee3c9832 100644 --- a/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py +++ b/aviary/subsystems/mass/flops_based/test/test_wing_detailed.py @@ -33,7 +33,8 @@ def test_case(self, case_name): self.prob.model.add_subsystem( "wing", - DetailedWingBendingFact(aviary_options=get_flops_inputs(case_name)), + DetailedWingBendingFact( + aviary_options=get_flops_inputs(case_name, preprocess=True)), promotes_inputs=['*'], promotes_outputs=['*'], ) @@ -128,8 +129,8 @@ def test_IO(self): if __name__ == "__main__": - unittest.main() - # test = DetailedWingBendingTest() - # test.setUp() + # unittest.main() + test = DetailedWingBendingTest() + test.setUp() # test.test_case(case_name='LargeSingleAisle1FLOPS') - # test.test_case_multiengine() + test.test_case_multiengine() diff --git a/aviary/subsystems/mass/flops_based/test/test_wing_simple.py b/aviary/subsystems/mass/flops_based/test/test_wing_simple.py index 6e3321ac7..da5d4148b 100644 --- a/aviary/subsystems/mass/flops_based/test/test_wing_simple.py +++ b/aviary/subsystems/mass/flops_based/test/test_wing_simple.py @@ -25,7 +25,8 @@ def test_case(self, case_name): prob.model.add_subsystem( "wing", - SimpleWingBendingFact(aviary_options=get_flops_inputs(case_name)), + SimpleWingBendingFact(aviary_options=get_flops_inputs( + case_name, preprocess=True)), promotes_inputs=['*'], promotes_outputs=['*'], ) diff --git a/aviary/subsystems/mass/gasp_based/equipment_and_useful_load.py b/aviary/subsystems/mass/gasp_based/equipment_and_useful_load.py index 9868497e6..642bafc27 100644 --- a/aviary/subsystems/mass/gasp_based/equipment_and_useful_load.py +++ b/aviary/subsystems/mass/gasp_based/equipment_and_useful_load.py @@ -25,7 +25,8 @@ def initialize(self): ) def setup(self): - num_engine_type = len(self.options['aviary_options'].get_val('engine_models')) + num_engine_type = len(self.options['aviary_options'].get_val( + Aircraft.Engine.NUM_ENGINES)) add_aviary_input( self, Aircraft.AirConditioning.MASS_COEFFICIENT, val=1, units="unitless") diff --git a/aviary/subsystems/mass/gasp_based/test/test_mass_summation.py b/aviary/subsystems/mass/gasp_based/test/test_mass_summation.py index ba03d22a5..5ddc566f0 100644 --- a/aviary/subsystems/mass/gasp_based/test/test_mass_summation.py +++ b/aviary/subsystems/mass/gasp_based/test/test_mass_summation.py @@ -42,9 +42,8 @@ def setUp(self): ) for (key, (val, units)) in get_items(V3_bug_fixed_options): - if key != 'engine_models': - if not is_option(key): - self.prob.model.set_input_defaults(key, val=val, units=units) + if not is_option(key): + self.prob.model.set_input_defaults(key, val=val, units=units) for (key, (val, units)) in get_items(V3_bug_fixed_non_metadata): self.prob.model.set_input_defaults(key, val=val, units=units) diff --git a/aviary/subsystems/propulsion/engine_deck.py b/aviary/subsystems/propulsion/engine_deck.py index fe8cdddee..9937662d4 100644 --- a/aviary/subsystems/propulsion/engine_deck.py +++ b/aviary/subsystems/propulsion/engine_deck.py @@ -27,7 +27,6 @@ import numpy as np import openmdao.api as om -from openmdao.core.system import System from openmdao.utils.units import convert_units @@ -40,7 +39,6 @@ from aviary.utils.aviary_values import AviaryValues, NamedValues, get_keys, get_items from aviary.variable_info.variable_meta_data import _MetaData from aviary.variable_info.variables import Aircraft, Dynamic, Mission, Settings -from aviary.variable_info.enums import Verbosity from aviary.utils.csv_data_file import read_data_file from aviary.interface.utils.markdown_utils import round_it @@ -1010,25 +1008,18 @@ def build_mission(self, num_nodes, aviary_inputs) -> om.Group: return engine_group + def get_parameters(self): + params = {Aircraft.Engine.SCALE_FACTOR: {'static_target': True}} + return params + def report(self, problem, reports_file, **kwargs): meta_data = kwargs['meta_data'] + engine_idx = kwargs['engine_idx'] outputs = [Aircraft.Engine.NUM_ENGINES, Aircraft.Engine.SCALED_SLS_THRUST, Aircraft.Engine.SCALE_FACTOR] - # determine which index in problem-level aviary values corresponds to this engine - engine_idx = None - for idx, engine in enumerate(problem.aviary_inputs.get_val('engine_models')): - if engine.name == self.name: - engine_idx = idx - - if engine_idx is None: - with open(reports_file, mode='a') as f: - f.write(f'\n### {self.name}') - f.write(f'\nEngine deck {self.name} not found\n') - return - # modified version of markdown table util adjusted to handle engine decks with open(reports_file, mode='a') as f: f.write(f'\n### {self.name}') @@ -1145,8 +1136,8 @@ def _set_reference_thrust(self): # both scale factor and target thrust provided: if thrust_provided: scaled_thrust = self.get_val(Aircraft.Engine.SCALED_SLS_THRUST, 'lbf') - if scale_performance: - if not math.isclose(scaled_thrust/ref_thrust, scale_factor): + if scale_performance: # using very rough tolerance + if not math.isclose(scaled_thrust/ref_thrust, scale_factor, abs_tol=1e-2): # user wants scaling but provided conflicting inputs, # cannot be resolved raise AttributeError( @@ -1154,6 +1145,11 @@ def _set_reference_thrust(self): 'aircraft:engine:scale_factor and ' 'aircraft:engine:scaled_sls_thrust' ) + # get thrust target & scale factor matching exactly. Scale factor is + # design variable, so don't touch it!! Instead change output thrust + else: + self.set_val(Aircraft.Engine.SCALED_SLS_THRUST, + ref_thrust*scale_factor, 'lbf') else: # engine is not scaled: just make sure scaled thrust = ref thrust self.set_val( diff --git a/aviary/subsystems/propulsion/engine_model.py b/aviary/subsystems/propulsion/engine_model.py index e6279c4b9..f0dc330b5 100644 --- a/aviary/subsystems/propulsion/engine_model.py +++ b/aviary/subsystems/propulsion/engine_model.py @@ -11,7 +11,7 @@ from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase from aviary.utils.aviary_values import AviaryValues -from aviary.variable_info.variables import Aircraft, Dynamic, Mission, Settings +from aviary.variable_info.variables import Settings from aviary.variable_info.enums import Verbosity @@ -43,7 +43,10 @@ def __init__( self, name: str = None, options: AviaryValues = None, meta_data: dict = None, ): super().__init__(name, meta_data=meta_data) - self.options = options.deepcopy() + if options is not None: + self.options = options.deepcopy() + else: + self.options = AviaryValues() # Hybrid throttle is currently the only optional independent variable, requiring # this flag so Aviary knows how to handle EngineModels during mission @@ -171,7 +174,7 @@ def _preprocess_inputs(self): # "Convert" numpy types to standard Python types. Wrap first # index in numpy array before calling item() to safeguard against # non-standard types, such as objects - val = val[0].item() + val = np.array(val[0]).item() else: val = val[0] # update options with single value (instead of vector) diff --git a/aviary/subsystems/propulsion/engine_scaling.py b/aviary/subsystems/propulsion/engine_scaling.py index 1f39da284..7c3cf72dd 100644 --- a/aviary/subsystems/propulsion/engine_scaling.py +++ b/aviary/subsystems/propulsion/engine_scaling.py @@ -111,7 +111,6 @@ def compute(self, inputs, outputs): scale_factor = 1 fuel_flow_scale_factor = np.ones(nn, dtype=engine_scale_factor.dtype) - # scale_idx = np.where(scale_performance) # if len(scale_idx[0]) > 0: if scale_performance: @@ -129,19 +128,11 @@ def compute(self, inputs, outputs): supersonic_idx = np.where(mach_number >= 1.0) fuel_flow_mach_scaling[supersonic_idx] = supersonic_fuel_factor - # fuel_flow_scale_factor[:, scale_idx[0]] = engine_scale_factor[scale_idx]\ - # * fuel_flow_mach_scaling[:, scale_idx[0]]\ - # * fuel_flow_equation_scaling[scale_idx]\ - # * mission_fuel_scaler fuel_flow_scale_factor = engine_scale_factor * fuel_flow_mach_scaling\ * fuel_flow_equation_scaling * mission_fuel_scaler scale_factor = engine_scale_factor - # scale factor only applies if engine performance is scaled - default to 1 otherwise - # scale_factor = np.ones(count, dtype=engine_scale_factor.dtype) - # scale_factor[scale_idx] = engine_scale_factor[scale_idx] - outputs[Dynamic.Mission.THRUST] = unscaled_net_thrust * scale_factor outputs[Dynamic.Mission.THRUST_MAX] = unscaled_max_thrust * scale_factor # user-specified constant_fuel_flow value is currently not scaled with engine @@ -157,12 +148,8 @@ def compute(self, inputs, outputs): def setup_partials(self): nn = self.options['num_nodes'] - # options = self.options['aviary_options'] - # count = len(options.get_val('engine_models')) # number of unique engine models # matrix derivatives have known sparsity pattern - specified here - # r = np.arange(nn * count, dtype=int) - # c = np.tile(np.arange(count, dtype=int), (nn)) r = np.arange(nn) c = np.tile(0, nn) @@ -257,7 +244,6 @@ def setup_partials(self): def compute_partials(self, inputs, J): nn = self.options['num_nodes'] options: AviaryValues = self.options['aviary_options'] - # count = len(options.get_val('engine_models')) # number of unique engine models scale_performance = options.get_val(Aircraft.Engine.SCALE_PERFORMANCE) subsonic_fuel_factor = options.get_val(Aircraft.Engine.SUBSONIC_FUEL_FLOW_SCALER) diff --git a/aviary/subsystems/propulsion/engine_sizing.py b/aviary/subsystems/propulsion/engine_sizing.py index 727bb4b98..32ccff84e 100644 --- a/aviary/subsystems/propulsion/engine_sizing.py +++ b/aviary/subsystems/propulsion/engine_sizing.py @@ -36,7 +36,6 @@ def setup(self): def compute(self, inputs, outputs): options: AviaryValues = self.options['aviary_options'] - # engine_models = options.get_val('engine_models') scale_engine = options.get_val(Aircraft.Engine.SCALE_PERFORMANCE) reference_sls_thrust = options.get_val(Aircraft.Engine.REFERENCE_SLS_THRUST, @@ -44,17 +43,8 @@ def compute(self, inputs, outputs): scaled_sls_thrust = inputs[Aircraft.Engine.SCALED_SLS_THRUST] - # set a default scaling factor of 1 for each engine - # nm = len(engine_models) - - # use dtype to make complex safe - # engine_scale_factor = np.ones(nm, dtype=scaled_sls_thrust.dtype) - # Engine is only scaled if required # engine scale factor is ratio of scaled thrust target and reference thrust - # scale_idx = np.where(scale_engine) - # engine_scale_factor[scale_idx] = scaled_sls_thrust[scale_idx] / \ - # reference_sls_thrust[scale_idx] engine_scale_factor = 1 if scale_engine: engine_scale_factor = scaled_sls_thrust / reference_sls_thrust @@ -62,30 +52,15 @@ def compute(self, inputs, outputs): outputs[Aircraft.Engine.SCALE_FACTOR] = engine_scale_factor def setup_partials(self): - # count = len(self.options['aviary_options'].get_val('engine_models')) - - # shape = np.arange(count, dtype=int) - self.declare_partials(Aircraft.Engine.SCALE_FACTOR, Aircraft.Engine.SCALED_SLS_THRUST) - # rows=shape, cols=shape) def compute_partials(self, inputs, J): options: AviaryValues = self.options['aviary_options'] - # engine_models = options.get_val('engine_models') scale_engine = options.get_val(Aircraft.Engine.SCALE_PERFORMANCE) reference_sls_thrust = options.get_val( Aircraft.Engine.REFERENCE_SLS_THRUST, units='lbf') - # nm = len(engine_models) - - # scaled_sls_thrust = inputs[Aircraft.Engine.SCALED_SLS_THRUST] - # use dtype to make complex safe - # deriv_scale_factor = np.zeros(nm, dtype=scaled_sls_thrust.dtype) - - # scale_idx = np.where(scale_engine) - # deriv_scale_factor[scale_idx] = 1.0 / reference_sls_thrust[scale_idx] - deriv_scale_factor = 0 if scale_engine: deriv_scale_factor = 1.0 / reference_sls_thrust diff --git a/aviary/subsystems/propulsion/propulsion_builder.py b/aviary/subsystems/propulsion/propulsion_builder.py index c64cde77f..e6647726e 100644 --- a/aviary/subsystems/propulsion/propulsion_builder.py +++ b/aviary/subsystems/propulsion/propulsion_builder.py @@ -11,20 +11,25 @@ import numpy as np from aviary.interface.utils.markdown_utils import write_markdown_variable_table + from aviary.subsystems.subsystem_builder_base import SubsystemBuilderBase from aviary.subsystems.propulsion.propulsion_premission import PropulsionPreMission from aviary.subsystems.propulsion.propulsion_mission import PropulsionMission +from aviary.subsystems.propulsion.engine_model import EngineModel + from aviary.variable_info.variables import Aircraft # NOTE These are currently needed to get around variable hierarchy being class-based. # Ideally, an alternate solution to loop through the hierarchy will be created and # these can be replaced. from aviary.utils.preprocessors import _get_engine_variables -from aviary.variable_info.variable_meta_data import _MetaData _default_name = 'propulsion' +# NOTE unlike the other subsystem builders, it is not reccomended to create additional +# propulsion subsystems, as propulsion is intended to be an agnostic carrier of +# all propulsion-related subsystem builders. class PropulsionBuilderBase(SubsystemBuilderBase): def __init__(self, name=None, meta_data=None): if name is None: @@ -41,34 +46,192 @@ def mission_outputs(self, **kwargs): class CorePropulsionBuilder(PropulsionBuilderBase): # code_origin is not necessary for this subsystem, catch with kwargs and ignore - def __init__(self, name=None, meta_data=None, **kwargs): + def __init__(self, name=None, meta_data=None, engine_models=None, **kwargs): if name is None: name = 'core_propulsion' super().__init__(name=name, meta_data=meta_data) + if not isinstance(engine_models, (list, np.ndarray)): + engine_models = [engine_models] + + for engine in engine_models: + if not isinstance(engine, EngineModel): + raise UserWarning('Engine provided to propulsion builder is not an ' + 'EngineModel object') + + self.engine_models = engine_models + def build_pre_mission(self, aviary_inputs): - return PropulsionPreMission(aviary_options=aviary_inputs) + return PropulsionPreMission(aviary_options=aviary_inputs, + engine_models=self.engine_models) def build_mission(self, num_nodes, aviary_inputs, **kwargs): - return PropulsionMission(num_nodes=num_nodes, aviary_options=aviary_inputs) + return PropulsionMission(num_nodes=num_nodes, aviary_options=aviary_inputs, + engine_models=self.engine_models) + + # NOTE untested! + def get_states(self): + """ + Call get_states() on all engine models and return combined result. + """ + states = {} + for engine in self.engine_models: + engine_states = engine.get_states() + states.update(engine_states) + + return states + def get_controls(self, phase_name=None): + """ + Call get_controls() on all engine models and return combined result. + """ + controls = {} + for engine in self.engine_models: + engine_controls = engine.get_controls(phase_name=phase_name) + controls.update(engine_controls) + + return controls + + # NOTE untested! def get_parameters(self, aviary_inputs=None, phase_info=None): + """ + Set expected shape of all variables that need to be vectorized for multiple + engine types. + """ num_engine_type = len(aviary_inputs.get_val(Aircraft.Engine.NUM_ENGINES)) params = {} - # add all variables from Engine & Nacelle to params - # TODO this assumes that no new categories are added for custom engine models - for var in _get_engine_variables(): - if var in aviary_inputs: - # TODO engine_wing_location - params[var] = {'shape': (num_engine_type, ), 'static_target': True} + # collect all the parameters for engines + for engine in self.engine_models: + engine_params = engine.get_parameters() + params.update(engine_params) + + # for any parameters that need to be vectorized for multiple engines, apply + # correct shape + engine_vars = _get_engine_variables() + for var in params: + if var in engine_vars: + # TODO shape for variables that are supposed to be vectors, like wing + # engine locations + params[var]['shape'] = (num_engine_type,) + params[var]['static_target'] = True - params = {} # For now - params[Aircraft.Engine.SCALE_FACTOR] = {'shape': (num_engine_type, ), - 'static_target': True} return params + # NOTE untested! + def get_constraints(self): + """ + Call get_constraints() on all engine models and return combined result. + """ + constraints = {} + for engine in self.engine_models: + engine_constraints = engine.get_constraints() + constraints.update(engine_constraints) + + return constraints + + # NOTE untested! + def get_linked_variables(self): + """ + Call get_linked_variables() on all engine models and return combined result. + """ + linked_vars = {} + for engine in self.engine_models: + engine_linked_vars = engine.get_linked_variables() + linked_vars.update(engine_linked_vars) + + return linked_vars + + def get_bus_variables(self): + """ + Call get_linked_variables() on all engine models and return combined result. + """ + bus_vars = {} + for engine in self.engine_models: + engine_bus_vars = engine.get_bus_variables() + bus_vars.update(engine_bus_vars) + + # append propulsion group name to all engine-level bus variables + # engine models only need to use variable paths starting at that engine group + complete_bus_vars = {} + for var in bus_vars: + info = bus_vars[var] + complete_bus_vars[self.name + '.' + var] = info + + return complete_bus_vars + + # NOTE untested! + def define_order(self): + """ + Call define_order() on all engine models and return combined result. + """ + subsys_order = [] + for engine in self.engine_models: + engine_subsys_order = engine.define_order() + subsys_order.append(engine_subsys_order) + + return subsys_order + + # NOTE untested! + def get_design_vars(self): + """ + Call get_design_vars() on all engine models and return combined result. + """ + design_vars = {} + for engine in self.engine_models: + engine_design_vars = engine.get_design_vars() + design_vars.update(engine_design_vars) + + return design_vars + + def get_initial_guesses(self): + """ + Call get_initial_guesses() on all engine models and return combined result. + """ + initial_guesses = {} + for engine in self.engine_models: + engine_initial_guesses = engine.get_initial_guesses() + initial_guesses.update(engine_initial_guesses) + + return initial_guesses + + # NOTE untested! + def get_mass_names(self): + """ + Call get_mass_names() on all engine models and return combined result. + """ + mass_names = {} + for engine in self.engine_models: + engine_mass_names = engine.get_mass_names() + mass_names.update(engine_mass_names) + + return mass_names + + # NOTE untested! + def preprocess_inputs(self): + """ + Call get_mass_names() on all engine models and return combined result. + """ + mass_names = {} + for engine in self.engine_models: + engine_mass_names = engine.get_mass_names() + mass_names.update(engine_mass_names) + + return mass_names + + # NOTE untested! + def get_outputs(self): + """ + Call get_outputs() on all engine models and return combined result. + """ + outputs = [] + for engine in self.engine_models: + engine_outputs = engine.get_outputs() + outputs.append(engine_outputs) + + return outputs + def report(self, prob, reports_folder, **kwargs): """ Generate the report for Aviary core propulsion analysis @@ -93,5 +256,6 @@ def report(self, prob, reports_folder, **kwargs): # each engine can append to this file kwargs['meta_data'] = self.meta_data - for engine in prob.aviary_inputs.get_val('engine_models'): + for idx, engine in enumerate(self.engine_models): + kwargs['engine_idx'] = idx engine.report(prob, filepath, **kwargs) diff --git a/aviary/subsystems/propulsion/propulsion_mission.py b/aviary/subsystems/propulsion/propulsion_mission.py index b61048b05..610403bb7 100644 --- a/aviary/subsystems/propulsion/propulsion_mission.py +++ b/aviary/subsystems/propulsion/propulsion_mission.py @@ -16,31 +16,35 @@ class PropulsionMission(om.Group): def initialize(self): self.options.declare( - 'num_nodes', - types=int, - lower=0 + 'num_nodes', types=int, lower=0 ) self.options.declare( 'aviary_options', types=AviaryValues, - desc='collection of Aircraft/Mission specific options') + desc='collection of Aircraft/Mission specific options' + ) + + self.options.declare( + 'engine_models', types=list, + desc='list of EngineModels on aircraft' + ) def setup(self): nn = self.options['num_nodes'] options: AviaryValues = self.options['aviary_options'] - engine_models = options.get_val('engine_models') + engine_models = self.options['engine_models'] num_engine_type = len(engine_models) - # TODO what if "engine" is not an EngineModel object? Type is never checked/enforced - if num_engine_type > 1: # We need a single component with scale_factor. Dymos can't find it when it is # already sliced across several component. + # TODO this only works for engine decks. Need to fix problem in generic way comp = om.ExecComp( "y=x", y={'val': np.ones(num_engine_type), 'units': 'unitless'}, - x={'val': np.ones(num_engine_type), 'units': 'unitless'} + x={'val': np.ones(num_engine_type), 'units': 'unitless'}, + has_diag_partials=True ) self.add_subsystem( "scale_passthrough", @@ -206,7 +210,8 @@ def initialize(self): def setup(self): nn = self.options['num_nodes'] - num_engine_type = len(self.options['aviary_options'].get_val('engine_models')) + num_engine_type = len(self.options['aviary_options'].get_val( + Aircraft.Engine.NUM_ENGINES)) self.add_input(Dynamic.Mission.THRUST, val=np.zeros( (nn, num_engine_type)), units='lbf') diff --git a/aviary/subsystems/propulsion/propulsion_premission.py b/aviary/subsystems/propulsion/propulsion_premission.py index e953414b2..0a8bc82a5 100644 --- a/aviary/subsystems/propulsion/propulsion_premission.py +++ b/aviary/subsystems/propulsion/propulsion_premission.py @@ -18,17 +18,21 @@ def initialize(self): self.options.declare( 'aviary_options', types=AviaryValues, desc='collection of Aircraft/Mission specific options') + self.options.declare( + 'engine_models', types=list, + desc='list of EngineModels on aircraft' + ) def setup(self): options = self.options['aviary_options'] - engine_models = options.get_val('engine_models') + engine_models = self.options['engine_models'] num_engine_type = len(engine_models) # Each engine model pre_mission component only needs to accept and output single # value relevant to that variable - this group's configure step will handle # promoting/connecting just the relevant index in vectorized inputs/outputs for # each component here - # Promotions are handled in configure() + # Promotions are handled in self.configure() for engine in engine_models: subsys = engine.build_pre_mission(options) if subsys: @@ -43,8 +47,8 @@ def setup(self): ) if num_engine_type > 1: - # Add an empty mux comp, which will be customized to handle all required outputs - # in self.configure() + # Add an empty mux comp, which will be customized to handle all required + # outputs in self.configure() self.add_subsystem( 'pre_mission_mux', subsys=om.MuxComp(), @@ -65,7 +69,8 @@ def configure(self): # so vectorized inputs/outputs are a problem. Slice all needed vector inputs and pass # pre_mission components only the value they need, then mux all the outputs back together - num_engine_type = len(self.options['aviary_options'].get_val('engine_models')) + num_engine_type = len(self.options['aviary_options'].get_val( + Aircraft.Engine.NUM_ENGINES)) # determine if openMDAO messages and warnings should be suppressed verbosity = self.options['aviary_options'].get_val(Settings.VERBOSITY) @@ -117,12 +122,12 @@ def configure(self): self.promotes( comp.name, inputs=input_dict[comp.name].keys(), src_indices=om.slicer[idx]) - # promote all other inputs/outputs for this component normally (handle special outputs later) + # promote all other inputs/outputs for this component normally (handle vectorized outputs later) self.promotes(comp.name, inputs=[ - input for input in comp_inputs if input not in input_dict[comp.name]], + comp_inputs[input]['prom_name'] for input in comp_inputs if input not in input_dict[comp.name]], outputs=[ - output for output in comp_outputs if output not in output_dict[comp.name]]) + comp_outputs[output]['prom_name'] for output in comp_outputs if output not in output_dict[comp.name]]) # add variables to the mux component and make connections to individual # component outputs diff --git a/aviary/subsystems/propulsion/test/test_custom_engine_model.py b/aviary/subsystems/propulsion/test/test_custom_engine_model.py index f06ae6176..d682914bc 100644 --- a/aviary/subsystems/propulsion/test/test_custom_engine_model.py +++ b/aviary/subsystems/propulsion/test/test_custom_engine_model.py @@ -98,7 +98,7 @@ def build_pre_mission(self, aviary_inputs=AviaryValues()): def build_mission(self, num_nodes, aviary_inputs): return SimpleEngine(num_nodes=num_nodes) - def get_controls(self): + def get_controls(self, **kwargs): controls_dict = { "different_throttle": {'units': 'unitless', 'lower': 0., 'upper': 0.1}, } @@ -124,8 +124,6 @@ def get_initial_guesses(self): return initial_guesses_dict -@unittest.skip('This test is not compatile with multiengine, requires rework so ' - 'engine-level methods can be called') @use_tempdirs class CustomEngineTest(unittest.TestCase): def test_custom_engine(self): @@ -171,7 +169,7 @@ def test_custom_engine(self): # Load aircraft and options data from user # Allow for user overrides here prob.load_inputs("models/test_aircraft/aircraft_for_bench_GwFm.csv", - phase_info, engine_builder=SimpleTestEngine()) + phase_info, engine_builders=[SimpleTestEngine()]) # Preprocess inputs prob.check_and_preprocess_inputs() @@ -268,7 +266,7 @@ def test_turboprop(self): # Load aircraft and options data from user # Allow for user overrides here prob.load_inputs("models/test_aircraft/aircraft_for_bench_FwFm.csv", - phase_info, engine_builder=engine) + phase_info, engine_builders=[engine]) # Preprocess inputs prob.check_and_preprocess_inputs() @@ -293,7 +291,7 @@ def test_turboprop(self): prob.set_initial_guesses() prob.set_val( - f'traj.cruise.rhs_all.{Aircraft.Design.MAX_TIP_SPEED}', 710., units='ft/s') + f'traj.cruise.rhs_all.{Aircraft.Design.MAX_PROPELLER_TIP_SPEED}', 710., units='ft/s') prob.set_val( f'traj.cruise.rhs_all.{Dynamic.Mission.PERCENT_ROTOR_RPM_CORRECTED}', 0.915, units='unitless') prob.set_val( @@ -309,3 +307,5 @@ def test_turboprop(self): if __name__ == '__main__': unittest.main() + # test = CustomEngineTest() + # test.test_custom_engine() diff --git a/aviary/subsystems/propulsion/test/test_data_interpolator.py b/aviary/subsystems/propulsion/test/test_data_interpolator.py index 914c4147d..f029b4184 100644 --- a/aviary/subsystems/propulsion/test/test_data_interpolator.py +++ b/aviary/subsystems/propulsion/test/test_data_interpolator.py @@ -13,6 +13,7 @@ from aviary.variable_info.variables import Dynamic from aviary.validation_cases.validation_data.flops_data.FLOPS_Test_Data import \ FLOPS_Test_Data +from aviary.subsystems.propulsion.utils import build_engine_deck class DataInterpolationTest(unittest.TestCase): @@ -21,7 +22,7 @@ def test_data_interpolation(self): aviary_values = FLOPS_Test_Data['LargeSingleAisle2FLOPS']['inputs'] - model = aviary_values.get_val('engine_models')[0] + model = build_engine_deck(aviary_values)[0] mach_number = model.data[keys.MACH] altitude = model.data[keys.ALTITUDE] diff --git a/aviary/subsystems/propulsion/test/test_engine_deck.py b/aviary/subsystems/propulsion/test/test_engine_deck.py index e994e8914..92bd20425 100644 --- a/aviary/subsystems/propulsion/test/test_engine_deck.py +++ b/aviary/subsystems/propulsion/test/test_engine_deck.py @@ -9,6 +9,7 @@ from aviary.utils.named_values import NamedValues from aviary.validation_cases.validation_data.flops_data.FLOPS_Test_Data import \ FLOPS_Test_Data +from aviary.subsystems.propulsion.utils import build_engine_deck class EngineDeckTest(unittest.TestCase): @@ -17,7 +18,7 @@ def test_flight_idle(self): aviary_values = FLOPS_Test_Data['LargeSingleAisle2FLOPS']['inputs'] - model = aviary_values.get_val('engine_models')[0] + model = build_engine_deck(aviary_values)[0] expected_mach_number = [] expected_altitude = [] @@ -53,7 +54,7 @@ def test_flight_idle_2(self): aviary_values = FLOPS_Test_Data['LargeSingleAisle1FLOPS']['inputs'] - model = aviary_values.get_val('engine_models')[0] + model = build_engine_deck(aviary_values)[0] # hardcoded data of processed engine model from LEAPS1 after flight idle # point generation, sorted in Aviary order diff --git a/aviary/subsystems/propulsion/test/test_propulsion_mission.py b/aviary/subsystems/propulsion/test/test_propulsion_mission.py index 495e877fb..1ad3d82f2 100644 --- a/aviary/subsystems/propulsion/test/test_propulsion_mission.py +++ b/aviary/subsystems/propulsion/test/test_propulsion_mission.py @@ -14,6 +14,7 @@ from aviary.utils.functions import get_path from aviary.validation_cases.validation_tests import get_flops_inputs from aviary.variable_info.variables import Aircraft, Dynamic, Mission +from aviary.subsystems.propulsion.utils import build_engine_deck class PropulsionMissionTest(unittest.TestCase): @@ -50,7 +51,8 @@ def test_case_1(self): engine = EngineDeck(options=options) preprocess_propulsion(options, [engine]) - self.prob.model = PropulsionMission(num_nodes=nn, aviary_options=options) + self.prob.model = PropulsionMission( + num_nodes=nn, aviary_options=options, engine_models=[engine]) IVC = om.IndepVarComp(Dynamic.Mission.MACH, np.linspace(0, 0.8, nn), @@ -99,8 +101,6 @@ def test_propulsion_sum(self): nn = 2 options = AviaryValues() options.set_val(Aircraft.Engine.NUM_ENGINES, np.array([3, 2])) - # it doesn't matter what goes in engine models, as long as it is length 2 - options.set_val('engine_models', [1, 1]) self.prob.model = om.Group() self.prob.model.add_subsystem('propsum', PropulsionSum(num_nodes=nn, @@ -151,12 +151,14 @@ def test_case_multiengine(self): options = get_flops_inputs('LargeSingleAisle2FLOPS') - engine = options.get_val('engine_models')[0] - engine2 = options.deepcopy().get_val('engine_models')[0] + engine = build_engine_deck(options)[0] + engine2 = build_engine_deck(options)[0] engine2.name = 'engine2' - preprocess_propulsion(options, [engine, engine2]) + engine_models = [engine, engine2] + preprocess_propulsion(options, engine_models=engine_models) - self.prob.model = PropulsionMission(num_nodes=20, aviary_options=options) + self.prob.model = PropulsionMission( + num_nodes=20, aviary_options=options, engine_models=engine_models) self.prob.model.add_subsystem(Dynamic.Mission.MACH, om.IndepVarComp(Dynamic.Mission.MACH, @@ -209,7 +211,7 @@ def test_case_multiengine(self): if __name__ == "__main__": - # unittest.main() - test = PropulsionMissionTest() - test.setUp() - test.test_case_multiengine() + unittest.main() + # test = PropulsionMissionTest() + # test.setUp() + # test.test_case_multiengine() diff --git a/aviary/subsystems/propulsion/test/test_propulsion_premission.py b/aviary/subsystems/propulsion/test/test_propulsion_premission.py index cf0abd56a..a56a17d3a 100644 --- a/aviary/subsystems/propulsion/test/test_propulsion_premission.py +++ b/aviary/subsystems/propulsion/test/test_propulsion_premission.py @@ -7,8 +7,11 @@ from aviary.subsystems.propulsion.propulsion_premission import ( PropulsionPreMission, PropulsionSum) from aviary.utils.aviary_values import AviaryValues +from aviary.subsystems.propulsion.utils import build_engine_deck from aviary.validation_cases.validation_tests import get_flops_inputs +from aviary.models.multi_engine_single_aisle.multi_engine_single_aisle_data import engine_1_inputs, engine_2_inputs from aviary.variable_info.variables import Aircraft, Settings +from aviary.utils.preprocessors import preprocess_options class PropulsionPreMissionTest(unittest.TestCase): @@ -16,11 +19,12 @@ def setUp(self): self.prob = om.Problem() def test_case(self): - aviary_values = get_flops_inputs('LargeSingleAisle2FLOPS') - aviary_values.set_val(Settings.VERBOSITY, 0) - options = aviary_values + options = get_flops_inputs('LargeSingleAisle2FLOPS') + options.set_val(Settings.VERBOSITY, 0) + options.set_val(Aircraft.Engine.NUM_ENGINES, np.array([2])) - self.prob.model = PropulsionPreMission(aviary_options=options) + self.prob.model = PropulsionPreMission(aviary_options=options, + engine_models=build_engine_deck(options)) self.prob.setup(force_alloc_complex=True) self.prob.set_val(Aircraft.Engine.SCALED_SLS_THRUST, options.get_val( @@ -38,12 +42,17 @@ def test_case(self): assert_check_partials(partial_data, atol=1e-10, rtol=1e-10) def test_multi_engine(self): - aviary_values = get_flops_inputs('MultiEngineSingleAisle') - aviary_values.set_val(Settings.VERBOSITY, 0) + options = get_flops_inputs('MultiEngineSingleAisle') + options.set_val(Settings.VERBOSITY, 0) + + engine1 = build_engine_deck(engine_1_inputs)[0] + engine2 = build_engine_deck(engine_2_inputs)[0] + engine_models = [engine1, engine2] - options = aviary_values + preprocess_options(options, engine_models=engine_models) - self.prob.model = PropulsionPreMission(aviary_options=options) + self.prob.model = PropulsionPreMission(aviary_options=options, + engine_models=engine_models) self.prob.setup(force_alloc_complex=True) self.prob.set_val(Aircraft.Engine.SCALED_SLS_THRUST, options.get_val( @@ -63,8 +72,6 @@ def test_multi_engine(self): def test_propulsion_sum(self): options = AviaryValues() options.set_val(Aircraft.Engine.NUM_ENGINES, np.array([1, 2, 5])) - # it doesn't matter what goes in engine models, as long as it is length 3 - options.set_val('engine_models', [1, 1, 1]) options.set_val(Settings.VERBOSITY, 0) self.prob.model = om.Group() self.prob.model.add_subsystem('propsum', @@ -89,7 +96,7 @@ def test_propulsion_sum(self): if __name__ == "__main__": - # unittest.main() - test = PropulsionPreMissionTest() - test.setUp() - test.test_multi_engine() + unittest.main() + # test = PropulsionPreMissionTest() + # test.setUp() + # test.test_case() diff --git a/aviary/subsystems/propulsion/turboprop_model.py b/aviary/subsystems/propulsion/turboprop_model.py index ede61c0a0..c52fc1b11 100644 --- a/aviary/subsystems/propulsion/turboprop_model.py +++ b/aviary/subsystems/propulsion/turboprop_model.py @@ -158,7 +158,10 @@ def build_mission(self, num_nodes, aviary_inputs, **kwargs): num_nodes), 'units': 'lbf'}, turboshaft_thrust={'val': np.zeros( num_nodes), 'units': 'lbf'}, - propeller_thrust={'val': np.zeros(num_nodes), 'units': 'lbf'}) + propeller_thrust={'val': np.zeros( + num_nodes), 'units': 'lbf'}, + has_diag_partials=True + ) turboprop_group.add_subsystem('thrust_adder', subsys=thrust_adder, diff --git a/aviary/subsystems/propulsion/utils.py b/aviary/subsystems/propulsion/utils.py index 95dc205d2..41485c87e 100644 --- a/aviary/subsystems/propulsion/utils.py +++ b/aviary/subsystems/propulsion/utils.py @@ -5,6 +5,7 @@ Matches each EngineModelVariables entry with default units (str) """ from enum import Enum, auto +from pathlib import Path import numpy as np import openmdao.api as om @@ -13,6 +14,8 @@ from aviary.utils.aviary_values import AviaryValues from aviary.variable_info.variables import Dynamic +from aviary.variable_info.variable_meta_data import _MetaData +from aviary.variable_info.variables import Aircraft class EngineModelVariables(Enum): @@ -104,6 +107,53 @@ def convert_geopotential_altitude(altitude): return altitude +# TODO build test for this function +def build_engine_deck(aviary_options: AviaryValues): + ''' + Creates an EngineDeck using avaliable inputs and options in aviary_options. + + Parameter + ---------- + aviary_options : AviaryValues + Options to use in creation of EngineDecks. + + Returns + ---------- + engine_models : + List of EngineDecks created using provided aviary_options. + ''' + # import locally placed to avoid circular import + from aviary.subsystems.propulsion.engine_deck import EngineDeck + + # Build a single engine deck, currently ignoring vectorization + # of AviaryValues (use first index) + engine_options = AviaryValues() + for var in Aircraft.Engine.__dict__.values(): + # check if this variable exist with useable metadata + try: + units = _MetaData[var]['units'] + try: + # add value from aviary_options to engine_options + aviary_val = aviary_options.get_val(var, units) + if isinstance(aviary_val, np.ndarray): + # "Convert" numpy types to standard Python types. Wrap first + # index in numpy array before calling item() to safeguard against + # non-standard types, such as objects + aviary_val = np.array(aviary_val[0]).item() + elif isinstance(aviary_val, (list, tuple)): + aviary_val = aviary_val[0] + engine_options.set_val(var, aviary_val, units) + # if not, use default value from _MetaData? + except KeyError: + # engine_options.set_val(var, _MetaData[var]['default_value'], units) + continue + except (KeyError, TypeError): + continue + + # name engine deck after filename + return [EngineDeck(Path(engine_options.get_val(Aircraft.Engine.DATA_FILE)).stem, options=engine_options)] + + class UncorrectData(om.Group): def initialize(self): self.options.declare( diff --git a/aviary/subsystems/test/test_dummy_subsystem.py b/aviary/subsystems/test/test_dummy_subsystem.py index 73ee69868..4c68f694b 100644 --- a/aviary/subsystems/test/test_dummy_subsystem.py +++ b/aviary/subsystems/test/test_dummy_subsystem.py @@ -289,7 +289,7 @@ def get_states(self): } } - def get_controls(self): + def get_controls(self, **kwargs): return {} def get_parameters(self, aviary_inputs=None, phase_info=None): diff --git a/aviary/subsystems/test/test_flops_based_premission.py b/aviary/subsystems/test/test_flops_based_premission.py index c1887ba3c..d2544dac4 100644 --- a/aviary/subsystems/test/test_flops_based_premission.py +++ b/aviary/subsystems/test/test_flops_based_premission.py @@ -13,8 +13,9 @@ from aviary.variable_info.variables import Aircraft, Mission, Settings from aviary.variable_info.variables_in import VariablesIn from aviary.utils.functions import set_aviary_initial_values -from aviary.interface.default_phase_info.height_energy import default_premission_subsystems -from aviary.utils.preprocessors import preprocess_crewpayload +from aviary.subsystems.propulsion.utils import build_engine_deck +from aviary.utils.test_utils.default_subsystems import get_default_premission_subsystems +from aviary.utils.preprocessors import preprocess_options class PreMissionGroupTest(unittest.TestCase): @@ -31,7 +32,10 @@ def test_case(self, case_name): flops_outputs.get_val(Aircraft.Propulsion.TOTAL_NUM_WING_ENGINES)) flops_inputs.set_val(Settings.VERBOSITY, 0.0) - preprocess_crewpayload(flops_inputs) + engine = build_engine_deck(flops_inputs) + preprocess_options(flops_inputs, engine_models=engine) + default_premission_subsystems = get_default_premission_subsystems( + 'FLOPS', engine) prob = self.prob @@ -104,6 +108,11 @@ def test_diff_configuration_mass(self): flops_outputs: AviaryValues = LargeSingleAisle2FLOPS['outputs'] flops_inputs.set_val(Settings.VERBOSITY, 0.0) + engine = build_engine_deck(flops_inputs) + preprocess_options(flops_inputs, engine_models=engine) + default_premission_subsystems = get_default_premission_subsystems( + 'FLOPS', engine) + prob.model.add_subsystem( "pre_mission", CorePreMission(aviary_options=flops_inputs, @@ -131,8 +140,6 @@ def test_diff_configuration_mass(self): # This is an option, not a variable continue - prob.run_model() - flops_validation_test( prob, "LargeSingleAisle2FLOPS", diff --git a/aviary/subsystems/test/test_premission.py b/aviary/subsystems/test/test_premission.py index 55a56b882..12e4b21b9 100644 --- a/aviary/subsystems/test/test_premission.py +++ b/aviary/subsystems/test/test_premission.py @@ -18,6 +18,7 @@ from aviary.utils.functions import set_aviary_initial_values from aviary.variable_info.variables_in import VariablesIn from aviary.variable_info.enums import LegacyCode +from aviary.subsystems.propulsion.utils import build_engine_deck FLOPS = LegacyCode.FLOPS @@ -67,7 +68,9 @@ def setUp(self): input_options.delete(Aircraft.Fuel.TOTAL_CAPACITY) input_options.delete(Aircraft.Nacelle.AVG_LENGTH) - prop = CorePropulsionBuilder('core_propulsion', BaseMetaData) + engine = build_engine_deck(input_options) + + prop = CorePropulsionBuilder('core_propulsion', BaseMetaData, engine) mass = CoreMassBuilder('core_mass', BaseMetaData, GASP) aero = CoreAerodynamicsBuilder('core_aerodynamics', BaseMetaData, FLOPS) geom = CoreGeometryBuilder('core_geometry', @@ -271,11 +274,12 @@ def test_manual_override(self): aviary_inputs = setup_options(GASP_input, FLOPS_input) aviary_inputs.delete(Aircraft.Fuselage.WETTED_AREA) + engine = build_engine_deck(aviary_inputs) prob = om.Problem() model = prob.model - prop = CorePropulsionBuilder('core_propulsion', BaseMetaData) + prop = CorePropulsionBuilder('core_propulsion', BaseMetaData, engine) mass = CoreMassBuilder('core_mass', BaseMetaData, GASP) aero = CoreAerodynamicsBuilder('core_aerodynamics', BaseMetaData, FLOPS) geom = CoreGeometryBuilder('core_geometry', @@ -351,3 +355,6 @@ def test_manual_override(self): if __name__ == "__main__": unittest.main() + # test = PreMissionTestCase() + # test.setUp() + # test.test_GASP_mass_FLOPS_everything_else() diff --git a/aviary/utils/aviary_values.py b/aviary/utils/aviary_values.py index 6bca9058e..23736a4ca 100644 --- a/aviary/utils/aviary_values.py +++ b/aviary/utils/aviary_values.py @@ -102,7 +102,9 @@ def _check_type(self, key, val, meta_data=_MetaData): if val.dtype == type(None): val = [val[0]] else: - val = [val[0].item()] + # item() gets us native Python equivalent object (i.e. int vs. numpy.int64) + # wrap first index in np array to ensures works on any dtype + val = [np.array(val[0]).item()] for item in val: has_bool = False # needs some fancy shenanigans because bools will register as ints if (isinstance(expected_types, type)): diff --git a/aviary/utils/preprocessors.py b/aviary/utils/preprocessors.py index be500a1c1..cb991bb20 100644 --- a/aviary/utils/preprocessors.py +++ b/aviary/utils/preprocessors.py @@ -3,14 +3,13 @@ import numpy as np import openmdao.api as om -from aviary.subsystems.propulsion.engine_deck import EngineDeck from aviary.utils.aviary_values import AviaryValues from aviary.utils.named_values import get_keys from aviary.variable_info.variable_meta_data import _MetaData from aviary.variable_info.variables import Aircraft, Mission -def preprocess_options(aviary_options: AviaryValues): +def preprocess_options(aviary_options: AviaryValues, **kwargs): """ Run all preprocessors on provided AviaryValues object @@ -19,14 +18,13 @@ def preprocess_options(aviary_options: AviaryValues): aviary_options : AviaryValues Options to be updated """ - preprocess_crewpayload(aviary_options) try: - engine_models = aviary_options.get_val('engine_models') + engine_models = kwargs['engine_models'] except KeyError: - preprocess_propulsion(aviary_options) - else: - # don't catch stray exceptions in preprocess_propulsion - preprocess_propulsion(aviary_options, engine_models) + engine_models = None + + preprocess_crewpayload(aviary_options) + preprocess_propulsion(aviary_options, engine_models) def preprocess_crewpayload(aviary_options: AviaryValues): @@ -134,54 +132,7 @@ def preprocess_propulsion(aviary_options: AviaryValues, engine_models: list = No EngineModel objects to be added to aviary_options. Replaced existing EngineModels in aviary_options ''' - ######################## - # Create Engine Models # - ######################## - # Check if EngineModels are provided, either as an argument or in aviary_options - # Build new engines if no engine models provided by the user in any capacity, such as - # from an input deck - build_engines = False - if not engine_models: - try: - engine_models = aviary_options.get_val('engine_models') - except KeyError: - build_engines = True - else: - # Add engine models to aviary options for component access - # TODO this overwrites any engine models already in aviary_options without - # warning - should they get combined into the engine_models list instead? - aviary_options.set_val('engine_models', engine_models) - - # If engine models are not provided, build a single engine deck, ignore vectorization - # of AviaryValues (use first index) - # TODO build test to verify this works as expected - if build_engines: - engine_options = AviaryValues() - for entry in Aircraft.Engine.__dict__: - var = getattr(Aircraft.Engine, entry) - # check if this variable exist with useable metadata - try: - units = _MetaData[var]['units'] - try: - # add value from aviary_options to engine_options - default_val = aviary_options.get_val(var, units) - if type(default_val) in (list, np.ndarray): - default_val = default_val[0] - engine_options.set_val(default_val, units) - # if not, use default value from _MetaData - except KeyError: - engine_options.set_val(_MetaData[var]['default_value'], units) - except KeyError: - continue - - engine_deck = EngineDeck(engine_options) - engine_models = [engine_deck] - - num_engine_type = len(engine_models) - # keys of originally provided aviary_options - # currently not used but might be useful in the future - # aviary_mapping = get_keys(aviary_options.deepcopy()) - + # TODO add verbosity check to warnings ############################## # Vectorize Engine Variables # ############################## @@ -189,6 +140,8 @@ def preprocess_propulsion(aviary_options: AviaryValues, engine_models: list = No # Combine aviary_options and all engine options into single AviaryValues # It is assumed that all EngineModels are up-to-date at this point and will NOT # be changed later on (otherwise preprocess_propulsion must be run again) + num_engine_type = len(engine_models) + complete_options_list = AviaryValues(aviary_options) for engine in engine_models: complete_options_list.update(engine.options) @@ -303,9 +256,9 @@ def preprocess_propulsion(aviary_options: AviaryValues, engine_models: list = No f'Mount location for engines of type <{eng_name}> not specified. ' 'Wing-mounted engines are assumed.') - # If wing mount type are specified but inconsistent, default num_engines to sum - # of specified mounted engines - elif total_engines_calc != num_engines: + # If wing mount type are specified but inconsistent, handle it + elif total_engines_calc > num_engines: + # more defined engine locations than number of engines - increase num engines eng_name = engine.name num_engines_all[i] = total_engines_calc warnings.warn( @@ -313,6 +266,13 @@ def preprocess_propulsion(aviary_options: AviaryValues, engine_models: list = No 'aircraft:engine:num_wing_engines do not match ' f'aircraft:engine:num_engines for EngineModel <{eng_name}>. Overwriting ' 'with the sum of wing and fuselage mounted engines.') + elif total_engines_calc < num_engines: + # fewer defined locations than num_engines - assume rest are wing mounted + eng_name = engine.name + num_wing_engines_all[i] = num_engines - num_fuse_engines + warnings.warn( + 'Mount location was not defined for all engines of EngineModel ' + f'<{eng_name}> - unspecified engines are assumed wing-mounted.') aviary_options.set_val(Aircraft.Engine.NUM_ENGINES, num_engines_all) aviary_options.set_val(Aircraft.Engine.NUM_WING_ENGINES, num_wing_engines_all) diff --git a/aviary/utils/process_input_decks.py b/aviary/utils/process_input_decks.py index 97fe98d3b..1bf7feb12 100644 --- a/aviary/utils/process_input_decks.py +++ b/aviary/utils/process_input_decks.py @@ -36,27 +36,32 @@ 'alternate': ProblemType.ALTERNATE, 'fallout': ProblemType.FALLOUT} -def create_vehicle(vehicle_deck='', verbosity=Verbosity.BRIEF, meta_data=_MetaData): +def create_vehicle(vehicle_deck='', meta_data=_MetaData, verbosity=None): """ Creates and initializes a vehicle with default or specified parameters. It sets up the aircraft values and initial guesses based on the input from the vehicle deck. Parameters ---------- - vehicle_deck (str): Path to the vehicle deck file. Default is an empty string. + vehicle_deck (str): + Path to the vehicle deck file. Default is an empty string. + meta_data (dict): + Variable metadata used when reading input file for unit validation, + default values, and other checks Returns ------- - tuple: Returns a tuple containing aircraft values and initial guesses. + (aircraft_values, initial_guesses): (tuple) + Returns a tuple containing aircraft values and initial guesses. """ aircraft_values = get_option_defaults(engine=False) # TODO remove all hardcoded GASP values here, find appropriate place for them - aircraft_values.set_val(Settings.VERBOSITY, val=verbosity) aircraft_values.set_val('INGASP.JENGSZ', val=4) aircraft_values.set_val('test_mode', val=False) aircraft_values.set_val('use_surrogates', val=True) aircraft_values.set_val('mass_defect', val=10000, units='lbm') + # TODO problem_type should get set by get_option_defaults?? aircraft_values.set_val(Settings.PROBLEM_TYPE, val=ProblemType.SIZING) aircraft_values.set_val(Aircraft.Electrical.HAS_HYBRID_SYSTEM, val=False) @@ -73,6 +78,19 @@ def create_vehicle(vehicle_deck='', verbosity=Verbosity.BRIEF, meta_data=_MetaDa 'reserves': 0 } + initial_guesses = { + # initial_guesses is a dictionary that contains values used to initialize the trajectory + 'actual_takeoff_mass': 0, + 'rotation_mass': 0, + 'operating_empty_mass': 0, + 'fuel_burn_per_passenger_mile': 0, + 'cruise_mass_final': 0, + 'flight_duration': 0, + 'time_to_climb': 0, + 'climb_range': 0, + 'reserves': 0 + } + if isinstance(vehicle_deck, AviaryValues): aircraft_values.update(vehicle_deck) else: @@ -80,6 +98,15 @@ def create_vehicle(vehicle_deck='', verbosity=Verbosity.BRIEF, meta_data=_MetaDa aircraft_values, initial_guesses = parse_inputs( vehicle_deck=vehicle_deck, aircraft_values=aircraft_values, initial_guesses=initial_guesses, meta_data=meta_data) + # make sure verbosity is always set + # if verbosity set via parameter, use that + if verbosity is not None: + # Enum conversion here, so user can pass either number or actual Enum as parameter + aircraft_values.set_val(Settings.VERBOSITY, Verbosity(verbosity)) + # else, if verbosity not specified anywhere, use default of BRIEF + elif verbosity is None and Settings.VERBOSITY not in aircraft_values: + aircraft_values.set_val(Settings.VERBOSITY, Verbosity.BRIEF) + return aircraft_values, initial_guesses diff --git a/aviary/utils/test_utils/default_subsystems.py b/aviary/utils/test_utils/default_subsystems.py new file mode 100644 index 000000000..d7e05f60f --- /dev/null +++ b/aviary/utils/test_utils/default_subsystems.py @@ -0,0 +1,24 @@ +from aviary.subsystems.propulsion.propulsion_builder import CorePropulsionBuilder +from aviary.subsystems.geometry.geometry_builder import CoreGeometryBuilder +from aviary.subsystems.mass.mass_builder import CoreMassBuilder +from aviary.subsystems.aerodynamics.aerodynamics_builder import CoreAerodynamicsBuilder +from aviary.variable_info.variable_meta_data import _MetaData as BaseMetaData +from aviary.variable_info.enums import LegacyCode + + +def get_default_premission_subsystems(legacy_code, engines=None): + legacy_code = LegacyCode(legacy_code) + prop = CorePropulsionBuilder('core_propulsion', BaseMetaData, engine_models=engines) + mass = CoreMassBuilder('core_mass', BaseMetaData, legacy_code) + aero = CoreAerodynamicsBuilder('core_aerodynamics', BaseMetaData, legacy_code) + geom = CoreGeometryBuilder('core_geometry', BaseMetaData, legacy_code) + + return [prop, geom, aero, mass] + + +def get_default_mission_subsystems(legacy_code, engines=None): + legacy_code = LegacyCode(legacy_code) + prop = CorePropulsionBuilder('core_propulsion', BaseMetaData, engine_models=engines) + aero = CoreAerodynamicsBuilder('core_aerodynamics', BaseMetaData, legacy_code) + + return [aero, prop] diff --git a/aviary/validation_cases/benchmark_tests/test_FLOPS_balanced_field_length.py b/aviary/validation_cases/benchmark_tests/test_FLOPS_balanced_field_length.py index f30f6d812..ed62ffd76 100644 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_balanced_field_length.py +++ b/aviary/validation_cases/benchmark_tests/test_FLOPS_balanced_field_length.py @@ -11,7 +11,7 @@ from aviary.interface.methods_for_level2 import AviaryProblem from aviary.utils.functions import set_aviary_initial_values -from aviary.utils.preprocessors import preprocess_crewpayload +from aviary.utils.preprocessors import preprocess_options from aviary.models.N3CC.N3CC_data import \ balanced_liftoff_user_options as _takeoff_liftoff_user_options from aviary.models.N3CC.N3CC_data import \ @@ -20,7 +20,8 @@ inputs as _inputs from aviary.variable_info.variables import Dynamic from aviary.variable_info.variables_in import VariablesIn -from aviary.interface.default_phase_info.height_energy import default_premission_subsystems +from aviary.subsystems.propulsion.utils import build_engine_deck +from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems from aviary.subsystems.premission import CorePreMission @@ -57,7 +58,9 @@ def bench_test_SNOPT(self): def _do_run(self, driver: Driver, optimizer, *args): aviary_options = _inputs.deepcopy() - preprocess_crewpayload(aviary_options) + + engine = build_engine_deck(aviary_options) + preprocess_options(aviary_options, engine_models=engine) takeoff_trajectory_builder = copy.deepcopy(_takeoff_trajectory_builder) takeoff_liftoff_user_options = _takeoff_liftoff_user_options.deepcopy() @@ -72,12 +75,14 @@ def _do_run(self, driver: Driver, optimizer, *args): driver.recording_options['record_derivatives'] = False + default_mission_subsystems = get_default_mission_subsystems('FLOPS', engine) + # Upstream static analysis for aero takeoff.model.add_subsystem( 'core_subsystems', CorePreMission( aviary_options=aviary_options, - subsystems=default_premission_subsystems, + subsystems=default_mission_subsystems, ), promotes_inputs=['aircraft:*', 'mission:*'], promotes_outputs=['aircraft:*', 'mission:*']) diff --git a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_sizing_N3CC.py b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_sizing_N3CC.py index a94a6c2f0..8dd79cb3f 100644 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_based_sizing_N3CC.py +++ b/aviary/validation_cases/benchmark_tests/test_FLOPS_based_sizing_N3CC.py @@ -27,7 +27,8 @@ from aviary.variable_info.variables import Aircraft, Dynamic, Mission from aviary.subsystems.premission import CorePreMission -from aviary.interface.default_phase_info.height_energy import default_premission_subsystems, default_mission_subsystems +from aviary.subsystems.propulsion.utils import build_engine_deck +from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems from aviary.utils.preprocessors import preprocess_crewpayload try: @@ -165,6 +166,10 @@ def run_trajectory(sim=True): num_segments=num_segments_descent, order=3, compressed=True, segment_ends=descent_seg_ends) + # default subsystems + engine = build_engine_deck(aviary_inputs) + default_mission_subsystems = get_default_mission_subsystems('FLOPS', engine) + climb_options = EnergyPhase( 'test_climb', user_options=AviaryValues({ @@ -223,7 +228,7 @@ def run_trajectory(sim=True): prob.model.add_subsystem( 'pre_mission', CorePreMission(aviary_options=aviary_inputs, - subsystems=default_premission_subsystems), + subsystems=default_mission_subsystems), promotes_inputs=['aircraft:*', 'mission:*'], promotes_outputs=['aircraft:*', 'mission:*']) diff --git a/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_landing.py b/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_landing.py index bc4b16846..4e8db9bbe 100644 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_landing.py +++ b/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_landing.py @@ -18,8 +18,9 @@ landing_fullstop_user_options as _landing_fullstop_user_options) from aviary.variable_info.variables import Dynamic -from aviary.interface.default_phase_info.height_energy import default_premission_subsystems -from aviary.utils.preprocessors import preprocess_crewpayload +from aviary.subsystems.propulsion.utils import build_engine_deck +from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems +from aviary.utils.preprocessors import preprocess_options from aviary.variable_info.variables_in import VariablesIn @@ -67,7 +68,10 @@ def _do_run(self, driver: Driver, optimizer, *args): driver.recording_options['record_derivatives'] = False - preprocess_crewpayload(aviary_options) + engine = build_engine_deck(aviary_options) + preprocess_options(aviary_options, engine_models=engine) + + default_premission_subsystems = get_default_mission_subsystems('FLOPS', engine) # Upstream static analysis for aero landing.model.add_subsystem( diff --git a/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_takeoff.py b/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_takeoff.py index e0752de37..2b75a5d49 100644 --- a/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_takeoff.py +++ b/aviary/validation_cases/benchmark_tests/test_FLOPS_detailed_takeoff.py @@ -18,8 +18,9 @@ takeoff_liftoff_user_options as _takeoff_liftoff_user_options) from aviary.variable_info.variables import Aircraft, Dynamic -from aviary.interface.default_phase_info.height_energy import default_premission_subsystems -from aviary.utils.preprocessors import preprocess_crewpayload +from aviary.subsystems.propulsion.utils import build_engine_deck +from aviary.utils.test_utils.default_subsystems import get_default_mission_subsystems +from aviary.utils.preprocessors import preprocess_options from aviary.variable_info.variables_in import VariablesIn @@ -73,7 +74,10 @@ def _do_run(self, driver: Driver, optimizer, *args): driver.recording_options['record_derivatives'] = False - preprocess_crewpayload(aviary_options) + engine = build_engine_deck(aviary_options) + preprocess_options(aviary_options, engine_models=engine) + + default_premission_subsystems = get_default_mission_subsystems('FLOPS', engine) # Upstream static analysis for aero takeoff.model.add_subsystem( diff --git a/aviary/validation_cases/benchmark_tests/test_bench_multiengine.py b/aviary/validation_cases/benchmark_tests/test_bench_multiengine.py index 305e81eac..f41b6c60d 100644 --- a/aviary/validation_cases/benchmark_tests/test_bench_multiengine.py +++ b/aviary/validation_cases/benchmark_tests/test_bench_multiengine.py @@ -7,8 +7,9 @@ from aviary.interface.default_phase_info.height_energy import phase_info from aviary.interface.methods_for_level2 import AviaryProblem -from aviary.models.multi_engine_single_aisle.multi_engine_single_aisle_data import inputs +from aviary.models.multi_engine_single_aisle.multi_engine_single_aisle_data import inputs, engine_1_inputs, engine_2_inputs from aviary.variable_info.enums import ThrottleAllocation +from aviary.subsystems.propulsion.utils import build_engine_deck # Build problem @@ -48,9 +49,14 @@ def test_multiengine_fixed(self): test_phase_info['cruise']['user_options']['throttle_allocation'] = method test_phase_info['descent']['user_options']['throttle_allocation'] = method + engine1 = build_engine_deck(engine_1_inputs)[0] + engine1.name = 'engine_1' + engine2 = build_engine_deck(engine_2_inputs)[0] + engine2.name = 'engine_2' + prob = AviaryProblem() - prob.load_inputs(inputs, test_phase_info) + prob.load_inputs(inputs, test_phase_info, engine_builders=[engine1, engine2]) prob.check_and_preprocess_inputs() prob.add_pre_mission_systems() @@ -86,9 +92,12 @@ def test_multiengine_static(self): test_phase_info['cruise']['user_options']['throttle_allocation'] = method test_phase_info['descent']['user_options']['throttle_allocation'] = method + engine1 = build_engine_deck(engine_1_inputs)[0] + engine2 = build_engine_deck(engine_2_inputs)[0] + prob = AviaryProblem() - prob.load_inputs(inputs, test_phase_info) + prob.load_inputs(inputs, test_phase_info, engine_builders=[engine1, engine2]) prob.check_and_preprocess_inputs() prob.add_pre_mission_systems() @@ -111,7 +120,7 @@ def test_multiengine_static(self): alloc_descent = prob.get_val('traj.descent.parameter_vals:throttle_allocations') assert_near_equal(alloc_climb[0], 0.5, tolerance=1e-2) - assert_near_equal(alloc_cruise[0], 0.56, tolerance=1e-2) + assert_near_equal(alloc_cruise[0], 0.64, tolerance=1e-2) assert_near_equal(alloc_descent[0], 0.999, tolerance=1e-2) @require_pyoptsparse(optimizer="SNOPT") @@ -126,7 +135,10 @@ def test_multiengine_dynamic(self): prob = AviaryProblem() - prob.load_inputs(inputs, test_phase_info) + engine1 = build_engine_deck(engine_1_inputs)[0] + engine2 = build_engine_deck(engine_2_inputs)[0] + + prob.load_inputs(inputs, test_phase_info, engine_builders=[engine1, engine2]) prob.check_and_preprocess_inputs() prob.add_pre_mission_systems() @@ -149,7 +161,7 @@ def test_multiengine_dynamic(self): alloc_descent = prob.get_val('traj.descent.controls:throttle_allocations') # Cruise is pretty constant, check exact value. - assert_near_equal(alloc_cruise[0], 0.565, tolerance=1e-2) + assert_near_equal(alloc_cruise[0], 0.646, tolerance=1e-2) # Check general trend: favors engine 1. self.assertGreater(alloc_climb[2], 0.55) diff --git a/aviary/validation_cases/validation_tests.py b/aviary/validation_cases/validation_tests.py index dbcb56d40..d7f7c6ec1 100644 --- a/aviary/validation_cases/validation_tests.py +++ b/aviary/validation_cases/validation_tests.py @@ -8,6 +8,7 @@ from aviary.utils.aviary_values import AviaryValues from aviary.utils.options import list_options as list_options_func +from aviary.subsystems.propulsion.utils import build_engine_deck from aviary.utils.preprocessors import preprocess_options from aviary.validation_cases.validation_data.flops_data.FLOPS_Test_Data import \ FLOPS_Test_Data, FLOPS_Lacking_Test_Data @@ -257,7 +258,7 @@ def flops_validation_test(prob: om.Problem, list_outputs=list_outputs) -def get_flops_data(case_name: str, keys: str = None) -> AviaryValues: +def get_flops_data(case_name: str, keys: str = None, preprocess: bool = False) -> AviaryValues: """ Returns an AviaryValues object containing input and output data for the named FLOPS validation case. @@ -271,7 +272,7 @@ def get_flops_data(case_name: str, keys: str = None) -> AviaryValues: List of variables whose values will be transferred from the validation data. The default is all variables. """ - flops_data_copy: AviaryValues = get_flops_inputs(case_name) + flops_data_copy: AviaryValues = get_flops_inputs(case_name, preprocess=preprocess) flops_data_copy.update(get_flops_outputs(case_name)) if keys is None: return flops_data_copy @@ -303,7 +304,8 @@ def get_flops_inputs(case_name: str, keys: str = None, preprocess: bool = False) flops_inputs_copy: AviaryValues = flops_data['inputs'].deepcopy() if preprocess: - preprocess_options(flops_inputs_copy) + preprocess_options(flops_inputs_copy, + engine_models=build_engine_deck(flops_inputs_copy)) if keys is None: return flops_inputs_copy keys_list = _assure_is_list(keys) diff --git a/aviary/variable_info/variable_meta_data.py b/aviary/variable_info/variable_meta_data.py index b49ca8356..410f1ebf5 100644 --- a/aviary/variable_info/variable_meta_data.py +++ b/aviary/variable_info/variable_meta_data.py @@ -1666,7 +1666,7 @@ "LEAPS1": None }, units='unitless', - types=(str, Path, None), + types=(str, Path), default_value=None, option=True, desc='filepath to data file containing engine performance tables'